From 5361a93b23c2e0d3de784b4736ea8ce8e2da813b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Mon, 27 Feb 2023 18:56:42 -0300 Subject: [PATCH 001/118] Add function that builds an R1CS with a RawR1CS --- gnark_backend_ffi/main.go | 64 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 62 insertions(+), 2 deletions(-) diff --git a/gnark_backend_ffi/main.go b/gnark_backend_ffi/main.go index 4b71d99..7cd3578 100644 --- a/gnark_backend_ffi/main.go +++ b/gnark_backend_ffi/main.go @@ -42,6 +42,67 @@ type AddTerm struct { Sum uint32 } +func buildR1CS(r RawR1CS) (*cs_bn254.R1CS, fr_bn254.Vector, fr_bn254.Vector, int, int) { + // Create R1CS. + r1cs := cs_bn254.NewR1CS(int(r.NumConstraints)) + + // Fill process RawR1CS. + nPublicVariables := 0 + nPrivateVariables := 0 + var allVariableIndices []int + var publicVariables fr_bn254.Vector + var privateVariables fr_bn254.Vector + for i, value := range r.Values { + variableName := strconv.Itoa(i) + if r.PublicInputs.Has(make([]byte, i)) { + allVariableIndices = append(allVariableIndices, r1cs.AddPublicVariable(variableName)) + publicVariables = append(publicVariables, value) + nPublicVariables++ + } else { + allVariableIndices = append(allVariableIndices, r1cs.AddSecretVariable(variableName)) + privateVariables = append(privateVariables, value) + nPrivateVariables++ + } + } + + // Generate constraints. + ONE := r1cs.AddPublicVariable("ONE") + ZERO := r1cs.AddPublicVariable("ZERO") + COEFFICIENT_ONE := r1cs.FromInterface(1) + for _, gate := range r.Gates { + var terms constraint.LinearExpression + + for _, mul_term := range gate.MulTerms { + coefficient := r1cs.FromInterface(mul_term.Coefficient) + + product := mul_term.Multiplicand * mul_term.Multiplier + productVariableName := strconv.FormatUint(uint64(product), 10) + productVariable := r1cs.AddSecretVariable(productVariableName) + + terms = append(terms, r1cs.MakeTerm(&coefficient, productVariable)) + } + + for _, add_term := range gate.AddTerms { + coefficient := r1cs.FromInterface(add_term.Coefficient) + sum := add_term.Sum + + sumVariable := allVariableIndices[sum] + + terms = append(terms, r1cs.MakeTerm(&coefficient, sumVariable)) + } + + r1cs.AddConstraint( + constraint.R1C{ + L: constraint.LinearExpression{r1cs.MakeTerm(&COEFFICIENT_ONE, ONE)}, + R: terms, + O: constraint.LinearExpression{r1cs.MakeTerm(&COEFFICIENT_ONE, ZERO)}, + }, + ) + } + + return r1cs, publicVariables, privateVariables, nPublicVariables, nPrivateVariables +} + //export ProveWithMeta func ProveWithMeta(rawR1CS string) *C.char { // Deserialize rawR1CS. @@ -51,8 +112,7 @@ func ProveWithMeta(rawR1CS string) *C.char { log.Fatal(err) } - // Create R1CS. - r1cs := cs_bn254.NewR1CS(0) + r1cs, publicVariables, privateVariables, nPublicVariables, nPrivateVariables := buildR1CS(r) // Add variables. witness, err := witness.New(r1cs.CurveID().ScalarField()) From 92c6196c4703cf1393980a3976e07944d0ae62cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Mon, 27 Feb 2023 18:57:17 -0300 Subject: [PATCH 002/118] Add function that fills the witnesses (private & public) --- gnark_backend_ffi/main.go | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/gnark_backend_ffi/main.go b/gnark_backend_ffi/main.go index 7cd3578..d0390df 100644 --- a/gnark_backend_ffi/main.go +++ b/gnark_backend_ffi/main.go @@ -103,6 +103,29 @@ func buildR1CS(r RawR1CS) (*cs_bn254.R1CS, fr_bn254.Vector, fr_bn254.Vector, int return r1cs, publicVariables, privateVariables, nPublicVariables, nPrivateVariables } +func buildWitnesses(r1cs *cs_bn254.R1CS, publicVariables fr_bn254.Vector, privateVariables fr_bn254.Vector, nPublicVariables int, nPrivateVariables int) witness.Witness { + witnessValues := make(chan any) + + go func() { + defer close(witnessValues) + for _, publicVariable := range publicVariables { + witnessValues <- publicVariable + } + for _, privateVariable := range privateVariables { + witnessValues <- privateVariable + } + }() + + witness, err := witness.New(r1cs.CurveID().ScalarField()) + if err != nil { + log.Fatal(err) + } + + witness.Fill(nPublicVariables, nPrivateVariables, witnessValues) + + return witness +} + //export ProveWithMeta func ProveWithMeta(rawR1CS string) *C.char { // Deserialize rawR1CS. @@ -114,14 +137,7 @@ func ProveWithMeta(rawR1CS string) *C.char { r1cs, publicVariables, privateVariables, nPublicVariables, nPrivateVariables := buildR1CS(r) - // Add variables. - witness, err := witness.New(r1cs.CurveID().ScalarField()) - if err != nil { - log.Fatal(err) - } - witness.Fill(0, 0, nil) - - // Add constraints. + witness := buildWitnesses(r1cs, publicVariables, privateVariables, nPublicVariables, nPrivateVariables) // Setup. pk, _, err := groth16.Setup(r1cs) From 215823ca7ca955e24b38df8e0dcf287f05bbfd7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Mon, 27 Feb 2023 18:57:27 -0300 Subject: [PATCH 003/118] Add imports --- gnark_backend_ffi/main.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gnark_backend_ffi/main.go b/gnark_backend_ffi/main.go index d0390df..8b9f2a4 100644 --- a/gnark_backend_ffi/main.go +++ b/gnark_backend_ffi/main.go @@ -6,12 +6,14 @@ import ( "encoding/json" "fmt" "log" + "strconv" "github.com/recoilme/btreeset" fr_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/fr" "github.com/consensys/gnark/backend/groth16" "github.com/consensys/gnark/backend/witness" + "github.com/consensys/gnark/constraint" cs_bn254 "github.com/consensys/gnark/constraint/bn254" ) From 63b3b6a40530b76b42dbff2f8ac7cf4d464f495f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Mon, 27 Feb 2023 18:58:04 -0300 Subject: [PATCH 004/118] Update main (for testing) --- gnark_backend_ffi/main.go | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/gnark_backend_ffi/main.go b/gnark_backend_ffi/main.go index 8b9f2a4..d993352 100644 --- a/gnark_backend_ffi/main.go +++ b/gnark_backend_ffi/main.go @@ -314,9 +314,34 @@ func Preprocess(rawR1CS string) (*C.char, *C.char) { } func main() { - rawR1CS := `{"gates":[],"public_inputs":[],"values":[],"num_variables":1}` + // rawR1CS := `{"gates":[{"mul_terms":[["0100000000000000000000000000000000000000000000000000000000000000",1],["000000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430",2],["000000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430",3]],"add_terms":[["0100000000000000000000000000000000000000000000000000000000000000",1],["000000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430",2],["000000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430",3]],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000"},{"mul_terms":[["000000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430",5]],"add_terms":[["000000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430",5]],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000"},{"mul_terms":[["000000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430",3]],"add_terms":[["000000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430",3]],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000"},{"mul_terms":[["000000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430",5]],"add_terms":[["000000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430",5]],"constant_term":"0100000000000000000000000000000000000000000000000000000000000000"}],"public_inputs":[2],"values":["0100000000000000000000000000000000000000000000000000000000000000","0200000000000000000000000000000000000000000000000000000000000000","0000000000000000000000000000000000000000000000000000000000000000","0000000000000000000000000000000000000000000000000000000000000000","0000000000000000000000000000000000000000000000000000000000000000","0000000000000000000000000000000000000000000000000000000000000000"],"num_variables":7}` + rawR1CS := `{"gates":[{"mul_terms":[["0100000000000000000000000000000000000000000000000000000000000000",1],["000000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430",2],["000000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430",3]],"add_terms":[["0100000000000000000000000000000000000000000000000000000000000000",1],["000000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430",2],["000000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430",3]],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000"},{"mul_terms":[["000000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430",5]],"add_terms":[["000000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430",5]],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000"},{"mul_terms":[["000000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430",3]],"add_terms":[["000000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430",3]],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000"},{"mul_terms":[["000000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430",5]],"add_terms":[["000000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430",5]],"constant_term":"0100000000000000000000000000000000000000000000000000000000000000"}],"public_inputs":[2],"values":[[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]],"num_variables":7}` - proof := ProveWithMeta(rawR1CS) + // Deserialize rawR1CS. + var r RawR1CS + err := json.Unmarshal([]byte(rawR1CS), &r) + if err != nil { + log.Fatal(err) + } - fmt.Println("Proof: ", proof) + r1cs, publicVariables, privateVariables, nPublicVariables, nPrivateVariables := buildR1CS(r) + + fmt.Println("R1CS: ", r1cs) + fmt.Println("Public Variables: ", publicVariables) + fmt.Println("Private Variables: ", privateVariables) + fmt.Println("Number of Public Variables: ", nPublicVariables) + fmt.Println("Number of Private Variables: ", nPrivateVariables) + + // get the constraints + constraints, resolver := r1cs.GetConstraints() + + for _, r1c := range constraints { + fmt.Println(r1c.String(resolver)) + // for more granularity use constraint.NewStringBuilder(resolver) that embeds a string.Builder + // and has WriteLinearExpression and WriteTerm methods. + } + + // proof := ProveWithMeta(rawR1CS) + + // fmt.Println("Proof: ", proof) } From 1fd9fdfd99ad496eaf683479ac749000d4b57b60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Mon, 27 Feb 2023 18:58:10 -0300 Subject: [PATCH 005/118] Remove print --- gnark_backend_ffi/main.go | 1 - 1 file changed, 1 deletion(-) diff --git a/gnark_backend_ffi/main.go b/gnark_backend_ffi/main.go index d993352..ff23ac0 100644 --- a/gnark_backend_ffi/main.go +++ b/gnark_backend_ffi/main.go @@ -152,7 +152,6 @@ func ProveWithMeta(rawR1CS string) *C.char { if err != nil { log.Fatal(err) } - fmt.Println("Proof: ", proof) // Serialize proof var serialized_proof bytes.Buffer From a1d1019c99b4d0330802f408b615bb21b89686fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Tue, 28 Feb 2023 15:59:17 -0300 Subject: [PATCH 006/118] Add test functions --- gnark_backend_ffi/main.go | 67 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/gnark_backend_ffi/main.go b/gnark_backend_ffi/main.go index ff23ac0..5b9b923 100644 --- a/gnark_backend_ffi/main.go +++ b/gnark_backend_ffi/main.go @@ -312,6 +312,73 @@ func Preprocess(rawR1CS string) (*C.char, *C.char) { return C.CString(pk_string), C.CString(vk_string) } +//export TestFeltDeserialization +func TestFeltDeserialization(encoded_felt string) *C.char { + // Decode the received felt. + decoded_felt, err := hex.DecodeString(encoded_felt) + if err != nil { + log.Fatal(err) + } + + // Deserialize the decoded felt. + var deserialized_felt fr_bn254.Element + deserialized_felt.SetBytes(decoded_felt) + fmt.Printf("| GO |\n%v\n", deserialized_felt) + + // Serialize the felt. + serialized_felt := deserialized_felt.Bytes() + + // Encode the serialized felt. + serialized_felt_string := hex.EncodeToString(serialized_felt[:]) + + return C.CString(serialized_felt_string) +} + +//export TestFeltVecDeserialization +func TestFeltVecDeserialization(encoded_felt_vec string) *C.char { + return C.CString("unimplemented") +} + +//export TestUSizeDeserialization +func TestUSizeDeserialization(encoded_usize string) *C.char { + return C.CString("unimplemented") +} + +//export TestMulTermDeserialization +func TestMulTermDeserialization(encoded_usize string) *C.char { + return C.CString("unimplemented") +} + +//export TestMulTermsDeserialization +func TestMulTermsDeserialization(encoded_usize string) *C.char { + return C.CString("unimplemented") +} + +//export TestAddTermDeserialization +func TestAddTermDeserialization(encoded_usize string) *C.char { + return C.CString("unimplemented") +} + +//export TestAddTermsDeserialization +func TestAddTermsDeserialization(encoded_usize string) *C.char { + return C.CString("unimplemented") +} + +//export TestRawGateDeserialization +func TestRawGateDeserialization(encoded_usize string) *C.char { + return C.CString("unimplemented") +} + +//export TestRawGateVecDeserialization +func TestRawGateVecDeserialization(encoded_usize string) *C.char { + return C.CString("unimplemented") +} + +//export TestRawR1CSDeserialization +func TestRawR1CSDeserialization(encoded_usize string) *C.char { + return C.CString("unimplemented") +} + func main() { // rawR1CS := `{"gates":[{"mul_terms":[["0100000000000000000000000000000000000000000000000000000000000000",1],["000000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430",2],["000000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430",3]],"add_terms":[["0100000000000000000000000000000000000000000000000000000000000000",1],["000000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430",2],["000000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430",3]],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000"},{"mul_terms":[["000000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430",5]],"add_terms":[["000000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430",5]],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000"},{"mul_terms":[["000000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430",3]],"add_terms":[["000000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430",3]],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000"},{"mul_terms":[["000000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430",5]],"add_terms":[["000000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430",5]],"constant_term":"0100000000000000000000000000000000000000000000000000000000000000"}],"public_inputs":[2],"values":["0100000000000000000000000000000000000000000000000000000000000000","0200000000000000000000000000000000000000000000000000000000000000","0000000000000000000000000000000000000000000000000000000000000000","0000000000000000000000000000000000000000000000000000000000000000","0000000000000000000000000000000000000000000000000000000000000000","0000000000000000000000000000000000000000000000000000000000000000"],"num_variables":7}` rawR1CS := `{"gates":[{"mul_terms":[["0100000000000000000000000000000000000000000000000000000000000000",1],["000000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430",2],["000000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430",3]],"add_terms":[["0100000000000000000000000000000000000000000000000000000000000000",1],["000000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430",2],["000000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430",3]],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000"},{"mul_terms":[["000000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430",5]],"add_terms":[["000000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430",5]],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000"},{"mul_terms":[["000000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430",3]],"add_terms":[["000000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430",3]],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000"},{"mul_terms":[["000000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430",5]],"add_terms":[["000000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430",5]],"constant_term":"0100000000000000000000000000000000000000000000000000000000000000"}],"public_inputs":[2],"values":[[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]],"num_variables":7}` From 27077335faf23ffc77b4b8ffb922ec6af6b40c47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Tue, 28 Feb 2023 15:59:29 -0300 Subject: [PATCH 007/118] Add hex dependency --- gnark_backend_ffi/main.go | 1 + 1 file changed, 1 insertion(+) diff --git a/gnark_backend_ffi/main.go b/gnark_backend_ffi/main.go index 5b9b923..d9a2ef2 100644 --- a/gnark_backend_ffi/main.go +++ b/gnark_backend_ffi/main.go @@ -3,6 +3,7 @@ package main import "C" import ( "bytes" + "encoding/hex" "encoding/json" "fmt" "log" From 249a945383bc233addf7f968a2a6fec4c5369c26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Tue, 28 Feb 2023 17:17:18 -0300 Subject: [PATCH 008/118] Update naming --- gnark_backend_ffi/main.go | 40 +++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/gnark_backend_ffi/main.go b/gnark_backend_ffi/main.go index d9a2ef2..fb5d31d 100644 --- a/gnark_backend_ffi/main.go +++ b/gnark_backend_ffi/main.go @@ -313,8 +313,8 @@ func Preprocess(rawR1CS string) (*C.char, *C.char) { return C.CString(pk_string), C.CString(vk_string) } -//export TestFeltDeserialization -func TestFeltDeserialization(encoded_felt string) *C.char { +//export TestFeltSerialization +func TestFeltSerialization(encoded_felt string) *C.char { // Decode the received felt. decoded_felt, err := hex.DecodeString(encoded_felt) if err != nil { @@ -335,48 +335,48 @@ func TestFeltDeserialization(encoded_felt string) *C.char { return C.CString(serialized_felt_string) } -//export TestFeltVecDeserialization -func TestFeltVecDeserialization(encoded_felt_vec string) *C.char { +//export TestFeltVecSerialization +func TestFeltsSerialization(encoded_felt_vec string) *C.char { return C.CString("unimplemented") } -//export TestUSizeDeserialization -func TestUSizeDeserialization(encoded_usize string) *C.char { +//export TestUSizeSerialization +func TestUSizeSerialization(encoded_usize string) *C.char { return C.CString("unimplemented") } -//export TestMulTermDeserialization -func TestMulTermDeserialization(encoded_usize string) *C.char { +//export TestMulTermSerialization +func TestMulTermSerialization(encoded_usize string) *C.char { return C.CString("unimplemented") } -//export TestMulTermsDeserialization -func TestMulTermsDeserialization(encoded_usize string) *C.char { +//export TestMulTermsSerialization +func TestMulTermsSerialization(encoded_usize string) *C.char { return C.CString("unimplemented") } -//export TestAddTermDeserialization -func TestAddTermDeserialization(encoded_usize string) *C.char { +//export TestAddTermSerialization +func TestAddTermSerialization(encoded_usize string) *C.char { return C.CString("unimplemented") } -//export TestAddTermsDeserialization -func TestAddTermsDeserialization(encoded_usize string) *C.char { +//export TestAddTermsSerialization +func TestAddTermsSerialization(encoded_usize string) *C.char { return C.CString("unimplemented") } -//export TestRawGateDeserialization -func TestRawGateDeserialization(encoded_usize string) *C.char { +//export TestRawGateSerialization +func TestRawGateSerialization(encoded_usize string) *C.char { return C.CString("unimplemented") } -//export TestRawGateVecDeserialization -func TestRawGateVecDeserialization(encoded_usize string) *C.char { +//export TestRawGateVecSerialization +func TestRawGatesSerialization(encoded_usize string) *C.char { return C.CString("unimplemented") } -//export TestRawR1CSDeserialization -func TestRawR1CSDeserialization(encoded_usize string) *C.char { +//export TestRawR1CSSerialization +func TestRawR1CSSerialization(encoded_usize string) *C.char { return C.CString("unimplemented") } From 96b0029eb8851e08fbf8a058bf20740c99eec565 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Tue, 28 Feb 2023 17:17:37 -0300 Subject: [PATCH 009/118] Add `rand` as a dev-dependencie --- Cargo.lock | 5 +++++ Cargo.toml | 3 +++ 2 files changed, 8 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 1685955..b2f41ee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -947,6 +947,7 @@ dependencies = [ "cfg-if", "hex", "hex-literal", + "rand", "serde", "serde_json", "thiserror", @@ -1115,6 +1116,7 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ + "libc", "rand_chacha", "rand_core 0.6.4", ] @@ -1140,6 +1142,9 @@ name = "rand_core" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] [[package]] name = "rayon" diff --git a/Cargo.toml b/Cargo.toml index 94c028c..2e81d85 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,9 @@ hex = "0.4" hex-literal = "0.3.4" thiserror = "1.0" +[dev-dependencies] +rand = "0.8" + [profile.test] opt-level = 3 lto = "thin" From 9497392f6c3d461988b6b3bbdaa58ff012b85760 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Tue, 28 Feb 2023 17:34:19 -0300 Subject: [PATCH 010/118] Fix parameter naming --- gnark_backend_ffi/main.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/gnark_backend_ffi/main.go b/gnark_backend_ffi/main.go index fb5d31d..9a1099d 100644 --- a/gnark_backend_ffi/main.go +++ b/gnark_backend_ffi/main.go @@ -341,42 +341,42 @@ func TestFeltsSerialization(encoded_felt_vec string) *C.char { } //export TestUSizeSerialization -func TestUSizeSerialization(encoded_usize string) *C.char { +func TestUSizeSerialization(encodedUsize string) *C.char { return C.CString("unimplemented") } //export TestMulTermSerialization -func TestMulTermSerialization(encoded_usize string) *C.char { +func TestMulTermSerialization(encodedMulTerm string) *C.char { return C.CString("unimplemented") } //export TestMulTermsSerialization -func TestMulTermsSerialization(encoded_usize string) *C.char { +func TestMulTermsSerialization(encodedMulTerms string) *C.char { return C.CString("unimplemented") } //export TestAddTermSerialization -func TestAddTermSerialization(encoded_usize string) *C.char { +func TestAddTermSerialization(encodedAddTerm string) *C.char { return C.CString("unimplemented") } //export TestAddTermsSerialization -func TestAddTermsSerialization(encoded_usize string) *C.char { +func TestAddTermsSerialization(encodedAddTerms string) *C.char { return C.CString("unimplemented") } //export TestRawGateSerialization -func TestRawGateSerialization(encoded_usize string) *C.char { +func TestRawGateSerialization(encodedRawGate string) *C.char { return C.CString("unimplemented") } //export TestRawGateVecSerialization -func TestRawGatesSerialization(encoded_usize string) *C.char { +func TestRawGatesSerialization(encodedRawGates string) *C.char { return C.CString("unimplemented") } //export TestRawR1CSSerialization -func TestRawR1CSSerialization(encoded_usize string) *C.char { +func TestRawR1CSSerialization(encodedR1CS string) *C.char { return C.CString("unimplemented") } From 4aa40a26dc82c512c544ab4eb6b898c693f6d4e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Tue, 28 Feb 2023 17:34:55 -0300 Subject: [PATCH 011/118] Fix export name --- gnark_backend_ffi/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gnark_backend_ffi/main.go b/gnark_backend_ffi/main.go index 9a1099d..d364816 100644 --- a/gnark_backend_ffi/main.go +++ b/gnark_backend_ffi/main.go @@ -370,7 +370,7 @@ func TestRawGateSerialization(encodedRawGate string) *C.char { return C.CString("unimplemented") } -//export TestRawGateVecSerialization +//export TestRawGatesSerialization func TestRawGatesSerialization(encodedRawGates string) *C.char { return C.CString("unimplemented") } From ce394350d824555c9c70601bb27bdd8233f3cfe6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Tue, 28 Feb 2023 18:13:21 -0300 Subject: [PATCH 012/118] Implement `TestFeltsSerialization` --- gnark_backend_ffi/main.go | 49 ++++++++++++++++++++++++++++++--------- 1 file changed, 38 insertions(+), 11 deletions(-) diff --git a/gnark_backend_ffi/main.go b/gnark_backend_ffi/main.go index d364816..e7e4880 100644 --- a/gnark_backend_ffi/main.go +++ b/gnark_backend_ffi/main.go @@ -314,30 +314,57 @@ func Preprocess(rawR1CS string) (*C.char, *C.char) { } //export TestFeltSerialization -func TestFeltSerialization(encoded_felt string) *C.char { +func TestFeltSerialization(encodedFelt string) *C.char { // Decode the received felt. - decoded_felt, err := hex.DecodeString(encoded_felt) + decodedFelt, err := hex.DecodeString(encodedFelt) if err != nil { log.Fatal(err) } // Deserialize the decoded felt. - var deserialized_felt fr_bn254.Element - deserialized_felt.SetBytes(decoded_felt) - fmt.Printf("| GO |\n%v\n", deserialized_felt) + var deserializedFelt fr_bn254.Element + deserializedFelt.SetBytes(decodedFelt) + fmt.Printf("| GO |\n%v\n", deserializedFelt) // Serialize the felt. - serialized_felt := deserialized_felt.Bytes() + serializedFelt := deserializedFelt.Bytes() // Encode the serialized felt. - serialized_felt_string := hex.EncodeToString(serialized_felt[:]) + serializedFeltString := hex.EncodeToString(serializedFelt[:]) - return C.CString(serialized_felt_string) + return C.CString(serializedFeltString) } -//export TestFeltVecSerialization -func TestFeltsSerialization(encoded_felt_vec string) *C.char { - return C.CString("unimplemented") +//export TestFeltsSerialization +func TestFeltsSerialization(encodedFelts string) *C.char { + // Decode the received felts. + decodedFelts, err := hex.DecodeString(encodedFelts) + if err != nil { + log.Fatal(err) + } + + // Unpack and deserialize the decoded felts. + var deserializedFelts fr_bn254.Vector + // Felts are 32 bytes long. + feltsToDeserialize := len(decodedFelts) / 32 + for i := 0; i < feltsToDeserialize; i++ { + var deserializedFelt fr_bn254.Element + deserializedFelt.SetBytes(decodedFelts[i*32 : (i+1)*32]) + fmt.Printf("| GO |\n%v\n", deserializedFelt) + deserializedFelts = append(deserializedFelts, deserializedFelt) + } + + // Serialize the felt. + var serializedFelts []byte + for _, felt := range deserializedFelts { + serializedFelt := felt.Bytes() + serializedFelts = append(serializedFelts, serializedFelt[:]...) + } + + // Encode the serialized felt. + serializedFeltsString := hex.EncodeToString(serializedFelts[:]) + + return C.CString(serializedFeltsString) } //export TestUSizeSerialization From 2704c9ff1bac38b10f939515fe74e30a8f81f577 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Tue, 28 Feb 2023 18:49:11 -0300 Subject: [PATCH 013/118] Implement `TestU64Serialization` --- gnark_backend_ffi/main.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/gnark_backend_ffi/main.go b/gnark_backend_ffi/main.go index e7e4880..05a0348 100644 --- a/gnark_backend_ffi/main.go +++ b/gnark_backend_ffi/main.go @@ -367,9 +367,10 @@ func TestFeltsSerialization(encodedFelts string) *C.char { return C.CString(serializedFeltsString) } -//export TestUSizeSerialization -func TestUSizeSerialization(encodedUsize string) *C.char { - return C.CString("unimplemented") +//export TestU64Serialization +func TestU64Serialization(number uint64) uint64 { + fmt.Println(number) + return number } //export TestMulTermSerialization From ec22dfb8993bac3a5fb4b77a75c575a062d0d07c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Tue, 28 Feb 2023 18:52:32 -0300 Subject: [PATCH 014/118] Expose structs and modules (for testing) --- src/gnark_backend_glue/mod.rs | 6 +++--- src/lib.rs | 8 ++++++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/gnark_backend_glue/mod.rs b/src/gnark_backend_glue/mod.rs index 27d8b6d..4fe8ddb 100644 --- a/src/gnark_backend_glue/mod.rs +++ b/src/gnark_backend_glue/mod.rs @@ -4,9 +4,9 @@ use std::os::raw::{c_char, c_uchar}; use acvm::{acir::circuit::Circuit, FieldElement}; mod acir_to_r1cs; +pub use acir_to_r1cs::{RawR1CS, RawGate}; mod errors; mod serialize; -use crate::gnark_backend_glue::acir_to_r1cs::RawR1CS; use crate::gnark_backend_glue::errors::GnarkBackendError; // Arkworks's types are generic for `Field` but Noir's types are concrete and @@ -44,7 +44,7 @@ extern "C" { #[derive(Debug)] #[repr(C)] -struct GoString { +pub struct GoString { ptr: *const c_char, length: usize, } @@ -60,7 +60,7 @@ impl TryFrom<&CString> for GoString { } #[repr(C)] -struct KeyPair { +pub struct KeyPair { proving_key: *const c_char, verifying_key: *const c_char, } diff --git a/src/lib.rs b/src/lib.rs index a6d50ce..5ec77ac 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,10 @@ -mod acvm; +// TODO: This is exposed for testing only, we should find a way to not expose it for +// the users. +pub mod acvm; pub mod acvm_interop; pub use acvm_interop::Gnark; -mod gnark_backend_glue; +// TODO: This is exposed for testing only, we should find a way to not expose it for +// the users. +pub mod gnark_backend_glue; From e646012e771a601b284ade55dc3e4ddeb999d221 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Tue, 28 Feb 2023 18:53:10 -0300 Subject: [PATCH 015/118] Add tests for felt, felt vector and u64 serialization Integrated with Go --- tests/serialization_tests.rs | 122 +++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 tests/serialization_tests.rs diff --git a/tests/serialization_tests.rs b/tests/serialization_tests.rs new file mode 100644 index 0000000..971633f --- /dev/null +++ b/tests/serialization_tests.rs @@ -0,0 +1,122 @@ +use noir_backend_using_gnark::gnark_backend_glue; +use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; +use std::ffi; + +extern "C" { + fn TestFeltSerialization(felt: gnark_backend_glue::GoString) -> *const ffi::c_char; + fn TestFeltsSerialization(felts: gnark_backend_glue::GoString) -> *const ffi::c_char; + fn TestU64Serialization(unsigned_integer: ffi::c_ulong) -> ffi::c_ulong; + fn TestMulTermSerialization(mul_term: gnark_backend_glue::GoString) -> *const ffi::c_char; + fn TestMulTermsSerialization(mul_terms: gnark_backend_glue::GoString) -> *const ffi::c_char; + fn TestAddTermSerialization(add_term: gnark_backend_glue::GoString) -> *const ffi::c_char; + fn TestAddTermsSerialization(add_terms: gnark_backend_glue::GoString) -> *const ffi::c_char; + fn TestRawGateSerialization(raw_gate: gnark_backend_glue::GoString) -> *const ffi::c_char; + fn TestRawGatesSerialization(raw_gates: gnark_backend_glue::GoString) -> *const ffi::c_char; + fn TestRawR1CSSerialization(raw_r1cs: gnark_backend_glue::GoString) -> *const ffi::c_char; +} + +fn serialize_felt(felt: &gnark_backend_glue::Fr) -> Vec { + let mut serialized_felt = Vec::new(); + felt.serialize_uncompressed(&mut serialized_felt).unwrap(); + // Turn little-endian to big-endian. + serialized_felt.reverse(); + serialized_felt +} + +fn deserialize_felt(felt_bytes: &[u8]) -> gnark_backend_glue::Fr { + let mut decoded = hex::decode(felt_bytes).unwrap(); + // Turn big-endian to little-endian. + decoded.reverse(); + gnark_backend_glue::Fr::deserialize_uncompressed(decoded.as_slice()).unwrap() +} + +fn serialize_felts(felts: &[gnark_backend_glue::Fr]) -> Vec { + felts + .iter() + .flat_map(serialize_felt) + .collect() +} + +#[test] +fn test_felt_serialization() { + // Sample a random felt. + let felt: gnark_backend_glue::Fr = rand::random(); + + println!("| RUST |\n{:?}", felt.0.0); + + // Serialize the random felt. + let serialized_felt = serialize_felt(&felt); + + // Encode the felt. + let encoded_felt = hex::encode(serialized_felt); + + // Prepare ping for Go. + let pre_ping = ffi::CString::new(encoded_felt).unwrap(); + let ping = gnark_backend_glue::GoString::try_from(&pre_ping).unwrap(); + + // Send and receive pong from Go. + let pong: *const ffi::c_char = unsafe { TestFeltSerialization(ping) }; + + // Prepare pong for Rust. + let go_pre_serialized_felt = unsafe { ffi::CStr::from_ptr(pong) }; + let go_serialized_felt = go_pre_serialized_felt.to_str().unwrap().as_bytes(); + + let go_felt = deserialize_felt(go_serialized_felt); + + assert_eq!(felt, go_felt) +} + +#[test] +fn test_felts_serialization() { + // Sample a random felt. + let felts: [gnark_backend_glue::Fr; 2] = rand::random(); + + println!("| RUST |\n{:?}", felts.iter().map(|felt| felt.0.0).collect::>()); + + // Serialize the random felts and pack them into one byte array. + let serialized_felts = serialize_felts(&felts); + + // Encode the packed felts. + let encoded_felts = hex::encode(serialized_felts); + + // Prepare ping for Go. + let pre_ping = ffi::CString::new(encoded_felts).unwrap(); + let ping = gnark_backend_glue::GoString::try_from(&pre_ping).unwrap(); + + // Send and receive pong from Go. + let pong: *const ffi::c_char = unsafe { TestFeltsSerialization(ping) }; + + // Prepare pong for Rust. + let go_pre_serialized_felt = unsafe { ffi::CStr::from_ptr(pong) }; + let go_serialized_felt = go_pre_serialized_felt.to_str().unwrap().as_bytes(); + + // Decode and deserialize the unpacked felts. + let go_felts: Vec = hex::decode(go_serialized_felt) + .unwrap() + .chunks_mut(32) + .map(|go_decoded_felt| { + // Turn big-endian to little-endian. + go_decoded_felt.reverse(); + // Here I reference after dereference because I had a mutable reference and I need a non-mutable one. + let felt: gnark_backend_glue::Fr = CanonicalDeserialize::deserialize_uncompressed(&*go_decoded_felt).unwrap(); + felt + }) + .collect(); + + assert_eq!(felts.to_vec(), go_felts) +} + +#[test] +fn test_u64_serialization() { + // Sample a random felt. + let number: u64 = rand::random(); + + println!("| RUST |\n{:?}", number); + + // Prepare ping for Go. + let ping = number; + // Send and receive pong from Go. + let pong = unsafe { TestU64Serialization(ping) }; + + assert_eq!(number, pong) +} From 5f98d33b501e83911dc5cfbe86cee1df7d882d18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Tue, 28 Feb 2023 18:53:32 -0300 Subject: [PATCH 016/118] cargo fmt --- src/gnark_backend_glue/mod.rs | 2 +- tests/serialization_tests.rs | 17 +++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/gnark_backend_glue/mod.rs b/src/gnark_backend_glue/mod.rs index 4fe8ddb..6045d90 100644 --- a/src/gnark_backend_glue/mod.rs +++ b/src/gnark_backend_glue/mod.rs @@ -4,7 +4,7 @@ use std::os::raw::{c_char, c_uchar}; use acvm::{acir::circuit::Circuit, FieldElement}; mod acir_to_r1cs; -pub use acir_to_r1cs::{RawR1CS, RawGate}; +pub use acir_to_r1cs::{RawGate, RawR1CS}; mod errors; mod serialize; use crate::gnark_backend_glue::errors::GnarkBackendError; diff --git a/tests/serialization_tests.rs b/tests/serialization_tests.rs index 971633f..6dbf60c 100644 --- a/tests/serialization_tests.rs +++ b/tests/serialization_tests.rs @@ -1,5 +1,5 @@ -use noir_backend_using_gnark::gnark_backend_glue; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; +use noir_backend_using_gnark::gnark_backend_glue; use std::ffi; extern "C" { @@ -31,10 +31,7 @@ fn deserialize_felt(felt_bytes: &[u8]) -> gnark_backend_glue::Fr { } fn serialize_felts(felts: &[gnark_backend_glue::Fr]) -> Vec { - felts - .iter() - .flat_map(serialize_felt) - .collect() + felts.iter().flat_map(serialize_felt).collect() } #[test] @@ -42,7 +39,7 @@ fn test_felt_serialization() { // Sample a random felt. let felt: gnark_backend_glue::Fr = rand::random(); - println!("| RUST |\n{:?}", felt.0.0); + println!("| RUST |\n{:?}", felt.0 .0); // Serialize the random felt. let serialized_felt = serialize_felt(&felt); @@ -71,7 +68,10 @@ fn test_felts_serialization() { // Sample a random felt. let felts: [gnark_backend_glue::Fr; 2] = rand::random(); - println!("| RUST |\n{:?}", felts.iter().map(|felt| felt.0.0).collect::>()); + println!( + "| RUST |\n{:?}", + felts.iter().map(|felt| felt.0 .0).collect::>() + ); // Serialize the random felts and pack them into one byte array. let serialized_felts = serialize_felts(&felts); @@ -98,7 +98,8 @@ fn test_felts_serialization() { // Turn big-endian to little-endian. go_decoded_felt.reverse(); // Here I reference after dereference because I had a mutable reference and I need a non-mutable one. - let felt: gnark_backend_glue::Fr = CanonicalDeserialize::deserialize_uncompressed(&*go_decoded_felt).unwrap(); + let felt: gnark_backend_glue::Fr = + CanonicalDeserialize::deserialize_uncompressed(&*go_decoded_felt).unwrap(); felt }) .collect(); From 879d13b2d47a9776c922ef64db04de673a959f2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Wed, 1 Mar 2023 10:08:12 -0300 Subject: [PATCH 017/118] Fix imports --- src/gnark_backend_wrapper/groth16/mod.rs | 6 ++- tests/serialization_tests.rs | 56 +++++++++++++++--------- 2 files changed, 40 insertions(+), 22 deletions(-) diff --git a/src/gnark_backend_wrapper/groth16/mod.rs b/src/gnark_backend_wrapper/groth16/mod.rs index 6045d90..f051f89 100644 --- a/src/gnark_backend_wrapper/groth16/mod.rs +++ b/src/gnark_backend_wrapper/groth16/mod.rs @@ -1,13 +1,15 @@ +use acvm::{acir::circuit::Circuit, FieldElement}; use std::ffi::{CStr, CString}; use std::num::TryFromIntError; use std::os::raw::{c_char, c_uchar}; -use acvm::{acir::circuit::Circuit, FieldElement}; mod acir_to_r1cs; pub use acir_to_r1cs::{RawGate, RawR1CS}; + mod errors; +use errors::GnarkBackendError; + mod serialize; -use crate::gnark_backend_glue::errors::GnarkBackendError; // Arkworks's types are generic for `Field` but Noir's types are concrete and // its value depends on the feature flag. diff --git a/tests/serialization_tests.rs b/tests/serialization_tests.rs index 6dbf60c..c9913ba 100644 --- a/tests/serialization_tests.rs +++ b/tests/serialization_tests.rs @@ -1,21 +1,37 @@ use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; -use noir_backend_using_gnark::gnark_backend_glue; +use noir_backend_using_gnark::gnark_backend_wrapper; use std::ffi; extern "C" { - fn TestFeltSerialization(felt: gnark_backend_glue::GoString) -> *const ffi::c_char; - fn TestFeltsSerialization(felts: gnark_backend_glue::GoString) -> *const ffi::c_char; + fn TestFeltSerialization(felt: gnark_backend_wrapper::groth16::GoString) -> *const ffi::c_char; + fn TestFeltsSerialization( + felts: gnark_backend_wrapper::groth16::GoString, + ) -> *const ffi::c_char; fn TestU64Serialization(unsigned_integer: ffi::c_ulong) -> ffi::c_ulong; - fn TestMulTermSerialization(mul_term: gnark_backend_glue::GoString) -> *const ffi::c_char; - fn TestMulTermsSerialization(mul_terms: gnark_backend_glue::GoString) -> *const ffi::c_char; - fn TestAddTermSerialization(add_term: gnark_backend_glue::GoString) -> *const ffi::c_char; - fn TestAddTermsSerialization(add_terms: gnark_backend_glue::GoString) -> *const ffi::c_char; - fn TestRawGateSerialization(raw_gate: gnark_backend_glue::GoString) -> *const ffi::c_char; - fn TestRawGatesSerialization(raw_gates: gnark_backend_glue::GoString) -> *const ffi::c_char; - fn TestRawR1CSSerialization(raw_r1cs: gnark_backend_glue::GoString) -> *const ffi::c_char; + fn TestMulTermSerialization( + mul_term: gnark_backend_wrapper::groth16::GoString, + ) -> *const ffi::c_char; + fn TestMulTermsSerialization( + mul_terms: gnark_backend_wrapper::groth16::GoString, + ) -> *const ffi::c_char; + fn TestAddTermSerialization( + add_term: gnark_backend_wrapper::groth16::GoString, + ) -> *const ffi::c_char; + fn TestAddTermsSerialization( + add_terms: gnark_backend_wrapper::groth16::GoString, + ) -> *const ffi::c_char; + fn TestRawGateSerialization( + raw_gate: gnark_backend_wrapper::groth16::GoString, + ) -> *const ffi::c_char; + fn TestRawGatesSerialization( + raw_gates: gnark_backend_wrapper::groth16::GoString, + ) -> *const ffi::c_char; + fn TestRawR1CSSerialization( + raw_r1cs: gnark_backend_wrapper::groth16::GoString, + ) -> *const ffi::c_char; } -fn serialize_felt(felt: &gnark_backend_glue::Fr) -> Vec { +fn serialize_felt(felt: &gnark_backend_wrapper::groth16::Fr) -> Vec { let mut serialized_felt = Vec::new(); felt.serialize_uncompressed(&mut serialized_felt).unwrap(); // Turn little-endian to big-endian. @@ -23,21 +39,21 @@ fn serialize_felt(felt: &gnark_backend_glue::Fr) -> Vec { serialized_felt } -fn deserialize_felt(felt_bytes: &[u8]) -> gnark_backend_glue::Fr { +fn deserialize_felt(felt_bytes: &[u8]) -> gnark_backend_wrapper::groth16::Fr { let mut decoded = hex::decode(felt_bytes).unwrap(); // Turn big-endian to little-endian. decoded.reverse(); - gnark_backend_glue::Fr::deserialize_uncompressed(decoded.as_slice()).unwrap() + gnark_backend_wrapper::groth16::Fr::deserialize_uncompressed(decoded.as_slice()).unwrap() } -fn serialize_felts(felts: &[gnark_backend_glue::Fr]) -> Vec { +fn serialize_felts(felts: &[gnark_backend_wrapper::groth16::Fr]) -> Vec { felts.iter().flat_map(serialize_felt).collect() } #[test] fn test_felt_serialization() { // Sample a random felt. - let felt: gnark_backend_glue::Fr = rand::random(); + let felt: gnark_backend_wrapper::groth16::Fr = rand::random(); println!("| RUST |\n{:?}", felt.0 .0); @@ -49,7 +65,7 @@ fn test_felt_serialization() { // Prepare ping for Go. let pre_ping = ffi::CString::new(encoded_felt).unwrap(); - let ping = gnark_backend_glue::GoString::try_from(&pre_ping).unwrap(); + let ping = gnark_backend_wrapper::groth16::GoString::try_from(&pre_ping).unwrap(); // Send and receive pong from Go. let pong: *const ffi::c_char = unsafe { TestFeltSerialization(ping) }; @@ -66,7 +82,7 @@ fn test_felt_serialization() { #[test] fn test_felts_serialization() { // Sample a random felt. - let felts: [gnark_backend_glue::Fr; 2] = rand::random(); + let felts: [gnark_backend_wrapper::groth16::Fr; 2] = rand::random(); println!( "| RUST |\n{:?}", @@ -81,7 +97,7 @@ fn test_felts_serialization() { // Prepare ping for Go. let pre_ping = ffi::CString::new(encoded_felts).unwrap(); - let ping = gnark_backend_glue::GoString::try_from(&pre_ping).unwrap(); + let ping = gnark_backend_wrapper::groth16::GoString::try_from(&pre_ping).unwrap(); // Send and receive pong from Go. let pong: *const ffi::c_char = unsafe { TestFeltsSerialization(ping) }; @@ -91,14 +107,14 @@ fn test_felts_serialization() { let go_serialized_felt = go_pre_serialized_felt.to_str().unwrap().as_bytes(); // Decode and deserialize the unpacked felts. - let go_felts: Vec = hex::decode(go_serialized_felt) + let go_felts: Vec = hex::decode(go_serialized_felt) .unwrap() .chunks_mut(32) .map(|go_decoded_felt| { // Turn big-endian to little-endian. go_decoded_felt.reverse(); // Here I reference after dereference because I had a mutable reference and I need a non-mutable one. - let felt: gnark_backend_glue::Fr = + let felt: gnark_backend_wrapper::groth16::Fr = CanonicalDeserialize::deserialize_uncompressed(&*go_decoded_felt).unwrap(); felt }) From c8c58c297de3326577880febf8a9a2fb840ffaef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Wed, 1 Mar 2023 10:22:18 -0300 Subject: [PATCH 018/118] Fix comment --- tests/serialization_tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/serialization_tests.rs b/tests/serialization_tests.rs index c9913ba..7d29b95 100644 --- a/tests/serialization_tests.rs +++ b/tests/serialization_tests.rs @@ -125,7 +125,7 @@ fn test_felts_serialization() { #[test] fn test_u64_serialization() { - // Sample a random felt. + // Sample a random number. let number: u64 = rand::random(); println!("| RUST |\n{:?}", number); From 081eb7a0fdbdc8dd945ccdebad237e0d2346ff17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Wed, 1 Mar 2023 11:54:10 -0300 Subject: [PATCH 019/118] Update felts serialization --- gnark_backend_ffi/main.go | 16 ++++----------- tests/serialization_tests.rs | 38 ++++++++++++++++++++++++++++++++++-- 2 files changed, 40 insertions(+), 14 deletions(-) diff --git a/gnark_backend_ffi/main.go b/gnark_backend_ffi/main.go index 05a0348..b01ddd7 100644 --- a/gnark_backend_ffi/main.go +++ b/gnark_backend_ffi/main.go @@ -345,20 +345,12 @@ func TestFeltsSerialization(encodedFelts string) *C.char { // Unpack and deserialize the decoded felts. var deserializedFelts fr_bn254.Vector - // Felts are 32 bytes long. - feltsToDeserialize := len(decodedFelts) / 32 - for i := 0; i < feltsToDeserialize; i++ { - var deserializedFelt fr_bn254.Element - deserializedFelt.SetBytes(decodedFelts[i*32 : (i+1)*32]) - fmt.Printf("| GO |\n%v\n", deserializedFelt) - deserializedFelts = append(deserializedFelts, deserializedFelt) - } + deserializedFelts.UnmarshalBinary(decodedFelts) // Serialize the felt. - var serializedFelts []byte - for _, felt := range deserializedFelts { - serializedFelt := felt.Bytes() - serializedFelts = append(serializedFelts, serializedFelt[:]...) + serializedFelts, err := deserializedFelts.MarshalBinary() + if err != nil { + log.Fatal(err) } // Encode the serialized felt. diff --git a/tests/serialization_tests.rs b/tests/serialization_tests.rs index 7d29b95..54f3b72 100644 --- a/tests/serialization_tests.rs +++ b/tests/serialization_tests.rs @@ -46,8 +46,42 @@ fn deserialize_felt(felt_bytes: &[u8]) -> gnark_backend_wrapper::groth16::Fr { gnark_backend_wrapper::groth16::Fr::deserialize_uncompressed(decoded.as_slice()).unwrap() } +// This serialization mimics gnark's serialization of a field elements vector. +// The length of the vector is encoded as a u32 on the first 4 bytes. fn serialize_felts(felts: &[gnark_backend_wrapper::groth16::Fr]) -> Vec { - felts.iter().flat_map(serialize_felt).collect() + let mut buff: Vec = Vec::new(); + let n_felts: u32 = felts.len().try_into().unwrap(); + buff.extend_from_slice(&n_felts.to_be_bytes()); + buff.extend_from_slice(&felts.iter().flat_map(serialize_felt).collect::>()); + buff +} + +fn serialize_mul_term(mul_term: &(gnark_backend_wrapper::groth16::Fr, acvm::Witness, acvm::Witness)) -> String { + let serialized_coefficient = serialize_felt(&mul_term.0); + let encoded_coefficient = hex::encode(serialized_coefficient); + + let serialized_multiplicand = serde_json::to_string(&mul_term.1).unwrap(); + let serialized_multiplier = serde_json::to_string(&mul_term.2).unwrap(); + + serde_json::to_string(&json!({ + "coefficient": encoded_coefficient, + "multiplicand": serialized_multiplicand, + "multiplier": serialized_multiplier + })) + .unwrap() +} + +fn serialize_add_term(mul_term: &(gnark_backend_wrapper::groth16::Fr, acvm::Witness)) -> Vec { + let serialized_coefficient = serialize_felt(&mul_term.0); + let encoded_coefficient = hex::encode(serialized_coefficient); + + let serialized_sum = serde_json::to_string(&mul_term.1).unwrap(); + + serde_json::to_vec(&json!({ + "coefficient": encoded_coefficient, + "sum": serialized_sum, + })) + .unwrap() } #[test] @@ -108,7 +142,7 @@ fn test_felts_serialization() { // Decode and deserialize the unpacked felts. let go_felts: Vec = hex::decode(go_serialized_felt) - .unwrap() + .unwrap()[4..] // Skip the vector length corresponding to the first four bytes. .chunks_mut(32) .map(|go_decoded_felt| { // Turn big-endian to little-endian. From a0eada01de6056c1d03e174f12e5aeb3a45fa436 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Wed, 1 Mar 2023 14:58:27 -0300 Subject: [PATCH 020/118] Update deps --- gnark_backend_ffi/go.mod | 4 ++++ gnark_backend_ffi/go.sum | 16 ++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/gnark_backend_ffi/go.mod b/gnark_backend_ffi/go.mod index 443e8c1..154fb80 100644 --- a/gnark_backend_ffi/go.mod +++ b/gnark_backend_ffi/go.mod @@ -6,13 +6,16 @@ require github.com/consensys/gnark-crypto v0.9.1 require ( github.com/blang/semver/v4 v4.0.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect github.com/fxamacker/cbor/v2 v2.4.0 // indirect github.com/google/pprof v0.0.0-20230207041349-798e818bf904 // indirect github.com/mattn/go-colorable v0.1.12 // indirect github.com/mattn/go-isatty v0.0.14 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rs/zerolog v1.29.0 // indirect github.com/x448/float16 v0.8.4 // indirect golang.org/x/sys v0.5.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) require ( @@ -20,5 +23,6 @@ require ( github.com/consensys/gnark v0.8.0 github.com/mmcloughlin/addchain v0.4.0 // indirect github.com/recoilme/btreeset v0.0.0-20200809183105-7b1adf6e3d3c + github.com/stretchr/testify v1.8.2 rsc.io/tmplfunc v0.0.3 // indirect ) diff --git a/gnark_backend_ffi/go.sum b/gnark_backend_ffi/go.sum index fff4a67..2214255 100644 --- a/gnark_backend_ffi/go.sum +++ b/gnark_backend_ffi/go.sum @@ -7,6 +7,9 @@ github.com/consensys/gnark v0.8.0/go.mod h1:aKmA7dIiLbTm0OV37xTq0z+Bpe4xER8EhRLi github.com/consensys/gnark-crypto v0.9.1 h1:mru55qKdWl3E035hAoh1jj9d7hVnYY5pfb6tmovSmII= github.com/consensys/gnark-crypto v0.9.1/go.mod h1:a2DQL4+5ywF6safEeZFEPGRiiGbjzGFRUN2sg06VuU4= github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fxamacker/cbor/v2 v2.4.0 h1:ri0ArlOR+5XunOP8CRUowT0pSJOwhW098ZCUyskZD88= github.com/fxamacker/cbor/v2 v2.4.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= @@ -21,16 +24,29 @@ github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iP github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU= github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/recoilme/btreeset v0.0.0-20200809183105-7b1adf6e3d3c h1:sK0DO2PhTuM2WVdCqvZN4YDJ0YBg/P0Q2IKb/0JDckw= github.com/recoilme/btreeset v0.0.0-20200809183105-7b1adf6e3d3c/go.mod h1:CokJMa/61pPRjQN8IEVINptiOHJkwoGeAyFlAWgyj2g= github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.29.0 h1:Zes4hju04hjbvkVkOhdl2HpZa+0PmVwigmo8XoORE5w= github.com/rs/zerolog v1.29.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU= rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA= From d232a6436d84bf709075af1fd2d81539856fa4d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Wed, 1 Mar 2023 14:59:05 -0300 Subject: [PATCH 021/118] Update Makefile Now we can either run all the tests or specify one. Also we can see the prints outputs with the new added flag --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 001e5fa..540bf09 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,7 @@ build: build-go $ RUSTFLAGS="-L${FFI_LIB_PATH}" cargo build test: build-go - $ RUSTFLAGS="-L${FFI_LIB_PATH}" cargo test + $ RUSTFLAGS="-L${FFI_LIB_PATH}" cargo test ${TEST} -- --nocapture clippy: $ cargo clippy --all-targets -- -D warnings From 47deb5741020dd69d3b08a74071542894e332cb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Wed, 1 Mar 2023 15:01:23 -0300 Subject: [PATCH 022/118] Implement `AddTerm` with JSON deserialization --- gnark_backend_ffi/structs/add_term.go | 46 ++++++++++++++++++++++ gnark_backend_ffi/structs/add_term_test.go | 35 ++++++++++++++++ 2 files changed, 81 insertions(+) create mode 100644 gnark_backend_ffi/structs/add_term.go create mode 100644 gnark_backend_ffi/structs/add_term_test.go diff --git a/gnark_backend_ffi/structs/add_term.go b/gnark_backend_ffi/structs/add_term.go new file mode 100644 index 0000000..e9a98e0 --- /dev/null +++ b/gnark_backend_ffi/structs/add_term.go @@ -0,0 +1,46 @@ +package structs + +import ( + "encoding/json" + "log" + + fr_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/fr" +) + +type AddTerm struct { + Coefficient fr_bn254.Element + Sum Witness +} + +func (m *AddTerm) UnmarshalJSON(data []byte) error { + var add_term_map map[string]interface{} + err := json.Unmarshal(data, &add_term_map) + if err != nil { + log.Fatal(err) + return err + } + + var coefficient fr_bn254.Element + var sum Witness + + // Deserialize coefficient. + if encodedCoefficient, ok := add_term_map["coefficient"].(string); ok { + coefficient = DeserializeFelt(encodedCoefficient) + } else { + log.Fatal("Error: couldn't deserialize coefficient.") + return &json.UnmarshalTypeError{} + } + + // Deserialize sum. + if m, ok := add_term_map["sum"].(float64); ok { + sum = Witness(m) + } else { + log.Fatal("Error: couldn't deserialize sum.") + return &json.UnmarshalTypeError{} + } + + m.Coefficient = coefficient + m.Sum = sum + + return nil +} diff --git a/gnark_backend_ffi/structs/add_term_test.go b/gnark_backend_ffi/structs/add_term_test.go new file mode 100644 index 0000000..830d62f --- /dev/null +++ b/gnark_backend_ffi/structs/add_term_test.go @@ -0,0 +1,35 @@ +package structs + +import ( + "encoding/json" + "log" + "testing" + + "github.com/stretchr/testify/assert" +) + +// TODO: Test error cases. + +func TestAddTermUnmarshalJSON(t *testing.T) { + addTerm := `{"coefficient":"0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5","sum":2422311469}` + + var a AddTerm + err := json.Unmarshal([]byte(addTerm), &a) + if err != nil { + log.Fatal(err) + } + + assert.NoError(t, err) +} + +func TestAddTermsUnmarshalJSON(t *testing.T) { + addTerms := `[{"coefficient":"0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5","sum":2422311469},{"coefficient":"0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5","sum":3583776697}]` + + var a []AddTerm + err := json.Unmarshal([]byte(addTerms), &a) + if err != nil { + log.Fatal(err) + } + + assert.NoError(t, err) +} From e35226efafb802b75ce27cbda960a306ba8bca7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Wed, 1 Mar 2023 15:01:31 -0300 Subject: [PATCH 023/118] Implement `MulTerm` with JSON deserialization --- gnark_backend_ffi/structs/mul_term.go | 57 ++++++++++++++++++++++ gnark_backend_ffi/structs/mul_term_test.go | 35 +++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 gnark_backend_ffi/structs/mul_term.go create mode 100644 gnark_backend_ffi/structs/mul_term_test.go diff --git a/gnark_backend_ffi/structs/mul_term.go b/gnark_backend_ffi/structs/mul_term.go new file mode 100644 index 0000000..4e065d6 --- /dev/null +++ b/gnark_backend_ffi/structs/mul_term.go @@ -0,0 +1,57 @@ +package structs + +import ( + "encoding/json" + "log" + + fr_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/fr" +) + +type MulTerm struct { + Coefficient fr_bn254.Element + Multiplicand Witness + Multiplier Witness +} + +func (m *MulTerm) UnmarshalJSON(data []byte) error { + var mul_term_map map[string]interface{} + err := json.Unmarshal(data, &mul_term_map) + if err != nil { + log.Fatal(err) + return err + } + + var coefficient fr_bn254.Element + var multiplicand Witness + var multiplier Witness + + // Deserialize coefficient. + if encodedCoefficient, ok := mul_term_map["coefficient"].(string); ok { + coefficient = DeserializeFelt(encodedCoefficient) + } else { + log.Fatal("Error: couldn't deserialize coefficient.") + return &json.UnmarshalTypeError{} + } + + // Deserialize multiplicand. + if m, ok := mul_term_map["multiplicand"].(float64); ok { + multiplicand = Witness(m) + } else { + log.Fatal("Error: couldn't deserialize multiplicand.") + return &json.UnmarshalTypeError{} + } + + // Deserialize multiplier. + if m, ok := mul_term_map["multiplier"].(float64); ok { + multiplier = Witness(m) + } else { + log.Fatal("Error: couldn't deserialize multiplier.") + return &json.UnmarshalTypeError{} + } + + m.Coefficient = coefficient + m.Multiplicand = multiplicand + m.Multiplier = multiplier + + return nil +} diff --git a/gnark_backend_ffi/structs/mul_term_test.go b/gnark_backend_ffi/structs/mul_term_test.go new file mode 100644 index 0000000..1001cd5 --- /dev/null +++ b/gnark_backend_ffi/structs/mul_term_test.go @@ -0,0 +1,35 @@ +package structs + +import ( + "encoding/json" + "log" + "testing" + + "github.com/stretchr/testify/assert" +) + +// TODO: Test error cases. + +func TestMulTermUnmarshalJSON(t *testing.T) { + mulTerm := `{"coefficient":"0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5","multiplicand":3583776697,"multiplier":2422311469}` + + var m MulTerm + err := json.Unmarshal([]byte(mulTerm), &m) + if err != nil { + log.Fatal(err) + } + + assert.NoError(t, err) +} + +func TestMulTermsUnmarshalJSON(t *testing.T) { + mulTerms := `[{"coefficient":"0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5","multiplicand":3583776697,"multiplier":2422311469},{"coefficient":"0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5","multiplicand":3583776697,"multiplier":2422311469}]` + + var m []MulTerm + err := json.Unmarshal([]byte(mulTerms), &m) + if err != nil { + log.Fatal(err) + } + + assert.NoError(t, err) +} From cb25e3cce25a2b753d36d478f0b42d018c4efab6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Wed, 1 Mar 2023 15:01:43 -0300 Subject: [PATCH 024/118] Implement `RawGate` with JSON deserialization --- gnark_backend_ffi/structs/raw_gate.go | 75 ++++++++++++++++++++++ gnark_backend_ffi/structs/raw_gate_test.go | 43 +++++++++++++ 2 files changed, 118 insertions(+) create mode 100644 gnark_backend_ffi/structs/raw_gate.go create mode 100644 gnark_backend_ffi/structs/raw_gate_test.go diff --git a/gnark_backend_ffi/structs/raw_gate.go b/gnark_backend_ffi/structs/raw_gate.go new file mode 100644 index 0000000..d70301c --- /dev/null +++ b/gnark_backend_ffi/structs/raw_gate.go @@ -0,0 +1,75 @@ +package structs + +import ( + "encoding/json" + "log" + + fr_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/fr" +) + +type RawGate struct { + MulTerms []MulTerm + AddTerms []AddTerm + ConstantTerm fr_bn254.Element +} + +func (g *RawGate) UnmarshalJSON(data []byte) error { + var rawGateMap map[string]interface{} + err := json.Unmarshal(data, &rawGateMap) + if err != nil { + log.Fatal(err) + return err + } + + var mulTerms []MulTerm + var addTerms []AddTerm + var constantTerm fr_bn254.Element + + // Deserialize mul terms. + if mulTermsValue, ok := rawGateMap["mul_terms"].([]interface{}); ok { + mulTermsJSON, err := json.Marshal(mulTermsValue) + if err != nil { + log.Fatal(err) + return err + } + err = json.Unmarshal(mulTermsJSON, &mulTerms) + if err != nil { + log.Fatal(err) + return err + } + } else { + log.Fatal("Error: couldn't deserialize mul terms.") + return &json.UnmarshalTypeError{} + } + + // Deserialize add terms. + if addTermsValue, ok := rawGateMap["add_terms"].([]interface{}); ok { + addTermsJSON, err := json.Marshal(addTermsValue) + if err != nil { + log.Fatal(err) + return err + } + err = json.Unmarshal(addTermsJSON, &addTerms) + if err != nil { + log.Fatal(err) + return err + } + } else { + log.Fatal("Error: couldn't deserialize add terms.") + return &json.UnmarshalTypeError{} + } + + // Deserialize constant term. + if encodedConstantTerm, ok := rawGateMap["constant_term"].(string); ok { + constantTerm = DeserializeFelt(encodedConstantTerm) + } else { + log.Fatal("Error: coefficient is not a felt.") + return &json.UnmarshalTypeError{} + } + + g.MulTerms = mulTerms + g.AddTerms = addTerms + g.ConstantTerm = constantTerm + + return nil +} diff --git a/gnark_backend_ffi/structs/raw_gate_test.go b/gnark_backend_ffi/structs/raw_gate_test.go new file mode 100644 index 0000000..67aafb0 --- /dev/null +++ b/gnark_backend_ffi/structs/raw_gate_test.go @@ -0,0 +1,43 @@ +package structs + +import ( + "encoding/json" + "fmt" + "log" + "testing" + + "github.com/stretchr/testify/assert" +) + +// TODO: Test error cases. + +func TestRawGateTermUnmarshalJSON(t *testing.T) { + mulTerms := `[{"coefficient":"0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5","multiplicand":3583776697,"multiplier":2422311469},{"coefficient":"0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5","multiplicand":3583776697,"multiplier":2422311469}]` + addTerms := `[{"coefficient":"0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5","sum":2422311469},{"coefficient":"0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5","sum":3583776697}]` + constantTerm := "0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5" + rawGate := fmt.Sprintf(`{"mul_terms":%s,"add_terms":%s,"constant_term":"%s"}`, mulTerms, addTerms, constantTerm) + + var r RawGate + err := json.Unmarshal([]byte(rawGate), &r) + if err != nil { + log.Fatal(err) + } + + assert.NoError(t, err) +} + +func TestRawGatesTermUnmarshalJSON(t *testing.T) { + mulTerms := `[{"coefficient":"0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5","multiplicand":3583776697,"multiplier":2422311469},{"coefficient":"0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5","multiplicand":3583776697,"multiplier":2422311469}]` + addTerms := `[{"coefficient":"0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5","sum":2422311469},{"coefficient":"0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5","sum":3583776697}]` + constantTerm := "0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5" + rawGate := fmt.Sprintf(`{"mul_terms":%s,"add_terms":%s,"constant_term":"%s"}`, mulTerms, addTerms, constantTerm) + rawGates := fmt.Sprintf(`[%s,%s]`, rawGate, rawGate) + + var r []RawGate + err := json.Unmarshal([]byte(rawGates), &r) + if err != nil { + log.Fatal(err) + } + + assert.NoError(t, err) +} From 86731d9eb08dc652df30b730768c5463d1d929fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Wed, 1 Mar 2023 15:01:51 -0300 Subject: [PATCH 025/118] Implement `RawR1CS` with JSON deserialization --- gnark_backend_ffi/structs/raw_r1cs.go | 96 ++++++++++++++++++++++ gnark_backend_ffi/structs/raw_r1cs_test.go | 33 ++++++++ 2 files changed, 129 insertions(+) create mode 100644 gnark_backend_ffi/structs/raw_r1cs.go create mode 100644 gnark_backend_ffi/structs/raw_r1cs_test.go diff --git a/gnark_backend_ffi/structs/raw_r1cs.go b/gnark_backend_ffi/structs/raw_r1cs.go new file mode 100644 index 0000000..8a91ea4 --- /dev/null +++ b/gnark_backend_ffi/structs/raw_r1cs.go @@ -0,0 +1,96 @@ +package structs + +import ( + "encoding/json" + "log" + + fr_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/fr" +) + +type RawR1CS struct { + Gates []RawGate + PublicInputs Witnesses + Values fr_bn254.Vector + NumVariables uint64 + NumConstraints uint64 +} + +func (r *RawR1CS) UnmarshalJSON(data []byte) error { + var rawR1CSMap map[string]interface{} + err := json.Unmarshal(data, &rawR1CSMap) + if err != nil { + log.Fatal(err) + return err + } + + var gates []RawGate + var publicInputs Witnesses + var values fr_bn254.Vector + var numVariables uint64 + var numConstraints uint64 + + // Deserialize gates. + if gatesValue, ok := rawR1CSMap["gates"].([]interface{}); ok { + gatesJSON, err := json.Marshal(gatesValue) + if err != nil { + log.Fatal(err) + return err + } + err = json.Unmarshal(gatesJSON, &gates) + if err != nil { + log.Fatal(err) + return err + } + } else { + log.Fatal("Error: couldn't deserialize raw gates.") + return &json.UnmarshalTypeError{} + } + + if publicInputsValue, ok := rawR1CSMap["public_inputs"].([]interface{}); ok { + publicInputsJSON, err := json.Marshal(publicInputsValue) + if err != nil { + log.Fatal(err) + return err + } + err = json.Unmarshal(publicInputsJSON, &publicInputs) + if err != nil { + log.Fatal(err) + return err + } + } else { + log.Fatal("Error: couldn't deserialize public inputs.") + return &json.UnmarshalTypeError{} + } + + // Deserialize values. + if encodedValues, ok := rawR1CSMap["values"].(string); ok { + values = DeserializeFelts(encodedValues) + } else { + log.Fatal("Error: couldn't deserialize values.") + return &json.UnmarshalTypeError{} + } + + // Deserialize num_variables. + if numVariablesValue, ok := rawR1CSMap["num_variables"].(float64); ok { + numVariables = uint64(numVariablesValue) + } else { + log.Fatal("Error: couldn't deserialize num_variables.") + return &json.UnmarshalTypeError{} + } + + // Deserialize num_constraints. + if numConstraintsValue, ok := rawR1CSMap["num_constraints"].(float64); ok { + numConstraints = uint64(numConstraintsValue) + } else { + log.Fatal("Error: couldn't deserialize num_constraints.") + return &json.UnmarshalTypeError{} + } + + r.Gates = gates + r.PublicInputs = publicInputs + r.Values = values + r.NumVariables = numVariables + r.NumConstraints = numConstraints + + return nil +} diff --git a/gnark_backend_ffi/structs/raw_r1cs_test.go b/gnark_backend_ffi/structs/raw_r1cs_test.go new file mode 100644 index 0000000..d6bd01f --- /dev/null +++ b/gnark_backend_ffi/structs/raw_r1cs_test.go @@ -0,0 +1,33 @@ +package structs + +import ( + "encoding/json" + "fmt" + "math/rand" + "testing" + + "github.com/stretchr/testify/assert" +) + +// TODO: Test error cases. + +func TestRawR1CSTermUnmarshalJSON(t *testing.T) { + multiplicand := rand.Uint32() + multiplier := rand.Uint32() + sum := rand.Uint32() + mulTerms := fmt.Sprintf(`[{"coefficient":"0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5","multiplicand":%d,"multiplier":%d},{"coefficient":"0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5","multiplicand":%d,"multiplier":%d}]`, multiplicand, multiplier, multiplicand, multiplier) + addTerms := fmt.Sprintf(`[{"coefficient":"0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5","sum":%d},{"coefficient":"0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5","sum":%d}]`, sum, sum) + constantTerm := "0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5" + rawGate := fmt.Sprintf(`{"mul_terms":%s,"add_terms":%s,"constant_term":"%s"}`, mulTerms, addTerms, constantTerm) + rawGates := fmt.Sprintf(`[%s,%s]`, rawGate, rawGate) + publicInputs := fmt.Sprintf("[%d,%d,%d]", multiplicand, multiplier, sum) + values := "000000020e863ed5c2ba04f5a88c64ad335acb2df798d830db50d760c1359328fd39c6380cf4783484cb019ebb7128d66d1009d0dc3b48acd936a157037af55753e9bd32" + numVariables := rand.Uint64() + numConstraints := rand.Uint64() + rawR1CS := fmt.Sprintf(`{"gates":%s,"public_inputs":%s,"values":"%s","num_variables":%d,"num_constraints":%d}`, rawGates, publicInputs, values, numVariables, numConstraints) + + var r RawR1CS + err := json.Unmarshal([]byte(rawR1CS), &r) + + assert.NoError(t, err) +} From 70928530fc2a9886a3353e1f6a66773f4663da77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Wed, 1 Mar 2023 15:02:00 -0300 Subject: [PATCH 026/118] Add `helpers` module --- gnark_backend_ffi/structs/helpers.go | 39 ++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 gnark_backend_ffi/structs/helpers.go diff --git a/gnark_backend_ffi/structs/helpers.go b/gnark_backend_ffi/structs/helpers.go new file mode 100644 index 0000000..f966086 --- /dev/null +++ b/gnark_backend_ffi/structs/helpers.go @@ -0,0 +1,39 @@ +package structs + +import ( + "encoding/hex" + "log" + + fr_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/fr" +) + +type Witness = uint32 +type Witnesses = []Witness + +func DeserializeFelt(encodedFelt string) fr_bn254.Element { + // Decode the received felt. + decodedFelt, err := hex.DecodeString(encodedFelt) + if err != nil { + log.Fatal(err) + } + + // Deserialize the decoded felt. + var deserializedFelt fr_bn254.Element + deserializedFelt.SetBytes(decodedFelt) + + return deserializedFelt +} + +func DeserializeFelts(encodedFelts string) fr_bn254.Vector { + // Decode the received felts. + decodedFelts, err := hex.DecodeString(encodedFelts) + if err != nil { + log.Fatal(err) + } + + // Unpack and deserialize the decoded felts. + var deserializedFelts fr_bn254.Vector + deserializedFelts.UnmarshalBinary(decodedFelts) + + return deserializedFelts +} From 7ed009f928cdd8ee96a6530b8b17b7be81845340 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Wed, 1 Mar 2023 15:03:03 -0300 Subject: [PATCH 027/118] Cleanup main function --- gnark_backend_ffi/main.go | 33 +-------------------------------- 1 file changed, 1 insertion(+), 32 deletions(-) diff --git a/gnark_backend_ffi/main.go b/gnark_backend_ffi/main.go index b01ddd7..d8e7190 100644 --- a/gnark_backend_ffi/main.go +++ b/gnark_backend_ffi/main.go @@ -400,35 +400,4 @@ func TestRawR1CSSerialization(encodedR1CS string) *C.char { return C.CString("unimplemented") } -func main() { - // rawR1CS := `{"gates":[{"mul_terms":[["0100000000000000000000000000000000000000000000000000000000000000",1],["000000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430",2],["000000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430",3]],"add_terms":[["0100000000000000000000000000000000000000000000000000000000000000",1],["000000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430",2],["000000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430",3]],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000"},{"mul_terms":[["000000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430",5]],"add_terms":[["000000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430",5]],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000"},{"mul_terms":[["000000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430",3]],"add_terms":[["000000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430",3]],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000"},{"mul_terms":[["000000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430",5]],"add_terms":[["000000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430",5]],"constant_term":"0100000000000000000000000000000000000000000000000000000000000000"}],"public_inputs":[2],"values":["0100000000000000000000000000000000000000000000000000000000000000","0200000000000000000000000000000000000000000000000000000000000000","0000000000000000000000000000000000000000000000000000000000000000","0000000000000000000000000000000000000000000000000000000000000000","0000000000000000000000000000000000000000000000000000000000000000","0000000000000000000000000000000000000000000000000000000000000000"],"num_variables":7}` - rawR1CS := `{"gates":[{"mul_terms":[["0100000000000000000000000000000000000000000000000000000000000000",1],["000000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430",2],["000000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430",3]],"add_terms":[["0100000000000000000000000000000000000000000000000000000000000000",1],["000000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430",2],["000000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430",3]],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000"},{"mul_terms":[["000000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430",5]],"add_terms":[["000000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430",5]],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000"},{"mul_terms":[["000000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430",3]],"add_terms":[["000000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430",3]],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000"},{"mul_terms":[["000000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430",5]],"add_terms":[["000000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430",5]],"constant_term":"0100000000000000000000000000000000000000000000000000000000000000"}],"public_inputs":[2],"values":[[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]],"num_variables":7}` - - // Deserialize rawR1CS. - var r RawR1CS - err := json.Unmarshal([]byte(rawR1CS), &r) - if err != nil { - log.Fatal(err) - } - - r1cs, publicVariables, privateVariables, nPublicVariables, nPrivateVariables := buildR1CS(r) - - fmt.Println("R1CS: ", r1cs) - fmt.Println("Public Variables: ", publicVariables) - fmt.Println("Private Variables: ", privateVariables) - fmt.Println("Number of Public Variables: ", nPublicVariables) - fmt.Println("Number of Private Variables: ", nPrivateVariables) - - // get the constraints - constraints, resolver := r1cs.GetConstraints() - - for _, r1c := range constraints { - fmt.Println(r1c.String(resolver)) - // for more granularity use constraint.NewStringBuilder(resolver) that embeds a string.Builder - // and has WriteLinearExpression and WriteTerm methods. - } - - // proof := ProveWithMeta(rawR1CS) - - // fmt.Println("Proof: ", proof) -} +func main() {} From c32ae922bfbf9c2f74022379e36c151b3f64b646 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Wed, 1 Mar 2023 15:03:47 -0300 Subject: [PATCH 028/118] Move struct to a module --- gnark_backend_ffi/main.go | 55 +++++---------------------------------- 1 file changed, 6 insertions(+), 49 deletions(-) diff --git a/gnark_backend_ffi/main.go b/gnark_backend_ffi/main.go index d8e7190..4f5779c 100644 --- a/gnark_backend_ffi/main.go +++ b/gnark_backend_ffi/main.go @@ -9,7 +9,7 @@ import ( "log" "strconv" - "github.com/recoilme/btreeset" + "gnark_backend_ffi/structs" fr_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/fr" "github.com/consensys/gnark/backend/groth16" @@ -18,34 +18,7 @@ import ( cs_bn254 "github.com/consensys/gnark/constraint/bn254" ) -// TODO: Deserialize rawR1CS. - -type RawR1CS struct { - Gates []RawGate - PublicInputs btreeset.BTreeSet - Values fr_bn254.Vector - NumVariables uint - NumConstraints uint -} - -type RawGate struct { - MulTerms []MulTerm - AddTerms []AddTerm - ConstantTerm fr_bn254.Element -} - -type MulTerm struct { - Coefficient fr_bn254.Element - Multiplicand uint32 - Multiplier uint32 -} - -type AddTerm struct { - Coefficient fr_bn254.Element - Sum uint32 -} - -func buildR1CS(r RawR1CS) (*cs_bn254.R1CS, fr_bn254.Vector, fr_bn254.Vector, int, int) { +func buildR1CS(r structs.RawR1CS) (*cs_bn254.R1CS, fr_bn254.Vector, fr_bn254.Vector, int, int) { // Create R1CS. r1cs := cs_bn254.NewR1CS(int(r.NumConstraints)) @@ -132,7 +105,7 @@ func buildWitnesses(r1cs *cs_bn254.R1CS, publicVariables fr_bn254.Vector, privat //export ProveWithMeta func ProveWithMeta(rawR1CS string) *C.char { // Deserialize rawR1CS. - var r RawR1CS + var r structs.RawR1CS err := json.Unmarshal([]byte(rawR1CS), &r) if err != nil { log.Fatal(err) @@ -315,15 +288,7 @@ func Preprocess(rawR1CS string) (*C.char, *C.char) { //export TestFeltSerialization func TestFeltSerialization(encodedFelt string) *C.char { - // Decode the received felt. - decodedFelt, err := hex.DecodeString(encodedFelt) - if err != nil { - log.Fatal(err) - } - - // Deserialize the decoded felt. - var deserializedFelt fr_bn254.Element - deserializedFelt.SetBytes(decodedFelt) + deserializedFelt := structs.DeserializeFelt(encodedFelt) fmt.Printf("| GO |\n%v\n", deserializedFelt) // Serialize the felt. @@ -337,15 +302,7 @@ func TestFeltSerialization(encodedFelt string) *C.char { //export TestFeltsSerialization func TestFeltsSerialization(encodedFelts string) *C.char { - // Decode the received felts. - decodedFelts, err := hex.DecodeString(encodedFelts) - if err != nil { - log.Fatal(err) - } - - // Unpack and deserialize the decoded felts. - var deserializedFelts fr_bn254.Vector - deserializedFelts.UnmarshalBinary(decodedFelts) + deserializedFelts := structs.DeserializeFelts(encodedFelts) // Serialize the felt. serializedFelts, err := deserializedFelts.MarshalBinary() @@ -366,7 +323,7 @@ func TestU64Serialization(number uint64) uint64 { } //export TestMulTermSerialization -func TestMulTermSerialization(encodedMulTerm string) *C.char { +func TestMulTermSerialization(mulTerm string) *C.char { return C.CString("unimplemented") } From 2dc0f828848ad16be5a24d91f3cb56ad10d1b15f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Wed, 1 Mar 2023 15:06:54 -0300 Subject: [PATCH 029/118] `PublicInputs` is no longer a BTreeSet --- gnark_backend_ffi/main.go | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/gnark_backend_ffi/main.go b/gnark_backend_ffi/main.go index 4f5779c..e102b22 100644 --- a/gnark_backend_ffi/main.go +++ b/gnark_backend_ffi/main.go @@ -30,14 +30,16 @@ func buildR1CS(r structs.RawR1CS) (*cs_bn254.R1CS, fr_bn254.Vector, fr_bn254.Vec var privateVariables fr_bn254.Vector for i, value := range r.Values { variableName := strconv.Itoa(i) - if r.PublicInputs.Has(make([]byte, i)) { - allVariableIndices = append(allVariableIndices, r1cs.AddPublicVariable(variableName)) - publicVariables = append(publicVariables, value) - nPublicVariables++ - } else { - allVariableIndices = append(allVariableIndices, r1cs.AddSecretVariable(variableName)) - privateVariables = append(privateVariables, value) - nPrivateVariables++ + for _, publicInput := range r.PublicInputs { + if uint32(i) == publicInput { + allVariableIndices = append(allVariableIndices, r1cs.AddPublicVariable(variableName)) + publicVariables = append(publicVariables, value) + nPublicVariables++ + } else { + allVariableIndices = append(allVariableIndices, r1cs.AddSecretVariable(variableName)) + privateVariables = append(privateVariables, value) + nPrivateVariables++ + } } } From 2ab5d84e26f1011a446cdbbdcb01c26cea54b398 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Wed, 1 Mar 2023 15:01:23 -0300 Subject: [PATCH 030/118] Implement `AddTerm` with JSON deserialization --- gnark_backend_ffi/structs/add_term.go | 46 ++++++++++++++++++++++ gnark_backend_ffi/structs/add_term_test.go | 35 ++++++++++++++++ 2 files changed, 81 insertions(+) create mode 100644 gnark_backend_ffi/structs/add_term.go create mode 100644 gnark_backend_ffi/structs/add_term_test.go diff --git a/gnark_backend_ffi/structs/add_term.go b/gnark_backend_ffi/structs/add_term.go new file mode 100644 index 0000000..e9a98e0 --- /dev/null +++ b/gnark_backend_ffi/structs/add_term.go @@ -0,0 +1,46 @@ +package structs + +import ( + "encoding/json" + "log" + + fr_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/fr" +) + +type AddTerm struct { + Coefficient fr_bn254.Element + Sum Witness +} + +func (m *AddTerm) UnmarshalJSON(data []byte) error { + var add_term_map map[string]interface{} + err := json.Unmarshal(data, &add_term_map) + if err != nil { + log.Fatal(err) + return err + } + + var coefficient fr_bn254.Element + var sum Witness + + // Deserialize coefficient. + if encodedCoefficient, ok := add_term_map["coefficient"].(string); ok { + coefficient = DeserializeFelt(encodedCoefficient) + } else { + log.Fatal("Error: couldn't deserialize coefficient.") + return &json.UnmarshalTypeError{} + } + + // Deserialize sum. + if m, ok := add_term_map["sum"].(float64); ok { + sum = Witness(m) + } else { + log.Fatal("Error: couldn't deserialize sum.") + return &json.UnmarshalTypeError{} + } + + m.Coefficient = coefficient + m.Sum = sum + + return nil +} diff --git a/gnark_backend_ffi/structs/add_term_test.go b/gnark_backend_ffi/structs/add_term_test.go new file mode 100644 index 0000000..830d62f --- /dev/null +++ b/gnark_backend_ffi/structs/add_term_test.go @@ -0,0 +1,35 @@ +package structs + +import ( + "encoding/json" + "log" + "testing" + + "github.com/stretchr/testify/assert" +) + +// TODO: Test error cases. + +func TestAddTermUnmarshalJSON(t *testing.T) { + addTerm := `{"coefficient":"0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5","sum":2422311469}` + + var a AddTerm + err := json.Unmarshal([]byte(addTerm), &a) + if err != nil { + log.Fatal(err) + } + + assert.NoError(t, err) +} + +func TestAddTermsUnmarshalJSON(t *testing.T) { + addTerms := `[{"coefficient":"0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5","sum":2422311469},{"coefficient":"0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5","sum":3583776697}]` + + var a []AddTerm + err := json.Unmarshal([]byte(addTerms), &a) + if err != nil { + log.Fatal(err) + } + + assert.NoError(t, err) +} From 9f593cab69c0ae053d69b3891eda80d709dbc5dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Wed, 1 Mar 2023 15:01:31 -0300 Subject: [PATCH 031/118] Implement `MulTerm` with JSON deserialization --- gnark_backend_ffi/structs/mul_term.go | 57 ++++++++++++++++++++++ gnark_backend_ffi/structs/mul_term_test.go | 35 +++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 gnark_backend_ffi/structs/mul_term.go create mode 100644 gnark_backend_ffi/structs/mul_term_test.go diff --git a/gnark_backend_ffi/structs/mul_term.go b/gnark_backend_ffi/structs/mul_term.go new file mode 100644 index 0000000..4e065d6 --- /dev/null +++ b/gnark_backend_ffi/structs/mul_term.go @@ -0,0 +1,57 @@ +package structs + +import ( + "encoding/json" + "log" + + fr_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/fr" +) + +type MulTerm struct { + Coefficient fr_bn254.Element + Multiplicand Witness + Multiplier Witness +} + +func (m *MulTerm) UnmarshalJSON(data []byte) error { + var mul_term_map map[string]interface{} + err := json.Unmarshal(data, &mul_term_map) + if err != nil { + log.Fatal(err) + return err + } + + var coefficient fr_bn254.Element + var multiplicand Witness + var multiplier Witness + + // Deserialize coefficient. + if encodedCoefficient, ok := mul_term_map["coefficient"].(string); ok { + coefficient = DeserializeFelt(encodedCoefficient) + } else { + log.Fatal("Error: couldn't deserialize coefficient.") + return &json.UnmarshalTypeError{} + } + + // Deserialize multiplicand. + if m, ok := mul_term_map["multiplicand"].(float64); ok { + multiplicand = Witness(m) + } else { + log.Fatal("Error: couldn't deserialize multiplicand.") + return &json.UnmarshalTypeError{} + } + + // Deserialize multiplier. + if m, ok := mul_term_map["multiplier"].(float64); ok { + multiplier = Witness(m) + } else { + log.Fatal("Error: couldn't deserialize multiplier.") + return &json.UnmarshalTypeError{} + } + + m.Coefficient = coefficient + m.Multiplicand = multiplicand + m.Multiplier = multiplier + + return nil +} diff --git a/gnark_backend_ffi/structs/mul_term_test.go b/gnark_backend_ffi/structs/mul_term_test.go new file mode 100644 index 0000000..1001cd5 --- /dev/null +++ b/gnark_backend_ffi/structs/mul_term_test.go @@ -0,0 +1,35 @@ +package structs + +import ( + "encoding/json" + "log" + "testing" + + "github.com/stretchr/testify/assert" +) + +// TODO: Test error cases. + +func TestMulTermUnmarshalJSON(t *testing.T) { + mulTerm := `{"coefficient":"0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5","multiplicand":3583776697,"multiplier":2422311469}` + + var m MulTerm + err := json.Unmarshal([]byte(mulTerm), &m) + if err != nil { + log.Fatal(err) + } + + assert.NoError(t, err) +} + +func TestMulTermsUnmarshalJSON(t *testing.T) { + mulTerms := `[{"coefficient":"0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5","multiplicand":3583776697,"multiplier":2422311469},{"coefficient":"0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5","multiplicand":3583776697,"multiplier":2422311469}]` + + var m []MulTerm + err := json.Unmarshal([]byte(mulTerms), &m) + if err != nil { + log.Fatal(err) + } + + assert.NoError(t, err) +} From 40e3a2a33c3072515f514e23e310205f3a874e48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Wed, 1 Mar 2023 15:01:43 -0300 Subject: [PATCH 032/118] Implement `RawGate` with JSON deserialization --- gnark_backend_ffi/structs/raw_gate.go | 75 ++++++++++++++++++++++ gnark_backend_ffi/structs/raw_gate_test.go | 43 +++++++++++++ 2 files changed, 118 insertions(+) create mode 100644 gnark_backend_ffi/structs/raw_gate.go create mode 100644 gnark_backend_ffi/structs/raw_gate_test.go diff --git a/gnark_backend_ffi/structs/raw_gate.go b/gnark_backend_ffi/structs/raw_gate.go new file mode 100644 index 0000000..d70301c --- /dev/null +++ b/gnark_backend_ffi/structs/raw_gate.go @@ -0,0 +1,75 @@ +package structs + +import ( + "encoding/json" + "log" + + fr_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/fr" +) + +type RawGate struct { + MulTerms []MulTerm + AddTerms []AddTerm + ConstantTerm fr_bn254.Element +} + +func (g *RawGate) UnmarshalJSON(data []byte) error { + var rawGateMap map[string]interface{} + err := json.Unmarshal(data, &rawGateMap) + if err != nil { + log.Fatal(err) + return err + } + + var mulTerms []MulTerm + var addTerms []AddTerm + var constantTerm fr_bn254.Element + + // Deserialize mul terms. + if mulTermsValue, ok := rawGateMap["mul_terms"].([]interface{}); ok { + mulTermsJSON, err := json.Marshal(mulTermsValue) + if err != nil { + log.Fatal(err) + return err + } + err = json.Unmarshal(mulTermsJSON, &mulTerms) + if err != nil { + log.Fatal(err) + return err + } + } else { + log.Fatal("Error: couldn't deserialize mul terms.") + return &json.UnmarshalTypeError{} + } + + // Deserialize add terms. + if addTermsValue, ok := rawGateMap["add_terms"].([]interface{}); ok { + addTermsJSON, err := json.Marshal(addTermsValue) + if err != nil { + log.Fatal(err) + return err + } + err = json.Unmarshal(addTermsJSON, &addTerms) + if err != nil { + log.Fatal(err) + return err + } + } else { + log.Fatal("Error: couldn't deserialize add terms.") + return &json.UnmarshalTypeError{} + } + + // Deserialize constant term. + if encodedConstantTerm, ok := rawGateMap["constant_term"].(string); ok { + constantTerm = DeserializeFelt(encodedConstantTerm) + } else { + log.Fatal("Error: coefficient is not a felt.") + return &json.UnmarshalTypeError{} + } + + g.MulTerms = mulTerms + g.AddTerms = addTerms + g.ConstantTerm = constantTerm + + return nil +} diff --git a/gnark_backend_ffi/structs/raw_gate_test.go b/gnark_backend_ffi/structs/raw_gate_test.go new file mode 100644 index 0000000..67aafb0 --- /dev/null +++ b/gnark_backend_ffi/structs/raw_gate_test.go @@ -0,0 +1,43 @@ +package structs + +import ( + "encoding/json" + "fmt" + "log" + "testing" + + "github.com/stretchr/testify/assert" +) + +// TODO: Test error cases. + +func TestRawGateTermUnmarshalJSON(t *testing.T) { + mulTerms := `[{"coefficient":"0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5","multiplicand":3583776697,"multiplier":2422311469},{"coefficient":"0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5","multiplicand":3583776697,"multiplier":2422311469}]` + addTerms := `[{"coefficient":"0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5","sum":2422311469},{"coefficient":"0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5","sum":3583776697}]` + constantTerm := "0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5" + rawGate := fmt.Sprintf(`{"mul_terms":%s,"add_terms":%s,"constant_term":"%s"}`, mulTerms, addTerms, constantTerm) + + var r RawGate + err := json.Unmarshal([]byte(rawGate), &r) + if err != nil { + log.Fatal(err) + } + + assert.NoError(t, err) +} + +func TestRawGatesTermUnmarshalJSON(t *testing.T) { + mulTerms := `[{"coefficient":"0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5","multiplicand":3583776697,"multiplier":2422311469},{"coefficient":"0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5","multiplicand":3583776697,"multiplier":2422311469}]` + addTerms := `[{"coefficient":"0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5","sum":2422311469},{"coefficient":"0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5","sum":3583776697}]` + constantTerm := "0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5" + rawGate := fmt.Sprintf(`{"mul_terms":%s,"add_terms":%s,"constant_term":"%s"}`, mulTerms, addTerms, constantTerm) + rawGates := fmt.Sprintf(`[%s,%s]`, rawGate, rawGate) + + var r []RawGate + err := json.Unmarshal([]byte(rawGates), &r) + if err != nil { + log.Fatal(err) + } + + assert.NoError(t, err) +} From 15181073752dc7b96e13baf79a32ae84a878f3cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Wed, 1 Mar 2023 15:01:51 -0300 Subject: [PATCH 033/118] Implement `RawR1CS` with JSON deserialization --- gnark_backend_ffi/structs/raw_r1cs.go | 96 ++++++++++++++++++++++ gnark_backend_ffi/structs/raw_r1cs_test.go | 33 ++++++++ 2 files changed, 129 insertions(+) create mode 100644 gnark_backend_ffi/structs/raw_r1cs.go create mode 100644 gnark_backend_ffi/structs/raw_r1cs_test.go diff --git a/gnark_backend_ffi/structs/raw_r1cs.go b/gnark_backend_ffi/structs/raw_r1cs.go new file mode 100644 index 0000000..8a91ea4 --- /dev/null +++ b/gnark_backend_ffi/structs/raw_r1cs.go @@ -0,0 +1,96 @@ +package structs + +import ( + "encoding/json" + "log" + + fr_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/fr" +) + +type RawR1CS struct { + Gates []RawGate + PublicInputs Witnesses + Values fr_bn254.Vector + NumVariables uint64 + NumConstraints uint64 +} + +func (r *RawR1CS) UnmarshalJSON(data []byte) error { + var rawR1CSMap map[string]interface{} + err := json.Unmarshal(data, &rawR1CSMap) + if err != nil { + log.Fatal(err) + return err + } + + var gates []RawGate + var publicInputs Witnesses + var values fr_bn254.Vector + var numVariables uint64 + var numConstraints uint64 + + // Deserialize gates. + if gatesValue, ok := rawR1CSMap["gates"].([]interface{}); ok { + gatesJSON, err := json.Marshal(gatesValue) + if err != nil { + log.Fatal(err) + return err + } + err = json.Unmarshal(gatesJSON, &gates) + if err != nil { + log.Fatal(err) + return err + } + } else { + log.Fatal("Error: couldn't deserialize raw gates.") + return &json.UnmarshalTypeError{} + } + + if publicInputsValue, ok := rawR1CSMap["public_inputs"].([]interface{}); ok { + publicInputsJSON, err := json.Marshal(publicInputsValue) + if err != nil { + log.Fatal(err) + return err + } + err = json.Unmarshal(publicInputsJSON, &publicInputs) + if err != nil { + log.Fatal(err) + return err + } + } else { + log.Fatal("Error: couldn't deserialize public inputs.") + return &json.UnmarshalTypeError{} + } + + // Deserialize values. + if encodedValues, ok := rawR1CSMap["values"].(string); ok { + values = DeserializeFelts(encodedValues) + } else { + log.Fatal("Error: couldn't deserialize values.") + return &json.UnmarshalTypeError{} + } + + // Deserialize num_variables. + if numVariablesValue, ok := rawR1CSMap["num_variables"].(float64); ok { + numVariables = uint64(numVariablesValue) + } else { + log.Fatal("Error: couldn't deserialize num_variables.") + return &json.UnmarshalTypeError{} + } + + // Deserialize num_constraints. + if numConstraintsValue, ok := rawR1CSMap["num_constraints"].(float64); ok { + numConstraints = uint64(numConstraintsValue) + } else { + log.Fatal("Error: couldn't deserialize num_constraints.") + return &json.UnmarshalTypeError{} + } + + r.Gates = gates + r.PublicInputs = publicInputs + r.Values = values + r.NumVariables = numVariables + r.NumConstraints = numConstraints + + return nil +} diff --git a/gnark_backend_ffi/structs/raw_r1cs_test.go b/gnark_backend_ffi/structs/raw_r1cs_test.go new file mode 100644 index 0000000..d6bd01f --- /dev/null +++ b/gnark_backend_ffi/structs/raw_r1cs_test.go @@ -0,0 +1,33 @@ +package structs + +import ( + "encoding/json" + "fmt" + "math/rand" + "testing" + + "github.com/stretchr/testify/assert" +) + +// TODO: Test error cases. + +func TestRawR1CSTermUnmarshalJSON(t *testing.T) { + multiplicand := rand.Uint32() + multiplier := rand.Uint32() + sum := rand.Uint32() + mulTerms := fmt.Sprintf(`[{"coefficient":"0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5","multiplicand":%d,"multiplier":%d},{"coefficient":"0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5","multiplicand":%d,"multiplier":%d}]`, multiplicand, multiplier, multiplicand, multiplier) + addTerms := fmt.Sprintf(`[{"coefficient":"0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5","sum":%d},{"coefficient":"0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5","sum":%d}]`, sum, sum) + constantTerm := "0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5" + rawGate := fmt.Sprintf(`{"mul_terms":%s,"add_terms":%s,"constant_term":"%s"}`, mulTerms, addTerms, constantTerm) + rawGates := fmt.Sprintf(`[%s,%s]`, rawGate, rawGate) + publicInputs := fmt.Sprintf("[%d,%d,%d]", multiplicand, multiplier, sum) + values := "000000020e863ed5c2ba04f5a88c64ad335acb2df798d830db50d760c1359328fd39c6380cf4783484cb019ebb7128d66d1009d0dc3b48acd936a157037af55753e9bd32" + numVariables := rand.Uint64() + numConstraints := rand.Uint64() + rawR1CS := fmt.Sprintf(`{"gates":%s,"public_inputs":%s,"values":"%s","num_variables":%d,"num_constraints":%d}`, rawGates, publicInputs, values, numVariables, numConstraints) + + var r RawR1CS + err := json.Unmarshal([]byte(rawR1CS), &r) + + assert.NoError(t, err) +} From 4c4cde22292ff65585c8d1222c2dd2701e11fe72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Wed, 1 Mar 2023 15:02:00 -0300 Subject: [PATCH 034/118] Add `helpers` module --- gnark_backend_ffi/structs/helpers.go | 39 ++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 gnark_backend_ffi/structs/helpers.go diff --git a/gnark_backend_ffi/structs/helpers.go b/gnark_backend_ffi/structs/helpers.go new file mode 100644 index 0000000..f966086 --- /dev/null +++ b/gnark_backend_ffi/structs/helpers.go @@ -0,0 +1,39 @@ +package structs + +import ( + "encoding/hex" + "log" + + fr_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/fr" +) + +type Witness = uint32 +type Witnesses = []Witness + +func DeserializeFelt(encodedFelt string) fr_bn254.Element { + // Decode the received felt. + decodedFelt, err := hex.DecodeString(encodedFelt) + if err != nil { + log.Fatal(err) + } + + // Deserialize the decoded felt. + var deserializedFelt fr_bn254.Element + deserializedFelt.SetBytes(decodedFelt) + + return deserializedFelt +} + +func DeserializeFelts(encodedFelts string) fr_bn254.Vector { + // Decode the received felts. + decodedFelts, err := hex.DecodeString(encodedFelts) + if err != nil { + log.Fatal(err) + } + + // Unpack and deserialize the decoded felts. + var deserializedFelts fr_bn254.Vector + deserializedFelts.UnmarshalBinary(decodedFelts) + + return deserializedFelts +} From 515d222223938621c5250f7bdd82b1fb85c997ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Wed, 1 Mar 2023 15:03:03 -0300 Subject: [PATCH 035/118] Cleanup main function --- gnark_backend_ffi/main.go | 90 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 86 insertions(+), 4 deletions(-) diff --git a/gnark_backend_ffi/main.go b/gnark_backend_ffi/main.go index 4b71d99..e30819f 100644 --- a/gnark_backend_ffi/main.go +++ b/gnark_backend_ffi/main.go @@ -3,6 +3,7 @@ package main import "C" import ( "bytes" + "encoding/hex" "encoding/json" "fmt" "log" @@ -235,10 +236,91 @@ func Preprocess(rawR1CS string) (*C.char, *C.char) { return C.CString(pk_string), C.CString(vk_string) } -func main() { - rawR1CS := `{"gates":[],"public_inputs":[],"values":[],"num_variables":1}` +//export TestFeltSerialization +func TestFeltSerialization(encodedFelt string) *C.char { + // Decode the received felt. + decodedFelt, err := hex.DecodeString(encodedFelt) + if err != nil { + log.Fatal(err) + } - proof := ProveWithMeta(rawR1CS) + // Deserialize the decoded felt. + var deserializedFelt fr_bn254.Element + deserializedFelt.SetBytes(decodedFelt) + fmt.Printf("| GO |\n%v\n", deserializedFelt) - fmt.Println("Proof: ", proof) + // Serialize the felt. + serializedFelt := deserializedFelt.Bytes() + + // Encode the serialized felt. + serializedFeltString := hex.EncodeToString(serializedFelt[:]) + + return C.CString(serializedFeltString) +} + +//export TestFeltsSerialization +func TestFeltsSerialization(encodedFelts string) *C.char { + // Decode the received felts. + decodedFelts, err := hex.DecodeString(encodedFelts) + if err != nil { + log.Fatal(err) + } + + // Unpack and deserialize the decoded felts. + var deserializedFelts fr_bn254.Vector + deserializedFelts.UnmarshalBinary(decodedFelts) + + // Serialize the felt. + serializedFelts, err := deserializedFelts.MarshalBinary() + if err != nil { + log.Fatal(err) + } + + // Encode the serialized felt. + serializedFeltsString := hex.EncodeToString(serializedFelts[:]) + + return C.CString(serializedFeltsString) } + +//export TestU64Serialization +func TestU64Serialization(number uint64) uint64 { + fmt.Println(number) + return number +} + +//export TestMulTermSerialization +func TestMulTermSerialization(encodedMulTerm string) *C.char { + return C.CString("unimplemented") +} + +//export TestMulTermsSerialization +func TestMulTermsSerialization(encodedMulTerms string) *C.char { + return C.CString("unimplemented") +} + +//export TestAddTermSerialization +func TestAddTermSerialization(encodedAddTerm string) *C.char { + return C.CString("unimplemented") +} + +//export TestAddTermsSerialization +func TestAddTermsSerialization(encodedAddTerms string) *C.char { + return C.CString("unimplemented") +} + +//export TestRawGateSerialization +func TestRawGateSerialization(encodedRawGate string) *C.char { + return C.CString("unimplemented") +} + +//export TestRawGatesSerialization +func TestRawGatesSerialization(encodedRawGates string) *C.char { + return C.CString("unimplemented") +} + +//export TestRawR1CSSerialization +func TestRawR1CSSerialization(encodedR1CS string) *C.char { + return C.CString("unimplemented") +} + +func main() {} From e7c73ab9407ae4f6fb3d17b4f84f7619d8f5f800 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Wed, 1 Mar 2023 14:58:27 -0300 Subject: [PATCH 036/118] Update deps --- gnark_backend_ffi/go.mod | 4 ++++ gnark_backend_ffi/go.sum | 16 ++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/gnark_backend_ffi/go.mod b/gnark_backend_ffi/go.mod index 443e8c1..154fb80 100644 --- a/gnark_backend_ffi/go.mod +++ b/gnark_backend_ffi/go.mod @@ -6,13 +6,16 @@ require github.com/consensys/gnark-crypto v0.9.1 require ( github.com/blang/semver/v4 v4.0.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect github.com/fxamacker/cbor/v2 v2.4.0 // indirect github.com/google/pprof v0.0.0-20230207041349-798e818bf904 // indirect github.com/mattn/go-colorable v0.1.12 // indirect github.com/mattn/go-isatty v0.0.14 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rs/zerolog v1.29.0 // indirect github.com/x448/float16 v0.8.4 // indirect golang.org/x/sys v0.5.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) require ( @@ -20,5 +23,6 @@ require ( github.com/consensys/gnark v0.8.0 github.com/mmcloughlin/addchain v0.4.0 // indirect github.com/recoilme/btreeset v0.0.0-20200809183105-7b1adf6e3d3c + github.com/stretchr/testify v1.8.2 rsc.io/tmplfunc v0.0.3 // indirect ) diff --git a/gnark_backend_ffi/go.sum b/gnark_backend_ffi/go.sum index fff4a67..2214255 100644 --- a/gnark_backend_ffi/go.sum +++ b/gnark_backend_ffi/go.sum @@ -7,6 +7,9 @@ github.com/consensys/gnark v0.8.0/go.mod h1:aKmA7dIiLbTm0OV37xTq0z+Bpe4xER8EhRLi github.com/consensys/gnark-crypto v0.9.1 h1:mru55qKdWl3E035hAoh1jj9d7hVnYY5pfb6tmovSmII= github.com/consensys/gnark-crypto v0.9.1/go.mod h1:a2DQL4+5ywF6safEeZFEPGRiiGbjzGFRUN2sg06VuU4= github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fxamacker/cbor/v2 v2.4.0 h1:ri0ArlOR+5XunOP8CRUowT0pSJOwhW098ZCUyskZD88= github.com/fxamacker/cbor/v2 v2.4.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= @@ -21,16 +24,29 @@ github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iP github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU= github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/recoilme/btreeset v0.0.0-20200809183105-7b1adf6e3d3c h1:sK0DO2PhTuM2WVdCqvZN4YDJ0YBg/P0Q2IKb/0JDckw= github.com/recoilme/btreeset v0.0.0-20200809183105-7b1adf6e3d3c/go.mod h1:CokJMa/61pPRjQN8IEVINptiOHJkwoGeAyFlAWgyj2g= github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.29.0 h1:Zes4hju04hjbvkVkOhdl2HpZa+0PmVwigmo8XoORE5w= github.com/rs/zerolog v1.29.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU= rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA= From 91608887e75cb3d230ad01e59a4902d0427df436 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Wed, 1 Mar 2023 15:03:47 -0300 Subject: [PATCH 037/118] Move struct to a module --- gnark_backend_ffi/main.go | 125 +++++++++++++++++++++++++------------- 1 file changed, 84 insertions(+), 41 deletions(-) diff --git a/gnark_backend_ffi/main.go b/gnark_backend_ffi/main.go index e30819f..a6aca2e 100644 --- a/gnark_backend_ffi/main.go +++ b/gnark_backend_ffi/main.go @@ -7,46 +7,105 @@ import ( "encoding/json" "fmt" "log" + "strconv" - "github.com/recoilme/btreeset" + "gnark_backend_ffi/structs" fr_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/fr" "github.com/consensys/gnark/backend/groth16" "github.com/consensys/gnark/backend/witness" + "github.com/consensys/gnark/constraint" cs_bn254 "github.com/consensys/gnark/constraint/bn254" ) -// TODO: Deserialize rawR1CS. +func buildR1CS(r structs.RawR1CS) (*cs_bn254.R1CS, fr_bn254.Vector, fr_bn254.Vector, int, int) { + // Create R1CS. + r1cs := cs_bn254.NewR1CS(int(r.NumConstraints)) + + // Fill process RawR1CS. + nPublicVariables := 0 + nPrivateVariables := 0 + var allVariableIndices []int + var publicVariables fr_bn254.Vector + var privateVariables fr_bn254.Vector + for i, value := range r.Values { + variableName := strconv.Itoa(i) + if r.PublicInputs.Has(make([]byte, i)) { + allVariableIndices = append(allVariableIndices, r1cs.AddPublicVariable(variableName)) + publicVariables = append(publicVariables, value) + nPublicVariables++ + } else { + allVariableIndices = append(allVariableIndices, r1cs.AddSecretVariable(variableName)) + privateVariables = append(privateVariables, value) + nPrivateVariables++ + } + } -type RawR1CS struct { - Gates []RawGate - PublicInputs btreeset.BTreeSet - Values fr_bn254.Vector - NumVariables uint - NumConstraints uint -} + // Generate constraints. + ONE := r1cs.AddPublicVariable("ONE") + ZERO := r1cs.AddPublicVariable("ZERO") + COEFFICIENT_ONE := r1cs.FromInterface(1) + for _, gate := range r.Gates { + var terms constraint.LinearExpression -type RawGate struct { - MulTerms []MulTerm - AddTerms []AddTerm - ConstantTerm fr_bn254.Element -} + for _, mul_term := range gate.MulTerms { + coefficient := r1cs.FromInterface(mul_term.Coefficient) + + product := mul_term.Multiplicand * mul_term.Multiplier + productVariableName := strconv.FormatUint(uint64(product), 10) + productVariable := r1cs.AddSecretVariable(productVariableName) + + terms = append(terms, r1cs.MakeTerm(&coefficient, productVariable)) + } + + for _, add_term := range gate.AddTerms { + coefficient := r1cs.FromInterface(add_term.Coefficient) + sum := add_term.Sum -type MulTerm struct { - Coefficient fr_bn254.Element - Multiplicand uint32 - Multiplier uint32 + sumVariable := allVariableIndices[sum] + + terms = append(terms, r1cs.MakeTerm(&coefficient, sumVariable)) + } + + r1cs.AddConstraint( + constraint.R1C{ + L: constraint.LinearExpression{r1cs.MakeTerm(&COEFFICIENT_ONE, ONE)}, + R: terms, + O: constraint.LinearExpression{r1cs.MakeTerm(&COEFFICIENT_ONE, ZERO)}, + }, + ) + } + + return r1cs, publicVariables, privateVariables, nPublicVariables, nPrivateVariables } -type AddTerm struct { - Coefficient fr_bn254.Element - Sum uint32 +func buildWitnesses(r1cs *cs_bn254.R1CS, publicVariables fr_bn254.Vector, privateVariables fr_bn254.Vector, nPublicVariables int, nPrivateVariables int) witness.Witness { + witnessValues := make(chan any) + + go func() { + defer close(witnessValues) + for _, publicVariable := range publicVariables { + witnessValues <- publicVariable + } + for _, privateVariable := range privateVariables { + witnessValues <- privateVariable + } + }() + + witness, err := witness.New(r1cs.CurveID().ScalarField()) + if err != nil { + log.Fatal(err) + } + + witness.Fill(nPublicVariables, nPrivateVariables, witnessValues) + + return witness } //export ProveWithMeta func ProveWithMeta(rawR1CS string) *C.char { // Deserialize rawR1CS. - var r RawR1CS + var r structs.RawR1CS err := json.Unmarshal([]byte(rawR1CS), &r) if err != nil { log.Fatal(err) @@ -238,15 +297,7 @@ func Preprocess(rawR1CS string) (*C.char, *C.char) { //export TestFeltSerialization func TestFeltSerialization(encodedFelt string) *C.char { - // Decode the received felt. - decodedFelt, err := hex.DecodeString(encodedFelt) - if err != nil { - log.Fatal(err) - } - - // Deserialize the decoded felt. - var deserializedFelt fr_bn254.Element - deserializedFelt.SetBytes(decodedFelt) + deserializedFelt := structs.DeserializeFelt(encodedFelt) fmt.Printf("| GO |\n%v\n", deserializedFelt) // Serialize the felt. @@ -260,15 +311,7 @@ func TestFeltSerialization(encodedFelt string) *C.char { //export TestFeltsSerialization func TestFeltsSerialization(encodedFelts string) *C.char { - // Decode the received felts. - decodedFelts, err := hex.DecodeString(encodedFelts) - if err != nil { - log.Fatal(err) - } - - // Unpack and deserialize the decoded felts. - var deserializedFelts fr_bn254.Vector - deserializedFelts.UnmarshalBinary(decodedFelts) + deserializedFelts := structs.DeserializeFelts(encodedFelts) // Serialize the felt. serializedFelts, err := deserializedFelts.MarshalBinary() @@ -289,7 +332,7 @@ func TestU64Serialization(number uint64) uint64 { } //export TestMulTermSerialization -func TestMulTermSerialization(encodedMulTerm string) *C.char { +func TestMulTermSerialization(mulTerm string) *C.char { return C.CString("unimplemented") } From 3d1402a7ce611f0052edd7769c41ce5c1464a3ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Wed, 1 Mar 2023 15:06:54 -0300 Subject: [PATCH 038/118] `PublicInputs` is no longer a BTreeSet --- gnark_backend_ffi/main.go | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/gnark_backend_ffi/main.go b/gnark_backend_ffi/main.go index a6aca2e..9f59cde 100644 --- a/gnark_backend_ffi/main.go +++ b/gnark_backend_ffi/main.go @@ -30,14 +30,16 @@ func buildR1CS(r structs.RawR1CS) (*cs_bn254.R1CS, fr_bn254.Vector, fr_bn254.Vec var privateVariables fr_bn254.Vector for i, value := range r.Values { variableName := strconv.Itoa(i) - if r.PublicInputs.Has(make([]byte, i)) { - allVariableIndices = append(allVariableIndices, r1cs.AddPublicVariable(variableName)) - publicVariables = append(publicVariables, value) - nPublicVariables++ - } else { - allVariableIndices = append(allVariableIndices, r1cs.AddSecretVariable(variableName)) - privateVariables = append(privateVariables, value) - nPrivateVariables++ + for _, publicInput := range r.PublicInputs { + if uint32(i) == publicInput { + allVariableIndices = append(allVariableIndices, r1cs.AddPublicVariable(variableName)) + publicVariables = append(publicVariables, value) + nPublicVariables++ + } else { + allVariableIndices = append(allVariableIndices, r1cs.AddSecretVariable(variableName)) + privateVariables = append(privateVariables, value) + nPrivateVariables++ + } } } From 28fd066d10364b1c3360f1d750ab1c8b30feb5c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Wed, 1 Mar 2023 15:17:45 -0300 Subject: [PATCH 039/118] Update function naming --- gnark_backend_ffi/main.go | 40 +++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/gnark_backend_ffi/main.go b/gnark_backend_ffi/main.go index 9f59cde..ec0c9ee 100644 --- a/gnark_backend_ffi/main.go +++ b/gnark_backend_ffi/main.go @@ -297,8 +297,8 @@ func Preprocess(rawR1CS string) (*C.char, *C.char) { return C.CString(pk_string), C.CString(vk_string) } -//export TestFeltSerialization -func TestFeltSerialization(encodedFelt string) *C.char { +//export IntegrationTestFeltSerialization +func IntegrationTestFeltSerialization(encodedFelt string) *C.char { deserializedFelt := structs.DeserializeFelt(encodedFelt) fmt.Printf("| GO |\n%v\n", deserializedFelt) @@ -311,8 +311,8 @@ func TestFeltSerialization(encodedFelt string) *C.char { return C.CString(serializedFeltString) } -//export TestFeltsSerialization -func TestFeltsSerialization(encodedFelts string) *C.char { +//export IntegrationTestFeltsSerialization +func IntegrationTestFeltsSerialization(encodedFelts string) *C.char { deserializedFelts := structs.DeserializeFelts(encodedFelts) // Serialize the felt. @@ -327,44 +327,44 @@ func TestFeltsSerialization(encodedFelts string) *C.char { return C.CString(serializedFeltsString) } -//export TestU64Serialization -func TestU64Serialization(number uint64) uint64 { +//export IntegrationTestU64Serialization +func IntegrationTestU64Serialization(number uint64) uint64 { fmt.Println(number) return number } -//export TestMulTermSerialization -func TestMulTermSerialization(mulTerm string) *C.char { +//export IntegrationTestMulTermSerialization +func IntegrationTestMulTermSerialization(mulTerm string) *C.char { return C.CString("unimplemented") } -//export TestMulTermsSerialization -func TestMulTermsSerialization(encodedMulTerms string) *C.char { +//export IntegrationTestMulTermsSerialization +func IntegrationTestMulTermsSerialization(encodedMulTerms string) *C.char { return C.CString("unimplemented") } -//export TestAddTermSerialization -func TestAddTermSerialization(encodedAddTerm string) *C.char { +//export IntegrationTestAddTermSerialization +func IntegrationTestAddTermSerialization(encodedAddTerm string) *C.char { return C.CString("unimplemented") } -//export TestAddTermsSerialization -func TestAddTermsSerialization(encodedAddTerms string) *C.char { +//export IntegrationTestAddTermsSerialization +func IntegrationTestAddTermsSerialization(encodedAddTerms string) *C.char { return C.CString("unimplemented") } -//export TestRawGateSerialization -func TestRawGateSerialization(encodedRawGate string) *C.char { +//export IntegrationTestRawGateSerialization +func IntegrationTestRawGateSerialization(encodedRawGate string) *C.char { return C.CString("unimplemented") } -//export TestRawGatesSerialization -func TestRawGatesSerialization(encodedRawGates string) *C.char { +//export IntegrationTestRawGatesSerialization +func IntegrationTestRawGatesSerialization(encodedRawGates string) *C.char { return C.CString("unimplemented") } -//export TestRawR1CSSerialization -func TestRawR1CSSerialization(encodedR1CS string) *C.char { +//export IntegrationTestRawR1CSSerialization +func IntegrationTestRawR1CSSerialization(encodedR1CS string) *C.char { return C.CString("unimplemented") } From 370a827b4ec4c80f3af5aa1e06d578f207f5e340 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Wed, 1 Mar 2023 16:04:13 -0300 Subject: [PATCH 040/118] Improve testing using randomness --- gnark_backend_ffi/structs/add_term_test.go | 10 +++++++-- gnark_backend_ffi/structs/helpers.go | 23 ++++++++++++++++++++ gnark_backend_ffi/structs/mul_term_test.go | 12 +++++++++-- gnark_backend_ffi/structs/raw_gate_test.go | 25 +++++++++++++++------- gnark_backend_ffi/structs/raw_r1cs_test.go | 13 +++++------ 5 files changed, 65 insertions(+), 18 deletions(-) diff --git a/gnark_backend_ffi/structs/add_term_test.go b/gnark_backend_ffi/structs/add_term_test.go index 830d62f..154ff57 100644 --- a/gnark_backend_ffi/structs/add_term_test.go +++ b/gnark_backend_ffi/structs/add_term_test.go @@ -2,7 +2,9 @@ package structs import ( "encoding/json" + "fmt" "log" + "math/rand" "testing" "github.com/stretchr/testify/assert" @@ -11,7 +13,9 @@ import ( // TODO: Test error cases. func TestAddTermUnmarshalJSON(t *testing.T) { - addTerm := `{"coefficient":"0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5","sum":2422311469}` + encodedCoefficient, _ := SampleEncodedFelt() + sum := rand.Uint32() + addTerm := fmt.Sprintf(`{"coefficient":"%s","sum":%d}`, encodedCoefficient, sum) var a AddTerm err := json.Unmarshal([]byte(addTerm), &a) @@ -23,7 +27,9 @@ func TestAddTermUnmarshalJSON(t *testing.T) { } func TestAddTermsUnmarshalJSON(t *testing.T) { - addTerms := `[{"coefficient":"0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5","sum":2422311469},{"coefficient":"0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5","sum":3583776697}]` + encodedCoefficient, _ := SampleEncodedFelt() + sum := rand.Uint32() + addTerms := fmt.Sprintf(`[{"coefficient":"%s","sum":%d},{"coefficient":"%s","sum":%d}]`, encodedCoefficient, sum, encodedCoefficient, sum) var a []AddTerm err := json.Unmarshal([]byte(addTerms), &a) diff --git a/gnark_backend_ffi/structs/helpers.go b/gnark_backend_ffi/structs/helpers.go index f966086..ad148ba 100644 --- a/gnark_backend_ffi/structs/helpers.go +++ b/gnark_backend_ffi/structs/helpers.go @@ -37,3 +37,26 @@ func DeserializeFelts(encodedFelts string) fr_bn254.Vector { return deserializedFelts } + +// Samples a felt and returns the encoded felt and the non-encoded felt. +func SampleEncodedFelt() (string, fr_bn254.Element) { + var felt fr_bn254.Element + felt.SetRandom() + + return hex.EncodeToString(felt.Marshal()), felt +} + +// Samples a felts vector and returns the encoded felts and the non-encoded felts vector. +func SampleEncodedFelts() (string, fr_bn254.Vector) { + var felt1 fr_bn254.Element + felt1.SetRandom() + + var felt2 fr_bn254.Element + felt2.SetRandom() + + felts := fr_bn254.Vector{felt1, felt2} + + binaryFelts, _ := felts.MarshalBinary() + + return hex.EncodeToString(binaryFelts), felts +} diff --git a/gnark_backend_ffi/structs/mul_term_test.go b/gnark_backend_ffi/structs/mul_term_test.go index 1001cd5..f5c4e71 100644 --- a/gnark_backend_ffi/structs/mul_term_test.go +++ b/gnark_backend_ffi/structs/mul_term_test.go @@ -2,7 +2,9 @@ package structs import ( "encoding/json" + "fmt" "log" + "math/rand" "testing" "github.com/stretchr/testify/assert" @@ -11,7 +13,10 @@ import ( // TODO: Test error cases. func TestMulTermUnmarshalJSON(t *testing.T) { - mulTerm := `{"coefficient":"0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5","multiplicand":3583776697,"multiplier":2422311469}` + encodedCoefficient, _ := SampleEncodedFelt() + multiplicand := rand.Uint32() + multiplier := rand.Uint32() + mulTerm := fmt.Sprintf(`{"coefficient":"%s","multiplicand":%d,"multiplier":%d}`, encodedCoefficient, multiplicand, multiplier) var m MulTerm err := json.Unmarshal([]byte(mulTerm), &m) @@ -23,7 +28,10 @@ func TestMulTermUnmarshalJSON(t *testing.T) { } func TestMulTermsUnmarshalJSON(t *testing.T) { - mulTerms := `[{"coefficient":"0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5","multiplicand":3583776697,"multiplier":2422311469},{"coefficient":"0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5","multiplicand":3583776697,"multiplier":2422311469}]` + encodedCoefficient, _ := SampleEncodedFelt() + multiplicand := rand.Uint32() + multiplier := rand.Uint32() + mulTerms := fmt.Sprintf(`[{"coefficient":"%s","multiplicand":%d,"multiplier":%d},{"coefficient":"%s","multiplicand":%d,"multiplier":%d}]`, encodedCoefficient, multiplicand, multiplier, encodedCoefficient, multiplicand, multiplier) var m []MulTerm err := json.Unmarshal([]byte(mulTerms), &m) diff --git a/gnark_backend_ffi/structs/raw_gate_test.go b/gnark_backend_ffi/structs/raw_gate_test.go index 67aafb0..a6a84b1 100644 --- a/gnark_backend_ffi/structs/raw_gate_test.go +++ b/gnark_backend_ffi/structs/raw_gate_test.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" "log" + "math/rand" "testing" "github.com/stretchr/testify/assert" @@ -12,10 +13,14 @@ import ( // TODO: Test error cases. func TestRawGateTermUnmarshalJSON(t *testing.T) { - mulTerms := `[{"coefficient":"0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5","multiplicand":3583776697,"multiplier":2422311469},{"coefficient":"0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5","multiplicand":3583776697,"multiplier":2422311469}]` - addTerms := `[{"coefficient":"0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5","sum":2422311469},{"coefficient":"0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5","sum":3583776697}]` - constantTerm := "0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5" - rawGate := fmt.Sprintf(`{"mul_terms":%s,"add_terms":%s,"constant_term":"%s"}`, mulTerms, addTerms, constantTerm) + encodedCoefficient, _ := SampleEncodedFelt() + multiplicand := rand.Uint32() + multiplier := rand.Uint32() + sum := rand.Uint32() + mulTerms := fmt.Sprintf(`[{"coefficient":"%s","multiplicand":%d,"multiplier":%d},{"coefficient":"%s","multiplicand":%d,"multiplier":%d}]`, encodedCoefficient, multiplicand, multiplier, encodedCoefficient, multiplicand, multiplier) + addTerms := fmt.Sprintf(`[{"coefficient":"%s","sum":%d},{"coefficient":"%s","sum":%d}]`, encodedCoefficient, sum, encodedCoefficient, sum) + encodedConstantTerm, _ := SampleEncodedFelt() + rawGate := fmt.Sprintf(`{"mul_terms":%s,"add_terms":%s,"constant_term":"%s"}`, mulTerms, addTerms, encodedConstantTerm) var r RawGate err := json.Unmarshal([]byte(rawGate), &r) @@ -27,10 +32,14 @@ func TestRawGateTermUnmarshalJSON(t *testing.T) { } func TestRawGatesTermUnmarshalJSON(t *testing.T) { - mulTerms := `[{"coefficient":"0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5","multiplicand":3583776697,"multiplier":2422311469},{"coefficient":"0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5","multiplicand":3583776697,"multiplier":2422311469}]` - addTerms := `[{"coefficient":"0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5","sum":2422311469},{"coefficient":"0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5","sum":3583776697}]` - constantTerm := "0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5" - rawGate := fmt.Sprintf(`{"mul_terms":%s,"add_terms":%s,"constant_term":"%s"}`, mulTerms, addTerms, constantTerm) + encodedCoefficient, _ := SampleEncodedFelt() + multiplicand := rand.Uint32() + multiplier := rand.Uint32() + sum := rand.Uint32() + mulTerms := fmt.Sprintf(`[{"coefficient":"%s","multiplicand":%d,"multiplier":%d},{"coefficient":"%s","multiplicand":%d,"multiplier":%d}]`, encodedCoefficient, multiplicand, multiplier, encodedCoefficient, multiplicand, multiplier) + addTerms := fmt.Sprintf(`[{"coefficient":"%s","sum":%d},{"coefficient":"%s","sum":%d}]`, encodedCoefficient, sum, encodedCoefficient, sum) + encodedConstantTerm, _ := SampleEncodedFelt() + rawGate := fmt.Sprintf(`{"mul_terms":%s,"add_terms":%s,"constant_term":"%s"}`, mulTerms, addTerms, encodedConstantTerm) rawGates := fmt.Sprintf(`[%s,%s]`, rawGate, rawGate) var r []RawGate diff --git a/gnark_backend_ffi/structs/raw_r1cs_test.go b/gnark_backend_ffi/structs/raw_r1cs_test.go index d6bd01f..7705565 100644 --- a/gnark_backend_ffi/structs/raw_r1cs_test.go +++ b/gnark_backend_ffi/structs/raw_r1cs_test.go @@ -12,19 +12,20 @@ import ( // TODO: Test error cases. func TestRawR1CSTermUnmarshalJSON(t *testing.T) { + encodedCoefficient, _ := SampleEncodedFelt() multiplicand := rand.Uint32() multiplier := rand.Uint32() sum := rand.Uint32() - mulTerms := fmt.Sprintf(`[{"coefficient":"0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5","multiplicand":%d,"multiplier":%d},{"coefficient":"0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5","multiplicand":%d,"multiplier":%d}]`, multiplicand, multiplier, multiplicand, multiplier) - addTerms := fmt.Sprintf(`[{"coefficient":"0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5","sum":%d},{"coefficient":"0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5","sum":%d}]`, sum, sum) - constantTerm := "0e3ef945f56c24501196feee0cc6446900dc410d0c6a4d3b4729c4788c0716e5" - rawGate := fmt.Sprintf(`{"mul_terms":%s,"add_terms":%s,"constant_term":"%s"}`, mulTerms, addTerms, constantTerm) + mulTerms := fmt.Sprintf(`[{"coefficient":"%s","multiplicand":%d,"multiplier":%d},{"coefficient":"%s","multiplicand":%d,"multiplier":%d}]`, encodedCoefficient, multiplicand, multiplier, encodedCoefficient, multiplicand, multiplier) + addTerms := fmt.Sprintf(`[{"coefficient":"%s","sum":%d},{"coefficient":"%s","sum":%d}]`, encodedCoefficient, sum, encodedCoefficient, sum) + encodedConstantTerm, _ := SampleEncodedFelt() + rawGate := fmt.Sprintf(`{"mul_terms":%s,"add_terms":%s,"constant_term":"%s"}`, mulTerms, addTerms, encodedConstantTerm) rawGates := fmt.Sprintf(`[%s,%s]`, rawGate, rawGate) publicInputs := fmt.Sprintf("[%d,%d,%d]", multiplicand, multiplier, sum) - values := "000000020e863ed5c2ba04f5a88c64ad335acb2df798d830db50d760c1359328fd39c6380cf4783484cb019ebb7128d66d1009d0dc3b48acd936a157037af55753e9bd32" + encodedValues, _ := SampleEncodedFelts() numVariables := rand.Uint64() numConstraints := rand.Uint64() - rawR1CS := fmt.Sprintf(`{"gates":%s,"public_inputs":%s,"values":"%s","num_variables":%d,"num_constraints":%d}`, rawGates, publicInputs, values, numVariables, numConstraints) + rawR1CS := fmt.Sprintf(`{"gates":%s,"public_inputs":%s,"values":"%s","num_variables":%d,"num_constraints":%d}`, rawGates, publicInputs, encodedValues, numVariables, numConstraints) var r RawR1CS err := json.Unmarshal([]byte(rawR1CS), &r) From 675dff8e5c5c8d7335e9baf16fd2697606f6b3ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Wed, 1 Mar 2023 17:07:54 -0300 Subject: [PATCH 041/118] Finished testing - Added unchecked helper methods for deserializing - The hole struct is asserted --- gnark_backend_ffi/structs/add_term_test.go | 10 ++- gnark_backend_ffi/structs/helpers.go | 71 ++++++++++++++++++++++ gnark_backend_ffi/structs/mul_term_test.go | 12 +++- gnark_backend_ffi/structs/raw_gate_test.go | 12 +++- gnark_backend_ffi/structs/raw_r1cs.go | 2 + gnark_backend_ffi/structs/raw_r1cs_test.go | 11 +++- 6 files changed, 109 insertions(+), 9 deletions(-) diff --git a/gnark_backend_ffi/structs/add_term_test.go b/gnark_backend_ffi/structs/add_term_test.go index 154ff57..38285f0 100644 --- a/gnark_backend_ffi/structs/add_term_test.go +++ b/gnark_backend_ffi/structs/add_term_test.go @@ -13,7 +13,7 @@ import ( // TODO: Test error cases. func TestAddTermUnmarshalJSON(t *testing.T) { - encodedCoefficient, _ := SampleEncodedFelt() + encodedCoefficient, nonEncodedCoefficient := SampleEncodedFelt() sum := rand.Uint32() addTerm := fmt.Sprintf(`{"coefficient":"%s","sum":%d}`, encodedCoefficient, sum) @@ -24,10 +24,12 @@ func TestAddTermUnmarshalJSON(t *testing.T) { } assert.NoError(t, err) + assert.Equal(t, nonEncodedCoefficient, a.Coefficient) + assert.Equal(t, sum, a.Sum) } func TestAddTermsUnmarshalJSON(t *testing.T) { - encodedCoefficient, _ := SampleEncodedFelt() + encodedCoefficient, nonEncodedCoefficient := SampleEncodedFelt() sum := rand.Uint32() addTerms := fmt.Sprintf(`[{"coefficient":"%s","sum":%d},{"coefficient":"%s","sum":%d}]`, encodedCoefficient, sum, encodedCoefficient, sum) @@ -38,4 +40,8 @@ func TestAddTermsUnmarshalJSON(t *testing.T) { } assert.NoError(t, err) + for _, addTerm := range a { + assert.Equal(t, nonEncodedCoefficient, addTerm.Coefficient) + assert.Equal(t, sum, addTerm.Sum) + } } diff --git a/gnark_backend_ffi/structs/helpers.go b/gnark_backend_ffi/structs/helpers.go index ad148ba..dc760dd 100644 --- a/gnark_backend_ffi/structs/helpers.go +++ b/gnark_backend_ffi/structs/helpers.go @@ -2,6 +2,7 @@ package structs import ( "encoding/hex" + "encoding/json" "log" fr_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/fr" @@ -38,6 +39,76 @@ func DeserializeFelts(encodedFelts string) fr_bn254.Vector { return deserializedFelts } +func UncheckedDeserializeAddTerm(addTerm string) AddTerm { + var a AddTerm + err := json.Unmarshal([]byte(addTerm), &a) + if err != nil { + log.Fatal(err) + } + + return a +} + +func UncheckedDeserializeAddTerms(addTerms string) []AddTerm { + var a []AddTerm + err := json.Unmarshal([]byte(addTerms), &a) + if err != nil { + log.Fatal(err) + } + + return a +} + +func UncheckedDeserializeMulTerm(mulTerm string) MulTerm { + var m MulTerm + err := json.Unmarshal([]byte(mulTerm), &m) + if err != nil { + log.Fatal(err) + } + + return m +} + +func UncheckedDeserializeMulTerms(mulTerms string) []MulTerm { + var m []MulTerm + err := json.Unmarshal([]byte(mulTerms), &m) + if err != nil { + log.Fatal(err) + } + + return m +} + +func UncheckedDeserializeRawGate(rawGate string) RawGate { + var r RawGate + err := json.Unmarshal([]byte(rawGate), &r) + if err != nil { + log.Fatal(err) + } + + return r +} + +func UncheckedDeserializeRawGates(rawGates string) []RawGate { + var r []RawGate + err := json.Unmarshal([]byte(rawGates), &r) + if err != nil { + log.Fatal(err) + } + + return r +} + +func UncheckedDeserializeRawR1CS(rawR1CS string) RawR1CS { + var r RawR1CS + err := json.Unmarshal([]byte(rawR1CS), &r) + if err != nil { + log.Fatal(err) + } + + return r +} + // Samples a felt and returns the encoded felt and the non-encoded felt. func SampleEncodedFelt() (string, fr_bn254.Element) { var felt fr_bn254.Element diff --git a/gnark_backend_ffi/structs/mul_term_test.go b/gnark_backend_ffi/structs/mul_term_test.go index f5c4e71..942ccfb 100644 --- a/gnark_backend_ffi/structs/mul_term_test.go +++ b/gnark_backend_ffi/structs/mul_term_test.go @@ -13,7 +13,7 @@ import ( // TODO: Test error cases. func TestMulTermUnmarshalJSON(t *testing.T) { - encodedCoefficient, _ := SampleEncodedFelt() + encodedCoefficient, nonEncodedCoefficient := SampleEncodedFelt() multiplicand := rand.Uint32() multiplier := rand.Uint32() mulTerm := fmt.Sprintf(`{"coefficient":"%s","multiplicand":%d,"multiplier":%d}`, encodedCoefficient, multiplicand, multiplier) @@ -25,10 +25,13 @@ func TestMulTermUnmarshalJSON(t *testing.T) { } assert.NoError(t, err) + assert.Equal(t, nonEncodedCoefficient, m.Coefficient) + assert.Equal(t, multiplicand, m.Multiplicand) + assert.Equal(t, multiplier, m.Multiplier) } func TestMulTermsUnmarshalJSON(t *testing.T) { - encodedCoefficient, _ := SampleEncodedFelt() + encodedCoefficient, nonEncodedCoefficient := SampleEncodedFelt() multiplicand := rand.Uint32() multiplier := rand.Uint32() mulTerms := fmt.Sprintf(`[{"coefficient":"%s","multiplicand":%d,"multiplier":%d},{"coefficient":"%s","multiplicand":%d,"multiplier":%d}]`, encodedCoefficient, multiplicand, multiplier, encodedCoefficient, multiplicand, multiplier) @@ -40,4 +43,9 @@ func TestMulTermsUnmarshalJSON(t *testing.T) { } assert.NoError(t, err) + for _, mulTerm := range m { + assert.Equal(t, nonEncodedCoefficient, mulTerm.Coefficient) + assert.Equal(t, multiplicand, mulTerm.Multiplicand) + assert.Equal(t, multiplier, mulTerm.Multiplier) + } } diff --git a/gnark_backend_ffi/structs/raw_gate_test.go b/gnark_backend_ffi/structs/raw_gate_test.go index a6a84b1..a95587e 100644 --- a/gnark_backend_ffi/structs/raw_gate_test.go +++ b/gnark_backend_ffi/structs/raw_gate_test.go @@ -19,7 +19,7 @@ func TestRawGateTermUnmarshalJSON(t *testing.T) { sum := rand.Uint32() mulTerms := fmt.Sprintf(`[{"coefficient":"%s","multiplicand":%d,"multiplier":%d},{"coefficient":"%s","multiplicand":%d,"multiplier":%d}]`, encodedCoefficient, multiplicand, multiplier, encodedCoefficient, multiplicand, multiplier) addTerms := fmt.Sprintf(`[{"coefficient":"%s","sum":%d},{"coefficient":"%s","sum":%d}]`, encodedCoefficient, sum, encodedCoefficient, sum) - encodedConstantTerm, _ := SampleEncodedFelt() + encodedConstantTerm, nonEncodedConstantTerm := SampleEncodedFelt() rawGate := fmt.Sprintf(`{"mul_terms":%s,"add_terms":%s,"constant_term":"%s"}`, mulTerms, addTerms, encodedConstantTerm) var r RawGate @@ -29,6 +29,9 @@ func TestRawGateTermUnmarshalJSON(t *testing.T) { } assert.NoError(t, err) + assert.Equal(t, UncheckedDeserializeMulTerms(mulTerms), r.MulTerms) + assert.Equal(t, UncheckedDeserializeAddTerms(addTerms), r.AddTerms) + assert.Equal(t, nonEncodedConstantTerm, r.ConstantTerm) } func TestRawGatesTermUnmarshalJSON(t *testing.T) { @@ -38,7 +41,7 @@ func TestRawGatesTermUnmarshalJSON(t *testing.T) { sum := rand.Uint32() mulTerms := fmt.Sprintf(`[{"coefficient":"%s","multiplicand":%d,"multiplier":%d},{"coefficient":"%s","multiplicand":%d,"multiplier":%d}]`, encodedCoefficient, multiplicand, multiplier, encodedCoefficient, multiplicand, multiplier) addTerms := fmt.Sprintf(`[{"coefficient":"%s","sum":%d},{"coefficient":"%s","sum":%d}]`, encodedCoefficient, sum, encodedCoefficient, sum) - encodedConstantTerm, _ := SampleEncodedFelt() + encodedConstantTerm, nonEncodedConstantTerm := SampleEncodedFelt() rawGate := fmt.Sprintf(`{"mul_terms":%s,"add_terms":%s,"constant_term":"%s"}`, mulTerms, addTerms, encodedConstantTerm) rawGates := fmt.Sprintf(`[%s,%s]`, rawGate, rawGate) @@ -49,4 +52,9 @@ func TestRawGatesTermUnmarshalJSON(t *testing.T) { } assert.NoError(t, err) + for _, rawGate := range r { + assert.Equal(t, UncheckedDeserializeMulTerms(mulTerms), rawGate.MulTerms) + assert.Equal(t, UncheckedDeserializeAddTerms(addTerms), rawGate.AddTerms) + assert.Equal(t, nonEncodedConstantTerm, rawGate.ConstantTerm) + } } diff --git a/gnark_backend_ffi/structs/raw_r1cs.go b/gnark_backend_ffi/structs/raw_r1cs.go index 8a91ea4..c648b58 100644 --- a/gnark_backend_ffi/structs/raw_r1cs.go +++ b/gnark_backend_ffi/structs/raw_r1cs.go @@ -2,6 +2,7 @@ package structs import ( "encoding/json" + "fmt" "log" fr_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/fr" @@ -79,6 +80,7 @@ func (r *RawR1CS) UnmarshalJSON(data []byte) error { } // Deserialize num_constraints. + fmt.Println("", rawR1CSMap["num_constraints"]) if numConstraintsValue, ok := rawR1CSMap["num_constraints"].(float64); ok { numConstraints = uint64(numConstraintsValue) } else { diff --git a/gnark_backend_ffi/structs/raw_r1cs_test.go b/gnark_backend_ffi/structs/raw_r1cs_test.go index 7705565..30228d7 100644 --- a/gnark_backend_ffi/structs/raw_r1cs_test.go +++ b/gnark_backend_ffi/structs/raw_r1cs_test.go @@ -22,13 +22,18 @@ func TestRawR1CSTermUnmarshalJSON(t *testing.T) { rawGate := fmt.Sprintf(`{"mul_terms":%s,"add_terms":%s,"constant_term":"%s"}`, mulTerms, addTerms, encodedConstantTerm) rawGates := fmt.Sprintf(`[%s,%s]`, rawGate, rawGate) publicInputs := fmt.Sprintf("[%d,%d,%d]", multiplicand, multiplier, sum) - encodedValues, _ := SampleEncodedFelts() - numVariables := rand.Uint64() - numConstraints := rand.Uint64() + encodedValues, nonEncodedValues := SampleEncodedFelts() + numVariables := uint64(10) + numConstraints := uint64(10) rawR1CS := fmt.Sprintf(`{"gates":%s,"public_inputs":%s,"values":"%s","num_variables":%d,"num_constraints":%d}`, rawGates, publicInputs, encodedValues, numVariables, numConstraints) var r RawR1CS err := json.Unmarshal([]byte(rawR1CS), &r) assert.NoError(t, err) + assert.Equal(t, UncheckedDeserializeRawGates(rawGates), r.Gates) + assert.Equal(t, Witnesses{multiplicand, multiplier, sum}, r.PublicInputs) + assert.Equal(t, nonEncodedValues, r.Values) + assert.Equal(t, numConstraints, r.NumConstraints) + assert.Equal(t, numVariables, r.NumVariables) } From 1303328fe331d0b9247d37e9f0c3e32544e1ba2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Wed, 1 Mar 2023 17:10:32 -0300 Subject: [PATCH 042/118] Update Makefile --- Makefile | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 001e5fa..7396a25 100644 --- a/Makefile +++ b/Makefile @@ -6,9 +6,8 @@ build-go: $ cd ${FFI_LIB_PATH}; \ go build -buildmode=c-archive -o libgnark_backend.a main.go -test-go: build-go - $ cd ${FFI_LIB_PATH}; \ - go test +# Temporary solution for testing the only tests we have. We should test recurively. +test-go: go test -run '' gnark_backend_ffi/structs build: build-go $ RUSTFLAGS="-L${FFI_LIB_PATH}" cargo build From 2c6962c3faa5fbeb6f63aaf3b93bd90ea261ccb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Wed, 1 Mar 2023 17:10:42 -0300 Subject: [PATCH 043/118] Enabled testing for Go --- .github/workflows/ci.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 6c35892..4ae34de 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -44,7 +44,6 @@ jobs: - name: Build run: make build-go - name: Test - if: ${{ false }} # disable for now run: make test-go test: From 81110fbd97bbff2ba799f520a5d062bcc674018b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Wed, 1 Mar 2023 17:12:27 -0300 Subject: [PATCH 044/118] Fix Makefile --- Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 7396a25..1b1465a 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,8 @@ build-go: go build -buildmode=c-archive -o libgnark_backend.a main.go # Temporary solution for testing the only tests we have. We should test recurively. -test-go: go test -run '' gnark_backend_ffi/structs +test-go: + go test -run '' gnark_backend_ffi/structs build: build-go $ RUSTFLAGS="-L${FFI_LIB_PATH}" cargo build From 57448a9b755d9ffaad22d6e580681c8c3cc8ace8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Wed, 1 Mar 2023 17:14:43 -0300 Subject: [PATCH 045/118] Fix Makefile --- Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 1b1465a..50a1f03 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,8 @@ build-go: # Temporary solution for testing the only tests we have. We should test recurively. test-go: - go test -run '' gnark_backend_ffi/structs + $ cd ${FFI_LIB_PATH}; \ + go test -run '' gnark_backend_ffi/structs build: build-go $ RUSTFLAGS="-L${FFI_LIB_PATH}" cargo build From 8722a8bb835811b3484399f231ff2f8b991188f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Wed, 1 Mar 2023 18:57:07 -0300 Subject: [PATCH 046/118] Remove old serialize terms functions --- tests/serialization_tests.rs | 34 ---------------------------------- 1 file changed, 34 deletions(-) diff --git a/tests/serialization_tests.rs b/tests/serialization_tests.rs index 1398ec5..7984eef 100644 --- a/tests/serialization_tests.rs +++ b/tests/serialization_tests.rs @@ -57,40 +57,6 @@ fn serialize_felts(felts: &[gnark_backend_wrapper::groth16::Fr]) -> Vec { buff } -fn serialize_mul_term( - mul_term: &( - gnark_backend_wrapper::groth16::Fr, - acvm::Witness, - acvm::Witness, - ), -) -> String { - let serialized_coefficient = serialize_felt(&mul_term.0); - let encoded_coefficient = hex::encode(serialized_coefficient); - - let serialized_multiplicand = serde_json::to_string(&mul_term.1).unwrap(); - let serialized_multiplier = serde_json::to_string(&mul_term.2).unwrap(); - - serde_json::to_string(&json!({ - "coefficient": encoded_coefficient, - "multiplicand": serialized_multiplicand, - "multiplier": serialized_multiplier - })) - .unwrap() -} - -fn serialize_add_term(mul_term: &(gnark_backend_wrapper::groth16::Fr, acvm::Witness)) -> Vec { - let serialized_coefficient = serialize_felt(&mul_term.0); - let encoded_coefficient = hex::encode(serialized_coefficient); - - let serialized_sum = serde_json::to_string(&mul_term.1).unwrap(); - - serde_json::to_vec(&json!({ - "coefficient": encoded_coefficient, - "sum": serialized_sum, - })) - .unwrap() -} - #[test] fn test_felt_serialization() { // Sample a random felt. From 5f8d92cf4ab9b93f8c387478c174cea74d091e87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Wed, 1 Mar 2023 18:57:19 -0300 Subject: [PATCH 047/118] cargo fmt --- tests/serialization_tests.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/serialization_tests.rs b/tests/serialization_tests.rs index 7984eef..679784c 100644 --- a/tests/serialization_tests.rs +++ b/tests/serialization_tests.rs @@ -1,5 +1,11 @@ use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; -use noir_backend_using_gnark::{acvm, gnark_backend_wrapper}; +use noir_backend_using_gnark::{ + acvm, + gnark_backend_wrapper::{ + self, + groth16::{AddTerm, MulTerm}, + }, +}; use serde_json::json; use std::ffi; From b1aa320fe061131a2552f88157a44231248047d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Wed, 1 Mar 2023 18:58:30 -0300 Subject: [PATCH 048/118] Add serialization integration tests - MulTerm - MulTerms - AddTerm - AddTerms - RawGate (TODO) - RawGates (TODO) - RawR1CS (TODO) --- tests/serialization_tests.rs | 152 +++++++++++++++++++++++++++++++++++ 1 file changed, 152 insertions(+) diff --git a/tests/serialization_tests.rs b/tests/serialization_tests.rs index 679784c..a02fe26 100644 --- a/tests/serialization_tests.rs +++ b/tests/serialization_tests.rs @@ -150,3 +150,155 @@ fn test_u64_serialization() { assert_eq!(number, pong) } + +#[test] +fn test_mul_term_serialization() { + // Sample random coefficient. + let coefficient: gnark_backend_wrapper::groth16::Fr = rand::random(); + // Sample a random multiplicand. + let multiplicand = acvm::Witness::new(rand::random()); + // Sample a random multiplier. + let multiplier: acvm::Witness = acvm::Witness::new(rand::random()); + // Sample a random mul term. + let mul_term = MulTerm { + coefficient, + multiplicand, + multiplier, + }; + + println!("| RUST |"); + println!("{:?}", mul_term.coefficient.0 .0); + println!("{:?}", mul_term.multiplicand.0); + println!("{:?}", mul_term.multiplier.0); + + // Serialize the mul term. + let serialized_mul_term = serde_json::to_string(&mul_term).unwrap(); + + // Prepare ping for Go. + let pre_ping = ffi::CString::new(serialized_mul_term).unwrap(); + let ping = gnark_backend_wrapper::groth16::GoString::try_from(&pre_ping).unwrap(); + + // Send and receive pong from Go. + let pong: *const ffi::c_char = unsafe { TestMulTermSerialization(ping) }; + + // TODO: + // * Prepare pong for Rust. + // * Assert that mul_term and go_mul_term are the same (go_mul_term is + // the pong's deserialization) +} + +#[test] +fn test_mul_terms_serialization() { + // Sample random coefficient. + let coefficient: gnark_backend_wrapper::groth16::Fr = rand::random(); + // Sample a random multiplicand. + let multiplicand = acvm::Witness::new(rand::random()); + // Sample a random multiplier. + let multiplier: acvm::Witness = acvm::Witness::new(rand::random()); + // Sample a random mul term. + let mul_terms = vec![ + MulTerm { + coefficient, + multiplicand, + multiplier, + }, + MulTerm { + coefficient, + multiplicand, + multiplier, + }, + ]; + + println!("| RUST |"); + for mul_term in &mul_terms { + println!("{:?}", mul_term.coefficient.0 .0); + println!("{:?}", mul_term.multiplicand.0); + println!("{:?}", mul_term.multiplier.0); + println!() + } + + // Serialize the mul term. + let serialized_mul_terms = serde_json::to_string(&mul_terms).unwrap(); + + // Prepare ping for Go. + let pre_ping = ffi::CString::new(serialized_mul_terms).unwrap(); + let ping = gnark_backend_wrapper::groth16::GoString::try_from(&pre_ping).unwrap(); + + // Send and receive pong from Go. + let pong: *const ffi::c_char = unsafe { TestMulTermsSerialization(ping) }; + + // TODO: + // * Prepare pong for Rust. + // * Assert that mul_term and go_mul_term are the same (go_mul_term is + // the pong's deserialization) +} + +#[test] +fn test_add_term_serialization() { + // Sample random coefficient. + let coefficient: gnark_backend_wrapper::groth16::Fr = rand::random(); + // Sample a random sum. + let sum = acvm::Witness::new(rand::random()); + // Sample a random mul term. + let add_term = AddTerm { coefficient, sum }; + + println!("| RUST |"); + println!("{:?}", add_term.coefficient.0 .0); + println!("{:?}", add_term.sum.0); + + // Serialize the mul term. + let serialized_add_term = serde_json::to_string(&add_term).unwrap(); + + // Prepare ping for Go. + let pre_ping = ffi::CString::new(serialized_add_term).unwrap(); + let ping = gnark_backend_wrapper::groth16::GoString::try_from(&pre_ping).unwrap(); + + // Send and receive pong from Go. + let pong: *const ffi::c_char = unsafe { TestAddTermSerialization(ping) }; + + // TODO: + // * Prepare pong for Rust. + // * Assert that add_term and go_add_term are the same (go_add_term is + // the pong's deserialization) +} + +#[test] +fn test_add_terms_serialization() { + // Sample random coefficient. + let coefficient: gnark_backend_wrapper::groth16::Fr = rand::random(); + // Sample a random sum. + let sum = acvm::Witness::new(rand::random()); + // Sample a random mul term. + let add_terms = vec![AddTerm { coefficient, sum }, AddTerm { coefficient, sum }]; + + println!("| RUST |"); + for add_term in &add_terms { + println!("{:?}", add_term.coefficient.0 .0); + println!("{:?}", add_term.sum.0); + println!() + } + + // Serialize the mul term. + let serialized_add_terms = serde_json::to_string(&add_terms).unwrap(); + + // Prepare ping for Go. + let pre_ping = ffi::CString::new(serialized_add_terms).unwrap(); + let ping = gnark_backend_wrapper::groth16::GoString::try_from(&pre_ping).unwrap(); + + // Send and receive pong from Go. + let pong: *const ffi::c_char = unsafe { TestAddTermsSerialization(ping) }; + + // TODO: + // * Prepare pong for Rust. + // * Assert that add_terms and go_add_terms are the same (go_add_terms is + // the pong's deserialization) +} + +#[test] +fn test_raw_gate_serialization() {} + +#[test] +fn test_raw_gates_serialization() {} + +#[test] +fn test_raw_r1cs_serialization() {} From a3ae1e48acb7e6d0ec98b205574b3756432985aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Wed, 1 Mar 2023 18:59:51 -0300 Subject: [PATCH 049/118] Expose `acir_to_r1cs` structs --- src/gnark_backend_wrapper/groth16/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gnark_backend_wrapper/groth16/mod.rs b/src/gnark_backend_wrapper/groth16/mod.rs index e52ea51..ab389e9 100644 --- a/src/gnark_backend_wrapper/groth16/mod.rs +++ b/src/gnark_backend_wrapper/groth16/mod.rs @@ -8,7 +8,7 @@ mod c_go_structures; mod errors; mod serialize; -use crate::gnark_backend_wrapper::groth16::acir_to_r1cs::RawR1CS; +pub use crate::gnark_backend_wrapper::groth16::acir_to_r1cs::{AddTerm, MulTerm, RawGate, RawR1CS}; pub use crate::gnark_backend_wrapper::groth16::c_go_structures::GoString; use crate::gnark_backend_wrapper::groth16::c_go_structures::KeyPair; use crate::gnark_backend_wrapper::groth16::errors::GnarkBackendError; From 3b55e07f6d8d9a0cce1ace285e377d59319df990 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Wed, 1 Mar 2023 19:00:34 -0300 Subject: [PATCH 050/118] Implement `MulTerm` and `AddTerm` structs --- .../groth16/acir_to_r1cs.rs | 26 ++++++++++++++++--- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/gnark_backend_wrapper/groth16/acir_to_r1cs.rs b/src/gnark_backend_wrapper/groth16/acir_to_r1cs.rs index 60195f1..bd7210f 100644 --- a/src/gnark_backend_wrapper/groth16/acir_to_r1cs.rs +++ b/src/gnark_backend_wrapper/groth16/acir_to_r1cs.rs @@ -26,6 +26,19 @@ pub struct RawGate { pub constant_term: Fr, } +#[derive(Clone, Debug)] +pub struct MulTerm { + pub coefficient: Fr, + pub multiplicand: acvm::Witness, + pub multiplier: acvm::Witness, +} + +#[derive(Clone, Debug)] +pub struct AddTerm { + pub coefficient: Fr, + pub sum: acvm::Witness, +} + impl RawR1CS { pub fn new( acir: acvm::Circuit, @@ -79,18 +92,23 @@ impl RawR1CS { impl RawGate { pub fn new(arithmetic_gate: acvm::Expression) -> Self { - let converted_mul_terms: Vec<_> = arithmetic_gate + let converted_mul_terms: Vec = arithmetic_gate .mul_terms .into_iter() - .map(|(coefficient, multiplicand, multiplier)| { - (from_felt(coefficient), multiplicand, multiplier) + .map(|(coefficient, multiplicand, multiplier)| MulTerm { + coefficient: from_felt(coefficient), + multiplicand, + multiplier, }) .collect(); let converted_linear_combinations: Vec<_> = arithmetic_gate .linear_combinations .into_iter() - .map(|(coefficient, sum)| (from_felt(coefficient), sum)) + .map(|(coefficient, sum)| AddTerm { + coefficient: from_felt(coefficient), + sum, + }) .collect(); Self { From f1d72d3ba2e11b0ecebe4a398e79d8d6aec7fc6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Wed, 1 Mar 2023 19:01:28 -0300 Subject: [PATCH 051/118] Update serialization --- .../groth16/acir_to_r1cs.rs | 13 +- .../groth16/serialize.rs | 125 ++++++++++-------- 2 files changed, 78 insertions(+), 60 deletions(-) diff --git a/src/gnark_backend_wrapper/groth16/acir_to_r1cs.rs b/src/gnark_backend_wrapper/groth16/acir_to_r1cs.rs index bd7210f..7016081 100644 --- a/src/gnark_backend_wrapper/groth16/acir_to_r1cs.rs +++ b/src/gnark_backend_wrapper/groth16/acir_to_r1cs.rs @@ -1,5 +1,6 @@ use super::{from_felt, Fr}; use crate::acvm; +use crate::gnark_backend_wrapper::groth16::serialize::{serialize_felt, serialize_felts}; use crate::gnark_backend_wrapper::groth16::GnarkBackendError; use std::num::TryFromIntError; @@ -10,19 +11,21 @@ use std::num::TryFromIntError; // - These structures only support arithmetic gates, while the compiler has other // gate types. These can be added later once the backend knows how to deal with things like XOR // or once ACIR is taught how to do convert these black box functions to Arithmetic gates. -#[derive(Clone)] +#[derive(Clone, Debug, serde::Serialize)] pub struct RawR1CS { pub gates: Vec, - pub public_inputs: acvm::PublicInputs, + pub public_inputs: Vec, + #[serde(serialize_with = "serialize_felts")] pub values: Vec, pub num_variables: usize, pub num_constraints: usize, } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, serde::Serialize)] pub struct RawGate { - pub mul_terms: Vec<(Fr, acvm::Witness, acvm::Witness)>, - pub add_terms: Vec<(Fr, acvm::Witness)>, + pub mul_terms: Vec, + pub add_terms: Vec, + #[serde(serialize_with = "serialize_felt")] pub constant_term: Fr, } diff --git a/src/gnark_backend_wrapper/groth16/serialize.rs b/src/gnark_backend_wrapper/groth16/serialize.rs index da7a0d7..ca158b1 100644 --- a/src/gnark_backend_wrapper/groth16/serialize.rs +++ b/src/gnark_backend_wrapper/groth16/serialize.rs @@ -1,73 +1,88 @@ -use super::acir_to_r1cs::{RawGate, RawR1CS}; -use acvm::acir::native_types::Witness; +use super::acir_to_r1cs::{AddTerm, MulTerm}; +use crate::gnark_backend_wrapper as gnark_backend; +use ark_serialize::CanonicalSerialize; use serde::{ser::SerializeStruct, Serialize}; -impl Serialize for RawR1CS { - fn serialize(&self, serializer: S) -> std::result::Result +impl Serialize for MulTerm { + fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, { - let mut s = serializer.serialize_struct("RawR1CS", 4)?; + let mut serialized_coefficient = Vec::new(); + self.coefficient + .serialize_uncompressed(&mut serialized_coefficient) + .map_err(serde::ser::Error::custom)?; + // Turn little-endian to big-endian. + serialized_coefficient.reverse(); + let encoded_coefficient = hex::encode(serialized_coefficient); - let mut serializable_values: Vec = Vec::new(); - for value in &self.values { - let mut serialized_value = Vec::new(); - ark_serialize::CanonicalSerialize::serialize_uncompressed(value, &mut serialized_value) - .map_err(|e| serde::ser::Error::custom(e.to_string()))?; - serializable_values.push(hex::encode(serialized_value)); - } - - s.serialize_field("gates", &self.gates)?; - s.serialize_field("public_inputs", &self.public_inputs)?; - s.serialize_field("values", &serializable_values)?; - s.serialize_field("num_variables", &self.num_variables)?; + let mut s = serializer.serialize_struct("MulTerm", 3)?; + s.serialize_field("coefficient", &encoded_coefficient)?; + s.serialize_field("multiplicand", &self.multiplicand)?; + s.serialize_field("multiplier", &self.multiplier)?; s.end() } } -impl Serialize for RawGate { - fn serialize(&self, serializer: S) -> std::result::Result +impl Serialize for AddTerm { + fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, { - let mut s = serializer.serialize_struct("RawGate", 3)?; + let mut serialized_coefficient = Vec::new(); + self.coefficient + .serialize_uncompressed(&mut serialized_coefficient) + .map_err(serde::ser::Error::custom)?; + // Turn little-endian to big-endian. + serialized_coefficient.reverse(); + let encoded_coefficient = hex::encode(serialized_coefficient); - let mut serializable_mul_terms: Vec<(String, Witness, Witness)> = Vec::new(); - for (coefficient, multiplier, multiplicand) in &self.mul_terms { - let mut serialized_coefficient = Vec::new(); - ark_serialize::CanonicalSerialize::serialize_uncompressed( - coefficient, - &mut serialized_coefficient, - ) - .map_err(|e| serde::ser::Error::custom(e.to_string()))?; - serializable_mul_terms.push(( - hex::encode(serialized_coefficient), - *multiplicand, - *multiplier, - )); - } + let mut s = serializer.serialize_struct("AddTerm", 2)?; + s.serialize_field("coefficient", &encoded_coefficient)?; + s.serialize_field("sum", &self.sum)?; + s.end() + } +} - let mut serializable_add_terms: Vec<(String, Witness)> = Vec::new(); - for (coefficient, sum) in &self.add_terms { - let mut serialized_coefficient = Vec::new(); - ark_serialize::CanonicalSerialize::serialize_uncompressed( - coefficient, - &mut serialized_coefficient, - ) - .map_err(|e| serde::ser::Error::custom(e.to_string()))?; - serializable_add_terms.push((hex::encode(serialized_coefficient), *sum)); - } +pub fn serialize_felt_unchecked(felt: &gnark_backend::groth16::Fr) -> Vec { + let mut serialized_felt = Vec::new(); + felt.serialize_uncompressed(&mut serialized_felt).unwrap(); + // Turn little-endian to big-endian. + serialized_felt.reverse(); + serialized_felt +} - let mut serializable_constant_term = Vec::new(); - ark_serialize::CanonicalSerialize::serialize_uncompressed( - &self.constant_term, - &mut serializable_constant_term, - ) - .map_err(|e| serde::ser::Error::custom(e.to_string()))?; +pub fn serialize_felt( + felt: &gnark_backend::groth16::Fr, + serializer: S, +) -> Result +where + S: serde::ser::Serializer, +{ + let mut serialized_felt = Vec::new(); + felt.serialize_uncompressed(&mut serialized_felt).map_err(serde::ser::Error::custom)?; + // Turn little-endian to big-endian. + serialized_felt.reverse(); + let encoded_coefficient = hex::encode(serialized_felt); + serializer.serialize_str(&encoded_coefficient) +} - s.serialize_field("mul_terms", &serializable_add_terms)?; - s.serialize_field("add_terms", &serializable_add_terms)?; - s.serialize_field("constant_term", &hex::encode(serializable_constant_term))?; - s.end() - } +pub fn serialize_felts( + felts: &[gnark_backend::groth16::Fr], + serializer: S, +) -> Result +where + S: serde::ser::Serializer, +{ + let mut buff: Vec = Vec::new(); + let n_felts: u32 = felts.len().try_into().map_err(serde::ser::Error::custom)?; + buff.extend_from_slice(&n_felts.to_be_bytes()); + buff.extend_from_slice( + &felts + .iter() + .flat_map(serialize_felt_unchecked) + .collect::>(), + ); + let encoded_buff = hex::encode(buff); + serializer.serialize_str(&encoded_buff) } From 9f9ab8339460fa36eec94650c168cb19224b36e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Wed, 1 Mar 2023 19:02:04 -0300 Subject: [PATCH 052/118] `public_inputs` is no longer a `BTreeSet` Now it is a `Vec` --- src/gnark_backend_wrapper/groth16/acir_to_r1cs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gnark_backend_wrapper/groth16/acir_to_r1cs.rs b/src/gnark_backend_wrapper/groth16/acir_to_r1cs.rs index 7016081..3685c77 100644 --- a/src/gnark_backend_wrapper/groth16/acir_to_r1cs.rs +++ b/src/gnark_backend_wrapper/groth16/acir_to_r1cs.rs @@ -68,7 +68,7 @@ impl RawR1CS { num_variables: (acir.current_witness_index + 1) .try_into() .map_err(|e: TryFromIntError| GnarkBackendError::Error(e.to_string()))?, - public_inputs: acir.public_inputs, + public_inputs: acir.public_inputs.0.into_iter().collect(), num_constraints, }) } From 53523e93fcb40e0f08b131c5104d1176bfa03df5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Wed, 1 Mar 2023 19:02:32 -0300 Subject: [PATCH 053/118] Implement Go-side integration test functions --- gnark_backend_ffi/main.go | 84 +++++++++++++++++++++++++++++++++++---- 1 file changed, 76 insertions(+), 8 deletions(-) diff --git a/gnark_backend_ffi/main.go b/gnark_backend_ffi/main.go index e102b22..a4b2092 100644 --- a/gnark_backend_ffi/main.go +++ b/gnark_backend_ffi/main.go @@ -325,23 +325,91 @@ func TestU64Serialization(number uint64) uint64 { } //export TestMulTermSerialization -func TestMulTermSerialization(mulTerm string) *C.char { - return C.CString("unimplemented") +func TestMulTermSerialization(mulTermJSON string) *C.char { + var deserializedMulTerm structs.MulTerm + err := json.Unmarshal([]byte(mulTermJSON), &deserializedMulTerm) + if err != nil { + log.Fatal(err) + } + + fmt.Println("| GO |") + fmt.Println("", deserializedMulTerm.Coefficient) + fmt.Println("", deserializedMulTerm.Multiplicand) + fmt.Println("", deserializedMulTerm.Multiplier) + + serializedMulTerm, err := json.Marshal(deserializedMulTerm) + if err != nil { + log.Fatal(err) + } + + return C.CString(string(serializedMulTerm)) } //export TestMulTermsSerialization -func TestMulTermsSerialization(encodedMulTerms string) *C.char { - return C.CString("unimplemented") +func TestMulTermsSerialization(mulTermsJSON string) *C.char { + var deserializedMulTerms []structs.MulTerm + err := json.Unmarshal([]byte(mulTermsJSON), &deserializedMulTerms) + if err != nil { + log.Fatal(err) + } + + fmt.Println("| GO |") + for _, deserializedMulTerm := range deserializedMulTerms { + fmt.Println("", deserializedMulTerm.Coefficient) + fmt.Println("", deserializedMulTerm.Multiplicand) + fmt.Println("", deserializedMulTerm.Multiplier) + fmt.Println() + } + + serializedMulTerms, err := json.Marshal(deserializedMulTerms) + if err != nil { + log.Fatal(err) + } + + return C.CString(string(serializedMulTerms)) } //export TestAddTermSerialization -func TestAddTermSerialization(encodedAddTerm string) *C.char { - return C.CString("unimplemented") +func TestAddTermSerialization(addTermJSON string) *C.char { + var deserializedAddTerm structs.AddTerm + err := json.Unmarshal([]byte(addTermJSON), &deserializedAddTerm) + if err != nil { + log.Fatal(err) + } + + fmt.Println("| GO |") + fmt.Println("", deserializedAddTerm.Coefficient) + fmt.Println("", deserializedAddTerm.Sum) + + serializedAddTerm, err := json.Marshal(deserializedAddTerm) + if err != nil { + log.Fatal(err) + } + + return C.CString(string(serializedAddTerm)) } //export TestAddTermsSerialization -func TestAddTermsSerialization(encodedAddTerms string) *C.char { - return C.CString("unimplemented") +func TestAddTermsSerialization(addTermsJSON string) *C.char { + var deserializedAddTerms []structs.AddTerm + err := json.Unmarshal([]byte(addTermsJSON), &deserializedAddTerms) + if err != nil { + log.Fatal(err) + } + + fmt.Println("| GO |") + for _, deserializedAddTerm := range deserializedAddTerms { + fmt.Println("", deserializedAddTerm.Coefficient) + fmt.Println("", deserializedAddTerm.Sum) + fmt.Println() + } + + serializedAddTerms, err := json.Marshal(deserializedAddTerms) + if err != nil { + log.Fatal(err) + } + + return C.CString(string(serializedAddTerms)) } //export TestRawGateSerialization From 8ab5414a269e4ce3cd296ccc42f0a30fd9d1a63a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Wed, 1 Mar 2023 19:09:48 -0300 Subject: [PATCH 054/118] cargo fmt --- src/gnark_backend_wrapper/groth16/serialize.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/gnark_backend_wrapper/groth16/serialize.rs b/src/gnark_backend_wrapper/groth16/serialize.rs index ca158b1..0d2c2b4 100644 --- a/src/gnark_backend_wrapper/groth16/serialize.rs +++ b/src/gnark_backend_wrapper/groth16/serialize.rs @@ -60,7 +60,8 @@ where S: serde::ser::Serializer, { let mut serialized_felt = Vec::new(); - felt.serialize_uncompressed(&mut serialized_felt).map_err(serde::ser::Error::custom)?; + felt.serialize_uncompressed(&mut serialized_felt) + .map_err(serde::ser::Error::custom)?; // Turn little-endian to big-endian. serialized_felt.reverse(); let encoded_coefficient = hex::encode(serialized_felt); From b09c0daf78a7e877c87706e6ad3aafb551352975 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Wed, 1 Mar 2023 19:16:23 -0300 Subject: [PATCH 055/118] Fix tests --- tests/serialization_tests.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/serialization_tests.rs b/tests/serialization_tests.rs index a02fe26..bbefe2b 100644 --- a/tests/serialization_tests.rs +++ b/tests/serialization_tests.rs @@ -211,7 +211,7 @@ fn test_mul_terms_serialization() { println!("| RUST |"); for mul_term in &mul_terms { - println!("{:?}", mul_term.coefficient.0 .0); + println!("{:?}", mul_term.coefficient.0.0); println!("{:?}", mul_term.multiplicand.0); println!("{:?}", mul_term.multiplier.0); println!() @@ -243,7 +243,7 @@ fn test_add_term_serialization() { let add_term = AddTerm { coefficient, sum }; println!("| RUST |"); - println!("{:?}", add_term.coefficient.0 .0); + println!("{:?}", add_term.coefficient.0.0); println!("{:?}", add_term.sum.0); // Serialize the mul term. From d21668ce5f307bea6e20358d2e6051d91ef88681 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Wed, 1 Mar 2023 19:19:25 -0300 Subject: [PATCH 056/118] cargo clippy --- src/acvm_interop.rs | 4 ++-- .../groth16/serialize.rs | 1 + tests/serialization_tests.rs | 19 +++++++++---------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/acvm_interop.rs b/src/acvm_interop.rs index f5b6cad..81f477d 100644 --- a/src/acvm_interop.rs +++ b/src/acvm_interop.rs @@ -93,7 +93,7 @@ impl PartialWitnessGenerator for Gnark { _initial_witness: &mut BTreeMap, _func_call: &BlackBoxFuncCall, ) -> Result<(), OpcodeResolutionError> { - todo!() + unimplemented!() } } @@ -104,7 +104,7 @@ impl GadgetCaller { _initial_witness: &mut BTreeMap, _gadget_call: &BlackBoxFuncCall, ) -> Result<(), OpcodeResolutionError> { - todo!() + unimplemented!() } } diff --git a/src/gnark_backend_wrapper/groth16/serialize.rs b/src/gnark_backend_wrapper/groth16/serialize.rs index 0d2c2b4..dd9e22e 100644 --- a/src/gnark_backend_wrapper/groth16/serialize.rs +++ b/src/gnark_backend_wrapper/groth16/serialize.rs @@ -46,6 +46,7 @@ impl Serialize for AddTerm { pub fn serialize_felt_unchecked(felt: &gnark_backend::groth16::Fr) -> Vec { let mut serialized_felt = Vec::new(); + #[allow(clippy::unwrap_used)] felt.serialize_uncompressed(&mut serialized_felt).unwrap(); // Turn little-endian to big-endian. serialized_felt.reverse(); diff --git a/tests/serialization_tests.rs b/tests/serialization_tests.rs index bbefe2b..8d0a087 100644 --- a/tests/serialization_tests.rs +++ b/tests/serialization_tests.rs @@ -6,7 +6,6 @@ use noir_backend_using_gnark::{ groth16::{AddTerm, MulTerm}, }, }; -use serde_json::json; use std::ffi; extern "C" { @@ -27,13 +26,13 @@ extern "C" { fn TestAddTermsSerialization( add_terms: gnark_backend_wrapper::groth16::GoString, ) -> *const ffi::c_char; - fn TestRawGateSerialization( + fn _TestRawGateSerialization( raw_gate: gnark_backend_wrapper::groth16::GoString, ) -> *const ffi::c_char; - fn TestRawGatesSerialization( + fn _TestRawGatesSerialization( raw_gates: gnark_backend_wrapper::groth16::GoString, ) -> *const ffi::c_char; - fn TestRawR1CSSerialization( + fn _TestRawR1CSSerialization( raw_r1cs: gnark_backend_wrapper::groth16::GoString, ) -> *const ffi::c_char; } @@ -179,7 +178,7 @@ fn test_mul_term_serialization() { let ping = gnark_backend_wrapper::groth16::GoString::try_from(&pre_ping).unwrap(); // Send and receive pong from Go. - let pong: *const ffi::c_char = unsafe { TestMulTermSerialization(ping) }; + let _pong: *const ffi::c_char = unsafe { TestMulTermSerialization(ping) }; // TODO: // * Prepare pong for Rust. @@ -211,7 +210,7 @@ fn test_mul_terms_serialization() { println!("| RUST |"); for mul_term in &mul_terms { - println!("{:?}", mul_term.coefficient.0.0); + println!("{:?}", mul_term.coefficient.0 .0); println!("{:?}", mul_term.multiplicand.0); println!("{:?}", mul_term.multiplier.0); println!() @@ -225,7 +224,7 @@ fn test_mul_terms_serialization() { let ping = gnark_backend_wrapper::groth16::GoString::try_from(&pre_ping).unwrap(); // Send and receive pong from Go. - let pong: *const ffi::c_char = unsafe { TestMulTermsSerialization(ping) }; + let _pong: *const ffi::c_char = unsafe { TestMulTermsSerialization(ping) }; // TODO: // * Prepare pong for Rust. @@ -243,7 +242,7 @@ fn test_add_term_serialization() { let add_term = AddTerm { coefficient, sum }; println!("| RUST |"); - println!("{:?}", add_term.coefficient.0.0); + println!("{:?}", add_term.coefficient.0 .0); println!("{:?}", add_term.sum.0); // Serialize the mul term. @@ -254,7 +253,7 @@ fn test_add_term_serialization() { let ping = gnark_backend_wrapper::groth16::GoString::try_from(&pre_ping).unwrap(); // Send and receive pong from Go. - let pong: *const ffi::c_char = unsafe { TestAddTermSerialization(ping) }; + let _pong: *const ffi::c_char = unsafe { TestAddTermSerialization(ping) }; // TODO: // * Prepare pong for Rust. @@ -286,7 +285,7 @@ fn test_add_terms_serialization() { let ping = gnark_backend_wrapper::groth16::GoString::try_from(&pre_ping).unwrap(); // Send and receive pong from Go. - let pong: *const ffi::c_char = unsafe { TestAddTermsSerialization(ping) }; + let _pong: *const ffi::c_char = unsafe { TestAddTermsSerialization(ping) }; // TODO: // * Prepare pong for Rust. From c52cb889d5d06725069c74867a5f73926bc56c2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Wed, 1 Mar 2023 19:49:58 -0300 Subject: [PATCH 057/118] Implement `Display` and `Copy` - `Copy` for `MulTerm` & `AddTerm` - `Display` for every local struct --- .../groth16/acir_to_r1cs.rs | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/src/gnark_backend_wrapper/groth16/acir_to_r1cs.rs b/src/gnark_backend_wrapper/groth16/acir_to_r1cs.rs index 3685c77..90ce419 100644 --- a/src/gnark_backend_wrapper/groth16/acir_to_r1cs.rs +++ b/src/gnark_backend_wrapper/groth16/acir_to_r1cs.rs @@ -2,6 +2,7 @@ use super::{from_felt, Fr}; use crate::acvm; use crate::gnark_backend_wrapper::groth16::serialize::{serialize_felt, serialize_felts}; use crate::gnark_backend_wrapper::groth16::GnarkBackendError; +use std::fmt::Debug; use std::num::TryFromIntError; // AcirCircuit and AcirArithGate are R1CS-friendly structs. @@ -121,3 +122,57 @@ impl RawGate { } } } + +impl Copy for MulTerm {} +impl Copy for AddTerm {} + +impl std::fmt::Display for MulTerm { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "Coefficient: {:?}", self.coefficient.0 .0)?; + write!(f, "Multiplicand: {:?}", self.multiplicand.0)?; + write!(f, "Multiplier: {:?}", self.multiplier.0)?; + write!(f, "") + } +} + +impl std::fmt::Display for AddTerm { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "Coefficient: {:?}", self.coefficient.0 .0)?; + write!(f, "Sum: {:?}", self.sum.0)?; + write!(f, "") + } +} + +impl std::fmt::Display for RawGate { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.mul_terms.fmt(f)?; + self.add_terms.fmt(f)?; + write!(f, "Constant term: {:?}", self.constant_term.0 .0)?; + write!(f, "") + } +} + +impl std::fmt::Display for RawR1CS { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.gates.fmt(f)?; + write!( + f, + "Public Inputs: {:?}", + self.public_inputs + .iter() + .map(|public_input| public_input.0) + .collect::>() + )?; + write!( + f, + "Values: {:?}", + self.values + .iter() + .map(|value| value.0 .0) + .collect::>() + )?; + write!(f, "Number of variables: {}", self.num_variables)?; + write!(f, "Number of constraints: {}", self.num_constraints)?; + write!(f, "") + } +} From 6857a1c2e22c6864f2e7d8e78b57ba7795cd6bcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Wed, 1 Mar 2023 20:12:59 -0300 Subject: [PATCH 058/118] Add missing integration tests --- gnark_backend_ffi/main.go | 67 +++++++++++++++-- tests/serialization_tests.rs | 139 +++++++++++++++++++++++++++++++++-- 2 files changed, 194 insertions(+), 12 deletions(-) diff --git a/gnark_backend_ffi/main.go b/gnark_backend_ffi/main.go index a4b2092..73be79b 100644 --- a/gnark_backend_ffi/main.go +++ b/gnark_backend_ffi/main.go @@ -413,18 +413,73 @@ func TestAddTermsSerialization(addTermsJSON string) *C.char { } //export TestRawGateSerialization -func TestRawGateSerialization(encodedRawGate string) *C.char { - return C.CString("unimplemented") +func TestRawGateSerialization(rawGateJSON string) *C.char { + var deserializedRawGate structs.RawGate + err := json.Unmarshal([]byte(rawGateJSON), &deserializedRawGate) + if err != nil { + log.Fatal(err) + } + + fmt.Println("| GO |") + fmt.Println("", deserializedRawGate.MulTerms) + fmt.Println("", deserializedRawGate.AddTerms) + fmt.Println("", deserializedRawGate.ConstantTerm) + fmt.Println() + + serializedRawGate, err := json.Marshal(deserializedRawGate) + if err != nil { + log.Fatal(err) + } + + return C.CString(string(serializedRawGate)) } //export TestRawGatesSerialization -func TestRawGatesSerialization(encodedRawGates string) *C.char { - return C.CString("unimplemented") +func TestRawGatesSerialization(rawGatesJSON string) *C.char { + var deserializedRawGates []structs.RawGate + err := json.Unmarshal([]byte(rawGatesJSON), &deserializedRawGates) + if err != nil { + log.Fatal(err) + } + + fmt.Println("| GO |") + for _, deserializedRawGate := range deserializedRawGates { + fmt.Println("", deserializedRawGate.MulTerms) + fmt.Println("", deserializedRawGate.AddTerms) + fmt.Println("", deserializedRawGate.ConstantTerm) + fmt.Println() + } + + serializedRawGate, err := json.Marshal(deserializedRawGates) + if err != nil { + log.Fatal(err) + } + + return C.CString(string(serializedRawGate)) } //export TestRawR1CSSerialization -func TestRawR1CSSerialization(encodedR1CS string) *C.char { - return C.CString("unimplemented") +func TestRawR1CSSerialization(rawR1CSJSON string) *C.char { + var deserializedRawR1CS structs.RawR1CS + err := json.Unmarshal([]byte(rawR1CSJSON), &deserializedRawR1CS) + if err != nil { + log.Fatal(err) + } + + fmt.Println("| GO |") + fmt.Println("Gates: ", deserializedRawR1CS.Gates) + fmt.Println("Public inputs: ", deserializedRawR1CS.PublicInputs) + fmt.Println("Values: ", deserializedRawR1CS.Values) + fmt.Println("Number of variables: ", deserializedRawR1CS.NumVariables) + fmt.Println("Number of constraints: ", deserializedRawR1CS.NumConstraints) + fmt.Println() + + serializedRawR1CS, err := json.Marshal(deserializedRawR1CS) + if err != nil { + log.Fatal(err) + } + + return C.CString(string(serializedRawR1CS)) } func main() {} diff --git a/tests/serialization_tests.rs b/tests/serialization_tests.rs index 8d0a087..c2fd5f6 100644 --- a/tests/serialization_tests.rs +++ b/tests/serialization_tests.rs @@ -26,13 +26,13 @@ extern "C" { fn TestAddTermsSerialization( add_terms: gnark_backend_wrapper::groth16::GoString, ) -> *const ffi::c_char; - fn _TestRawGateSerialization( + fn TestRawGateSerialization( raw_gate: gnark_backend_wrapper::groth16::GoString, ) -> *const ffi::c_char; - fn _TestRawGatesSerialization( + fn TestRawGatesSerialization( raw_gates: gnark_backend_wrapper::groth16::GoString, ) -> *const ffi::c_char; - fn _TestRawR1CSSerialization( + fn TestRawR1CSSerialization( raw_r1cs: gnark_backend_wrapper::groth16::GoString, ) -> *const ffi::c_char; } @@ -294,10 +294,137 @@ fn test_add_terms_serialization() { } #[test] -fn test_raw_gate_serialization() {} +fn test_raw_gate_serialization() { + let coefficient: gnark_backend_wrapper::groth16::Fr = rand::random(); + let multiplicand = acvm::Witness::new(rand::random()); + let multiplier: acvm::Witness = acvm::Witness::new(rand::random()); + let sum = acvm::Witness::new(rand::random()); + let add_term = AddTerm { coefficient, sum }; + let add_terms = vec![add_term, add_term]; + let mul_term = MulTerm { + coefficient, + multiplicand, + multiplier, + }; + let mul_terms = vec![mul_term, mul_term]; + let constant_term: gnark_backend_wrapper::groth16::Fr = rand::random(); + let raw_gate = RawGate { + mul_terms, + add_terms, + constant_term, + }; + + println!("| RUST |"); + println!("{raw_gate:?}"); + + // Serialize the raw gate. + let serialized_raw_gate = serde_json::to_string(&raw_gate).unwrap(); + + // Prepare ping for Go. + let pre_ping = ffi::CString::new(serialized_raw_gate).unwrap(); + let ping = gnark_backend_wrapper::groth16::GoString::try_from(&pre_ping).unwrap(); + + // Send and receive pong from Go. + let _pong: *const ffi::c_char = unsafe { TestRawGateSerialization(ping) }; + + // TODO: + // * Prepare pong for Rust. + // * Assert that add_terms and go_add_terms are the same (go_add_terms is + // the pong's deserialization) +} #[test] -fn test_raw_gates_serialization() {} +fn test_raw_gates_serialization() { + let coefficient: gnark_backend_wrapper::groth16::Fr = rand::random(); + let multiplicand = acvm::Witness::new(rand::random()); + let multiplier: acvm::Witness = acvm::Witness::new(rand::random()); + let sum = acvm::Witness::new(rand::random()); + let add_term = AddTerm { coefficient, sum }; + let add_terms = vec![add_term, add_term]; + let mul_term = MulTerm { + coefficient, + multiplicand, + multiplier, + }; + let mul_terms = vec![mul_term, mul_term]; + let constant_term: gnark_backend_wrapper::groth16::Fr = rand::random(); + let raw_gate = RawGate { + mul_terms, + add_terms, + constant_term, + }; + let raw_gates = vec![raw_gate.clone(), raw_gate]; + + println!("| RUST |"); + println!("{raw_gates:?}"); + + // Serialize the raw gate. + let serialized_raw_gates = serde_json::to_string(&raw_gates).unwrap(); + + // Prepare ping for Go. + let pre_ping = ffi::CString::new(serialized_raw_gates).unwrap(); + let ping = gnark_backend_wrapper::groth16::GoString::try_from(&pre_ping).unwrap(); + + // Send and receive pong from Go. + let _pong: *const ffi::c_char = unsafe { TestRawGatesSerialization(ping) }; + + // TODO: + // * Prepare pong for Rust. + // * Assert that add_terms and go_add_terms are the same (go_add_terms is + // the pong's deserialization) +} #[test] -fn test_raw_r1cs_serialization() {} +fn test_raw_r1cs_serialization() { + let coefficient: gnark_backend_wrapper::groth16::Fr = rand::random(); + let multiplicand = acvm::Witness::new(rand::random()); + let multiplier: acvm::Witness = acvm::Witness::new(rand::random()); + let sum = acvm::Witness::new(rand::random()); + let add_term = AddTerm { coefficient, sum }; + let add_terms = vec![add_term, add_term]; + let mul_term = MulTerm { + coefficient, + multiplicand, + multiplier, + }; + let mul_terms = vec![mul_term, mul_term]; + let constant_term: gnark_backend_wrapper::groth16::Fr = rand::random(); + let raw_gate = RawGate { + mul_terms, + add_terms, + constant_term, + }; + let raw_gates = vec![raw_gate.clone(), raw_gate]; + let public_inputs = vec![ + acvm::Witness::new(rand::random()), + acvm::Witness::new(rand::random()), + ]; + let values: [gnark_backend_wrapper::groth16::Fr; 2] = rand::random(); + let num_constraints: u64 = rand::random(); + let num_variables: u64 = rand::random(); + let raw_r1cs = RawR1CS { + gates: raw_gates, + public_inputs, + values: values.to_vec(), + num_variables, + num_constraints, + }; + + println!("| RUST |"); + println!("{raw_r1cs:?}"); + + // Serialize the raw gate. + let serialized_raw_gates = serde_json::to_string(&raw_r1cs).unwrap(); + + // Prepare ping for Go. + let pre_ping = ffi::CString::new(serialized_raw_gates).unwrap(); + let ping = gnark_backend_wrapper::groth16::GoString::try_from(&pre_ping).unwrap(); + + // Send and receive pong from Go. + let _pong: *const ffi::c_char = unsafe { TestRawR1CSSerialization(ping) }; + + // TODO: + // * Prepare pong for Rust. + // * Assert that add_terms and go_add_terms are the same (go_add_terms is + // the pong's deserialization) +} From 8b7761890a0de1e8e5c5b0c463a9c5f2ae7c48f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Wed, 1 Mar 2023 20:15:14 -0300 Subject: [PATCH 059/118] Update `RawR1CS` fields types `num_variables` & `num_constraints` from `usize` to `u64` to make it compatible with the Go API --- src/gnark_backend_wrapper/groth16/acir_to_r1cs.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/gnark_backend_wrapper/groth16/acir_to_r1cs.rs b/src/gnark_backend_wrapper/groth16/acir_to_r1cs.rs index 90ce419..5f73eeb 100644 --- a/src/gnark_backend_wrapper/groth16/acir_to_r1cs.rs +++ b/src/gnark_backend_wrapper/groth16/acir_to_r1cs.rs @@ -18,8 +18,8 @@ pub struct RawR1CS { pub public_inputs: Vec, #[serde(serialize_with = "serialize_felts")] pub values: Vec, - pub num_variables: usize, - pub num_constraints: usize, + pub num_variables: u64, + pub num_constraints: u64, } #[derive(Clone, Debug, serde::Serialize)] @@ -48,7 +48,9 @@ impl RawR1CS { acir: acvm::Circuit, values: Vec, ) -> Result { - let num_constraints = Self::num_constraints(&acir)?; + let num_constraints: u64 = Self::num_constraints(&acir)? + .try_into() + .map_err(|e: TryFromIntError| GnarkBackendError::Error(e.to_string()))?; // Currently non-arithmetic gates are not supported // so we extract all of the arithmetic gates only let gates: Vec<_> = acir @@ -66,9 +68,7 @@ impl RawR1CS { Ok(Self { gates, values, - num_variables: (acir.current_witness_index + 1) - .try_into() - .map_err(|e: TryFromIntError| GnarkBackendError::Error(e.to_string()))?, + num_variables: u64::from(acir.current_witness_index) + 1, public_inputs: acir.public_inputs.0.into_iter().collect(), num_constraints, }) From a40df290a0841a59f422665d818902934073a3f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Wed, 1 Mar 2023 20:15:47 -0300 Subject: [PATCH 060/118] Change `write!` with `writeln!` & `Display` with `Debug` --- .../groth16/acir_to_r1cs.rs | 45 +++++++++---------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/src/gnark_backend_wrapper/groth16/acir_to_r1cs.rs b/src/gnark_backend_wrapper/groth16/acir_to_r1cs.rs index 5f73eeb..6875b1e 100644 --- a/src/gnark_backend_wrapper/groth16/acir_to_r1cs.rs +++ b/src/gnark_backend_wrapper/groth16/acir_to_r1cs.rs @@ -2,7 +2,6 @@ use super::{from_felt, Fr}; use crate::acvm; use crate::gnark_backend_wrapper::groth16::serialize::{serialize_felt, serialize_felts}; use crate::gnark_backend_wrapper::groth16::GnarkBackendError; -use std::fmt::Debug; use std::num::TryFromIntError; // AcirCircuit and AcirArithGate are R1CS-friendly structs. @@ -12,7 +11,7 @@ use std::num::TryFromIntError; // - These structures only support arithmetic gates, while the compiler has other // gate types. These can be added later once the backend knows how to deal with things like XOR // or once ACIR is taught how to do convert these black box functions to Arithmetic gates. -#[derive(Clone, Debug, serde::Serialize)] +#[derive(Clone, serde::Serialize)] pub struct RawR1CS { pub gates: Vec, pub public_inputs: Vec, @@ -22,7 +21,7 @@ pub struct RawR1CS { pub num_constraints: u64, } -#[derive(Clone, Debug, serde::Serialize)] +#[derive(Clone, serde::Serialize)] pub struct RawGate { pub mul_terms: Vec, pub add_terms: Vec, @@ -30,14 +29,14 @@ pub struct RawGate { pub constant_term: Fr, } -#[derive(Clone, Debug)] +#[derive(Clone)] pub struct MulTerm { pub coefficient: Fr, pub multiplicand: acvm::Witness, pub multiplier: acvm::Witness, } -#[derive(Clone, Debug)] +#[derive(Clone)] pub struct AddTerm { pub coefficient: Fr, pub sum: acvm::Witness, @@ -126,36 +125,36 @@ impl RawGate { impl Copy for MulTerm {} impl Copy for AddTerm {} -impl std::fmt::Display for MulTerm { +impl std::fmt::Debug for MulTerm { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "Coefficient: {:?}", self.coefficient.0 .0)?; - write!(f, "Multiplicand: {:?}", self.multiplicand.0)?; - write!(f, "Multiplier: {:?}", self.multiplier.0)?; - write!(f, "") + writeln!(f, "Coefficient: {:?}", self.coefficient.0 .0)?; + writeln!(f, "Multiplicand: {:?}", self.multiplicand.0)?; + writeln!(f, "Multiplier: {:?}", self.multiplier.0)?; + writeln!(f) } } -impl std::fmt::Display for AddTerm { +impl std::fmt::Debug for AddTerm { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "Coefficient: {:?}", self.coefficient.0 .0)?; - write!(f, "Sum: {:?}", self.sum.0)?; - write!(f, "") + writeln!(f, "Coefficient: {:?}", self.coefficient.0 .0)?; + writeln!(f, "Sum: {:?}", self.sum.0)?; + writeln!(f) } } -impl std::fmt::Display for RawGate { +impl std::fmt::Debug for RawGate { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.mul_terms.fmt(f)?; self.add_terms.fmt(f)?; - write!(f, "Constant term: {:?}", self.constant_term.0 .0)?; - write!(f, "") + writeln!(f, "Constant term: {:?}", self.constant_term.0 .0)?; + writeln!(f) } } -impl std::fmt::Display for RawR1CS { +impl std::fmt::Debug for RawR1CS { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.gates.fmt(f)?; - write!( + writeln!( f, "Public Inputs: {:?}", self.public_inputs @@ -163,7 +162,7 @@ impl std::fmt::Display for RawR1CS { .map(|public_input| public_input.0) .collect::>() )?; - write!( + writeln!( f, "Values: {:?}", self.values @@ -171,8 +170,8 @@ impl std::fmt::Display for RawR1CS { .map(|value| value.0 .0) .collect::>() )?; - write!(f, "Number of variables: {}", self.num_variables)?; - write!(f, "Number of constraints: {}", self.num_constraints)?; - write!(f, "") + writeln!(f, "Number of variables: {}", self.num_variables)?; + writeln!(f, "Number of constraints: {}", self.num_constraints)?; + writeln!(f) } } From ec076b5934f8a7a94fc71399ec2f63d29898a9e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Wed, 1 Mar 2023 20:16:00 -0300 Subject: [PATCH 061/118] cargo fmt --- tests/serialization_tests.rs | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/tests/serialization_tests.rs b/tests/serialization_tests.rs index c2fd5f6..ff56728 100644 --- a/tests/serialization_tests.rs +++ b/tests/serialization_tests.rs @@ -3,7 +3,7 @@ use noir_backend_using_gnark::{ acvm, gnark_backend_wrapper::{ self, - groth16::{AddTerm, MulTerm}, + groth16::{AddTerm, MulTerm, RawGate, RawR1CS}, }, }; use std::ffi; @@ -166,9 +166,7 @@ fn test_mul_term_serialization() { }; println!("| RUST |"); - println!("{:?}", mul_term.coefficient.0 .0); - println!("{:?}", mul_term.multiplicand.0); - println!("{:?}", mul_term.multiplier.0); + println!("{mul_term:?}"); // Serialize the mul term. let serialized_mul_term = serde_json::to_string(&mul_term).unwrap(); @@ -209,12 +207,7 @@ fn test_mul_terms_serialization() { ]; println!("| RUST |"); - for mul_term in &mul_terms { - println!("{:?}", mul_term.coefficient.0 .0); - println!("{:?}", mul_term.multiplicand.0); - println!("{:?}", mul_term.multiplier.0); - println!() - } + println!("{mul_terms:?}"); // Serialize the mul term. let serialized_mul_terms = serde_json::to_string(&mul_terms).unwrap(); @@ -242,8 +235,7 @@ fn test_add_term_serialization() { let add_term = AddTerm { coefficient, sum }; println!("| RUST |"); - println!("{:?}", add_term.coefficient.0 .0); - println!("{:?}", add_term.sum.0); + println!("{add_term:?}"); // Serialize the mul term. let serialized_add_term = serde_json::to_string(&add_term).unwrap(); @@ -271,11 +263,7 @@ fn test_add_terms_serialization() { let add_terms = vec![AddTerm { coefficient, sum }, AddTerm { coefficient, sum }]; println!("| RUST |"); - for add_term in &add_terms { - println!("{:?}", add_term.coefficient.0 .0); - println!("{:?}", add_term.sum.0); - println!() - } + println!("{add_terms:?}"); // Serialize the mul term. let serialized_add_terms = serde_json::to_string(&add_terms).unwrap(); From 65a2991fbdb4424a6d3e4f09531113e744e0af5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Wed, 1 Mar 2023 20:24:18 -0300 Subject: [PATCH 062/118] Fix imports --- src/gnark_backend_wrapper/mod.rs | 1 + tests/serialization_tests.rs | 79 +++++++++++++++++--------------- 2 files changed, 42 insertions(+), 38 deletions(-) diff --git a/src/gnark_backend_wrapper/mod.rs b/src/gnark_backend_wrapper/mod.rs index 786d6e2..ca2c7bb 100644 --- a/src/gnark_backend_wrapper/mod.rs +++ b/src/gnark_backend_wrapper/mod.rs @@ -1,6 +1,7 @@ cfg_if::cfg_if! { if #[cfg(feature = "groth16")] { mod groth16; + pub use groth16::{AddTerm, Fr, GoString, MulTerm, RawGate, RawR1CS}; pub use groth16::verify_with_meta; pub use groth16::prove_with_meta; pub use groth16::verify_with_vk; diff --git a/tests/serialization_tests.rs b/tests/serialization_tests.rs index ff56728..808dca1 100644 --- a/tests/serialization_tests.rs +++ b/tests/serialization_tests.rs @@ -3,41 +3,44 @@ use noir_backend_using_gnark::{ acvm, gnark_backend_wrapper::{ self, - groth16::{AddTerm, MulTerm, RawGate, RawR1CS}, + AddTerm, + MulTerm, + RawGate, + RawR1CS, }, }; use std::ffi; extern "C" { - fn TestFeltSerialization(felt: gnark_backend_wrapper::groth16::GoString) -> *const ffi::c_char; + fn TestFeltSerialization(felt: gnark_backend_wrapper::GoString) -> *const ffi::c_char; fn TestFeltsSerialization( - felts: gnark_backend_wrapper::groth16::GoString, + felts: gnark_backend_wrapper::GoString, ) -> *const ffi::c_char; fn TestU64Serialization(unsigned_integer: ffi::c_ulong) -> ffi::c_ulong; fn TestMulTermSerialization( - mul_term: gnark_backend_wrapper::groth16::GoString, + mul_term: gnark_backend_wrapper::GoString, ) -> *const ffi::c_char; fn TestMulTermsSerialization( - mul_terms: gnark_backend_wrapper::groth16::GoString, + mul_terms: gnark_backend_wrapper::GoString, ) -> *const ffi::c_char; fn TestAddTermSerialization( - add_term: gnark_backend_wrapper::groth16::GoString, + add_term: gnark_backend_wrapper::GoString, ) -> *const ffi::c_char; fn TestAddTermsSerialization( - add_terms: gnark_backend_wrapper::groth16::GoString, + add_terms: gnark_backend_wrapper::GoString, ) -> *const ffi::c_char; fn TestRawGateSerialization( - raw_gate: gnark_backend_wrapper::groth16::GoString, + raw_gate: gnark_backend_wrapper::GoString, ) -> *const ffi::c_char; fn TestRawGatesSerialization( - raw_gates: gnark_backend_wrapper::groth16::GoString, + raw_gates: gnark_backend_wrapper::GoString, ) -> *const ffi::c_char; fn TestRawR1CSSerialization( - raw_r1cs: gnark_backend_wrapper::groth16::GoString, + raw_r1cs: gnark_backend_wrapper::GoString, ) -> *const ffi::c_char; } -fn serialize_felt(felt: &gnark_backend_wrapper::groth16::Fr) -> Vec { +fn serialize_felt(felt: &gnark_backend_wrapper::Fr) -> Vec { let mut serialized_felt = Vec::new(); felt.serialize_uncompressed(&mut serialized_felt).unwrap(); // Turn little-endian to big-endian. @@ -45,16 +48,16 @@ fn serialize_felt(felt: &gnark_backend_wrapper::groth16::Fr) -> Vec { serialized_felt } -fn deserialize_felt(felt_bytes: &[u8]) -> gnark_backend_wrapper::groth16::Fr { +fn deserialize_felt(felt_bytes: &[u8]) -> gnark_backend_wrapper::Fr { let mut decoded = hex::decode(felt_bytes).unwrap(); // Turn big-endian to little-endian. decoded.reverse(); - gnark_backend_wrapper::groth16::Fr::deserialize_uncompressed(decoded.as_slice()).unwrap() + gnark_backend_wrapper::Fr::deserialize_uncompressed(decoded.as_slice()).unwrap() } // This serialization mimics gnark's serialization of a field elements vector. // The length of the vector is encoded as a u32 on the first 4 bytes. -fn serialize_felts(felts: &[gnark_backend_wrapper::groth16::Fr]) -> Vec { +fn serialize_felts(felts: &[gnark_backend_wrapper::Fr]) -> Vec { let mut buff: Vec = Vec::new(); let n_felts: u32 = felts.len().try_into().unwrap(); buff.extend_from_slice(&n_felts.to_be_bytes()); @@ -65,7 +68,7 @@ fn serialize_felts(felts: &[gnark_backend_wrapper::groth16::Fr]) -> Vec { #[test] fn test_felt_serialization() { // Sample a random felt. - let felt: gnark_backend_wrapper::groth16::Fr = rand::random(); + let felt: gnark_backend_wrapper::Fr = rand::random(); println!("| RUST |\n{:?}", felt.0 .0); @@ -77,7 +80,7 @@ fn test_felt_serialization() { // Prepare ping for Go. let pre_ping = ffi::CString::new(encoded_felt).unwrap(); - let ping = gnark_backend_wrapper::groth16::GoString::try_from(&pre_ping).unwrap(); + let ping = gnark_backend_wrapper::GoString::try_from(&pre_ping).unwrap(); // Send and receive pong from Go. let pong: *const ffi::c_char = unsafe { TestFeltSerialization(ping) }; @@ -94,7 +97,7 @@ fn test_felt_serialization() { #[test] fn test_felts_serialization() { // Sample a random felt. - let felts: [gnark_backend_wrapper::groth16::Fr; 2] = rand::random(); + let felts: [gnark_backend_wrapper::Fr; 2] = rand::random(); println!( "| RUST |\n{:?}", @@ -109,7 +112,7 @@ fn test_felts_serialization() { // Prepare ping for Go. let pre_ping = ffi::CString::new(encoded_felts).unwrap(); - let ping = gnark_backend_wrapper::groth16::GoString::try_from(&pre_ping).unwrap(); + let ping = gnark_backend_wrapper::GoString::try_from(&pre_ping).unwrap(); // Send and receive pong from Go. let pong: *const ffi::c_char = unsafe { TestFeltsSerialization(ping) }; @@ -119,14 +122,14 @@ fn test_felts_serialization() { let go_serialized_felt = go_pre_serialized_felt.to_str().unwrap().as_bytes(); // Decode and deserialize the unpacked felts. - let go_felts: Vec = hex::decode(go_serialized_felt) + let go_felts: Vec = hex::decode(go_serialized_felt) .unwrap()[4..] // Skip the vector length corresponding to the first four bytes. .chunks_mut(32) .map(|go_decoded_felt| { // Turn big-endian to little-endian. go_decoded_felt.reverse(); // Here I reference after dereference because I had a mutable reference and I need a non-mutable one. - let felt: gnark_backend_wrapper::groth16::Fr = + let felt: gnark_backend_wrapper::Fr = CanonicalDeserialize::deserialize_uncompressed(&*go_decoded_felt).unwrap(); felt }) @@ -153,7 +156,7 @@ fn test_u64_serialization() { #[test] fn test_mul_term_serialization() { // Sample random coefficient. - let coefficient: gnark_backend_wrapper::groth16::Fr = rand::random(); + let coefficient: gnark_backend_wrapper::Fr = rand::random(); // Sample a random multiplicand. let multiplicand = acvm::Witness::new(rand::random()); // Sample a random multiplier. @@ -173,7 +176,7 @@ fn test_mul_term_serialization() { // Prepare ping for Go. let pre_ping = ffi::CString::new(serialized_mul_term).unwrap(); - let ping = gnark_backend_wrapper::groth16::GoString::try_from(&pre_ping).unwrap(); + let ping = gnark_backend_wrapper::GoString::try_from(&pre_ping).unwrap(); // Send and receive pong from Go. let _pong: *const ffi::c_char = unsafe { TestMulTermSerialization(ping) }; @@ -187,7 +190,7 @@ fn test_mul_term_serialization() { #[test] fn test_mul_terms_serialization() { // Sample random coefficient. - let coefficient: gnark_backend_wrapper::groth16::Fr = rand::random(); + let coefficient: gnark_backend_wrapper::Fr = rand::random(); // Sample a random multiplicand. let multiplicand = acvm::Witness::new(rand::random()); // Sample a random multiplier. @@ -214,7 +217,7 @@ fn test_mul_terms_serialization() { // Prepare ping for Go. let pre_ping = ffi::CString::new(serialized_mul_terms).unwrap(); - let ping = gnark_backend_wrapper::groth16::GoString::try_from(&pre_ping).unwrap(); + let ping = gnark_backend_wrapper::GoString::try_from(&pre_ping).unwrap(); // Send and receive pong from Go. let _pong: *const ffi::c_char = unsafe { TestMulTermsSerialization(ping) }; @@ -228,7 +231,7 @@ fn test_mul_terms_serialization() { #[test] fn test_add_term_serialization() { // Sample random coefficient. - let coefficient: gnark_backend_wrapper::groth16::Fr = rand::random(); + let coefficient: gnark_backend_wrapper::Fr = rand::random(); // Sample a random sum. let sum = acvm::Witness::new(rand::random()); // Sample a random mul term. @@ -242,7 +245,7 @@ fn test_add_term_serialization() { // Prepare ping for Go. let pre_ping = ffi::CString::new(serialized_add_term).unwrap(); - let ping = gnark_backend_wrapper::groth16::GoString::try_from(&pre_ping).unwrap(); + let ping = gnark_backend_wrapper::GoString::try_from(&pre_ping).unwrap(); // Send and receive pong from Go. let _pong: *const ffi::c_char = unsafe { TestAddTermSerialization(ping) }; @@ -256,7 +259,7 @@ fn test_add_term_serialization() { #[test] fn test_add_terms_serialization() { // Sample random coefficient. - let coefficient: gnark_backend_wrapper::groth16::Fr = rand::random(); + let coefficient: gnark_backend_wrapper::Fr = rand::random(); // Sample a random sum. let sum = acvm::Witness::new(rand::random()); // Sample a random mul term. @@ -270,7 +273,7 @@ fn test_add_terms_serialization() { // Prepare ping for Go. let pre_ping = ffi::CString::new(serialized_add_terms).unwrap(); - let ping = gnark_backend_wrapper::groth16::GoString::try_from(&pre_ping).unwrap(); + let ping = gnark_backend_wrapper::GoString::try_from(&pre_ping).unwrap(); // Send and receive pong from Go. let _pong: *const ffi::c_char = unsafe { TestAddTermsSerialization(ping) }; @@ -283,7 +286,7 @@ fn test_add_terms_serialization() { #[test] fn test_raw_gate_serialization() { - let coefficient: gnark_backend_wrapper::groth16::Fr = rand::random(); + let coefficient: gnark_backend_wrapper::Fr = rand::random(); let multiplicand = acvm::Witness::new(rand::random()); let multiplier: acvm::Witness = acvm::Witness::new(rand::random()); let sum = acvm::Witness::new(rand::random()); @@ -295,7 +298,7 @@ fn test_raw_gate_serialization() { multiplier, }; let mul_terms = vec![mul_term, mul_term]; - let constant_term: gnark_backend_wrapper::groth16::Fr = rand::random(); + let constant_term: gnark_backend_wrapper::Fr = rand::random(); let raw_gate = RawGate { mul_terms, add_terms, @@ -310,7 +313,7 @@ fn test_raw_gate_serialization() { // Prepare ping for Go. let pre_ping = ffi::CString::new(serialized_raw_gate).unwrap(); - let ping = gnark_backend_wrapper::groth16::GoString::try_from(&pre_ping).unwrap(); + let ping = gnark_backend_wrapper::GoString::try_from(&pre_ping).unwrap(); // Send and receive pong from Go. let _pong: *const ffi::c_char = unsafe { TestRawGateSerialization(ping) }; @@ -323,7 +326,7 @@ fn test_raw_gate_serialization() { #[test] fn test_raw_gates_serialization() { - let coefficient: gnark_backend_wrapper::groth16::Fr = rand::random(); + let coefficient: gnark_backend_wrapper::Fr = rand::random(); let multiplicand = acvm::Witness::new(rand::random()); let multiplier: acvm::Witness = acvm::Witness::new(rand::random()); let sum = acvm::Witness::new(rand::random()); @@ -335,7 +338,7 @@ fn test_raw_gates_serialization() { multiplier, }; let mul_terms = vec![mul_term, mul_term]; - let constant_term: gnark_backend_wrapper::groth16::Fr = rand::random(); + let constant_term: gnark_backend_wrapper::Fr = rand::random(); let raw_gate = RawGate { mul_terms, add_terms, @@ -351,7 +354,7 @@ fn test_raw_gates_serialization() { // Prepare ping for Go. let pre_ping = ffi::CString::new(serialized_raw_gates).unwrap(); - let ping = gnark_backend_wrapper::groth16::GoString::try_from(&pre_ping).unwrap(); + let ping = gnark_backend_wrapper::GoString::try_from(&pre_ping).unwrap(); // Send and receive pong from Go. let _pong: *const ffi::c_char = unsafe { TestRawGatesSerialization(ping) }; @@ -364,7 +367,7 @@ fn test_raw_gates_serialization() { #[test] fn test_raw_r1cs_serialization() { - let coefficient: gnark_backend_wrapper::groth16::Fr = rand::random(); + let coefficient: gnark_backend_wrapper::Fr = rand::random(); let multiplicand = acvm::Witness::new(rand::random()); let multiplier: acvm::Witness = acvm::Witness::new(rand::random()); let sum = acvm::Witness::new(rand::random()); @@ -376,7 +379,7 @@ fn test_raw_r1cs_serialization() { multiplier, }; let mul_terms = vec![mul_term, mul_term]; - let constant_term: gnark_backend_wrapper::groth16::Fr = rand::random(); + let constant_term: gnark_backend_wrapper::Fr = rand::random(); let raw_gate = RawGate { mul_terms, add_terms, @@ -387,7 +390,7 @@ fn test_raw_r1cs_serialization() { acvm::Witness::new(rand::random()), acvm::Witness::new(rand::random()), ]; - let values: [gnark_backend_wrapper::groth16::Fr; 2] = rand::random(); + let values: [gnark_backend_wrapper::Fr; 2] = rand::random(); let num_constraints: u64 = rand::random(); let num_variables: u64 = rand::random(); let raw_r1cs = RawR1CS { @@ -406,7 +409,7 @@ fn test_raw_r1cs_serialization() { // Prepare ping for Go. let pre_ping = ffi::CString::new(serialized_raw_gates).unwrap(); - let ping = gnark_backend_wrapper::groth16::GoString::try_from(&pre_ping).unwrap(); + let ping = gnark_backend_wrapper::GoString::try_from(&pre_ping).unwrap(); // Send and receive pong from Go. let _pong: *const ffi::c_char = unsafe { TestRawR1CSSerialization(ping) }; From 52b86f55d9c3e5a15e726f365ed2aec6ee2ba1d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Wed, 1 Mar 2023 20:24:30 -0300 Subject: [PATCH 063/118] cargo fmt --- tests/serialization_tests.rs | 43 +++++++++--------------------------- 1 file changed, 10 insertions(+), 33 deletions(-) diff --git a/tests/serialization_tests.rs b/tests/serialization_tests.rs index 808dca1..f88ffb7 100644 --- a/tests/serialization_tests.rs +++ b/tests/serialization_tests.rs @@ -1,43 +1,21 @@ use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use noir_backend_using_gnark::{ acvm, - gnark_backend_wrapper::{ - self, - AddTerm, - MulTerm, - RawGate, - RawR1CS, - }, + gnark_backend_wrapper::{self, AddTerm, MulTerm, RawGate, RawR1CS}, }; use std::ffi; extern "C" { fn TestFeltSerialization(felt: gnark_backend_wrapper::GoString) -> *const ffi::c_char; - fn TestFeltsSerialization( - felts: gnark_backend_wrapper::GoString, - ) -> *const ffi::c_char; + fn TestFeltsSerialization(felts: gnark_backend_wrapper::GoString) -> *const ffi::c_char; fn TestU64Serialization(unsigned_integer: ffi::c_ulong) -> ffi::c_ulong; - fn TestMulTermSerialization( - mul_term: gnark_backend_wrapper::GoString, - ) -> *const ffi::c_char; - fn TestMulTermsSerialization( - mul_terms: gnark_backend_wrapper::GoString, - ) -> *const ffi::c_char; - fn TestAddTermSerialization( - add_term: gnark_backend_wrapper::GoString, - ) -> *const ffi::c_char; - fn TestAddTermsSerialization( - add_terms: gnark_backend_wrapper::GoString, - ) -> *const ffi::c_char; - fn TestRawGateSerialization( - raw_gate: gnark_backend_wrapper::GoString, - ) -> *const ffi::c_char; - fn TestRawGatesSerialization( - raw_gates: gnark_backend_wrapper::GoString, - ) -> *const ffi::c_char; - fn TestRawR1CSSerialization( - raw_r1cs: gnark_backend_wrapper::GoString, - ) -> *const ffi::c_char; + fn TestMulTermSerialization(mul_term: gnark_backend_wrapper::GoString) -> *const ffi::c_char; + fn TestMulTermsSerialization(mul_terms: gnark_backend_wrapper::GoString) -> *const ffi::c_char; + fn TestAddTermSerialization(add_term: gnark_backend_wrapper::GoString) -> *const ffi::c_char; + fn TestAddTermsSerialization(add_terms: gnark_backend_wrapper::GoString) -> *const ffi::c_char; + fn TestRawGateSerialization(raw_gate: gnark_backend_wrapper::GoString) -> *const ffi::c_char; + fn TestRawGatesSerialization(raw_gates: gnark_backend_wrapper::GoString) -> *const ffi::c_char; + fn TestRawR1CSSerialization(raw_r1cs: gnark_backend_wrapper::GoString) -> *const ffi::c_char; } fn serialize_felt(felt: &gnark_backend_wrapper::Fr) -> Vec { @@ -122,8 +100,7 @@ fn test_felts_serialization() { let go_serialized_felt = go_pre_serialized_felt.to_str().unwrap().as_bytes(); // Decode and deserialize the unpacked felts. - let go_felts: Vec = hex::decode(go_serialized_felt) - .unwrap()[4..] // Skip the vector length corresponding to the first four bytes. + let go_felts: Vec = hex::decode(go_serialized_felt).unwrap()[4..] // Skip the vector length corresponding to the first four bytes. .chunks_mut(32) .map(|go_decoded_felt| { // Turn big-endian to little-endian. From 8903c46d46a0a6f66d0d66c6cbd7f85cee03087b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Wed, 1 Mar 2023 20:39:52 -0300 Subject: [PATCH 064/118] Update `extern` function names --- tests/serialization_tests.rs | 58 +++++++++++++++++++++++------------- 1 file changed, 38 insertions(+), 20 deletions(-) diff --git a/tests/serialization_tests.rs b/tests/serialization_tests.rs index f88ffb7..d350481 100644 --- a/tests/serialization_tests.rs +++ b/tests/serialization_tests.rs @@ -6,16 +6,34 @@ use noir_backend_using_gnark::{ use std::ffi; extern "C" { - fn TestFeltSerialization(felt: gnark_backend_wrapper::GoString) -> *const ffi::c_char; - fn TestFeltsSerialization(felts: gnark_backend_wrapper::GoString) -> *const ffi::c_char; - fn TestU64Serialization(unsigned_integer: ffi::c_ulong) -> ffi::c_ulong; - fn TestMulTermSerialization(mul_term: gnark_backend_wrapper::GoString) -> *const ffi::c_char; - fn TestMulTermsSerialization(mul_terms: gnark_backend_wrapper::GoString) -> *const ffi::c_char; - fn TestAddTermSerialization(add_term: gnark_backend_wrapper::GoString) -> *const ffi::c_char; - fn TestAddTermsSerialization(add_terms: gnark_backend_wrapper::GoString) -> *const ffi::c_char; - fn TestRawGateSerialization(raw_gate: gnark_backend_wrapper::GoString) -> *const ffi::c_char; - fn TestRawGatesSerialization(raw_gates: gnark_backend_wrapper::GoString) -> *const ffi::c_char; - fn TestRawR1CSSerialization(raw_r1cs: gnark_backend_wrapper::GoString) -> *const ffi::c_char; + fn IntegrationTestFeltSerialization( + felt: gnark_backend_wrapper::GoString, + ) -> *const ffi::c_char; + fn IntegrationTestFeltsSerialization( + felts: gnark_backend_wrapper::GoString, + ) -> *const ffi::c_char; + fn IntegrationTestU64Serialization(unsigned_integer: ffi::c_ulong) -> ffi::c_ulong; + fn IntegrationTestMulTermSerialization( + mul_term: gnark_backend_wrapper::GoString, + ) -> *const ffi::c_char; + fn IntegrationTestMulTermsSerialization( + mul_terms: gnark_backend_wrapper::GoString, + ) -> *const ffi::c_char; + fn IntegrationTestAddTermSerialization( + add_term: gnark_backend_wrapper::GoString, + ) -> *const ffi::c_char; + fn IntegrationTestAddTermsSerialization( + add_terms: gnark_backend_wrapper::GoString, + ) -> *const ffi::c_char; + fn IntegrationTestRawGateSerialization( + raw_gate: gnark_backend_wrapper::GoString, + ) -> *const ffi::c_char; + fn IntegrationTestRawGatesSerialization( + raw_gates: gnark_backend_wrapper::GoString, + ) -> *const ffi::c_char; + fn IntegrationTestRawR1CSSerialization( + raw_r1cs: gnark_backend_wrapper::GoString, + ) -> *const ffi::c_char; } fn serialize_felt(felt: &gnark_backend_wrapper::Fr) -> Vec { @@ -61,7 +79,7 @@ fn test_felt_serialization() { let ping = gnark_backend_wrapper::GoString::try_from(&pre_ping).unwrap(); // Send and receive pong from Go. - let pong: *const ffi::c_char = unsafe { TestFeltSerialization(ping) }; + let pong: *const ffi::c_char = unsafe { IntegrationTestFeltSerialization(ping) }; // Prepare pong for Rust. let go_pre_serialized_felt = unsafe { ffi::CStr::from_ptr(pong) }; @@ -93,7 +111,7 @@ fn test_felts_serialization() { let ping = gnark_backend_wrapper::GoString::try_from(&pre_ping).unwrap(); // Send and receive pong from Go. - let pong: *const ffi::c_char = unsafe { TestFeltsSerialization(ping) }; + let pong: *const ffi::c_char = unsafe { IntegrationTestFeltsSerialization(ping) }; // Prepare pong for Rust. let go_pre_serialized_felt = unsafe { ffi::CStr::from_ptr(pong) }; @@ -125,7 +143,7 @@ fn test_u64_serialization() { // Prepare ping for Go. let ping = number; // Send and receive pong from Go. - let pong = unsafe { TestU64Serialization(ping) }; + let pong = unsafe { IntegrationTestU64Serialization(ping) }; assert_eq!(number, pong) } @@ -156,7 +174,7 @@ fn test_mul_term_serialization() { let ping = gnark_backend_wrapper::GoString::try_from(&pre_ping).unwrap(); // Send and receive pong from Go. - let _pong: *const ffi::c_char = unsafe { TestMulTermSerialization(ping) }; + let _pong: *const ffi::c_char = unsafe { IntegrationTestMulTermSerialization(ping) }; // TODO: // * Prepare pong for Rust. @@ -197,7 +215,7 @@ fn test_mul_terms_serialization() { let ping = gnark_backend_wrapper::GoString::try_from(&pre_ping).unwrap(); // Send and receive pong from Go. - let _pong: *const ffi::c_char = unsafe { TestMulTermsSerialization(ping) }; + let _pong: *const ffi::c_char = unsafe { IntegrationTestMulTermsSerialization(ping) }; // TODO: // * Prepare pong for Rust. @@ -225,7 +243,7 @@ fn test_add_term_serialization() { let ping = gnark_backend_wrapper::GoString::try_from(&pre_ping).unwrap(); // Send and receive pong from Go. - let _pong: *const ffi::c_char = unsafe { TestAddTermSerialization(ping) }; + let _pong: *const ffi::c_char = unsafe { IntegrationTestAddTermSerialization(ping) }; // TODO: // * Prepare pong for Rust. @@ -253,7 +271,7 @@ fn test_add_terms_serialization() { let ping = gnark_backend_wrapper::GoString::try_from(&pre_ping).unwrap(); // Send and receive pong from Go. - let _pong: *const ffi::c_char = unsafe { TestAddTermsSerialization(ping) }; + let _pong: *const ffi::c_char = unsafe { IntegrationTestAddTermsSerialization(ping) }; // TODO: // * Prepare pong for Rust. @@ -293,7 +311,7 @@ fn test_raw_gate_serialization() { let ping = gnark_backend_wrapper::GoString::try_from(&pre_ping).unwrap(); // Send and receive pong from Go. - let _pong: *const ffi::c_char = unsafe { TestRawGateSerialization(ping) }; + let _pong: *const ffi::c_char = unsafe { IntegrationTestRawGateSerialization(ping) }; // TODO: // * Prepare pong for Rust. @@ -334,7 +352,7 @@ fn test_raw_gates_serialization() { let ping = gnark_backend_wrapper::GoString::try_from(&pre_ping).unwrap(); // Send and receive pong from Go. - let _pong: *const ffi::c_char = unsafe { TestRawGatesSerialization(ping) }; + let _pong: *const ffi::c_char = unsafe { IntegrationTestRawGatesSerialization(ping) }; // TODO: // * Prepare pong for Rust. @@ -389,7 +407,7 @@ fn test_raw_r1cs_serialization() { let ping = gnark_backend_wrapper::GoString::try_from(&pre_ping).unwrap(); // Send and receive pong from Go. - let _pong: *const ffi::c_char = unsafe { TestRawR1CSSerialization(ping) }; + let _pong: *const ffi::c_char = unsafe { IntegrationTestRawR1CSSerialization(ping) }; // TODO: // * Prepare pong for Rust. From 4a3f8be1e356c8bf91f0a9a8b589c30edcd6ba0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Thu, 2 Mar 2023 13:37:09 -0300 Subject: [PATCH 065/118] Fix R1CS building --- gnark_backend_ffi/main.go | 157 +++++++++++++++++++++++++++++--------- 1 file changed, 121 insertions(+), 36 deletions(-) diff --git a/gnark_backend_ffi/main.go b/gnark_backend_ffi/main.go index 1a3ae94..1612015 100644 --- a/gnark_backend_ffi/main.go +++ b/gnark_backend_ffi/main.go @@ -31,7 +31,7 @@ func buildR1CS(r structs.RawR1CS) (*cs_bn254.R1CS, fr_bn254.Vector, fr_bn254.Vec for i, value := range r.Values { variableName := strconv.Itoa(i) for _, publicInput := range r.PublicInputs { - if uint32(i) == publicInput { + if uint32(i+1) == publicInput { allVariableIndices = append(allVariableIndices, r1cs.AddPublicVariable(variableName)) publicVariables = append(publicVariables, value) nPublicVariables++ @@ -45,17 +45,20 @@ func buildR1CS(r structs.RawR1CS) (*cs_bn254.R1CS, fr_bn254.Vector, fr_bn254.Vec // Generate constraints. ONE := r1cs.AddPublicVariable("ONE") - ZERO := r1cs.AddPublicVariable("ZERO") + ZERO := r1cs.AddInternalVariable() COEFFICIENT_ONE := r1cs.FromInterface(1) for _, gate := range r.Gates { var terms constraint.LinearExpression for _, mul_term := range gate.MulTerms { coefficient := r1cs.FromInterface(mul_term.Coefficient) + multiplicand := r.Values[mul_term.Multiplicand] + multiplier := r.Values[mul_term.Multiplier] - product := mul_term.Multiplicand * mul_term.Multiplier - productVariableName := strconv.FormatUint(uint64(product), 10) - productVariable := r1cs.AddSecretVariable(productVariableName) + var product fr_bn254.Element + product.Mul(&multiplicand, &multiplier) + + productVariable := r1cs.AddInternalVariable() terms = append(terms, r1cs.MakeTerm(&coefficient, productVariable)) } @@ -139,17 +142,16 @@ func ProveWithMeta(rawR1CS string) *C.char { //export ProveWithPK func ProveWithPK(rawR1CS string, provingKey string) *C.char { - // Create R1CS. - r1cs := cs_bn254.NewR1CS(1) - - // Add variables. - witness, err := witness.New(r1cs.CurveID().ScalarField()) + // Deserialize rawR1CS. + var r structs.RawR1CS + err := json.Unmarshal([]byte(rawR1CS), &r) if err != nil { log.Fatal(err) } - witness.Fill(0, 0, nil) - // Add constraints. + r1cs, publicVariables, privateVariables, nPublicVariables, nPrivateVariables := buildR1CS(r) + + witness := buildWitnesses(r1cs, publicVariables, privateVariables, nPublicVariables, nPrivateVariables) // Deserialize proving key. pk := groth16.NewProvingKey(r1cs.CurveID()) @@ -173,18 +175,17 @@ func ProveWithPK(rawR1CS string, provingKey string) *C.char { } //export VerifyWithMeta -func VerifyWithMeta(rawr1cs string, proof string) bool { - // Create R1CS. - r1cs := cs_bn254.NewR1CS(1) - - // Add variables. - witness, err := witness.New(r1cs.CurveID().ScalarField()) +func VerifyWithMeta(rawR1CS string, proof string) bool { + // Deserialize rawR1CS. + var r structs.RawR1CS + err := json.Unmarshal([]byte(rawR1CS), &r) if err != nil { log.Fatal(err) } - witness.Fill(0, 0, nil) - // Add constraints. + r1cs, publicVariables, privateVariables, nPublicVariables, nPrivateVariables := buildR1CS(r) + + witness := buildWitnesses(r1cs, publicVariables, privateVariables, nPublicVariables, nPrivateVariables) // Deserialize proof. p := groth16.NewProof(r1cs.CurveID()) @@ -214,18 +215,17 @@ func VerifyWithMeta(rawr1cs string, proof string) bool { } //export VerifyWithVK -func VerifyWithVK(rawr1cs string, proof string, verifyingKey string) bool { - // Create R1CS. - r1cs := cs_bn254.NewR1CS(1) - - // Add variables. - witness, err := witness.New(r1cs.CurveID().ScalarField()) +func VerifyWithVK(rawR1CS string, proof string, verifyingKey string) bool { + // Deserialize rawR1CS. + var r structs.RawR1CS + err := json.Unmarshal([]byte(rawR1CS), &r) if err != nil { log.Fatal(err) } - witness.Fill(0, 0, nil) - // Add constraints. + r1cs, publicVariables, privateVariables, nPublicVariables, nPrivateVariables := buildR1CS(r) + + witness := buildWitnesses(r1cs, publicVariables, privateVariables, nPublicVariables, nPrivateVariables) // Deserialize proof. p := groth16.NewProof(r1cs.CurveID()) @@ -257,17 +257,14 @@ func VerifyWithVK(rawr1cs string, proof string, verifyingKey string) bool { //export Preprocess func Preprocess(rawR1CS string) (*C.char, *C.char) { - // Create R1CS. - r1cs := cs_bn254.NewR1CS(1) - - // Add variables. - witness, err := witness.New(r1cs.CurveID().ScalarField()) + // Deserialize rawR1CS. + var r structs.RawR1CS + err := json.Unmarshal([]byte(rawR1CS), &r) if err != nil { log.Fatal(err) } - witness.Fill(0, 0, nil) - // Add constraints. + r1cs, _, _, _, _ := buildR1CS(r) // Setup. pk, vk, err := groth16.Setup(r1cs) @@ -482,4 +479,92 @@ func IntegrationTestRawR1CSSerialization(rawR1CSJSON string) *C.char { return C.CString(string(serializedRawR1CS)) } -func main() {} +func main() { + rawR1CS := `{"gates":[{"mul_terms":[],"add_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","sum":1},{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":2},{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":3}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000"},{"mul_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","multiplicand":3,"multiplier":4}],"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":5}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000"},{"mul_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","multiplicand":3,"multiplier":5}],"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":3}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000"},{"mul_terms":[],"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":5}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000001"}],"public_inputs":[2],"values":"00000006000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","num_variables":7,"num_constraints":11}` + + var r structs.RawR1CS + err := json.Unmarshal([]byte(rawR1CS), &r) + if err != nil { + log.Fatal(err) + } + + r1cs, publicVariables, privateVariables, nPublicVariables, nPrivateVariables := buildR1CS(r) + + fmt.Println("R1CS:\n", r1cs) + fmt.Println("R1CS Public:\n", r1cs.Public) + fmt.Println("R1CS Private:\n", r1cs.Secret) + fmt.Println("R1CS Constraints:\n", r1cs.Constraints) + fmt.Println("R1CS Number of Constraints:\n", r1cs.GetNbConstraints()) + fmt.Println("R1CS Number of Internal Variables:\n", r1cs.GetNbInternalVariables()) + fmt.Println("R1CS Number of Public Variables:\n", r1cs.GetNbPublicVariables()) + fmt.Println("R1CS Number of Private Variables:\n", r1cs.GetNbSecretVariables()) + fmt.Println() + fmt.Println("Public variables:\n", publicVariables) + fmt.Println() + fmt.Println("Private variables:\n", privateVariables) + fmt.Println() + fmt.Println("Number of public variables: ", nPublicVariables) + fmt.Println() + fmt.Println("Number of private variables: ", nPrivateVariables) + fmt.Println() + + witness := buildWitnesses(r1cs, publicVariables, privateVariables, nPublicVariables, nPrivateVariables) + + fmt.Println("Witness:\n", witness) + fmt.Println() + publicWitnesses, _ := witness.Public() + fmt.Println("Public:\n", publicWitnesses) + fmt.Println() + witnessVector := witness.Vector().(fr_bn254.Vector) + fmt.Println("Vector:\n", witnessVector) + fmt.Println() + + // Setup. + pk, vk, err := groth16.Setup(r1cs) + if err != nil { + log.Fatal(err) + } + + // fmt.Println("Proving key:\n", pk) + // fmt.Println() + // fmt.Println("Verification key:\n", vk) + // fmt.Println() + fmt.Println("Verification key publics: ", vk.NbPublicWitness()) + fmt.Println() + + fmt.Println(len(witnessVector), len(r1cs.Public), len(r1cs.Secret)) + fmt.Println() + + // Prove. + proof, err := groth16.Prove(r1cs, pk, witness) + if err != nil { + log.Fatal(err) + } + + fmt.Println("Proof:\n", proof) + fmt.Println() + + // Verify. + verified := groth16.Verify(proof, vk, publicWitnesses) + + fmt.Println("Verifies with valid public inputs: ", verified == nil) + fmt.Println() + + // Invalid verification (same proof, wrong public value). + invalidRawR1CS := `{"gates":[{"mul_terms":[],"add_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","sum":1},{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":2},{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":3}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000"},{"mul_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","multiplicand":3,"multiplier":4}],"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":5}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000"},{"mul_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","multiplicand":3,"multiplier":5}],"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":3}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000"},{"mul_terms":[],"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":5}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000001"}],"public_inputs":[2],"values":"00000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000150000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","num_variables":7,"num_constraints":11}` + err = json.Unmarshal([]byte(invalidRawR1CS), &r) + if err != nil { + log.Fatal(err) + } + + invalidR1CS, publicVariables, privateVariables, nPublicVariables, nPrivateVariables := buildR1CS(r) + invalidWitness := buildWitnesses(invalidR1CS, publicVariables, privateVariables, nPublicVariables, nPrivateVariables) + invalidPublicWitnesses, _ := invalidWitness.Public() + invalidVerified := groth16.Verify(proof, vk, invalidPublicWitnesses) + + fmt.Println("Valid Public Witnesses: ", publicWitnesses) + fmt.Println("Invalid Public Witnesses: ", invalidPublicWitnesses) + fmt.Println() + + fmt.Println("Verifies with invalid public inputs: ", invalidVerified == nil) +} From d88c93253db9cc7552d39799330832ea8522a7d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Thu, 2 Mar 2023 14:52:16 -0300 Subject: [PATCH 066/118] Update `acvm` --- Cargo.lock | 19 ++++++++----------- src/acvm_interop.rs | 24 ++++++++++++++++++++---- 2 files changed, 28 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b2f41ee..17a2f1c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,8 +4,8 @@ version = 3 [[package]] name = "acir" -version = "0.4.1" -source = "git+https://github.com/noir-lang/acvm#373c18fc05edf673cfec9e8bbb78bd7d7514999e" +version = "0.5.0" +source = "git+https://github.com/noir-lang/acvm#62a13b1953ebbf6bd0db447e9c2a423f4e053633" dependencies = [ "acir_field", "flate2", @@ -15,25 +15,22 @@ dependencies = [ [[package]] name = "acir_field" -version = "0.4.1" -source = "git+https://github.com/noir-lang/acvm#373c18fc05edf673cfec9e8bbb78bd7d7514999e" +version = "0.5.0" +source = "git+https://github.com/noir-lang/acvm#62a13b1953ebbf6bd0db447e9c2a423f4e053633" dependencies = [ "ark-bls12-381", "ark-bn254", "ark-ff", - "ark-serialize", - "blake2", "cfg-if", "hex", "num-bigint", - "num-traits", "serde", ] [[package]] name = "acvm" -version = "0.4.1" -source = "git+https://github.com/noir-lang/acvm#373c18fc05edf673cfec9e8bbb78bd7d7514999e" +version = "0.5.0" +source = "git+https://github.com/noir-lang/acvm#62a13b1953ebbf6bd0db447e9c2a423f4e053633" dependencies = [ "acir", "acvm_stdlib", @@ -48,8 +45,8 @@ dependencies = [ [[package]] name = "acvm_stdlib" -version = "0.4.1" -source = "git+https://github.com/noir-lang/acvm#373c18fc05edf673cfec9e8bbb78bd7d7514999e" +version = "0.5.0" +source = "git+https://github.com/noir-lang/acvm#62a13b1953ebbf6bd0db447e9c2a423f4e053633" dependencies = [ "acir", ] diff --git a/src/acvm_interop.rs b/src/acvm_interop.rs index d62000f..5cbf490 100644 --- a/src/acvm_interop.rs +++ b/src/acvm_interop.rs @@ -72,19 +72,35 @@ impl ProofSystemCompiler for Gnark { witness_values: std::collections::BTreeMap, proving_key: &[u8], ) -> Vec { - // TODO: modify gnark serializer to accept the BTreeMap - let values: Vec = witness_values.values().copied().collect(); + let num_witnesses = circuit.num_vars(); + let values = (1..num_witnesses) + .map(|wit_index| { + // Get the value if it exists, if not then default to zero value. + witness_values + .get(&Witness(wit_index)) + .map_or(FieldElement::zero(), |field| *field) + }) + .collect(); gnark_backend::prove_with_pk(circuit, values, proving_key).unwrap() } fn verify_with_vk( &self, proof: &[u8], - public_inputs: Vec, + public_inputs: BTreeMap, circuit: &Circuit, verification_key: &[u8], ) -> bool { - gnark_backend::verify_with_vk(circuit, proof, &public_inputs, verification_key).unwrap() + let num_witnesses = circuit.num_vars(); + let public = (1..num_witnesses) + .map(|wit_index| { + // Get the value if it exists, if not then default to zero value. + public_inputs + .get(&Witness(wit_index)) + .map_or(FieldElement::zero(), |field| *field) + }) + .collect::>(); + gnark_backend::verify_with_vk(circuit, proof, &public, verification_key).unwrap() } } From 8b6196787054efde8d5a4469c50bf9218d04afcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Thu, 2 Mar 2023 16:53:02 -0300 Subject: [PATCH 067/118] Automatically build go backend when compiling --- build.rs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/build.rs b/build.rs index 6c44e85..e811ec8 100644 --- a/build.rs +++ b/build.rs @@ -1,8 +1,16 @@ -#[allow(clippy::all)] +fn build_go_backend() { + std::process::Command::new("make") + .arg("-C") + .arg(std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")).to_str().unwrap()) + .arg("build-go").spawn().unwrap(); +} + fn main() { + build_go_backend(); + let path = "gnark_backend_ffi"; let lib = "gnark_backend"; - println!("cargo:rustc-link-search=native={}", path); - println!("cargo:rustc-link-lib=static={}", lib); + println!("cargo:rustc-link-search=native={path}"); + println!("cargo:rustc-link-lib=static={lib}"); } From df6eb170ba55f0b8248a3b12298fd763dfd67d22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Thu, 2 Mar 2023 16:55:16 -0300 Subject: [PATCH 068/118] Fix `preprocess` When preprocessing (a.k.a. compiling the circuit or generating proving and verifying keys) we have to sample random witnesses because we don't know the ones that the user is going to use. Nevertheless, the ACIR circuit does know this. We should find a way of knowing this too because this won't let us sample random circuit variables (witnesses) because they're pre-set in the ACIR circuit. --- src/gnark_backend_wrapper/groth16/mod.rs | 26 ++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/gnark_backend_wrapper/groth16/mod.rs b/src/gnark_backend_wrapper/groth16/mod.rs index ab389e9..3fe0b6d 100644 --- a/src/gnark_backend_wrapper/groth16/mod.rs +++ b/src/gnark_backend_wrapper/groth16/mod.rs @@ -1,4 +1,6 @@ +use acvm::acir::native_types::Witness; use acvm::{acir::circuit::Circuit, FieldElement}; +use std::collections::BTreeMap; use std::ffi::{CStr, CString}; use std::num::TryFromIntError; use std::os::raw::{c_char, c_uchar}; @@ -171,14 +173,30 @@ pub fn get_exact_circuit_size(circuit: &Circuit) -> Result Result<(Vec, Vec), GnarkBackendError> { + // TODO: Sample random public_inputs + let mut witness_values = BTreeMap::new(); + witness_values.insert(Witness(1), FieldElement::from(10_u128)); + witness_values.insert(Witness(2), FieldElement::from(21_u128)); + let num_witnesses = circuit.num_vars(); + let values = (1..num_witnesses) + .map(|wit_index| { + // Get the value if it exists, if not then default to zero value. + witness_values + .get(&Witness(wit_index)) + .map_or(FieldElement::zero(), |field| *field) + }) + .collect(); + + let rawr1cs = RawR1CS::new(circuit.clone(), values)?; + // Serialize to json and then convert to GoString - let circuit_json = serde_json::to_string(circuit) + let rawr1cs_json = serde_json::to_string(&rawr1cs) .map_err(|e| GnarkBackendError::SerializeCircuitError(e.to_string()))?; - let circuit_c_str = CString::new(circuit_json) + let rawr1cs_c_str = CString::new(rawr1cs_json) .map_err(|e| GnarkBackendError::SerializeCircuitError(e.to_string()))?; - let circuit_go_string = GoString::try_from(&circuit_c_str)?; + let rawr1cs_go_string = GoString::try_from(&rawr1cs_c_str)?; - let key_pair: KeyPair = unsafe { Preprocess(circuit_go_string) }; + let key_pair: KeyPair = unsafe { Preprocess(rawr1cs_go_string) }; let proving_key_c_str = unsafe { CStr::from_ptr(key_pair.proving_key) }; let proving_key_bytes = proving_key_c_str From 31b8786e8f29d2421c7efa27feb056e4737d2e89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Thu, 2 Mar 2023 16:55:26 -0300 Subject: [PATCH 069/118] cargo fmt --- build.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/build.rs b/build.rs index e811ec8..30d45a0 100644 --- a/build.rs +++ b/build.rs @@ -1,8 +1,14 @@ fn build_go_backend() { std::process::Command::new("make") .arg("-C") - .arg(std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")).to_str().unwrap()) - .arg("build-go").spawn().unwrap(); + .arg( + std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .to_str() + .unwrap(), + ) + .arg("build-go") + .spawn() + .unwrap(); } fn main() { From 2976f0564db3b43f825a228b70fbf8d80d7c632b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Thu, 2 Mar 2023 16:55:53 -0300 Subject: [PATCH 070/118] Encode proving and verifying keys and proof --- gnark_backend_ffi/main.go | 56 +++++++++++++++++++++++++-------------- 1 file changed, 36 insertions(+), 20 deletions(-) diff --git a/gnark_backend_ffi/main.go b/gnark_backend_ffi/main.go index 1612015..1887505 100644 --- a/gnark_backend_ffi/main.go +++ b/gnark_backend_ffi/main.go @@ -121,13 +121,13 @@ func ProveWithMeta(rawR1CS string) *C.char { witness := buildWitnesses(r1cs, publicVariables, privateVariables, nPublicVariables, nPrivateVariables) // Setup. - pk, _, err := groth16.Setup(r1cs) + provingKey, _, err := groth16.Setup(r1cs) if err != nil { log.Fatal(err) } // Prove. - proof, err := groth16.Prove(r1cs, pk, witness) + proof, err := groth16.Prove(r1cs, provingKey, witness) if err != nil { log.Fatal(err) } @@ -135,13 +135,13 @@ func ProveWithMeta(rawR1CS string) *C.char { // Serialize proof var serialized_proof bytes.Buffer proof.WriteTo(&serialized_proof) - proof_string := serialized_proof.String() + proof_string := hex.EncodeToString(serialized_proof.Bytes()) return C.CString(proof_string) } //export ProveWithPK -func ProveWithPK(rawR1CS string, provingKey string) *C.char { +func ProveWithPK(rawR1CS string, encodedProvingKey string) *C.char { // Deserialize rawR1CS. var r structs.RawR1CS err := json.Unmarshal([]byte(rawR1CS), &r) @@ -154,14 +154,18 @@ func ProveWithPK(rawR1CS string, provingKey string) *C.char { witness := buildWitnesses(r1cs, publicVariables, privateVariables, nPublicVariables, nPrivateVariables) // Deserialize proving key. - pk := groth16.NewProvingKey(r1cs.CurveID()) - _, err = pk.ReadFrom(bytes.NewReader([]byte(provingKey))) + provingKey := groth16.NewProvingKey(r1cs.CurveID()) + decodedProvingKey, err := hex.DecodeString(encodedProvingKey) + if err != nil { + log.Fatal(err) + } + _, err = provingKey.ReadFrom(bytes.NewReader([]byte(decodedProvingKey))) if err != nil { log.Fatal(err) } // Prove. - proof, err := groth16.Prove(r1cs, pk, witness) + proof, err := groth16.Prove(r1cs, provingKey, witness) if err != nil { log.Fatal(err) } @@ -169,13 +173,13 @@ func ProveWithPK(rawR1CS string, provingKey string) *C.char { // Serialize proof var serialized_proof bytes.Buffer proof.WriteTo(&serialized_proof) - proof_string := serialized_proof.String() + proof_string := hex.EncodeToString(serialized_proof.Bytes()) return C.CString(proof_string) } //export VerifyWithMeta -func VerifyWithMeta(rawR1CS string, proof string) bool { +func VerifyWithMeta(rawR1CS string, encodedProof string) bool { // Deserialize rawR1CS. var r structs.RawR1CS err := json.Unmarshal([]byte(rawR1CS), &r) @@ -188,8 +192,12 @@ func VerifyWithMeta(rawR1CS string, proof string) bool { witness := buildWitnesses(r1cs, publicVariables, privateVariables, nPublicVariables, nPrivateVariables) // Deserialize proof. - p := groth16.NewProof(r1cs.CurveID()) - _, err = p.ReadFrom(bytes.NewReader([]byte(proof))) + proof := groth16.NewProof(r1cs.CurveID()) + decodedProof, err := hex.DecodeString(encodedProof) + if err != nil { + log.Fatal(err) + } + _, err = proof.ReadFrom(bytes.NewReader([]byte(decodedProof))) if err != nil { log.Fatal(err) } @@ -207,7 +215,7 @@ func VerifyWithMeta(rawR1CS string, proof string) bool { } // Verify. - if groth16.Verify(p, vk, publicInputs) != nil { + if groth16.Verify(proof, vk, publicInputs) != nil { return false } @@ -215,7 +223,7 @@ func VerifyWithMeta(rawR1CS string, proof string) bool { } //export VerifyWithVK -func VerifyWithVK(rawR1CS string, proof string, verifyingKey string) bool { +func VerifyWithVK(rawR1CS string, encodedProof string, encodedVerifyingKey string) bool { // Deserialize rawR1CS. var r structs.RawR1CS err := json.Unmarshal([]byte(rawR1CS), &r) @@ -228,15 +236,23 @@ func VerifyWithVK(rawR1CS string, proof string, verifyingKey string) bool { witness := buildWitnesses(r1cs, publicVariables, privateVariables, nPublicVariables, nPrivateVariables) // Deserialize proof. - p := groth16.NewProof(r1cs.CurveID()) - _, err = p.ReadFrom(bytes.NewReader([]byte(proof))) + proof := groth16.NewProof(r1cs.CurveID()) + decodedProof, err := hex.DecodeString(encodedProof) + if err != nil { + log.Fatal(err) + } + _, err = proof.ReadFrom(bytes.NewReader([]byte(decodedProof))) if err != nil { log.Fatal(err) } // Deserialize verifying key. - vk := groth16.NewVerifyingKey(r1cs.CurveID()) - _, err = vk.ReadFrom(bytes.NewReader([]byte(verifyingKey))) + verifyingKey := groth16.NewVerifyingKey(r1cs.CurveID()) + decodedVerifyingKey, err := hex.DecodeString(encodedVerifyingKey) + if err != nil { + log.Fatal(err) + } + _, err = verifyingKey.ReadFrom(bytes.NewReader(decodedVerifyingKey)) if err != nil { log.Fatal(err) } @@ -248,7 +264,7 @@ func VerifyWithVK(rawR1CS string, proof string, verifyingKey string) bool { } // Verify. - if groth16.Verify(p, vk, publicInputs) != nil { + if groth16.Verify(proof, verifyingKey, publicInputs) != nil { return false } @@ -275,12 +291,12 @@ func Preprocess(rawR1CS string) (*C.char, *C.char) { // Serialize proving key. var serialized_pk bytes.Buffer pk.WriteTo(&serialized_pk) - pk_string := serialized_pk.String() + pk_string := hex.EncodeToString(serialized_pk.Bytes()) // Serialize verifying key. var serialized_vk bytes.Buffer vk.WriteTo(&serialized_vk) - vk_string := serialized_vk.String() + vk_string := hex.EncodeToString(serialized_vk.Bytes()) return C.CString(pk_string), C.CString(vk_string) } From 78f1e6e053bcfd3877e576a6b3e076dcf4220e37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Thu, 2 Mar 2023 18:13:05 -0300 Subject: [PATCH 071/118] Add opcode resolution when preprocessing --- src/gnark_backend_wrapper/groth16/errors.rs | 4 ++++ src/gnark_backend_wrapper/groth16/mod.rs | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/gnark_backend_wrapper/groth16/errors.rs b/src/gnark_backend_wrapper/groth16/errors.rs index b04d1e6..cc05a37 100644 --- a/src/gnark_backend_wrapper/groth16/errors.rs +++ b/src/gnark_backend_wrapper/groth16/errors.rs @@ -1,3 +1,4 @@ +use acvm::OpcodeResolutionError; use thiserror::Error; #[derive(Error, Debug)] @@ -23,6 +24,9 @@ pub enum GnarkBackendError { #[error("Verify did not return a valid bool")] VerifyInvalidBoolError, + #[error("Opcode resolution error: {0}")] + OpcodeResolutionError(#[from] OpcodeResolutionError), + #[error("an error occurred: {0}")] Error(String), } diff --git a/src/gnark_backend_wrapper/groth16/mod.rs b/src/gnark_backend_wrapper/groth16/mod.rs index 3fe0b6d..767b565 100644 --- a/src/gnark_backend_wrapper/groth16/mod.rs +++ b/src/gnark_backend_wrapper/groth16/mod.rs @@ -1,4 +1,5 @@ use acvm::acir::native_types::Witness; +use acvm::PartialWitnessGenerator; use acvm::{acir::circuit::Circuit, FieldElement}; use std::collections::BTreeMap; use std::ffi::{CStr, CString}; @@ -14,6 +15,7 @@ pub use crate::gnark_backend_wrapper::groth16::acir_to_r1cs::{AddTerm, MulTerm, pub use crate::gnark_backend_wrapper::groth16::c_go_structures::GoString; use crate::gnark_backend_wrapper::groth16::c_go_structures::KeyPair; use crate::gnark_backend_wrapper::groth16::errors::GnarkBackendError; +use crate::Gnark; // Arkworks's types are generic for `Field` but Noir's types are concrete and // its value depends on the feature flag. @@ -177,6 +179,8 @@ pub fn preprocess(circuit: &Circuit) -> Result<(Vec, Vec), GnarkBackendE let mut witness_values = BTreeMap::new(); witness_values.insert(Witness(1), FieldElement::from(10_u128)); witness_values.insert(Witness(2), FieldElement::from(21_u128)); + let backend = Gnark; + backend.solve(&mut witness_values, circuit.opcodes.clone())?; let num_witnesses = circuit.num_vars(); let values = (1..num_witnesses) .map(|wit_index| { From 7ec68e4cf82ca22fc1eb4b4e7b8c4fd6ea323ce8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Thu, 2 Mar 2023 18:13:28 -0300 Subject: [PATCH 072/118] Fix example raw R1CS --- gnark_backend_ffi/main.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gnark_backend_ffi/main.go b/gnark_backend_ffi/main.go index 1887505..ad6f871 100644 --- a/gnark_backend_ffi/main.go +++ b/gnark_backend_ffi/main.go @@ -496,7 +496,7 @@ func IntegrationTestRawR1CSSerialization(rawR1CSJSON string) *C.char { } func main() { - rawR1CS := `{"gates":[{"mul_terms":[],"add_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","sum":1},{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":2},{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":3}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000"},{"mul_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","multiplicand":3,"multiplier":4}],"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":5}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000"},{"mul_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","multiplicand":3,"multiplier":5}],"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":3}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000"},{"mul_terms":[],"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":5}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000001"}],"public_inputs":[2],"values":"00000006000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","num_variables":7,"num_constraints":11}` + rawR1CS := `{"gates":[{"mul_terms":[],"add_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","sum":1},{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":2},{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":3}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000"},{"mul_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","multiplicand":3,"multiplier":4}],"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":5}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000"},{"mul_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","multiplicand":3,"multiplier":5}],"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":3}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000"},{"mul_terms":[],"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":5}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000001"}],"public_inputs":[2],"values":"00000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000001530644e72e131a029b85045b68181585d2833e84879b9709143e1f593effffff61ecb77bd78084ea62f78e68b69af66c6eb09c25caa8d47a2427885010d1745d200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000","num_variables":7,"num_constraints":11}` var r structs.RawR1CS err := json.Unmarshal([]byte(rawR1CS), &r) @@ -548,7 +548,7 @@ func main() { fmt.Println("Verification key publics: ", vk.NbPublicWitness()) fmt.Println() - fmt.Println(len(witnessVector), len(r1cs.Public), len(r1cs.Secret)) + fmt.Println("Num Witnesses: ", len(witnessVector), "Num Public: ", len(r1cs.Public), "Num Private: ", len(r1cs.Secret)) fmt.Println() // Prove. From ec0e8763df02bc109af9ce1736017a7469547d99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Fri, 3 Mar 2023 12:56:46 -0300 Subject: [PATCH 073/118] Add examples --- Cargo.lock | 15 ++- Cargo.toml | 3 +- gnark_backend_ffi/main.go | 204 +++++++++++++++++++++++++++----------- src/acvm_interop.rs | 19 +--- 4 files changed, 166 insertions(+), 75 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 17a2f1c..9414607 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5,7 +5,8 @@ version = 3 [[package]] name = "acir" version = "0.5.0" -source = "git+https://github.com/noir-lang/acvm#62a13b1953ebbf6bd0db447e9c2a423f4e053633" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "104242ac56c936464e3ac9618e1f635151e83334d8d4138f9a39490ca11acaa9" dependencies = [ "acir_field", "flate2", @@ -16,21 +17,26 @@ dependencies = [ [[package]] name = "acir_field" version = "0.5.0" -source = "git+https://github.com/noir-lang/acvm#62a13b1953ebbf6bd0db447e9c2a423f4e053633" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebd6cc7ebc948cde55bf10a8c4f3e1479e03f34e00ee8ab83e86891b693dd503" dependencies = [ "ark-bls12-381", "ark-bn254", "ark-ff", + "ark-serialize", + "blake2", "cfg-if", "hex", "num-bigint", + "num-traits", "serde", ] [[package]] name = "acvm" version = "0.5.0" -source = "git+https://github.com/noir-lang/acvm#62a13b1953ebbf6bd0db447e9c2a423f4e053633" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6145438d6c89c208cae93e49b925b0e2ac1963048a8ee4e002ca0f0de87d789e" dependencies = [ "acir", "acvm_stdlib", @@ -46,7 +52,8 @@ dependencies = [ [[package]] name = "acvm_stdlib" version = "0.5.0" -source = "git+https://github.com/noir-lang/acvm#62a13b1953ebbf6bd0db447e9c2a423f4e053633" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aaabcf52a534df7ed591451cf5ac2a765416fee4e38e0c523cc29da8c244aa7c" dependencies = [ "acir", ] diff --git a/Cargo.toml b/Cargo.toml index 83a607d..fe879cb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,8 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -acvm = { git = "https://github.com/noir-lang/acvm" } +# acvm = { git = "https://github.com/noir-lang/acvm" } +acvm = "0.5" ark-ff = "0.4.0" ark-bls12-381 = "0.4.0" diff --git a/gnark_backend_ffi/main.go b/gnark_backend_ffi/main.go index ad6f871..d5ed5c3 100644 --- a/gnark_backend_ffi/main.go +++ b/gnark_backend_ffi/main.go @@ -7,7 +7,6 @@ import ( "encoding/json" "fmt" "log" - "strconv" "gnark_backend_ffi/structs" @@ -29,14 +28,16 @@ func buildR1CS(r structs.RawR1CS) (*cs_bn254.R1CS, fr_bn254.Vector, fr_bn254.Vec var publicVariables fr_bn254.Vector var privateVariables fr_bn254.Vector for i, value := range r.Values { - variableName := strconv.Itoa(i) + i++ for _, publicInput := range r.PublicInputs { - if uint32(i+1) == publicInput { - allVariableIndices = append(allVariableIndices, r1cs.AddPublicVariable(variableName)) + if uint32(i) == publicInput { + allVariableIndices = append(allVariableIndices, r1cs.AddPublicVariable(fmt.Sprintf("public_%d", i))) + // fmt.Println(fmt.Sprintf("public_%d", i), value.String()) publicVariables = append(publicVariables, value) nPublicVariables++ } else { - allVariableIndices = append(allVariableIndices, r1cs.AddSecretVariable(variableName)) + allVariableIndices = append(allVariableIndices, r1cs.AddSecretVariable(fmt.Sprintf("secret_%d", i))) + // fmt.Println(fmt.Sprintf("secret_%d", i), value.String()) privateVariables = append(privateVariables, value) nPrivateVariables++ } @@ -44,16 +45,17 @@ func buildR1CS(r structs.RawR1CS) (*cs_bn254.R1CS, fr_bn254.Vector, fr_bn254.Vec } // Generate constraints. - ONE := r1cs.AddPublicVariable("ONE") - ZERO := r1cs.AddInternalVariable() + ONE := r1cs.AddPublicVariable("1") COEFFICIENT_ONE := r1cs.FromInterface(1) - for _, gate := range r.Gates { + for g, gate := range r.Gates { + fmt.Println("GATE ", g) var terms constraint.LinearExpression for _, mul_term := range gate.MulTerms { coefficient := r1cs.FromInterface(mul_term.Coefficient) multiplicand := r.Values[mul_term.Multiplicand] multiplier := r.Values[mul_term.Multiplier] + fmt.Println(mul_term.Coefficient.String(), " * ", multiplicand.String(), " * ", multiplier.String()) var product fr_bn254.Element product.Mul(&multiplicand, &multiplier) @@ -64,6 +66,7 @@ func buildR1CS(r structs.RawR1CS) (*cs_bn254.R1CS, fr_bn254.Vector, fr_bn254.Vec } for _, add_term := range gate.AddTerms { + fmt.Println(add_term.Coefficient.String(), " * ", r.Values[add_term.Sum].String()) coefficient := r1cs.FromInterface(add_term.Coefficient) sum := add_term.Sum @@ -76,9 +79,10 @@ func buildR1CS(r structs.RawR1CS) (*cs_bn254.R1CS, fr_bn254.Vector, fr_bn254.Vec constraint.R1C{ L: constraint.LinearExpression{r1cs.MakeTerm(&COEFFICIENT_ONE, ONE)}, R: terms, - O: constraint.LinearExpression{r1cs.MakeTerm(&COEFFICIENT_ONE, ZERO)}, + O: constraint.LinearExpression{}, }, ) + fmt.Println() } return r1cs, publicVariables, privateVariables, nPublicVariables, nPrivateVariables @@ -495,7 +499,73 @@ func IntegrationTestRawR1CSSerialization(rawR1CSJSON string) *C.char { return C.CString(string(serializedRawR1CS)) } +func ExampleR1CS() { + // build a constraint system; this is (usually) done by the frontend package + // for this Example we want to manipulate the constraints and output a string representation + // and build the linear expressions "manually". + r1cs := cs_bn254.NewR1CS(0) + + ONE := r1cs.AddPublicVariable("1") // the "ONE" wire + Y := r1cs.AddPublicVariable("Y") + X := r1cs.AddSecretVariable("X") + + v0 := r1cs.AddInternalVariable() // X² + v1 := r1cs.AddInternalVariable() // X³ + + // coefficients + cOne := r1cs.FromInterface(1) + cFive := r1cs.FromInterface(5) + + // X² == X * X + r1cs.AddConstraint(constraint.R1C{ + L: constraint.LinearExpression{r1cs.MakeTerm(&cOne, X)}, + R: constraint.LinearExpression{r1cs.MakeTerm(&cOne, X)}, + O: constraint.LinearExpression{r1cs.MakeTerm(&cOne, v0)}, + }) + + // X³ == X² * X + r1cs.AddConstraint(constraint.R1C{ + L: constraint.LinearExpression{r1cs.MakeTerm(&cOne, v0)}, + R: constraint.LinearExpression{r1cs.MakeTerm(&cOne, X)}, + O: constraint.LinearExpression{r1cs.MakeTerm(&cOne, v1)}, + }) + + // Y == X³ + X + 5 + r1cs.AddConstraint(constraint.R1C{ + R: constraint.LinearExpression{r1cs.MakeTerm(&cOne, ONE)}, + L: constraint.LinearExpression{r1cs.MakeTerm(&cOne, Y)}, + O: constraint.LinearExpression{ + r1cs.MakeTerm(&cFive, ONE), + r1cs.MakeTerm(&cOne, X), + r1cs.MakeTerm(&cOne, v1), + }, + }) + + fmt.Println("Number of constraints", r1cs.GetNbConstraints()) + fmt.Println("Number of coefficients", r1cs.GetNbCoefficients()) + fmt.Println("Number of internal variables", r1cs.GetNbInternalVariables()) + fmt.Println("Number of public variables", r1cs.GetNbPublicVariables()) + fmt.Println("Number of secret variables", r1cs.GetNbSecretVariables()) + fmt.Println("Coefficients", r1cs.Coefficients) + + // get the constraints + constraints, r := r1cs.GetConstraints() + + for _, r1c := range constraints { + fmt.Println(r1c.String(r)) + // for more granularity use constraint.NewStringBuilder(r) that embeds a string.Builder + // and has WriteLinearExpression and WriteTerm methods. + } + + // Output: + // X ⋅ X == v0 + // v0 ⋅ X == v1 + // Y ⋅ 1 == 5 + X + v1 +} + func main() { + // ExampleR1CS() + // invalidRawR1CS := `{"gates":[{"mul_terms":[],"add_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","sum":1},{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":2},{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":3}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000"},{"mul_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","multiplicand":3,"multiplier":4}],"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":5}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000"},{"mul_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","multiplicand":3,"multiplier":5}],"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":3}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000"},{"mul_terms":[],"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":5}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000001"}],"public_inputs":[2],"values":"00000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","num_variables":7,"num_constraints":11}` rawR1CS := `{"gates":[{"mul_terms":[],"add_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","sum":1},{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":2},{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":3}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000"},{"mul_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","multiplicand":3,"multiplier":4}],"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":5}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000"},{"mul_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","multiplicand":3,"multiplier":5}],"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":3}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000"},{"mul_terms":[],"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":5}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000001"}],"public_inputs":[2],"values":"00000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000001530644e72e131a029b85045b68181585d2833e84879b9709143e1f593effffff61ecb77bd78084ea62f78e68b69af66c6eb09c25caa8d47a2427885010d1745d200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000","num_variables":7,"num_constraints":11}` var r structs.RawR1CS @@ -504,36 +574,58 @@ func main() { log.Fatal(err) } - r1cs, publicVariables, privateVariables, nPublicVariables, nPrivateVariables := buildR1CS(r) + r1cs, _, _, _, _ := buildR1CS(r) - fmt.Println("R1CS:\n", r1cs) - fmt.Println("R1CS Public:\n", r1cs.Public) - fmt.Println("R1CS Private:\n", r1cs.Secret) - fmt.Println("R1CS Constraints:\n", r1cs.Constraints) - fmt.Println("R1CS Number of Constraints:\n", r1cs.GetNbConstraints()) - fmt.Println("R1CS Number of Internal Variables:\n", r1cs.GetNbInternalVariables()) - fmt.Println("R1CS Number of Public Variables:\n", r1cs.GetNbPublicVariables()) - fmt.Println("R1CS Number of Private Variables:\n", r1cs.GetNbSecretVariables()) - fmt.Println() - fmt.Println("Public variables:\n", publicVariables) - fmt.Println() - fmt.Println("Private variables:\n", privateVariables) - fmt.Println() - fmt.Println("Number of public variables: ", nPublicVariables) - fmt.Println() - fmt.Println("Number of private variables: ", nPrivateVariables) + constraints, res := r1cs.GetConstraints() + for _, r1c := range constraints { + fmt.Println(r1c.String(res)) + } fmt.Println() + fmt.Println("NbValues: ", len(r.Values)) + for _, value := range r.Values { + fmt.Println("Value: ", value.String()) + } + fmt.Println("NbPublicInputs: ", len(r.PublicInputs), "PublicInputs: ", r.PublicInputs) + + for i, value := range r.Values { + i++ + for _, publicInput := range r.PublicInputs { + if uint32(i) == publicInput { + fmt.Println("PublicInput Value: ", value.String()) + } + } + } + + r1cs, publicVariables, privateVariables, nPublicVariables, nPrivateVariables := buildR1CS(r) + + // fmt.Println("R1CS:\n", r1cs) + // fmt.Println("R1CS Public:\n", r1cs.Public) + // fmt.Println("R1CS Private:\n", r1cs.Secret) + // fmt.Println("R1CS Constraints:\n", r1cs.Constraints) + // fmt.Println("R1CS Number of Constraints:\n", r1cs.GetNbConstraints()) + // fmt.Println("R1CS Number of Internal Variables:\n", r1cs.GetNbInternalVariables()) + // fmt.Println("R1CS Number of Public Variables:\n", r1cs.GetNbPublicVariables()) + // fmt.Println("R1CS Number of Private Variables:\n", r1cs.GetNbSecretVariables()) + // fmt.Println() + // fmt.Println("Public variables:\n", publicVariables) + // fmt.Println() + // fmt.Println("Private variables:\n", privateVariables) + // fmt.Println() + // fmt.Println("Number of public variables: ", nPublicVariables) + // fmt.Println() + // fmt.Println("Number of private variables: ", nPrivateVariables) + // fmt.Println() witness := buildWitnesses(r1cs, publicVariables, privateVariables, nPublicVariables, nPrivateVariables) - fmt.Println("Witness:\n", witness) - fmt.Println() + // fmt.Println("Witness:\n", witness) + // fmt.Println() publicWitnesses, _ := witness.Public() - fmt.Println("Public:\n", publicWitnesses) - fmt.Println() - witnessVector := witness.Vector().(fr_bn254.Vector) - fmt.Println("Vector:\n", witnessVector) - fmt.Println() + // fmt.Println("Public:\n", publicWitnesses) + // fmt.Println() + // witnessVector := witness.Vector().(fr_bn254.Vector) + // fmt.Println("Vector:\n", witnessVector) + // fmt.Println() // Setup. pk, vk, err := groth16.Setup(r1cs) @@ -541,15 +633,15 @@ func main() { log.Fatal(err) } - // fmt.Println("Proving key:\n", pk) + // // fmt.Println("Proving key:\n", pk) + // // fmt.Println() + // // fmt.Println("Verification key:\n", vk) + // // fmt.Println() + // fmt.Println("Verification key publics: ", vk.NbPublicWitness()) // fmt.Println() - // fmt.Println("Verification key:\n", vk) - // fmt.Println() - fmt.Println("Verification key publics: ", vk.NbPublicWitness()) - fmt.Println() - fmt.Println("Num Witnesses: ", len(witnessVector), "Num Public: ", len(r1cs.Public), "Num Private: ", len(r1cs.Secret)) - fmt.Println() + // fmt.Println("Num Witnesses: ", len(witnessVector), "Num Public: ", len(r1cs.Public), "Num Private: ", len(r1cs.Secret)) + // fmt.Println() // Prove. proof, err := groth16.Prove(r1cs, pk, witness) @@ -557,8 +649,8 @@ func main() { log.Fatal(err) } - fmt.Println("Proof:\n", proof) - fmt.Println() + // fmt.Println("Proof:\n", proof) + // fmt.Println() // Verify. verified := groth16.Verify(proof, vk, publicWitnesses) @@ -566,21 +658,21 @@ func main() { fmt.Println("Verifies with valid public inputs: ", verified == nil) fmt.Println() - // Invalid verification (same proof, wrong public value). - invalidRawR1CS := `{"gates":[{"mul_terms":[],"add_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","sum":1},{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":2},{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":3}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000"},{"mul_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","multiplicand":3,"multiplier":4}],"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":5}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000"},{"mul_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","multiplicand":3,"multiplier":5}],"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":3}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000"},{"mul_terms":[],"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":5}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000001"}],"public_inputs":[2],"values":"00000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000150000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","num_variables":7,"num_constraints":11}` - err = json.Unmarshal([]byte(invalidRawR1CS), &r) - if err != nil { - log.Fatal(err) - } + // // // Invalid verification (same proof, wrong public value). + // // invalidRawR1CS := `{"gates":[{"mul_terms":[],"add_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","sum":1},{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":2},{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":3}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000"},{"mul_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","multiplicand":3,"multiplier":4}],"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":5}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000"},{"mul_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","multiplicand":3,"multiplier":5}],"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":3}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000"},{"mul_terms":[],"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":5}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000001"}],"public_inputs":[2],"values":"00000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","num_variables":7,"num_constraints":11}` + // // err = json.Unmarshal([]byte(invalidRawR1CS), &r) + // // if err != nil { + // // log.Fatal(err) + // // } - invalidR1CS, publicVariables, privateVariables, nPublicVariables, nPrivateVariables := buildR1CS(r) - invalidWitness := buildWitnesses(invalidR1CS, publicVariables, privateVariables, nPublicVariables, nPrivateVariables) - invalidPublicWitnesses, _ := invalidWitness.Public() - invalidVerified := groth16.Verify(proof, vk, invalidPublicWitnesses) + // // invalidR1CS, publicVariables, privateVariables, nPublicVariables, nPrivateVariables := buildR1CS(r) + // // invalidWitness := buildWitnesses(invalidR1CS, publicVariables, privateVariables, nPublicVariables, nPrivateVariables) + // // invalidPublicWitnesses, _ := invalidWitness.Public() + // // invalidVerified := groth16.Verify(proof, vk, invalidPublicWitnesses) - fmt.Println("Valid Public Witnesses: ", publicWitnesses) - fmt.Println("Invalid Public Witnesses: ", invalidPublicWitnesses) - fmt.Println() + // // fmt.Println("Valid Public Witnesses: ", publicWitnesses) + // // fmt.Println("Invalid Public Witnesses: ", invalidPublicWitnesses) + // // fmt.Println() - fmt.Println("Verifies with invalid public inputs: ", invalidVerified == nil) + // // fmt.Println("Verifies with invalid public inputs: ", invalidVerified == nil) } diff --git a/src/acvm_interop.rs b/src/acvm_interop.rs index 5cbf490..9f338c5 100644 --- a/src/acvm_interop.rs +++ b/src/acvm_interop.rs @@ -4,6 +4,7 @@ use acvm::acir::{ circuit::opcodes::BlackBoxFuncCall, circuit::Circuit, native_types::Witness, BlackBoxFunc, }; +use acvm::pwg::witness_to_value; use acvm::{ FieldElement, Language, OpcodeResolutionError, PartialWitnessGenerator, ProofSystemCompiler, SmartContract, @@ -74,12 +75,7 @@ impl ProofSystemCompiler for Gnark { ) -> Vec { let num_witnesses = circuit.num_vars(); let values = (1..num_witnesses) - .map(|wit_index| { - // Get the value if it exists, if not then default to zero value. - witness_values - .get(&Witness(wit_index)) - .map_or(FieldElement::zero(), |field| *field) - }) + .map(|wit_index| *witness_to_value(&witness_values, Witness(wit_index)).unwrap_or(&FieldElement::zero())) .collect(); gnark_backend::prove_with_pk(circuit, values, proving_key).unwrap() } @@ -92,14 +88,9 @@ impl ProofSystemCompiler for Gnark { verification_key: &[u8], ) -> bool { let num_witnesses = circuit.num_vars(); - let public = (1..num_witnesses) - .map(|wit_index| { - // Get the value if it exists, if not then default to zero value. - public_inputs - .get(&Witness(wit_index)) - .map_or(FieldElement::zero(), |field| *field) - }) - .collect::>(); + let public: Vec = (1..num_witnesses) + .map(|wit_index| *witness_to_value(&public_inputs, Witness(wit_index)).unwrap_or(&FieldElement::zero())) + .collect(); gnark_backend::verify_with_vk(circuit, proof, &public, verification_key).unwrap() } } From 2b350459500dad9c89cd17ceb2eea2f7f4a48aab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Fri, 3 Mar 2023 16:41:02 -0300 Subject: [PATCH 074/118] Update - The ONE public variable must be set before every other variable - It is not necessary to count the public and the secret variables when building the R1CS because the are already being counted after added - The `sum` from the `AddTerm` is already the index of the variable in the term - Cleanup some prints --- gnark_backend_ffi/main.go | 206 ++++++++++++++++++-------------------- 1 file changed, 99 insertions(+), 107 deletions(-) diff --git a/gnark_backend_ffi/main.go b/gnark_backend_ffi/main.go index d5ed5c3..671ede9 100644 --- a/gnark_backend_ffi/main.go +++ b/gnark_backend_ffi/main.go @@ -17,45 +17,36 @@ import ( cs_bn254 "github.com/consensys/gnark/constraint/bn254" ) -func buildR1CS(r structs.RawR1CS) (*cs_bn254.R1CS, fr_bn254.Vector, fr_bn254.Vector, int, int) { +func buildR1CS(r structs.RawR1CS) (*cs_bn254.R1CS, fr_bn254.Vector, fr_bn254.Vector) { // Create R1CS. r1cs := cs_bn254.NewR1CS(int(r.NumConstraints)) - // Fill process RawR1CS. - nPublicVariables := 0 - nPrivateVariables := 0 - var allVariableIndices []int + // Define the R1CS variables. + ONE := r1cs.AddPublicVariable("1") var publicVariables fr_bn254.Vector var privateVariables fr_bn254.Vector for i, value := range r.Values { i++ for _, publicInput := range r.PublicInputs { if uint32(i) == publicInput { - allVariableIndices = append(allVariableIndices, r1cs.AddPublicVariable(fmt.Sprintf("public_%d", i))) - // fmt.Println(fmt.Sprintf("public_%d", i), value.String()) + r1cs.AddPublicVariable(fmt.Sprintf("public_%d", i)) publicVariables = append(publicVariables, value) - nPublicVariables++ } else { - allVariableIndices = append(allVariableIndices, r1cs.AddSecretVariable(fmt.Sprintf("secret_%d", i))) - // fmt.Println(fmt.Sprintf("secret_%d", i), value.String()) + r1cs.AddSecretVariable(fmt.Sprintf("secret_%d", i)) privateVariables = append(privateVariables, value) - nPrivateVariables++ } } } // Generate constraints. - ONE := r1cs.AddPublicVariable("1") COEFFICIENT_ONE := r1cs.FromInterface(1) - for g, gate := range r.Gates { - fmt.Println("GATE ", g) + for _, gate := range r.Gates { var terms constraint.LinearExpression for _, mul_term := range gate.MulTerms { coefficient := r1cs.FromInterface(mul_term.Coefficient) multiplicand := r.Values[mul_term.Multiplicand] multiplier := r.Values[mul_term.Multiplier] - fmt.Println(mul_term.Coefficient.String(), " * ", multiplicand.String(), " * ", multiplier.String()) var product fr_bn254.Element product.Mul(&multiplicand, &multiplier) @@ -66,29 +57,25 @@ func buildR1CS(r structs.RawR1CS) (*cs_bn254.R1CS, fr_bn254.Vector, fr_bn254.Vec } for _, add_term := range gate.AddTerms { - fmt.Println(add_term.Coefficient.String(), " * ", r.Values[add_term.Sum].String()) coefficient := r1cs.FromInterface(add_term.Coefficient) sum := add_term.Sum - sumVariable := allVariableIndices[sum] + terms = append(terms, r1cs.MakeTerm(&coefficient, int(sum))) + } - terms = append(terms, r1cs.MakeTerm(&coefficient, sumVariable)) + r1c := constraint.R1C{ + L: constraint.LinearExpression{r1cs.MakeTerm(&COEFFICIENT_ONE, ONE)}, + R: terms, + O: constraint.LinearExpression{}, } - r1cs.AddConstraint( - constraint.R1C{ - L: constraint.LinearExpression{r1cs.MakeTerm(&COEFFICIENT_ONE, ONE)}, - R: terms, - O: constraint.LinearExpression{}, - }, - ) - fmt.Println() + r1cs.AddConstraint(r1c) } - return r1cs, publicVariables, privateVariables, nPublicVariables, nPrivateVariables + return r1cs, publicVariables, privateVariables } -func buildWitnesses(r1cs *cs_bn254.R1CS, publicVariables fr_bn254.Vector, privateVariables fr_bn254.Vector, nPublicVariables int, nPrivateVariables int) witness.Witness { +func buildWitnesses(r1cs *cs_bn254.R1CS, publicVariables fr_bn254.Vector, privateVariables fr_bn254.Vector) witness.Witness { witnessValues := make(chan any) go func() { @@ -106,7 +93,7 @@ func buildWitnesses(r1cs *cs_bn254.R1CS, publicVariables fr_bn254.Vector, privat log.Fatal(err) } - witness.Fill(nPublicVariables, nPrivateVariables, witnessValues) + witness.Fill(r1cs.GetNbPublicVariables(), r1cs.GetNbConstraints(), witnessValues) return witness } @@ -120,9 +107,9 @@ func ProveWithMeta(rawR1CS string) *C.char { log.Fatal(err) } - r1cs, publicVariables, privateVariables, nPublicVariables, nPrivateVariables := buildR1CS(r) + r1cs, publicVariables, privateVariables := buildR1CS(r) - witness := buildWitnesses(r1cs, publicVariables, privateVariables, nPublicVariables, nPrivateVariables) + witness := buildWitnesses(r1cs, publicVariables, privateVariables) // Setup. provingKey, _, err := groth16.Setup(r1cs) @@ -153,9 +140,9 @@ func ProveWithPK(rawR1CS string, encodedProvingKey string) *C.char { log.Fatal(err) } - r1cs, publicVariables, privateVariables, nPublicVariables, nPrivateVariables := buildR1CS(r) + r1cs, publicVariables, privateVariables := buildR1CS(r) - witness := buildWitnesses(r1cs, publicVariables, privateVariables, nPublicVariables, nPrivateVariables) + witness := buildWitnesses(r1cs, publicVariables, privateVariables) // Deserialize proving key. provingKey := groth16.NewProvingKey(r1cs.CurveID()) @@ -191,9 +178,9 @@ func VerifyWithMeta(rawR1CS string, encodedProof string) bool { log.Fatal(err) } - r1cs, publicVariables, privateVariables, nPublicVariables, nPrivateVariables := buildR1CS(r) + r1cs, publicVariables, privateVariables := buildR1CS(r) - witness := buildWitnesses(r1cs, publicVariables, privateVariables, nPublicVariables, nPrivateVariables) + witness := buildWitnesses(r1cs, publicVariables, privateVariables) // Deserialize proof. proof := groth16.NewProof(r1cs.CurveID()) @@ -235,9 +222,9 @@ func VerifyWithVK(rawR1CS string, encodedProof string, encodedVerifyingKey strin log.Fatal(err) } - r1cs, publicVariables, privateVariables, nPublicVariables, nPrivateVariables := buildR1CS(r) + r1cs, publicVariables, privateVariables := buildR1CS(r) - witness := buildWitnesses(r1cs, publicVariables, privateVariables, nPublicVariables, nPrivateVariables) + witness := buildWitnesses(r1cs, publicVariables, privateVariables) // Deserialize proof. proof := groth16.NewProof(r1cs.CurveID()) @@ -284,7 +271,7 @@ func Preprocess(rawR1CS string) (*C.char, *C.char) { log.Fatal(err) } - r1cs, _, _, _, _ := buildR1CS(r) + r1cs, _, _ := buildR1CS(r) // Setup. pk, vk, err := groth16.Setup(r1cs) @@ -308,7 +295,7 @@ func Preprocess(rawR1CS string) (*C.char, *C.char) { //export IntegrationTestFeltSerialization func IntegrationTestFeltSerialization(encodedFelt string) *C.char { deserializedFelt := structs.DeserializeFelt(encodedFelt) - fmt.Printf("| GO |\n%v\n", deserializedFelt) + fmt.Printf("| GO |n%vn", deserializedFelt) // Serialize the felt. serializedFelt := deserializedFelt.Bytes() @@ -565,8 +552,18 @@ func ExampleR1CS() { func main() { // ExampleR1CS() - // invalidRawR1CS := `{"gates":[{"mul_terms":[],"add_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","sum":1},{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":2},{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":3}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000"},{"mul_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","multiplicand":3,"multiplier":4}],"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":5}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000"},{"mul_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","multiplicand":3,"multiplier":5}],"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":3}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000"},{"mul_terms":[],"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":5}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000001"}],"public_inputs":[2],"values":"00000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","num_variables":7,"num_constraints":11}` - rawR1CS := `{"gates":[{"mul_terms":[],"add_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","sum":1},{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":2},{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":3}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000"},{"mul_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","multiplicand":3,"multiplier":4}],"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":5}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000"},{"mul_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","multiplicand":3,"multiplier":5}],"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":3}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000"},{"mul_terms":[],"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":5}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000001"}],"public_inputs":[2],"values":"00000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000001530644e72e131a029b85045b68181585d2833e84879b9709143e1f593effffff61ecb77bd78084ea62f78e68b69af66c6eb09c25caa8d47a2427885010d1745d200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000","num_variables":7,"num_constraints":11}` + + // constrain x == y + // constrain 0 == 0 + // rawR1CS := `{"gates":[{"add_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","sum":1},{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":2},{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":3}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[]},{"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":5}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","multiplicand":3,"multiplier":4}]},{"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":3}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","multiplicand":3,"multiplier":5}]},{"add_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","sum":5}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[]}],"num_constraints":11,"num_variables":7,"public_inputs":[2],"values":"00000006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}` + // constrain 1 == 1 + // rawR1CS := `{"gates":[{"add_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","sum":1},{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":2},{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":3}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[]},{"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":5}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","multiplicand":3,"multiplier":4}]},{"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":3}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","multiplicand":3,"multiplier":5}]},{"add_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","sum":5}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[]}],"num_constraints":11,"num_variables":7,"public_inputs":[2],"values":"00000006000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}` + // constrain 2 == 2 + // rawR1CS := `{"gates":[{"add_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","sum":1},{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":2},{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":3}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[]},{"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":5}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","multiplicand":3,"multiplier":4}]},{"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":3}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","multiplicand":3,"multiplier":5}]},{"add_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","sum":5}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[]}],"num_constraints":11,"num_variables":7,"public_inputs":[2],"values":"00000006000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}` + // constrain 3 == 3 + rawR1CS := `{"gates":[{"add_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","sum":1},{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":2},{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":3}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[]},{"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":5}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","multiplicand":3,"multiplier":4}]},{"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":3}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","multiplicand":3,"multiplier":5}]},{"add_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","sum":5}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[]}],"num_constraints":11,"num_variables":7,"public_inputs":[2],"values":"00000006000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}` + // Invalid + invalidRawR1CS := `{"gates":[{"add_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","sum":1},{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":2},{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":3}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[]},{"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":5}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","multiplicand":3,"multiplier":4}]},{"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":3}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","multiplicand":3,"multiplier":5}]},{"add_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","sum":5}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[]}],"num_constraints":11,"num_variables":7,"public_inputs":[2],"values":"00000006000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}` var r structs.RawR1CS err := json.Unmarshal([]byte(rawR1CS), &r) @@ -574,7 +571,41 @@ func main() { log.Fatal(err) } - r1cs, _, _, _, _ := buildR1CS(r) + fmt.Println("Gates: ", len(r.Gates)) + mulTerms := 0 + addTerms := 0 + for g, gate := range r.Gates { + fmt.Println("Gate", g) + fmt.Println() + + fmt.Println("MulTerms:") + mulTerms += len(gate.MulTerms) + for _, mulTerm := range gate.MulTerms { + fmt.Println("MulTerm:", mulTerm) + var product fr_bn254.Element + product.Mul(&r.Values[mulTerm.Multiplier], &r.Values[mulTerm.Multiplicand]) + fmt.Println("Multiplication", mulTerm.Coefficient.String(), "*", r.Values[mulTerm.Multiplier].String(), "*", r.Values[mulTerm.Multiplicand].String(), "=", product.String()) + fmt.Println("Product:", product.String()) + } + fmt.Println() + + addTerms += len(gate.AddTerms) + fmt.Println("AddTerms:") + for _, addTerm := range gate.AddTerms { + fmt.Println("AddTerm:", addTerm) + fmt.Println("Addition", addTerm.Coefficient.String(), "*", r.Values[addTerm.Sum].String()) + } + fmt.Println() + + fmt.Println("ConstantTerm:", gate.ConstantTerm) + fmt.Println() + + fmt.Println() + } + fmt.Println("MulTerms: ", mulTerms) + fmt.Println("AddTerms: ", mulTerms) + + r1cs, publicVariables, privateVariables := buildR1CS(r) constraints, res := r1cs.GetConstraints() for _, r1c := range constraints { @@ -587,45 +618,8 @@ func main() { } fmt.Println("NbPublicInputs: ", len(r.PublicInputs), "PublicInputs: ", r.PublicInputs) - for i, value := range r.Values { - i++ - for _, publicInput := range r.PublicInputs { - if uint32(i) == publicInput { - fmt.Println("PublicInput Value: ", value.String()) - } - } - } - - r1cs, publicVariables, privateVariables, nPublicVariables, nPrivateVariables := buildR1CS(r) - - // fmt.Println("R1CS:\n", r1cs) - // fmt.Println("R1CS Public:\n", r1cs.Public) - // fmt.Println("R1CS Private:\n", r1cs.Secret) - // fmt.Println("R1CS Constraints:\n", r1cs.Constraints) - // fmt.Println("R1CS Number of Constraints:\n", r1cs.GetNbConstraints()) - // fmt.Println("R1CS Number of Internal Variables:\n", r1cs.GetNbInternalVariables()) - // fmt.Println("R1CS Number of Public Variables:\n", r1cs.GetNbPublicVariables()) - // fmt.Println("R1CS Number of Private Variables:\n", r1cs.GetNbSecretVariables()) - // fmt.Println() - // fmt.Println("Public variables:\n", publicVariables) - // fmt.Println() - // fmt.Println("Private variables:\n", privateVariables) - // fmt.Println() - // fmt.Println("Number of public variables: ", nPublicVariables) - // fmt.Println() - // fmt.Println("Number of private variables: ", nPrivateVariables) - // fmt.Println() - - witness := buildWitnesses(r1cs, publicVariables, privateVariables, nPublicVariables, nPrivateVariables) - - // fmt.Println("Witness:\n", witness) - // fmt.Println() + witness := buildWitnesses(r1cs, publicVariables, privateVariables) publicWitnesses, _ := witness.Public() - // fmt.Println("Public:\n", publicWitnesses) - // fmt.Println() - // witnessVector := witness.Vector().(fr_bn254.Vector) - // fmt.Println("Vector:\n", witnessVector) - // fmt.Println() // Setup. pk, vk, err := groth16.Setup(r1cs) @@ -633,46 +627,44 @@ func main() { log.Fatal(err) } - // // fmt.Println("Proving key:\n", pk) - // // fmt.Println() - // // fmt.Println("Verification key:\n", vk) - // // fmt.Println() - // fmt.Println("Verification key publics: ", vk.NbPublicWitness()) - // fmt.Println() - - // fmt.Println("Num Witnesses: ", len(witnessVector), "Num Public: ", len(r1cs.Public), "Num Private: ", len(r1cs.Secret)) - // fmt.Println() - // Prove. proof, err := groth16.Prove(r1cs, pk, witness) if err != nil { log.Fatal(err) } - // fmt.Println("Proof:\n", proof) - // fmt.Println() - // Verify. verified := groth16.Verify(proof, vk, publicWitnesses) fmt.Println("Verifies with valid public inputs: ", verified == nil) fmt.Println() - // // // Invalid verification (same proof, wrong public value). - // // invalidRawR1CS := `{"gates":[{"mul_terms":[],"add_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","sum":1},{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":2},{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":3}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000"},{"mul_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","multiplicand":3,"multiplier":4}],"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":5}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000"},{"mul_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","multiplicand":3,"multiplier":5}],"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":3}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000"},{"mul_terms":[],"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":5}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000001"}],"public_inputs":[2],"values":"00000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","num_variables":7,"num_constraints":11}` - // // err = json.Unmarshal([]byte(invalidRawR1CS), &r) - // // if err != nil { - // // log.Fatal(err) - // // } + // Invalid verification (same proof, wrong public value). + err = json.Unmarshal([]byte(invalidRawR1CS), &r) + if err != nil { + log.Fatal(err) + } - // // invalidR1CS, publicVariables, privateVariables, nPublicVariables, nPrivateVariables := buildR1CS(r) - // // invalidWitness := buildWitnesses(invalidR1CS, publicVariables, privateVariables, nPublicVariables, nPrivateVariables) - // // invalidPublicWitnesses, _ := invalidWitness.Public() - // // invalidVerified := groth16.Verify(proof, vk, invalidPublicWitnesses) + invalidR1CS, publicVariables, privateVariables := buildR1CS(r) - // // fmt.Println("Valid Public Witnesses: ", publicWitnesses) - // // fmt.Println("Invalid Public Witnesses: ", invalidPublicWitnesses) - // // fmt.Println() + constraints, res = invalidR1CS.GetConstraints() + for _, r1c := range constraints { + fmt.Println(r1c.String(res)) + } + fmt.Println() + fmt.Println("NbValues: ", len(r.Values)) + for _, value := range r.Values { + fmt.Println("Value: ", value.String()) + } + fmt.Println("NbPublicInputs: ", len(r.PublicInputs), "PublicInputs: ", r.PublicInputs) + + invalidWitness := buildWitnesses(invalidR1CS, publicVariables, privateVariables) + invalidPublicWitnesses, _ := invalidWitness.Public() + invalidVerified := groth16.Verify(proof, vk, invalidPublicWitnesses) + + fmt.Println("Valid Public Witnesses: ", publicWitnesses.Vector().(fr_bn254.Vector).String()) + fmt.Println("Invalid Public Witnesses: ", invalidPublicWitnesses.Vector().(fr_bn254.Vector).String()) + fmt.Println() - // // fmt.Println("Verifies with invalid public inputs: ", invalidVerified == nil) + fmt.Println("Verifies with invalid public inputs: ", invalidVerified == nil) } From 7ef8ccf39ce8f968d33c34aca8e95900ee2d51a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Fri, 3 Mar 2023 16:52:02 -0300 Subject: [PATCH 075/118] Fix public variables counting when building witnesses --- gnark_backend_ffi/main.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gnark_backend_ffi/main.go b/gnark_backend_ffi/main.go index 671ede9..a4ad7c5 100644 --- a/gnark_backend_ffi/main.go +++ b/gnark_backend_ffi/main.go @@ -93,7 +93,9 @@ func buildWitnesses(r1cs *cs_bn254.R1CS, publicVariables fr_bn254.Vector, privat log.Fatal(err) } - witness.Fill(r1cs.GetNbPublicVariables(), r1cs.GetNbConstraints(), witnessValues) + // -1 because the first variable is the constant 1. + realNbPublicVariables := r1cs.GetNbPublicVariables() - 1 + witness.Fill(realNbPublicVariables, r1cs.GetNbSecretVariables(), witnessValues) return witness } From 368d69910e94739bf2e62dea9035bc9ba07a3315 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Fri, 3 Mar 2023 16:54:59 -0300 Subject: [PATCH 076/118] Cleanup prints --- gnark_backend_ffi/main.go | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/gnark_backend_ffi/main.go b/gnark_backend_ffi/main.go index a4ad7c5..aecd4f8 100644 --- a/gnark_backend_ffi/main.go +++ b/gnark_backend_ffi/main.go @@ -76,6 +76,9 @@ func buildR1CS(r structs.RawR1CS) (*cs_bn254.R1CS, fr_bn254.Vector, fr_bn254.Vec } func buildWitnesses(r1cs *cs_bn254.R1CS, publicVariables fr_bn254.Vector, privateVariables fr_bn254.Vector) witness.Witness { + fmt.Println("Public Variables", publicVariables.String()) + fmt.Println("Private Variables", privateVariables.String()) + witnessValues := make(chan any) go func() { @@ -653,12 +656,6 @@ func main() { for _, r1c := range constraints { fmt.Println(r1c.String(res)) } - fmt.Println() - fmt.Println("NbValues: ", len(r.Values)) - for _, value := range r.Values { - fmt.Println("Value: ", value.String()) - } - fmt.Println("NbPublicInputs: ", len(r.PublicInputs), "PublicInputs: ", r.PublicInputs) invalidWitness := buildWitnesses(invalidR1CS, publicVariables, privateVariables) invalidPublicWitnesses, _ := invalidWitness.Public() From 4f369f198d7fa42b6ff1af0165748d99ef9f4dd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Fri, 3 Mar 2023 17:10:02 -0300 Subject: [PATCH 077/118] Fix proving & verifying key serialization --- src/gnark_backend_wrapper/groth16/mod.rs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/gnark_backend_wrapper/groth16/mod.rs b/src/gnark_backend_wrapper/groth16/mod.rs index 767b565..01c03eb 100644 --- a/src/gnark_backend_wrapper/groth16/mod.rs +++ b/src/gnark_backend_wrapper/groth16/mod.rs @@ -205,16 +205,21 @@ pub fn preprocess(circuit: &Circuit) -> Result<(Vec, Vec), GnarkBackendE let proving_key_c_str = unsafe { CStr::from_ptr(key_pair.proving_key) }; let proving_key_bytes = proving_key_c_str .to_str() - .map_err(|e| GnarkBackendError::DeserializeProofError(e.to_string()))? - .as_bytes(); + .map_err(|e| GnarkBackendError::DeserializeProofError(e.to_string()))?; + let proving_key_str = proving_key_c_str + .to_str() + .map_err(|e| GnarkBackendError::DeserializeKeyError(e.to_string()))?; + let decoded_proving_key = hex::decode(proving_key_str) + .map_err(|e| GnarkBackendError::DeserializeProofError(e.to_string()))?; let verifying_key_c_str = unsafe { CStr::from_ptr(key_pair.verifying_key) }; - let verifying_key_bytes = verifying_key_c_str + let verifying_key_str = verifying_key_c_str .to_str() - .map_err(|e| GnarkBackendError::DeserializeKeyError(e.to_string()))? - .as_bytes(); + .map_err(|e| GnarkBackendError::DeserializeKeyError(e.to_string()))?; + let decoded_verifying_key = hex::decode(verifying_key_str) + .map_err(|e| GnarkBackendError::DeserializeProofError(e.to_string()))?; - Ok((proving_key_bytes.to_vec(), verifying_key_bytes.to_vec())) + Ok((decoded_proving_key, decoded_verifying_key)) } #[cfg(test)] From 12f13e32d5dce0e85d18b6f270b404092ae698a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Fri, 3 Mar 2023 17:34:58 -0300 Subject: [PATCH 078/118] Add constraint for multiplication terms --- gnark_backend_ffi/main.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/gnark_backend_ffi/main.go b/gnark_backend_ffi/main.go index aecd4f8..f860998 100644 --- a/gnark_backend_ffi/main.go +++ b/gnark_backend_ffi/main.go @@ -47,13 +47,18 @@ func buildR1CS(r structs.RawR1CS) (*cs_bn254.R1CS, fr_bn254.Vector, fr_bn254.Vec coefficient := r1cs.FromInterface(mul_term.Coefficient) multiplicand := r.Values[mul_term.Multiplicand] multiplier := r.Values[mul_term.Multiplier] - var product fr_bn254.Element product.Mul(&multiplicand, &multiplier) productVariable := r1cs.AddInternalVariable() - terms = append(terms, r1cs.MakeTerm(&coefficient, productVariable)) + mulR1C := constraint.R1C{ + L: constraint.LinearExpression{r1cs.MakeTerm(&COEFFICIENT_ONE, int(mul_term.Multiplicand))}, + R: constraint.LinearExpression{r1cs.MakeTerm(&COEFFICIENT_ONE, int(mul_term.Multiplier))}, + O: constraint.LinearExpression{r1cs.MakeTerm(&coefficient, productVariable)}, + } + + r1cs.AddConstraint(mulR1C) } for _, add_term := range gate.AddTerms { From f7efa84ca9b916d889c76d9611e8fb03e7dfbb72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Fri, 3 Mar 2023 17:35:47 -0300 Subject: [PATCH 079/118] Cleanup prints --- gnark_backend_ffi/main.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/gnark_backend_ffi/main.go b/gnark_backend_ffi/main.go index f860998..8f79d30 100644 --- a/gnark_backend_ffi/main.go +++ b/gnark_backend_ffi/main.go @@ -81,9 +81,6 @@ func buildR1CS(r structs.RawR1CS) (*cs_bn254.R1CS, fr_bn254.Vector, fr_bn254.Vec } func buildWitnesses(r1cs *cs_bn254.R1CS, publicVariables fr_bn254.Vector, privateVariables fr_bn254.Vector) witness.Witness { - fmt.Println("Public Variables", publicVariables.String()) - fmt.Println("Private Variables", privateVariables.String()) - witnessValues := make(chan any) go func() { From a665713809b1002e51083fbf9174be28fdeb6948 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Fri, 3 Mar 2023 17:36:37 -0300 Subject: [PATCH 080/118] Update values flattening function --- src/acvm_interop.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/acvm_interop.rs b/src/acvm_interop.rs index 9f338c5..4f5c201 100644 --- a/src/acvm_interop.rs +++ b/src/acvm_interop.rs @@ -75,7 +75,10 @@ impl ProofSystemCompiler for Gnark { ) -> Vec { let num_witnesses = circuit.num_vars(); let values = (1..num_witnesses) - .map(|wit_index| *witness_to_value(&witness_values, Witness(wit_index)).unwrap_or(&FieldElement::zero())) + .map(|wit_index| { + *witness_to_value(&witness_values, Witness(wit_index)) + .unwrap_or(&FieldElement::zero()) + }) .collect(); gnark_backend::prove_with_pk(circuit, values, proving_key).unwrap() } @@ -89,7 +92,10 @@ impl ProofSystemCompiler for Gnark { ) -> bool { let num_witnesses = circuit.num_vars(); let public: Vec = (1..num_witnesses) - .map(|wit_index| *witness_to_value(&public_inputs, Witness(wit_index)).unwrap_or(&FieldElement::zero())) + .map(|wit_index| { + *witness_to_value(&public_inputs, Witness(wit_index)) + .unwrap_or(&FieldElement::zero()) + }) .collect(); gnark_backend::verify_with_vk(circuit, proof, &public, verification_key).unwrap() } From 642ba6ce40f114dce6557db3444e31b92f1652b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Fri, 3 Mar 2023 17:38:49 -0300 Subject: [PATCH 081/118] Update prover initial values --- src/gnark_backend_wrapper/groth16/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gnark_backend_wrapper/groth16/mod.rs b/src/gnark_backend_wrapper/groth16/mod.rs index 01c03eb..e59ec42 100644 --- a/src/gnark_backend_wrapper/groth16/mod.rs +++ b/src/gnark_backend_wrapper/groth16/mod.rs @@ -177,8 +177,8 @@ pub fn get_exact_circuit_size(circuit: &Circuit) -> Result Result<(Vec, Vec), GnarkBackendError> { // TODO: Sample random public_inputs let mut witness_values = BTreeMap::new(); - witness_values.insert(Witness(1), FieldElement::from(10_u128)); - witness_values.insert(Witness(2), FieldElement::from(21_u128)); + witness_values.insert(Witness(1), FieldElement::from(3_u128)); + witness_values.insert(Witness(2), FieldElement::from(3_u128)); let backend = Gnark; backend.solve(&mut witness_values, circuit.opcodes.clone())?; let num_witnesses = circuit.num_vars(); From 664fbfbc338192452137e9e015ed60d69f2eb537 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Fri, 3 Mar 2023 18:13:48 -0300 Subject: [PATCH 082/118] Fix proving & verifying keys and proof serialization --- src/gnark_backend_wrapper/groth16/mod.rs | 26 +++++++++++------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/src/gnark_backend_wrapper/groth16/mod.rs b/src/gnark_backend_wrapper/groth16/mod.rs index e59ec42..2f73b27 100644 --- a/src/gnark_backend_wrapper/groth16/mod.rs +++ b/src/gnark_backend_wrapper/groth16/mod.rs @@ -86,21 +86,21 @@ pub fn prove_with_pk( .map_err(|e| GnarkBackendError::SerializeCircuitError(e.to_string()))?; let rawr1cs_go_string = GoString::try_from(&rawr1cs_c_str)?; - let proving_key_serialized = String::from_utf8(proving_key.to_vec()) - .map_err(|e| GnarkBackendError::SerializeKeyError(e.to_string()))?; + let proving_key_serialized = hex::encode(proving_key); let proving_key_c_str = CString::new(proving_key_serialized) .map_err(|e| GnarkBackendError::SerializeKeyError(e.to_string()))?; let proving_key_go_string = GoString::try_from(&proving_key_c_str) .map_err(|e| GnarkBackendError::SerializeKeyError(e.to_string()))?; - let result: *const c_char = unsafe { ProveWithPK(rawr1cs_go_string, proving_key_go_string) }; - let c_str = unsafe { CStr::from_ptr(result) }; - let bytes = c_str + let proof: *const c_char = unsafe { ProveWithPK(rawr1cs_go_string, proving_key_go_string) }; + let proof_c_str = unsafe { CStr::from_ptr(proof) }; + let proof_str = proof_c_str .to_str() - .map_err(|e| GnarkBackendError::DeserializeProofError(e.to_string()))? - .as_bytes(); + .map_err(|e| GnarkBackendError::DeserializeProofError(e.to_string()))?; + let decoded_proof = hex::decode(proof_str) + .map_err(|e| GnarkBackendError::DeserializeProofError(e.to_string()))?; - Ok(bytes.to_vec()) + Ok(decoded_proof) } pub fn verify_with_meta( @@ -146,21 +146,19 @@ pub fn verify_with_vk( .map_err(|e| GnarkBackendError::SerializeCircuitError(e.to_string()))?; let rawr1cs_go_string = GoString::try_from(&rawr1cs_c_str)?; - let proof_serialized = String::from_utf8(proof.to_vec()) - .map_err(|e| GnarkBackendError::SerializeProofError(e.to_string()))?; + let proof_serialized = hex::encode(proof); let proof_c_str = CString::new(proof_serialized) .map_err(|e| GnarkBackendError::SerializeProofError(e.to_string()))?; let proof_go_string = GoString::try_from(&proof_c_str)?; - let verifying_key_serialized = String::from_utf8(verifying_key.to_vec()) - .map_err(|e| GnarkBackendError::SerializeKeyError(e.to_string()))?; + let verifying_key_serialized = hex::encode(verifying_key); let verifying_key_c_str = CString::new(verifying_key_serialized) .map_err(|e| GnarkBackendError::SerializeKeyError(e.to_string()))?; let verifying_key_go_string = GoString::try_from(&verifying_key_c_str)?; - let result = + let verifies = unsafe { VerifyWithVK(rawr1cs_go_string, proof_go_string, verifying_key_go_string) }; - match result { + match verifies { 0 => Ok(false), 1 => Ok(true), _ => Err(GnarkBackendError::VerifyInvalidBoolError), From 42d983db0760dc1a0a04132679c351bd76807302 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Sat, 4 Mar 2023 09:09:52 -0300 Subject: [PATCH 083/118] Fix dependencies --- src/acvm/mod.rs | 12 ++++--- src/gnark_backend_wrapper/groth16/mod.rs | 41 ++++++++++-------------- 2 files changed, 25 insertions(+), 28 deletions(-) diff --git a/src/acvm/mod.rs b/src/acvm/mod.rs index a279614..90bfb53 100644 --- a/src/acvm/mod.rs +++ b/src/acvm/mod.rs @@ -1,5 +1,9 @@ -pub use acvm::acir::{ - circuit::{Circuit, Opcode, PublicInputs}, - native_types::{Expression, Witness}, - FieldElement, +pub use acvm::{ + acir::{ + circuit::{Circuit, Opcode, PublicInputs}, + native_types::{Expression, Witness}, + FieldElement, + }, + pwg::witness_to_value, + PartialWitnessGenerator, }; diff --git a/src/gnark_backend_wrapper/groth16/mod.rs b/src/gnark_backend_wrapper/groth16/mod.rs index 2f73b27..79a6dd3 100644 --- a/src/gnark_backend_wrapper/groth16/mod.rs +++ b/src/gnark_backend_wrapper/groth16/mod.rs @@ -1,6 +1,4 @@ -use acvm::acir::native_types::Witness; -use acvm::PartialWitnessGenerator; -use acvm::{acir::circuit::Circuit, FieldElement}; +use crate::acvm; use std::collections::BTreeMap; use std::ffi::{CStr, CString}; use std::num::TryFromIntError; @@ -50,8 +48,8 @@ extern "C" { } pub fn prove_with_meta( - circuit: Circuit, - values: Vec, + circuit: acvm::Circuit, + values: Vec, ) -> Result, GnarkBackendError> { let rawr1cs = RawR1CS::new(circuit, values)?; @@ -73,8 +71,8 @@ pub fn prove_with_meta( } pub fn prove_with_pk( - circuit: &Circuit, - values: Vec, + circuit: &acvm::Circuit, + values: Vec, proving_key: &[u8], ) -> Result, GnarkBackendError> { let rawr1cs = RawR1CS::new(circuit.clone(), values)?; @@ -104,9 +102,9 @@ pub fn prove_with_pk( } pub fn verify_with_meta( - circuit: Circuit, + circuit: acvm::Circuit, proof: &[u8], - public_inputs: &[FieldElement], + public_inputs: &[acvm::FieldElement], ) -> Result { let rawr1cs = RawR1CS::new(circuit, public_inputs.to_vec())?; @@ -132,9 +130,9 @@ pub fn verify_with_meta( } pub fn verify_with_vk( - circuit: &Circuit, + circuit: &acvm::Circuit, proof: &[u8], - public_inputs: &[FieldElement], + public_inputs: &[acvm::FieldElement], verifying_key: &[u8], ) -> Result { let rawr1cs = RawR1CS::new(circuit.clone(), public_inputs.to_vec())?; @@ -165,27 +163,25 @@ pub fn verify_with_vk( } } -pub fn get_exact_circuit_size(circuit: &Circuit) -> Result { +pub fn get_exact_circuit_size(circuit: &acvm::Circuit) -> Result { let size: u32 = RawR1CS::num_constraints(circuit)? .try_into() .map_err(|e: TryFromIntError| GnarkBackendError::Error(e.to_string()))?; Ok(size) } -pub fn preprocess(circuit: &Circuit) -> Result<(Vec, Vec), GnarkBackendError> { +pub fn preprocess(circuit: &acvm::Circuit) -> Result<(Vec, Vec), GnarkBackendError> { // TODO: Sample random public_inputs let mut witness_values = BTreeMap::new(); - witness_values.insert(Witness(1), FieldElement::from(3_u128)); - witness_values.insert(Witness(2), FieldElement::from(3_u128)); + witness_values.insert(acvm::Witness(1), acvm::FieldElement::from(3_u128)); + witness_values.insert(acvm::Witness(2), acvm::FieldElement::from(3_u128)); let backend = Gnark; - backend.solve(&mut witness_values, circuit.opcodes.clone())?; + acvm::PartialWitnessGenerator::solve(&backend, &mut witness_values, circuit.opcodes.clone())?; let num_witnesses = circuit.num_vars(); let values = (1..num_witnesses) .map(|wit_index| { - // Get the value if it exists, if not then default to zero value. - witness_values - .get(&Witness(wit_index)) - .map_or(FieldElement::zero(), |field| *field) + *acvm::witness_to_value(&witness_values, acvm::Witness(wit_index)) + .unwrap_or(&acvm::FieldElement::zero()) }) .collect(); @@ -201,9 +197,6 @@ pub fn preprocess(circuit: &Circuit) -> Result<(Vec, Vec), GnarkBackendE let key_pair: KeyPair = unsafe { Preprocess(rawr1cs_go_string) }; let proving_key_c_str = unsafe { CStr::from_ptr(key_pair.proving_key) }; - let proving_key_bytes = proving_key_c_str - .to_str() - .map_err(|e| GnarkBackendError::DeserializeProofError(e.to_string()))?; let proving_key_str = proving_key_c_str .to_str() .map_err(|e| GnarkBackendError::DeserializeKeyError(e.to_string()))?; @@ -236,7 +229,7 @@ mod tests { #[test] fn get_exact_circuit_size_should_return_zero_with_an_empty_circuit() { - let size = get_exact_circuit_size(&Circuit::default()).unwrap(); + let size = get_exact_circuit_size(&acvm::Circuit::default()).unwrap(); assert_eq!(size, 0); } } From 4c6b37198c2c4b48f1debee6936c05724e7a6491 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Sat, 4 Mar 2023 18:48:39 -0300 Subject: [PATCH 084/118] Improve naming --- gnark_backend_ffi/main.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/gnark_backend_ffi/main.go b/gnark_backend_ffi/main.go index 8f79d30..97088e9 100644 --- a/gnark_backend_ffi/main.go +++ b/gnark_backend_ffi/main.go @@ -239,7 +239,7 @@ func VerifyWithVK(rawR1CS string, encodedProof string, encodedVerifyingKey strin if err != nil { log.Fatal(err) } - _, err = proof.ReadFrom(bytes.NewReader([]byte(decodedProof))) + _, err = proof.ReadFrom(bytes.NewReader(decodedProof)) if err != nil { log.Fatal(err) } @@ -281,22 +281,22 @@ func Preprocess(rawR1CS string) (*C.char, *C.char) { r1cs, _, _ := buildR1CS(r) // Setup. - pk, vk, err := groth16.Setup(r1cs) + provingKey, verifyingKey, err := groth16.Setup(r1cs) if err != nil { log.Fatal(err) } // Serialize proving key. - var serialized_pk bytes.Buffer - pk.WriteTo(&serialized_pk) - pk_string := hex.EncodeToString(serialized_pk.Bytes()) + var serializedProvingKey bytes.Buffer + provingKey.WriteTo(&serializedProvingKey) + provingKeyString := hex.EncodeToString(serializedProvingKey.Bytes()) // Serialize verifying key. - var serialized_vk bytes.Buffer - vk.WriteTo(&serialized_vk) - vk_string := hex.EncodeToString(serialized_vk.Bytes()) + var serializedVerifyingKey bytes.Buffer + verifyingKey.WriteTo(&serializedVerifyingKey) + verifyingKeyString := hex.EncodeToString(serializedVerifyingKey.Bytes()) - return C.CString(pk_string), C.CString(vk_string) + return C.CString(provingKeyString), C.CString(verifyingKeyString) } //export IntegrationTestFeltSerialization From c2ff2f5e73b6368043ff0ed55fc5bf126b7ec958 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Sat, 4 Mar 2023 18:48:51 -0300 Subject: [PATCH 085/118] Add product to terms --- gnark_backend_ffi/main.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gnark_backend_ffi/main.go b/gnark_backend_ffi/main.go index 97088e9..c8e5121 100644 --- a/gnark_backend_ffi/main.go +++ b/gnark_backend_ffi/main.go @@ -59,6 +59,8 @@ func buildR1CS(r structs.RawR1CS) (*cs_bn254.R1CS, fr_bn254.Vector, fr_bn254.Vec } r1cs.AddConstraint(mulR1C) + + terms = append(terms, r1cs.MakeTerm(&coefficient, productVariable)) } for _, add_term := range gate.AddTerms { From 05bf26f5b94092fe80b21694594b0f83e64ade05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Sat, 4 Mar 2023 18:49:47 -0300 Subject: [PATCH 086/118] Use `0` as an index for the `ONE_WIRE` Because it is declared as the first variable it refers to it --- gnark_backend_ffi/main.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gnark_backend_ffi/main.go b/gnark_backend_ffi/main.go index c8e5121..5e6912a 100644 --- a/gnark_backend_ffi/main.go +++ b/gnark_backend_ffi/main.go @@ -22,7 +22,7 @@ func buildR1CS(r structs.RawR1CS) (*cs_bn254.R1CS, fr_bn254.Vector, fr_bn254.Vec r1cs := cs_bn254.NewR1CS(int(r.NumConstraints)) // Define the R1CS variables. - ONE := r1cs.AddPublicVariable("1") + _ = r1cs.AddPublicVariable("1") // ONE_WIRE var publicVariables fr_bn254.Vector var privateVariables fr_bn254.Vector for i, value := range r.Values { @@ -71,7 +71,7 @@ func buildR1CS(r structs.RawR1CS) (*cs_bn254.R1CS, fr_bn254.Vector, fr_bn254.Vec } r1c := constraint.R1C{ - L: constraint.LinearExpression{r1cs.MakeTerm(&COEFFICIENT_ONE, ONE)}, + L: constraint.LinearExpression{r1cs.MakeTerm(&COEFFICIENT_ONE, 0)}, R: terms, O: constraint.LinearExpression{}, } From dfd8f1f4ec46d32f27fe7a9a5731d02c072507d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Sat, 4 Mar 2023 18:50:32 -0300 Subject: [PATCH 087/118] Update `NbPublicVariables` sent to `witness.Fill` --- gnark_backend_ffi/main.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/gnark_backend_ffi/main.go b/gnark_backend_ffi/main.go index 5e6912a..d158ff4 100644 --- a/gnark_backend_ffi/main.go +++ b/gnark_backend_ffi/main.go @@ -100,9 +100,8 @@ func buildWitnesses(r1cs *cs_bn254.R1CS, publicVariables fr_bn254.Vector, privat log.Fatal(err) } - // -1 because the first variable is the constant 1. - realNbPublicVariables := r1cs.GetNbPublicVariables() - 1 - witness.Fill(realNbPublicVariables, r1cs.GetNbSecretVariables(), witnessValues) + // -1 because the first variable is the ONE_WIRE. + witness.Fill(r1cs.GetNbPublicVariables()-1, r1cs.GetNbSecretVariables(), witnessValues) return witness } From 2cb4dc3a27439efe7ef8e296f594d8d35a56955f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Sat, 4 Mar 2023 18:51:15 -0300 Subject: [PATCH 088/118] Replace old example with a simpler one --- gnark_backend_ffi/main.go | 304 ++++++++++++++++++++------------------ 1 file changed, 160 insertions(+), 144 deletions(-) diff --git a/gnark_backend_ffi/main.go b/gnark_backend_ffi/main.go index d158ff4..f3952e8 100644 --- a/gnark_backend_ffi/main.go +++ b/gnark_backend_ffi/main.go @@ -494,179 +494,195 @@ func IntegrationTestRawR1CSSerialization(rawR1CSJSON string) *C.char { return C.CString(string(serializedRawR1CS)) } -func ExampleR1CS() { - // build a constraint system; this is (usually) done by the frontend package - // for this Example we want to manipulate the constraints and output a string representation - // and build the linear expressions "manually". - r1cs := cs_bn254.NewR1CS(0) +func ExampleSimpleCircuit() { + publicVariables := []fr_bn254.Element{fr_bn254.NewElement(2), fr_bn254.NewElement(6)} + secretVariables := []fr_bn254.Element{fr_bn254.NewElement(3)} - ONE := r1cs.AddPublicVariable("1") // the "ONE" wire + /* R1CS Building */ + + fmt.Println("Building R1CS...") + // x * y == z + // x is secret + // y is public + r1cs := cs_bn254.NewR1CS(1) + + // Variables + _ = r1cs.AddPublicVariable("1") // the ONE_WIRE Y := r1cs.AddPublicVariable("Y") + Z := r1cs.AddPublicVariable("Z") X := r1cs.AddSecretVariable("X") - v0 := r1cs.AddInternalVariable() // X² - v1 := r1cs.AddInternalVariable() // X³ - - // coefficients + // Coefficients cOne := r1cs.FromInterface(1) - cFive := r1cs.FromInterface(5) - // X² == X * X + // Constraints + fmt.Println("Adding constraints...") r1cs.AddConstraint(constraint.R1C{ L: constraint.LinearExpression{r1cs.MakeTerm(&cOne, X)}, - R: constraint.LinearExpression{r1cs.MakeTerm(&cOne, X)}, - O: constraint.LinearExpression{r1cs.MakeTerm(&cOne, v0)}, - }) - - // X³ == X² * X - r1cs.AddConstraint(constraint.R1C{ - L: constraint.LinearExpression{r1cs.MakeTerm(&cOne, v0)}, - R: constraint.LinearExpression{r1cs.MakeTerm(&cOne, X)}, - O: constraint.LinearExpression{r1cs.MakeTerm(&cOne, v1)}, + R: constraint.LinearExpression{r1cs.MakeTerm(&cOne, Y)}, + O: constraint.LinearExpression{r1cs.MakeTerm(&cOne, Z)}, }) + fmt.Println("Constraints added.") + fmt.Println("R1CS built.") - // Y == X³ + X + 5 - r1cs.AddConstraint(constraint.R1C{ - R: constraint.LinearExpression{r1cs.MakeTerm(&cOne, ONE)}, - L: constraint.LinearExpression{r1cs.MakeTerm(&cOne, Y)}, - O: constraint.LinearExpression{ - r1cs.MakeTerm(&cFive, ONE), - r1cs.MakeTerm(&cOne, X), - r1cs.MakeTerm(&cOne, v1), - }, - }) - - fmt.Println("Number of constraints", r1cs.GetNbConstraints()) - fmt.Println("Number of coefficients", r1cs.GetNbCoefficients()) - fmt.Println("Number of internal variables", r1cs.GetNbInternalVariables()) - fmt.Println("Number of public variables", r1cs.GetNbPublicVariables()) - fmt.Println("Number of secret variables", r1cs.GetNbSecretVariables()) - fmt.Println("Coefficients", r1cs.Coefficients) - - // get the constraints constraints, r := r1cs.GetConstraints() for _, r1c := range constraints { fmt.Println(r1c.String(r)) - // for more granularity use constraint.NewStringBuilder(r) that embeds a string.Builder - // and has WriteLinearExpression and WriteTerm methods. } - // Output: - // X ⋅ X == v0 - // v0 ⋅ X == v1 - // Y ⋅ 1 == 5 + X + v1 -} + /* Universal SRS Generation */ -func main() { - // ExampleR1CS() - - // constrain x == y - // constrain 0 == 0 - // rawR1CS := `{"gates":[{"add_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","sum":1},{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":2},{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":3}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[]},{"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":5}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","multiplicand":3,"multiplier":4}]},{"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":3}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","multiplicand":3,"multiplier":5}]},{"add_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","sum":5}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[]}],"num_constraints":11,"num_variables":7,"public_inputs":[2],"values":"00000006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}` - // constrain 1 == 1 - // rawR1CS := `{"gates":[{"add_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","sum":1},{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":2},{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":3}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[]},{"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":5}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","multiplicand":3,"multiplier":4}]},{"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":3}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","multiplicand":3,"multiplier":5}]},{"add_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","sum":5}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[]}],"num_constraints":11,"num_variables":7,"public_inputs":[2],"values":"00000006000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}` - // constrain 2 == 2 - // rawR1CS := `{"gates":[{"add_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","sum":1},{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":2},{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":3}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[]},{"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":5}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","multiplicand":3,"multiplier":4}]},{"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":3}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","multiplicand":3,"multiplier":5}]},{"add_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","sum":5}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[]}],"num_constraints":11,"num_variables":7,"public_inputs":[2],"values":"00000006000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}` - // constrain 3 == 3 - rawR1CS := `{"gates":[{"add_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","sum":1},{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":2},{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":3}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[]},{"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":5}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","multiplicand":3,"multiplier":4}]},{"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":3}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","multiplicand":3,"multiplier":5}]},{"add_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","sum":5}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[]}],"num_constraints":11,"num_variables":7,"public_inputs":[2],"values":"00000006000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}` - // Invalid - invalidRawR1CS := `{"gates":[{"add_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","sum":1},{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":2},{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":3}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[]},{"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":5}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","multiplicand":3,"multiplier":4}]},{"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":3}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","multiplicand":3,"multiplier":5}]},{"add_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","sum":5}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[]}],"num_constraints":11,"num_variables":7,"public_inputs":[2],"values":"00000006000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}` + fmt.Println("Generating SRS...") - var r structs.RawR1CS - err := json.Unmarshal([]byte(rawR1CS), &r) - if err != nil { - log.Fatal(err) - } + pk, vk, _ := groth16.Setup(r1cs) - fmt.Println("Gates: ", len(r.Gates)) - mulTerms := 0 - addTerms := 0 - for g, gate := range r.Gates { - fmt.Println("Gate", g) - fmt.Println() + fmt.Println("VERIFYING KEY", vk) + var vkBuff bytes.Buffer + vk.WriteTo(&vkBuff) + encodedVK := hex.EncodeToString(vkBuff.Bytes()) + decodedVK, _ := hex.DecodeString(encodedVK) + vk2 := groth16.NewVerifyingKey(r1cs.CurveID()) + vk2.ReadFrom(bytes.NewReader(decodedVK)) + fmt.Println("VERIFYING KEY", vk2) + fmt.Println("VERIFYING KEYS MATCH", !vk.IsDifferent(vk2)) - fmt.Println("MulTerms:") - mulTerms += len(gate.MulTerms) - for _, mulTerm := range gate.MulTerms { - fmt.Println("MulTerm:", mulTerm) - var product fr_bn254.Element - product.Mul(&r.Values[mulTerm.Multiplier], &r.Values[mulTerm.Multiplicand]) - fmt.Println("Multiplication", mulTerm.Coefficient.String(), "*", r.Values[mulTerm.Multiplier].String(), "*", r.Values[mulTerm.Multiplicand].String(), "=", product.String()) - fmt.Println("Product:", product.String()) - } - fmt.Println() + fmt.Println("SRS generated.") - addTerms += len(gate.AddTerms) - fmt.Println("AddTerms:") - for _, addTerm := range gate.AddTerms { - fmt.Println("AddTerm:", addTerm) - fmt.Println("Addition", addTerm.Coefficient.String(), "*", r.Values[addTerm.Sum].String()) - } - fmt.Println() + /* Proving */ - fmt.Println("ConstantTerm:", gate.ConstantTerm) - fmt.Println() + fmt.Println("Proving...") - fmt.Println() - } - fmt.Println("MulTerms: ", mulTerms) - fmt.Println("AddTerms: ", mulTerms) + witness := buildWitnesses(r1cs, publicVariables, secretVariables) - r1cs, publicVariables, privateVariables := buildR1CS(r) + p, _ := groth16.Prove(r1cs, pk, witness) - constraints, res := r1cs.GetConstraints() - for _, r1c := range constraints { - fmt.Println(r1c.String(res)) - } - fmt.Println() - fmt.Println("NbValues: ", len(r.Values)) - for _, value := range r.Values { - fmt.Println("Value: ", value.String()) - } - fmt.Println("NbPublicInputs: ", len(r.PublicInputs), "PublicInputs: ", r.PublicInputs) - - witness := buildWitnesses(r1cs, publicVariables, privateVariables) - publicWitnesses, _ := witness.Public() - - // Setup. - pk, vk, err := groth16.Setup(r1cs) - if err != nil { - log.Fatal(err) - } - - // Prove. - proof, err := groth16.Prove(r1cs, pk, witness) - if err != nil { - log.Fatal(err) - } - - // Verify. - verified := groth16.Verify(proof, vk, publicWitnesses) + fmt.Println("Proof generated.") - fmt.Println("Verifies with valid public inputs: ", verified == nil) - fmt.Println() - - // Invalid verification (same proof, wrong public value). - err = json.Unmarshal([]byte(invalidRawR1CS), &r) - if err != nil { - log.Fatal(err) - } + /* Verification */ - invalidR1CS, publicVariables, privateVariables := buildR1CS(r) + fmt.Println("Verifying...") - constraints, res = invalidR1CS.GetConstraints() - for _, r1c := range constraints { - fmt.Println(r1c.String(res)) - } + publicWitness, _ := witness.Public() - invalidWitness := buildWitnesses(invalidR1CS, publicVariables, privateVariables) - invalidPublicWitnesses, _ := invalidWitness.Public() - invalidVerified := groth16.Verify(proof, vk, invalidPublicWitnesses) + verifies := groth16.Verify(p, vk, publicWitness) - fmt.Println("Valid Public Witnesses: ", publicWitnesses.Vector().(fr_bn254.Vector).String()) - fmt.Println("Invalid Public Witnesses: ", invalidPublicWitnesses.Vector().(fr_bn254.Vector).String()) - fmt.Println() + fmt.Println("Verifies:", verifies == nil) +} - fmt.Println("Verifies with invalid public inputs: ", invalidVerified == nil) +func main() { + ExampleSimpleCircuit() + + // // constrain x == y + // // constrain 0 == 0 + // // rawR1CS := `{"gates":[{"add_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","sum":1},{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":2},{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":3}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[]},{"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":5}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","multiplicand":3,"multiplier":4}]},{"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":3}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","multiplicand":3,"multiplier":5}]},{"add_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","sum":5}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[]}],"num_constraints":11,"num_variables":7,"public_inputs":[2],"values":"00000006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}` + // // constrain 1 == 1 + // // rawR1CS := `{"gates":[{"add_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","sum":1},{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":2},{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":3}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[]},{"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":5}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","multiplicand":3,"multiplier":4}]},{"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":3}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","multiplicand":3,"multiplier":5}]},{"add_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","sum":5}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[]}],"num_constraints":11,"num_variables":7,"public_inputs":[2],"values":"00000006000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}` + // // constrain 2 == 2 + // rawR1CS := `{"gates":[{"add_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","sum":1},{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":2},{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":3}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[]},{"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":5}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","multiplicand":3,"multiplier":4}]},{"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":3}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","multiplicand":3,"multiplier":5}]},{"add_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","sum":5}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[]}],"num_constraints":11,"num_variables":7,"public_inputs":[2],"values":"00000006000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}` + // // constrain 3 == 3 + // // rawR1CS := `{"gates":[{"mul_terms":[],"add_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","sum":1},{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":2},{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":3}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000"},{"mul_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","multiplicand":3,"multiplier":4}],"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":5}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000"},{"mul_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","multiplicand":3,"multiplier":5}],"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":3}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000"},{"mul_terms":[],"add_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","sum":5}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000"}],"public_inputs":[2],"values":"00000006000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","num_variables":7,"num_constraints":11}` + // // Invalid + // invalidRawR1CS := `{"gates":[{"add_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","sum":1},{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":2},{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":3}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[]},{"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":5}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","multiplicand":3,"multiplier":4}]},{"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":3}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","multiplicand":3,"multiplier":5}]},{"add_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","sum":5}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[]}],"num_constraints":11,"num_variables":7,"public_inputs":[2],"values":"00000006000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}` + + // var r structs.RawR1CS + // err := json.Unmarshal([]byte(rawR1CS), &r) + // if err != nil { + // log.Fatal(err) + // } + + // // fmt.Println("Gates: ", len(r.Gates)) + // // mulTerms := 0 + // // addTerms := 0 + // // for g, gate := range r.Gates { + // // fmt.Println("Gate", g) + // // fmt.Println() + + // // fmt.Println("MulTerms:") + // // mulTerms += len(gate.MulTerms) + // // for _, mulTerm := range gate.MulTerms { + // // fmt.Println("MulTerm:", mulTerm) + // // var product fr_bn254.Element + // // product.Mul(&r.Values[mulTerm.Multiplier], &r.Values[mulTerm.Multiplicand]) + // // fmt.Println("Multiplication", mulTerm.Coefficient.String(), "*", r.Values[mulTerm.Multiplier].String(), "*", r.Values[mulTerm.Multiplicand].String(), "=", product.String()) + // // fmt.Println("Product:", product.String()) + // // } + // // fmt.Println() + + // // addTerms += len(gate.AddTerms) + // // fmt.Println("AddTerms:") + // // for _, addTerm := range gate.AddTerms { + // // fmt.Println("AddTerm:", addTerm) + // // fmt.Println("Addition", addTerm.Coefficient.String(), "*", r.Values[addTerm.Sum].String()) + // // } + // // fmt.Println() + + // // fmt.Println("ConstantTerm:", gate.ConstantTerm) + // // fmt.Println() + + // // fmt.Println() + // // } + // // fmt.Println("MulTerms: ", mulTerms) + // // fmt.Println("AddTerms: ", mulTerms) + + // r1cs, publicVariables, privateVariables := buildR1CS(r) + + // constraints, res := r1cs.GetConstraints() + // for _, r1c := range constraints { + // fmt.Println(r1c.String(res)) + // } + // fmt.Println() + // fmt.Println("NbValues: ", len(r.Values)) + // for _, value := range r.Values { + // fmt.Println("Value: ", value.String()) + // } + // fmt.Println("NbPublicInputs: ", len(r.PublicInputs), "PublicInputs: ", r.PublicInputs) + + // witness := buildWitnesses(r1cs, publicVariables, privateVariables) + // publicWitnesses, _ := witness.Public() + + // // Setup. + // fmt.Println("Setting up...") + // pk, vk, err := groth16.Setup(r1cs) + // if err != nil { + // log.Fatal(err) + // } + // fmt.Println("Set up") + + // // Prove. + // fmt.Println("Proving...") + // proof, err := groth16.Prove(r1cs, pk, witness) + // if err != nil { + // log.Fatal(err) + // } + // fmt.Println("Proved") + + // // Verify. + // verified := groth16.Verify(proof, vk, publicWitnesses) + + // fmt.Println("Verifies with valid public inputs: ", verified == nil) + // fmt.Println() + + // // Invalid verification (same proof, wrong public value). + // err = json.Unmarshal([]byte(invalidRawR1CS), &r) + // if err != nil { + // log.Fatal(err) + // } + + // invalidR1CS, publicVariables, privateVariables := buildR1CS(r) + + // constraints, res = invalidR1CS.GetConstraints() + // for _, r1c := range constraints { + // fmt.Println(r1c.String(res)) + // } + + // invalidWitness := buildWitnesses(invalidR1CS, publicVariables, privateVariables) + // invalidPublicWitnesses, _ := invalidWitness.Public() + // invalidVerified := groth16.Verify(proof, vk, invalidPublicWitnesses) + + // fmt.Println("Valid Public Witnesses: ", publicWitnesses.Vector().(fr_bn254.Vector).String()) + // fmt.Println("Invalid Public Witnesses: ", invalidPublicWitnesses.Vector().(fr_bn254.Vector).String()) + // fmt.Println() + + // fmt.Println("Verifies with invalid public inputs: ", invalidVerified == nil) } From 8a0e9b17b9a1c48233e00e87308682a80c739177 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Sat, 4 Mar 2023 18:54:04 -0300 Subject: [PATCH 089/118] Fix errors --- src/gnark_backend_wrapper/groth16/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gnark_backend_wrapper/groth16/mod.rs b/src/gnark_backend_wrapper/groth16/mod.rs index 79a6dd3..344ede3 100644 --- a/src/gnark_backend_wrapper/groth16/mod.rs +++ b/src/gnark_backend_wrapper/groth16/mod.rs @@ -201,14 +201,14 @@ pub fn preprocess(circuit: &acvm::Circuit) -> Result<(Vec, Vec), GnarkBa .to_str() .map_err(|e| GnarkBackendError::DeserializeKeyError(e.to_string()))?; let decoded_proving_key = hex::decode(proving_key_str) - .map_err(|e| GnarkBackendError::DeserializeProofError(e.to_string()))?; + .map_err(|e| GnarkBackendError::DeserializeKeyError(e.to_string()))?; let verifying_key_c_str = unsafe { CStr::from_ptr(key_pair.verifying_key) }; let verifying_key_str = verifying_key_c_str .to_str() .map_err(|e| GnarkBackendError::DeserializeKeyError(e.to_string()))?; let decoded_verifying_key = hex::decode(verifying_key_str) - .map_err(|e| GnarkBackendError::DeserializeProofError(e.to_string()))?; + .map_err(|e| GnarkBackendError::DeserializeKeyError(e.to_string()))?; Ok((decoded_proving_key, decoded_verifying_key)) } From 7b03e06f92fe61f0928175f19af0c4e93eae5feb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Sat, 4 Mar 2023 19:23:48 -0300 Subject: [PATCH 090/118] Add target for installing `nargo` --- Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Makefile b/Makefile index 6ec0a97..031f3c3 100644 --- a/Makefile +++ b/Makefile @@ -20,3 +20,6 @@ test: build-go clippy: $ cargo clippy --all-targets -- -D warnings +nargo: + $ cargo install --force --locked --git https://github.com/lambdaclass/noir --branch fork nargo + From e4015b094d890d2600f60b795278260c1377e4c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Sat, 4 Mar 2023 19:51:15 -0300 Subject: [PATCH 091/118] Cleanup simple circuit example --- gnark_backend_ffi/main.go | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/gnark_backend_ffi/main.go b/gnark_backend_ffi/main.go index f3952e8..cbf46d2 100644 --- a/gnark_backend_ffi/main.go +++ b/gnark_backend_ffi/main.go @@ -537,16 +537,6 @@ func ExampleSimpleCircuit() { pk, vk, _ := groth16.Setup(r1cs) - fmt.Println("VERIFYING KEY", vk) - var vkBuff bytes.Buffer - vk.WriteTo(&vkBuff) - encodedVK := hex.EncodeToString(vkBuff.Bytes()) - decodedVK, _ := hex.DecodeString(encodedVK) - vk2 := groth16.NewVerifyingKey(r1cs.CurveID()) - vk2.ReadFrom(bytes.NewReader(decodedVK)) - fmt.Println("VERIFYING KEY", vk2) - fmt.Println("VERIFYING KEYS MATCH", !vk.IsDifferent(vk2)) - fmt.Println("SRS generated.") /* Proving */ From 736ab9c52909bc1ca646058290140bad3e5df8df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Sat, 4 Mar 2023 20:38:07 -0300 Subject: [PATCH 092/118] Fix `preprocess` random values sampling --- Cargo.toml | 2 -- src/gnark_backend_wrapper/groth16/mod.rs | 18 +++++------------- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index fe879cb..2b1f83b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,8 +20,6 @@ cfg-if = "1" hex = "0.4" hex-literal = "0.3.4" thiserror = "1.0" - -[dev-dependencies] rand = "0.8" [profile.test] diff --git a/src/gnark_backend_wrapper/groth16/mod.rs b/src/gnark_backend_wrapper/groth16/mod.rs index 344ede3..328d6f2 100644 --- a/src/gnark_backend_wrapper/groth16/mod.rs +++ b/src/gnark_backend_wrapper/groth16/mod.rs @@ -171,19 +171,11 @@ pub fn get_exact_circuit_size(circuit: &acvm::Circuit) -> Result Result<(Vec, Vec), GnarkBackendError> { - // TODO: Sample random public_inputs - let mut witness_values = BTreeMap::new(); - witness_values.insert(acvm::Witness(1), acvm::FieldElement::from(3_u128)); - witness_values.insert(acvm::Witness(2), acvm::FieldElement::from(3_u128)); - let backend = Gnark; - acvm::PartialWitnessGenerator::solve(&backend, &mut witness_values, circuit.opcodes.clone())?; - let num_witnesses = circuit.num_vars(); - let values = (1..num_witnesses) - .map(|wit_index| { - *acvm::witness_to_value(&witness_values, acvm::Witness(wit_index)) - .unwrap_or(&acvm::FieldElement::zero()) - }) - .collect(); + let num_witnesses: usize = circuit + .num_vars() + .try_into() + .map_err(|e: TryFromIntError| GnarkBackendError::Error(e.to_string()))?; + let values = vec![acvm::FieldElement::from(rand::random::()); num_witnesses - 1]; let rawr1cs = RawR1CS::new(circuit.clone(), values)?; From cb9a3ec8b6e2c11000be9b6d406096558d4ea987 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Sat, 4 Mar 2023 22:21:05 -0300 Subject: [PATCH 093/118] Add an integration test --- .gitignore | 4 + .../test_programs/priv_x_eq_pub_y/Nargo.toml | 5 + .../test_programs/priv_x_eq_pub_y/Prover.toml | 2 + .../priv_x_eq_pub_y/Verifier.toml | 1 + .../test_programs/priv_x_eq_pub_y/src/main.nr | 3 + tests/tests.rs | 114 ++++++++++++++++++ 6 files changed, 129 insertions(+) create mode 100644 tests/test_programs/priv_x_eq_pub_y/Nargo.toml create mode 100644 tests/test_programs/priv_x_eq_pub_y/Prover.toml create mode 100644 tests/test_programs/priv_x_eq_pub_y/Verifier.toml create mode 100644 tests/test_programs/priv_x_eq_pub_y/src/main.nr create mode 100644 tests/tests.rs diff --git a/.gitignore b/.gitignore index f2e972d..b5cf87c 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,7 @@ # These are backup files generated by rustfmt **/*.rs.bk + +# nargo (integration tests) +tests/test_programs/*/target +tests/test_programs/*/proofs diff --git a/tests/test_programs/priv_x_eq_pub_y/Nargo.toml b/tests/test_programs/priv_x_eq_pub_y/Nargo.toml new file mode 100644 index 0000000..e0b467c --- /dev/null +++ b/tests/test_programs/priv_x_eq_pub_y/Nargo.toml @@ -0,0 +1,5 @@ +[package] +authors = [""] +compiler_version = "0.1" + +[dependencies] \ No newline at end of file diff --git a/tests/test_programs/priv_x_eq_pub_y/Prover.toml b/tests/test_programs/priv_x_eq_pub_y/Prover.toml new file mode 100644 index 0000000..b38bd4e --- /dev/null +++ b/tests/test_programs/priv_x_eq_pub_y/Prover.toml @@ -0,0 +1,2 @@ +x = 10 +y = 10 diff --git a/tests/test_programs/priv_x_eq_pub_y/Verifier.toml b/tests/test_programs/priv_x_eq_pub_y/Verifier.toml new file mode 100644 index 0000000..13c53d7 --- /dev/null +++ b/tests/test_programs/priv_x_eq_pub_y/Verifier.toml @@ -0,0 +1 @@ +y = "0x000000000000000000000000000000000000000000000000000000000000000a" diff --git a/tests/test_programs/priv_x_eq_pub_y/src/main.nr b/tests/test_programs/priv_x_eq_pub_y/src/main.nr new file mode 100644 index 0000000..3bd6ddb --- /dev/null +++ b/tests/test_programs/priv_x_eq_pub_y/src/main.nr @@ -0,0 +1,3 @@ +fn main(x : Field, y : pub Field) { + constrain x == y; +} diff --git a/tests/tests.rs b/tests/tests.rs new file mode 100644 index 0000000..a91874a --- /dev/null +++ b/tests/tests.rs @@ -0,0 +1,114 @@ +fn nargo_cmd() -> std::process::Command { + std::process::Command::new("nargo") +} + +fn nargo_execute(test_program_dir: &std::path::PathBuf) -> std::io::Result { + nargo_cmd() + .current_dir(test_program_dir) + .arg("execute") + // .arg("[WITNESS_NAME]") + .output() +} + +fn nargo_test(test_program_dir: &std::path::PathBuf) -> std::io::Result { + nargo_cmd() + .current_dir(test_program_dir) + .arg("test") + .output() +} + +fn nargo_check(test_program_dir: &std::path::PathBuf) -> std::io::Result { + nargo_cmd() + .current_dir(test_program_dir) + .arg("check") + .output() +} + +fn nargo_gates(test_program_dir: &std::path::PathBuf) -> std::io::Result { + nargo_cmd() + .current_dir(test_program_dir) + .arg("gates") + .output() +} + +fn nargo_compile(test_program_dir: &std::path::PathBuf) -> std::io::Result { + nargo_cmd() + .current_dir(test_program_dir) + .arg("compile") + .arg("my_test_circuit") + .output() +} + +fn nargo_prove(test_program_dir: &std::path::PathBuf) -> std::io::Result { + nargo_cmd() + .current_dir(test_program_dir) + .arg("prove") + .arg("my_test_proof") + .arg("my_test_circuit") + .output() +} + +fn nargo_verify(test_program_dir: &std::path::PathBuf) -> std::io::Result { + nargo_cmd() + .current_dir(test_program_dir) + .arg("verify") + .arg("my_test_proof") + .arg("my_test_circuit") + .output() +} + +fn test_program_dir_path(dir_name: &str) -> std::path::PathBuf { + std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join(format!("tests/test_programs/{dir_name}")) +} + +fn assert_nargo_cmd_works(cmd_name: &str, test_test_program_dir: &std::path::PathBuf) { + let cmd_output = match cmd_name { + "check" => nargo_check(test_test_program_dir), + "contract" => todo!(), + "compile" => nargo_compile(test_test_program_dir), + "new" => panic!("This cmd doesn't depend on the backend"), + "execute" => nargo_execute(test_test_program_dir), + "prove" => nargo_prove(test_test_program_dir), + "verify" => nargo_verify(test_test_program_dir), + "test" => nargo_test(test_test_program_dir), + "gates" => nargo_gates(test_test_program_dir), + e => panic!("{e} is not a valid nargo cmd"), + } + .unwrap(); + + assert!( + cmd_output.status.success(), + "stderr(nargo {cmd_name}): {}", + String::from_utf8(cmd_output.stderr).unwrap() + ); +} + +fn install_nargo() { + std::process::Command::new("make") + .arg("-C") + .arg( + std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .to_str() + .unwrap(), + ) + .arg("nargo") + .output() + .unwrap(); +} + +#[test] +fn test_integration() { + let test_test_program_dir = test_program_dir_path("priv_x_eq_pub_y"); + + // Ensure our nargo's fork is being used here. + install_nargo(); + + assert_nargo_cmd_works("check", &test_test_program_dir); + assert_nargo_cmd_works("compile", &test_test_program_dir); + assert_nargo_cmd_works("execute", &test_test_program_dir); + assert_nargo_cmd_works("prove", &test_test_program_dir); + assert_nargo_cmd_works("verify", &test_test_program_dir); + assert_nargo_cmd_works("test", &test_test_program_dir); + assert_nargo_cmd_works("gates", &test_test_program_dir); +} From 5e1c18a90498c0f236115db3b08ce084b6e27fe6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Mon, 6 Mar 2023 11:57:50 -0300 Subject: [PATCH 094/118] Rename `acvm_interop` -> `backend` --- src/{acvm_interop.rs => backend.rs} | 0 src/lib.rs | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) rename src/{acvm_interop.rs => backend.rs} (100%) diff --git a/src/acvm_interop.rs b/src/backend.rs similarity index 100% rename from src/acvm_interop.rs rename to src/backend.rs diff --git a/src/lib.rs b/src/lib.rs index 1b48111..6745ef8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -33,8 +33,8 @@ pub mod acvm; -pub mod acvm_interop; -pub use acvm_interop::Gnark; +pub mod backend; +pub use backend::Gnark; // TODO: This is exposed for testing only, we should find a way to not expose it for // the users. From 6ca8204c127f71e775f17e4cdc1188245a355816 Mon Sep 17 00:00:00 2001 From: Ivan Litteri <67517699+ilitteri@users.noreply.github.com> Date: Mon, 6 Mar 2023 18:42:26 -0300 Subject: [PATCH 095/118] Deserialization for felts (#50) * Derive `Deserialize` and `Serialize` in fields * Implement `Deserialize`-like methods for felts --- .../groth16/acir_to_r1cs.rs | 33 ++++-- .../groth16/serialize.rs | 107 +++++++++--------- 2 files changed, 80 insertions(+), 60 deletions(-) diff --git a/src/gnark_backend_wrapper/groth16/acir_to_r1cs.rs b/src/gnark_backend_wrapper/groth16/acir_to_r1cs.rs index d36e8c3..e5c455b 100644 --- a/src/gnark_backend_wrapper/groth16/acir_to_r1cs.rs +++ b/src/gnark_backend_wrapper/groth16/acir_to_r1cs.rs @@ -1,6 +1,8 @@ use super::{from_felt, Fr}; use crate::acvm; -use crate::gnark_backend_wrapper::groth16::serialize::{serialize_felt, serialize_felts}; +use crate::gnark_backend_wrapper::groth16::serialize::{ + deserialize_felt, deserialize_felts, serialize_felt, serialize_felts, +}; use crate::gnark_backend_wrapper::groth16::GnarkBackendError; use std::num::TryFromIntError; @@ -11,33 +13,50 @@ use std::num::TryFromIntError; // - These structures only support arithmetic gates, while the compiler has other // gate types. These can be added later once the backend knows how to deal with things like XOR // or once ACIR is taught how to do convert these black box functions to Arithmetic gates. -#[derive(Clone, serde::Serialize)] +#[derive(Clone, serde::Serialize, serde::Deserialize)] pub struct RawR1CS { pub gates: Vec, pub public_inputs: Vec, - #[serde(serialize_with = "serialize_felts")] + #[serde( + serialize_with = "serialize_felts", + deserialize_with = "deserialize_felts" + )] pub values: Vec, pub num_variables: u64, pub num_constraints: u64, } -#[derive(Clone, serde::Serialize)] +/* +1. Implementar Deserialize para +*/ +#[derive(Clone, serde::Serialize, serde::Deserialize)] pub struct RawGate { pub mul_terms: Vec, pub add_terms: Vec, - #[serde(serialize_with = "serialize_felt")] + #[serde( + serialize_with = "serialize_felt", + deserialize_with = "deserialize_felt" + )] pub constant_term: Fr, } -#[derive(Clone)] +#[derive(Clone, serde::Serialize, serde::Deserialize)] pub struct MulTerm { + #[serde( + serialize_with = "serialize_felt", + deserialize_with = "deserialize_felt" + )] pub coefficient: Fr, pub multiplicand: acvm::Witness, pub multiplier: acvm::Witness, } -#[derive(Clone)] +#[derive(Clone, serde::Serialize, serde::Deserialize)] pub struct AddTerm { + #[serde( + serialize_with = "serialize_felt", + deserialize_with = "deserialize_felt" + )] pub coefficient: Fr, pub sum: acvm::Witness, } diff --git a/src/gnark_backend_wrapper/groth16/serialize.rs b/src/gnark_backend_wrapper/groth16/serialize.rs index dd9e22e..07511d2 100644 --- a/src/gnark_backend_wrapper/groth16/serialize.rs +++ b/src/gnark_backend_wrapper/groth16/serialize.rs @@ -1,50 +1,8 @@ -use super::acir_to_r1cs::{AddTerm, MulTerm}; use crate::gnark_backend_wrapper as gnark_backend; -use ark_serialize::CanonicalSerialize; -use serde::{ser::SerializeStruct, Serialize}; +use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; +use serde::Deserialize; -impl Serialize for MulTerm { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - let mut serialized_coefficient = Vec::new(); - self.coefficient - .serialize_uncompressed(&mut serialized_coefficient) - .map_err(serde::ser::Error::custom)?; - // Turn little-endian to big-endian. - serialized_coefficient.reverse(); - let encoded_coefficient = hex::encode(serialized_coefficient); - - let mut s = serializer.serialize_struct("MulTerm", 3)?; - s.serialize_field("coefficient", &encoded_coefficient)?; - s.serialize_field("multiplicand", &self.multiplicand)?; - s.serialize_field("multiplier", &self.multiplier)?; - s.end() - } -} - -impl Serialize for AddTerm { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - let mut serialized_coefficient = Vec::new(); - self.coefficient - .serialize_uncompressed(&mut serialized_coefficient) - .map_err(serde::ser::Error::custom)?; - // Turn little-endian to big-endian. - serialized_coefficient.reverse(); - let encoded_coefficient = hex::encode(serialized_coefficient); - - let mut s = serializer.serialize_struct("AddTerm", 2)?; - s.serialize_field("coefficient", &encoded_coefficient)?; - s.serialize_field("sum", &self.sum)?; - s.end() - } -} - -pub fn serialize_felt_unchecked(felt: &gnark_backend::groth16::Fr) -> Vec { +pub fn serialize_felt_unchecked(felt: &gnark_backend::Fr) -> Vec { let mut serialized_felt = Vec::new(); #[allow(clippy::unwrap_used)] felt.serialize_uncompressed(&mut serialized_felt).unwrap(); @@ -53,10 +11,7 @@ pub fn serialize_felt_unchecked(felt: &gnark_backend::groth16::Fr) -> Vec { serialized_felt } -pub fn serialize_felt( - felt: &gnark_backend::groth16::Fr, - serializer: S, -) -> Result +pub fn serialize_felt(felt: &gnark_backend::Fr, serializer: S) -> Result where S: serde::ser::Serializer, { @@ -69,10 +24,7 @@ where serializer.serialize_str(&encoded_coefficient) } -pub fn serialize_felts( - felts: &[gnark_backend::groth16::Fr], - serializer: S, -) -> Result +pub fn serialize_felts(felts: &[gnark_backend::Fr], serializer: S) -> Result where S: serde::ser::Serializer, { @@ -88,3 +40,52 @@ where let encoded_buff = hex::encode(buff); serializer.serialize_str(&encoded_buff) } + +pub fn deserialize_felt<'de, D>(deserializer: D) -> Result +where + D: serde::Deserializer<'de>, +{ + let felt_bytes = String::deserialize(deserializer)?; + let mut decoded = hex::decode(felt_bytes).map_err(serde::de::Error::custom)?; + // Turn big-endian to little-endian. + decoded.reverse(); + gnark_backend::Fr::deserialize_uncompressed(decoded.as_slice()) + .map_err(serde::de::Error::custom) +} + +pub fn deserialize_felts<'de, D>(deserializer: D) -> Result, D::Error> +where + D: serde::Deserializer<'de>, +{ + let serialized_felts = String::deserialize(deserializer)?; + + let mut decoded_felts = hex::decode(serialized_felts).map_err(serde::de::Error::custom)?; + + let n_felts: usize = u32::from_be_bytes( + decoded_felts + .get(..4) + .ok_or_else(|| serde::de::Error::custom("Error getting felts size"))? + .try_into() + .map_err(serde::de::Error::custom)?, + ) + .try_into() + .map_err(serde::de::Error::custom)?; + let mut deserialized_felts: Vec = Vec::with_capacity(n_felts); + + decoded_felts + .get_mut(4..) // Skip the vector length corresponding to the first four bytes. + .ok_or_else(|| serde::de::Error::custom("Error getting decoded felts"))? + .chunks_mut(32) + .try_for_each(|decoded_felt| { + // Turn big-endian to little-endian. + decoded_felt.reverse(); + // Here I reference after dereference because I had a mutable reference and I need a non-mutable one. + let felt: gnark_backend::Fr = + CanonicalDeserialize::deserialize_uncompressed(&*decoded_felt) + .map_err(serde::de::Error::custom)?; + deserialized_felts.push(felt); + Ok::<(), D::Error>(()) + })?; + + Ok(deserialized_felts) +} From 05fd0af4ab8d353c52cedfec669877d1f0014a15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Wed, 8 Mar 2023 11:05:42 -0300 Subject: [PATCH 096/118] Abstract groth16 backend structures --- .../backend/groth16/structs/helpers.go | 62 ++++++++++++ .../backend/groth16/structs/raw_gate.go | 76 +++++++++++++++ .../backend/groth16/structs/raw_gate_test.go | 61 ++++++++++++ .../backend/groth16/structs/raw_r1cs.go | 97 +++++++++++++++++++ .../backend/groth16/structs/raw_r1cs_test.go | 40 ++++++++ 5 files changed, 336 insertions(+) create mode 100644 gnark_backend_ffi/backend/groth16/structs/helpers.go create mode 100644 gnark_backend_ffi/backend/groth16/structs/raw_gate.go create mode 100644 gnark_backend_ffi/backend/groth16/structs/raw_gate_test.go create mode 100644 gnark_backend_ffi/backend/groth16/structs/raw_r1cs.go create mode 100644 gnark_backend_ffi/backend/groth16/structs/raw_r1cs_test.go diff --git a/gnark_backend_ffi/backend/groth16/structs/helpers.go b/gnark_backend_ffi/backend/groth16/structs/helpers.go new file mode 100644 index 0000000..d525d5e --- /dev/null +++ b/gnark_backend_ffi/backend/groth16/structs/helpers.go @@ -0,0 +1,62 @@ +package structs + +import ( + "encoding/hex" + "encoding/json" + "log" + + fr_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/fr" +) + +func UncheckedDeserializeRawGate(rawGate string) RawGate { + var r RawGate + err := json.Unmarshal([]byte(rawGate), &r) + if err != nil { + log.Fatal(err) + } + + return r +} + +func UncheckedDeserializeRawGates(rawGates string) []RawGate { + var r []RawGate + err := json.Unmarshal([]byte(rawGates), &r) + if err != nil { + log.Fatal(err) + } + + return r +} + +func UncheckedDeserializeRawR1CS(rawR1CS string) RawR1CS { + var r RawR1CS + err := json.Unmarshal([]byte(rawR1CS), &r) + if err != nil { + log.Fatal(err) + } + + return r +} + +// Samples a felt and returns the encoded felt and the non-encoded felt. +func SampleEncodedFelt() (string, fr_bn254.Element) { + var felt fr_bn254.Element + felt.SetRandom() + + return hex.EncodeToString(felt.Marshal()), felt +} + +// Samples a felts vector and returns the encoded felts and the non-encoded felts vector. +func SampleEncodedFelts() (string, fr_bn254.Vector) { + var felt1 fr_bn254.Element + felt1.SetRandom() + + var felt2 fr_bn254.Element + felt2.SetRandom() + + felts := fr_bn254.Vector{felt1, felt2} + + binaryFelts, _ := felts.MarshalBinary() + + return hex.EncodeToString(binaryFelts), felts +} diff --git a/gnark_backend_ffi/backend/groth16/structs/raw_gate.go b/gnark_backend_ffi/backend/groth16/structs/raw_gate.go new file mode 100644 index 0000000..dc7bef7 --- /dev/null +++ b/gnark_backend_ffi/backend/groth16/structs/raw_gate.go @@ -0,0 +1,76 @@ +package structs + +import ( + "encoding/json" + "gnark_backend_ffi/backend" + "log" + + fr_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/fr" +) + +type RawGate struct { + MulTerms []backend.MulTerm + AddTerms []backend.AddTerm + ConstantTerm fr_bn254.Element +} + +func (g *RawGate) UnmarshalJSON(data []byte) error { + var rawGateMap map[string]interface{} + err := json.Unmarshal(data, &rawGateMap) + if err != nil { + log.Fatal(err) + return err + } + + var mulTerms []backend.MulTerm + var addTerms []backend.AddTerm + var constantTerm fr_bn254.Element + + // Deserialize mul terms. + if mulTermsValue, ok := rawGateMap["mul_terms"].([]interface{}); ok { + mulTermsJSON, err := json.Marshal(mulTermsValue) + if err != nil { + log.Fatal(err) + return err + } + err = json.Unmarshal(mulTermsJSON, &mulTerms) + if err != nil { + log.Fatal(err) + return err + } + } else { + log.Fatal("Error: couldn't deserialize mul terms.") + return &json.UnmarshalTypeError{} + } + + // Deserialize add terms. + if addTermsValue, ok := rawGateMap["add_terms"].([]interface{}); ok { + addTermsJSON, err := json.Marshal(addTermsValue) + if err != nil { + log.Fatal(err) + return err + } + err = json.Unmarshal(addTermsJSON, &addTerms) + if err != nil { + log.Fatal(err) + return err + } + } else { + log.Fatal("Error: couldn't deserialize add terms.") + return &json.UnmarshalTypeError{} + } + + // Deserialize constant term. + if encodedConstantTerm, ok := rawGateMap["constant_term"].(string); ok { + constantTerm = backend.DeserializeFelt(encodedConstantTerm) + } else { + log.Fatal("Error: coefficient is not a felt.") + return &json.UnmarshalTypeError{} + } + + g.MulTerms = mulTerms + g.AddTerms = addTerms + g.ConstantTerm = constantTerm + + return nil +} diff --git a/gnark_backend_ffi/backend/groth16/structs/raw_gate_test.go b/gnark_backend_ffi/backend/groth16/structs/raw_gate_test.go new file mode 100644 index 0000000..93447e4 --- /dev/null +++ b/gnark_backend_ffi/backend/groth16/structs/raw_gate_test.go @@ -0,0 +1,61 @@ +package structs + +import ( + "encoding/json" + "fmt" + "gnark_backend_ffi/backend" + "log" + "math/rand" + "testing" + + "github.com/stretchr/testify/assert" +) + +// TODO: Test error cases. + +func TestRawGateTermUnmarshalJSON(t *testing.T) { + encodedCoefficient, _ := SampleEncodedFelt() + multiplicand := rand.Uint32() + multiplier := rand.Uint32() + sum := rand.Uint32() + mulTerms := fmt.Sprintf(`[{"coefficient":"%s","multiplicand":%d,"multiplier":%d},{"coefficient":"%s","multiplicand":%d,"multiplier":%d}]`, encodedCoefficient, multiplicand, multiplier, encodedCoefficient, multiplicand, multiplier) + addTerms := fmt.Sprintf(`[{"coefficient":"%s","sum":%d},{"coefficient":"%s","sum":%d}]`, encodedCoefficient, sum, encodedCoefficient, sum) + encodedConstantTerm, nonEncodedConstantTerm := SampleEncodedFelt() + rawGate := fmt.Sprintf(`{"mul_terms":%s,"add_terms":%s,"constant_term":"%s"}`, mulTerms, addTerms, encodedConstantTerm) + + var r RawGate + err := json.Unmarshal([]byte(rawGate), &r) + if err != nil { + log.Fatal(err) + } + + assert.NoError(t, err) + assert.Equal(t, backend.UncheckedDeserializeMulTerms(mulTerms), r.MulTerms) + assert.Equal(t, backend.UncheckedDeserializeAddTerms(addTerms), r.AddTerms) + assert.Equal(t, nonEncodedConstantTerm, r.ConstantTerm) +} + +func TestRawGatesTermUnmarshalJSON(t *testing.T) { + encodedCoefficient, _ := SampleEncodedFelt() + multiplicand := rand.Uint32() + multiplier := rand.Uint32() + sum := rand.Uint32() + mulTerms := fmt.Sprintf(`[{"coefficient":"%s","multiplicand":%d,"multiplier":%d},{"coefficient":"%s","multiplicand":%d,"multiplier":%d}]`, encodedCoefficient, multiplicand, multiplier, encodedCoefficient, multiplicand, multiplier) + addTerms := fmt.Sprintf(`[{"coefficient":"%s","sum":%d},{"coefficient":"%s","sum":%d}]`, encodedCoefficient, sum, encodedCoefficient, sum) + encodedConstantTerm, nonEncodedConstantTerm := SampleEncodedFelt() + rawGate := fmt.Sprintf(`{"mul_terms":%s,"add_terms":%s,"constant_term":"%s"}`, mulTerms, addTerms, encodedConstantTerm) + rawGates := fmt.Sprintf(`[%s,%s]`, rawGate, rawGate) + + var r []RawGate + err := json.Unmarshal([]byte(rawGates), &r) + if err != nil { + log.Fatal(err) + } + + assert.NoError(t, err) + for _, rawGate := range r { + assert.Equal(t, backend.UncheckedDeserializeMulTerms(mulTerms), rawGate.MulTerms) + assert.Equal(t, backend.UncheckedDeserializeAddTerms(addTerms), rawGate.AddTerms) + assert.Equal(t, nonEncodedConstantTerm, rawGate.ConstantTerm) + } +} diff --git a/gnark_backend_ffi/backend/groth16/structs/raw_r1cs.go b/gnark_backend_ffi/backend/groth16/structs/raw_r1cs.go new file mode 100644 index 0000000..92aa2d5 --- /dev/null +++ b/gnark_backend_ffi/backend/groth16/structs/raw_r1cs.go @@ -0,0 +1,97 @@ +package structs + +import ( + "encoding/json" + "gnark_backend_ffi/backend" + "log" + + fr_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/fr" +) + +type RawR1CS struct { + Gates []RawGate + PublicInputs backend.Witnesses + Values fr_bn254.Vector + NumVariables uint64 + NumConstraints uint64 +} + +func (r *RawR1CS) UnmarshalJSON(data []byte) error { + var rawR1CSMap map[string]interface{} + err := json.Unmarshal(data, &rawR1CSMap) + if err != nil { + log.Fatal(err) + return err + } + + var gates []RawGate + var publicInputs backend.Witnesses + var values fr_bn254.Vector + var numVariables uint64 + var numConstraints uint64 + + // Deserialize gates. + if gatesValue, ok := rawR1CSMap["gates"].([]interface{}); ok { + gatesJSON, err := json.Marshal(gatesValue) + if err != nil { + log.Fatal(err) + return err + } + err = json.Unmarshal(gatesJSON, &gates) + if err != nil { + log.Fatal(err) + return err + } + } else { + log.Fatal("Error: couldn't deserialize raw gates.") + return &json.UnmarshalTypeError{} + } + + if publicInputsValue, ok := rawR1CSMap["public_inputs"].([]interface{}); ok { + publicInputsJSON, err := json.Marshal(publicInputsValue) + if err != nil { + log.Fatal(err) + return err + } + err = json.Unmarshal(publicInputsJSON, &publicInputs) + if err != nil { + log.Fatal(err) + return err + } + } else { + log.Fatal("Error: couldn't deserialize public inputs.") + return &json.UnmarshalTypeError{} + } + + // Deserialize values. + if encodedValues, ok := rawR1CSMap["values"].(string); ok { + values = backend.DeserializeFelts(encodedValues) + } else { + log.Fatal("Error: couldn't deserialize values.") + return &json.UnmarshalTypeError{} + } + + // Deserialize num_variables. + if numVariablesValue, ok := rawR1CSMap["num_variables"].(float64); ok { + numVariables = uint64(numVariablesValue) + } else { + log.Fatal("Error: couldn't deserialize num_variables.") + return &json.UnmarshalTypeError{} + } + + // Deserialize num_constraints. + if numConstraintsValue, ok := rawR1CSMap["num_constraints"].(float64); ok { + numConstraints = uint64(numConstraintsValue) + } else { + log.Fatal("Error: couldn't deserialize num_constraints.") + return &json.UnmarshalTypeError{} + } + + r.Gates = gates + r.PublicInputs = publicInputs + r.Values = values + r.NumVariables = numVariables + r.NumConstraints = numConstraints + + return nil +} diff --git a/gnark_backend_ffi/backend/groth16/structs/raw_r1cs_test.go b/gnark_backend_ffi/backend/groth16/structs/raw_r1cs_test.go new file mode 100644 index 0000000..6a63e08 --- /dev/null +++ b/gnark_backend_ffi/backend/groth16/structs/raw_r1cs_test.go @@ -0,0 +1,40 @@ +package structs + +import ( + "encoding/json" + "fmt" + "gnark_backend_ffi/backend" + "math/rand" + "testing" + + "github.com/stretchr/testify/assert" +) + +// TODO: Test error cases. + +func TestRawR1CSTermUnmarshalJSON(t *testing.T) { + encodedCoefficient, _ := SampleEncodedFelt() + multiplicand := rand.Uint32() + multiplier := rand.Uint32() + sum := rand.Uint32() + mulTerms := fmt.Sprintf(`[{"coefficient":"%s","multiplicand":%d,"multiplier":%d},{"coefficient":"%s","multiplicand":%d,"multiplier":%d}]`, encodedCoefficient, multiplicand, multiplier, encodedCoefficient, multiplicand, multiplier) + addTerms := fmt.Sprintf(`[{"coefficient":"%s","sum":%d},{"coefficient":"%s","sum":%d}]`, encodedCoefficient, sum, encodedCoefficient, sum) + encodedConstantTerm, _ := SampleEncodedFelt() + rawGate := fmt.Sprintf(`{"mul_terms":%s,"add_terms":%s,"constant_term":"%s"}`, mulTerms, addTerms, encodedConstantTerm) + rawGates := fmt.Sprintf(`[%s,%s]`, rawGate, rawGate) + publicInputs := fmt.Sprintf("[%d,%d,%d]", multiplicand, multiplier, sum) + encodedValues, nonEncodedValues := SampleEncodedFelts() + numVariables := uint64(10) + numConstraints := uint64(10) + rawR1CS := fmt.Sprintf(`{"gates":%s,"public_inputs":%s,"values":"%s","num_variables":%d,"num_constraints":%d}`, rawGates, publicInputs, encodedValues, numVariables, numConstraints) + + var r RawR1CS + err := json.Unmarshal([]byte(rawR1CS), &r) + + assert.NoError(t, err) + assert.Equal(t, UncheckedDeserializeRawGates(rawGates), r.Gates) + assert.Equal(t, backend.Witnesses{multiplicand, multiplier, sum}, r.PublicInputs) + assert.Equal(t, nonEncodedValues, r.Values) + assert.Equal(t, numConstraints, r.NumConstraints) + assert.Equal(t, numVariables, r.NumVariables) +} From 669c58464bfce2fe28f14893680ff6d84a3c9ddf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Wed, 8 Mar 2023 11:05:52 -0300 Subject: [PATCH 097/118] Abstract plonk backend structures --- .../backend/plonk/structs/acir.go | 9 +++++ .../plonk/structs/arithmetic_opcode.go | 13 +++++++ .../structs/black_box_function_call_opcode.go | 35 +++++++++++++++++++ .../backend/plonk/structs/directive_opcode.go | 20 +++++++++++ .../backend/plonk/structs/opcode.go | 16 +++++++++ 5 files changed, 93 insertions(+) create mode 100644 gnark_backend_ffi/backend/plonk/structs/acir.go create mode 100644 gnark_backend_ffi/backend/plonk/structs/arithmetic_opcode.go create mode 100644 gnark_backend_ffi/backend/plonk/structs/black_box_function_call_opcode.go create mode 100644 gnark_backend_ffi/backend/plonk/structs/directive_opcode.go create mode 100644 gnark_backend_ffi/backend/plonk/structs/opcode.go diff --git a/gnark_backend_ffi/backend/plonk/structs/acir.go b/gnark_backend_ffi/backend/plonk/structs/acir.go new file mode 100644 index 0000000..b65be04 --- /dev/null +++ b/gnark_backend_ffi/backend/plonk/structs/acir.go @@ -0,0 +1,9 @@ +package structs + +import "gnark_backend_ffi/backend" + +type ACIR struct { + CurrentWitness uint32 + Opcodes []Opcode + PublicInputs backend.Witnesses +} diff --git a/gnark_backend_ffi/backend/plonk/structs/arithmetic_opcode.go b/gnark_backend_ffi/backend/plonk/structs/arithmetic_opcode.go new file mode 100644 index 0000000..1bffad5 --- /dev/null +++ b/gnark_backend_ffi/backend/plonk/structs/arithmetic_opcode.go @@ -0,0 +1,13 @@ +package structs + +import ( + "gnark_backend_ffi/backend" + + fr_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/fr" +) + +type GateTerms struct { + MulTerms []backend.MulTerm + AddTerms []backend.AddTerm + qM fr_bn254.Element +} diff --git a/gnark_backend_ffi/backend/plonk/structs/black_box_function_call_opcode.go b/gnark_backend_ffi/backend/plonk/structs/black_box_function_call_opcode.go new file mode 100644 index 0000000..a21077d --- /dev/null +++ b/gnark_backend_ffi/backend/plonk/structs/black_box_function_call_opcode.go @@ -0,0 +1,35 @@ +package structs + +import "gnark_backend_ffi/backend" + +type BlackBoxFunction = int + +const ( + AES BlackBoxFunction = iota + AND + XOR + RANGE + SHA256 + Blake2s + MerkleMembership + SchnorrVerify + Pedersen + // 128 here specifies that this function + // should have 128 bits of security + HashToField128Security + EcdsaSecp256k1 + FixedBaseScalarMul + Keccak256 +) + +type FunctionInput struct { + Witness backend.Witness + NumBits uint32 +} + +type BlackBoxFunctionFields struct { + Opcode Opcode + Name BlackBoxFunction + Inputs []FunctionInput + Outputs backend.Witnesses +} diff --git a/gnark_backend_ffi/backend/plonk/structs/directive_opcode.go b/gnark_backend_ffi/backend/plonk/structs/directive_opcode.go new file mode 100644 index 0000000..3c36632 --- /dev/null +++ b/gnark_backend_ffi/backend/plonk/structs/directive_opcode.go @@ -0,0 +1,20 @@ +package structs + +import "gnark_backend_ffi/backend" + +type DirectiveOpcode = int + +const ( + // Inverts the value of x and stores it in the result variable + Invert DirectiveOpcode = iota +) + +type InvertFields struct { + X backend.Witness + Result backend.Witness +} + +type DirectiveFields struct { + Opcode DirectiveOpcode + Invert InvertFields +} diff --git a/gnark_backend_ffi/backend/plonk/structs/opcode.go b/gnark_backend_ffi/backend/plonk/structs/opcode.go new file mode 100644 index 0000000..e6297fb --- /dev/null +++ b/gnark_backend_ffi/backend/plonk/structs/opcode.go @@ -0,0 +1,16 @@ +package structs + +type Opcode = int + +const ( + Arithmetic Opcode = iota + BlackBoxFunctionCall + Directive +) + +type OpcodeFields struct { + Opcode Opcode + Arithmetic GateTerms + BlackBoxFunctionCall BlackBoxFunctionFields + Directive DirectiveFields +} From 479bc9bf850603275a247025ef8989faa9ab0b20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Wed, 8 Mar 2023 11:06:07 -0300 Subject: [PATCH 098/118] Add general backend structures and helpers --- gnark_backend_ffi/backend/add_term.go | 46 +++++++++ gnark_backend_ffi/backend/add_term_test.go | 47 ++++++++++ gnark_backend_ffi/backend/helpers.go | 103 +++++++++++++++++++++ gnark_backend_ffi/backend/mul_term.go | 57 ++++++++++++ gnark_backend_ffi/backend/mul_term_test.go | 51 ++++++++++ 5 files changed, 304 insertions(+) create mode 100644 gnark_backend_ffi/backend/add_term.go create mode 100644 gnark_backend_ffi/backend/add_term_test.go create mode 100644 gnark_backend_ffi/backend/helpers.go create mode 100644 gnark_backend_ffi/backend/mul_term.go create mode 100644 gnark_backend_ffi/backend/mul_term_test.go diff --git a/gnark_backend_ffi/backend/add_term.go b/gnark_backend_ffi/backend/add_term.go new file mode 100644 index 0000000..439fe83 --- /dev/null +++ b/gnark_backend_ffi/backend/add_term.go @@ -0,0 +1,46 @@ +package backend + +import ( + "encoding/json" + "log" + + fr_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/fr" +) + +type AddTerm struct { + Coefficient fr_bn254.Element + Sum Witness +} + +func (m *AddTerm) UnmarshalJSON(data []byte) error { + var add_term_map map[string]interface{} + err := json.Unmarshal(data, &add_term_map) + if err != nil { + log.Fatal(err) + return err + } + + var coefficient fr_bn254.Element + var sum Witness + + // Deserialize coefficient. + if encodedCoefficient, ok := add_term_map["coefficient"].(string); ok { + coefficient = DeserializeFelt(encodedCoefficient) + } else { + log.Fatal("Error: couldn't deserialize coefficient.") + return &json.UnmarshalTypeError{} + } + + // Deserialize sum. + if m, ok := add_term_map["sum"].(float64); ok { + sum = Witness(m) + } else { + log.Fatal("Error: couldn't deserialize sum.") + return &json.UnmarshalTypeError{} + } + + m.Coefficient = coefficient + m.Sum = sum + + return nil +} diff --git a/gnark_backend_ffi/backend/add_term_test.go b/gnark_backend_ffi/backend/add_term_test.go new file mode 100644 index 0000000..ecc79ac --- /dev/null +++ b/gnark_backend_ffi/backend/add_term_test.go @@ -0,0 +1,47 @@ +package backend + +import ( + "encoding/json" + "fmt" + "log" + "math/rand" + "testing" + + "github.com/stretchr/testify/assert" +) + +// TODO: Test error cases. + +func TestAddTermUnmarshalJSON(t *testing.T) { + encodedCoefficient, nonEncodedCoefficient := SampleEncodedFelt() + sum := rand.Uint32() + addTerm := fmt.Sprintf(`{"coefficient":"%s","sum":%d}`, encodedCoefficient, sum) + + var a AddTerm + err := json.Unmarshal([]byte(addTerm), &a) + if err != nil { + log.Fatal(err) + } + + assert.NoError(t, err) + assert.Equal(t, nonEncodedCoefficient, a.Coefficient) + assert.Equal(t, sum, a.Sum) +} + +func TestAddTermsUnmarshalJSON(t *testing.T) { + encodedCoefficient, nonEncodedCoefficient := SampleEncodedFelt() + sum := rand.Uint32() + addTerms := fmt.Sprintf(`[{"coefficient":"%s","sum":%d},{"coefficient":"%s","sum":%d}]`, encodedCoefficient, sum, encodedCoefficient, sum) + + var a []AddTerm + err := json.Unmarshal([]byte(addTerms), &a) + if err != nil { + log.Fatal(err) + } + + assert.NoError(t, err) + for _, addTerm := range a { + assert.Equal(t, nonEncodedCoefficient, addTerm.Coefficient) + assert.Equal(t, sum, addTerm.Sum) + } +} diff --git a/gnark_backend_ffi/backend/helpers.go b/gnark_backend_ffi/backend/helpers.go new file mode 100644 index 0000000..f6de906 --- /dev/null +++ b/gnark_backend_ffi/backend/helpers.go @@ -0,0 +1,103 @@ +package backend + +import ( + "encoding/hex" + "encoding/json" + "log" + + fr_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/fr" +) + +type Witness = uint32 +type Witnesses = []Witness + +func DeserializeFelt(encodedFelt string) fr_bn254.Element { + // Decode the received felt. + decodedFelt, err := hex.DecodeString(encodedFelt) + if err != nil { + log.Fatal(err) + } + + // Deserialize the decoded felt. + var deserializedFelt fr_bn254.Element + deserializedFelt.SetBytes(decodedFelt) + + return deserializedFelt +} + +func DeserializeFelts(encodedFelts string) fr_bn254.Vector { + // Decode the received felts. + decodedFelts, err := hex.DecodeString(encodedFelts) + if err != nil { + log.Fatal(err) + } + + // Unpack and deserialize the decoded felts. + var deserializedFelts fr_bn254.Vector + deserializedFelts.UnmarshalBinary(decodedFelts) + + return deserializedFelts +} + +func UncheckedDeserializeAddTerm(addTerm string) AddTerm { + var a AddTerm + err := json.Unmarshal([]byte(addTerm), &a) + if err != nil { + log.Fatal(err) + } + + return a +} + +func UncheckedDeserializeAddTerms(addTerms string) []AddTerm { + var a []AddTerm + err := json.Unmarshal([]byte(addTerms), &a) + if err != nil { + log.Fatal(err) + } + + return a +} + +func UncheckedDeserializeMulTerm(mulTerm string) MulTerm { + var m MulTerm + err := json.Unmarshal([]byte(mulTerm), &m) + if err != nil { + log.Fatal(err) + } + + return m +} + +func UncheckedDeserializeMulTerms(mulTerms string) []MulTerm { + var m []MulTerm + err := json.Unmarshal([]byte(mulTerms), &m) + if err != nil { + log.Fatal(err) + } + + return m +} + +// Samples a felt and returns the encoded felt and the non-encoded felt. +func SampleEncodedFelt() (string, fr_bn254.Element) { + var felt fr_bn254.Element + felt.SetRandom() + + return hex.EncodeToString(felt.Marshal()), felt +} + +// Samples a felts vector and returns the encoded felts and the non-encoded felts vector. +func SampleEncodedFelts() (string, fr_bn254.Vector) { + var felt1 fr_bn254.Element + felt1.SetRandom() + + var felt2 fr_bn254.Element + felt2.SetRandom() + + felts := fr_bn254.Vector{felt1, felt2} + + binaryFelts, _ := felts.MarshalBinary() + + return hex.EncodeToString(binaryFelts), felts +} diff --git a/gnark_backend_ffi/backend/mul_term.go b/gnark_backend_ffi/backend/mul_term.go new file mode 100644 index 0000000..c2f6c78 --- /dev/null +++ b/gnark_backend_ffi/backend/mul_term.go @@ -0,0 +1,57 @@ +package backend + +import ( + "encoding/json" + "log" + + fr_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/fr" +) + +type MulTerm struct { + Coefficient fr_bn254.Element + Multiplicand Witness + Multiplier Witness +} + +func (m *MulTerm) UnmarshalJSON(data []byte) error { + var mul_term_map map[string]interface{} + err := json.Unmarshal(data, &mul_term_map) + if err != nil { + log.Fatal(err) + return err + } + + var coefficient fr_bn254.Element + var multiplicand Witness + var multiplier Witness + + // Deserialize coefficient. + if encodedCoefficient, ok := mul_term_map["coefficient"].(string); ok { + coefficient = DeserializeFelt(encodedCoefficient) + } else { + log.Fatal("Error: couldn't deserialize coefficient.") + return &json.UnmarshalTypeError{} + } + + // Deserialize multiplicand. + if m, ok := mul_term_map["multiplicand"].(float64); ok { + multiplicand = Witness(m) + } else { + log.Fatal("Error: couldn't deserialize multiplicand.") + return &json.UnmarshalTypeError{} + } + + // Deserialize multiplier. + if m, ok := mul_term_map["multiplier"].(float64); ok { + multiplier = Witness(m) + } else { + log.Fatal("Error: couldn't deserialize multiplier.") + return &json.UnmarshalTypeError{} + } + + m.Coefficient = coefficient + m.Multiplicand = multiplicand + m.Multiplier = multiplier + + return nil +} diff --git a/gnark_backend_ffi/backend/mul_term_test.go b/gnark_backend_ffi/backend/mul_term_test.go new file mode 100644 index 0000000..51ca2dd --- /dev/null +++ b/gnark_backend_ffi/backend/mul_term_test.go @@ -0,0 +1,51 @@ +package backend + +import ( + "encoding/json" + "fmt" + "log" + "math/rand" + "testing" + + "github.com/stretchr/testify/assert" +) + +// TODO: Test error cases. + +func TestMulTermUnmarshalJSON(t *testing.T) { + encodedCoefficient, nonEncodedCoefficient := SampleEncodedFelt() + multiplicand := rand.Uint32() + multiplier := rand.Uint32() + mulTerm := fmt.Sprintf(`{"coefficient":"%s","multiplicand":%d,"multiplier":%d}`, encodedCoefficient, multiplicand, multiplier) + + var m MulTerm + err := json.Unmarshal([]byte(mulTerm), &m) + if err != nil { + log.Fatal(err) + } + + assert.NoError(t, err) + assert.Equal(t, nonEncodedCoefficient, m.Coefficient) + assert.Equal(t, multiplicand, m.Multiplicand) + assert.Equal(t, multiplier, m.Multiplier) +} + +func TestMulTermsUnmarshalJSON(t *testing.T) { + encodedCoefficient, nonEncodedCoefficient := SampleEncodedFelt() + multiplicand := rand.Uint32() + multiplier := rand.Uint32() + mulTerms := fmt.Sprintf(`[{"coefficient":"%s","multiplicand":%d,"multiplier":%d},{"coefficient":"%s","multiplicand":%d,"multiplier":%d}]`, encodedCoefficient, multiplicand, multiplier, encodedCoefficient, multiplicand, multiplier) + + var m []MulTerm + err := json.Unmarshal([]byte(mulTerms), &m) + if err != nil { + log.Fatal(err) + } + + assert.NoError(t, err) + for _, mulTerm := range m { + assert.Equal(t, nonEncodedCoefficient, mulTerm.Coefficient) + assert.Equal(t, multiplicand, mulTerm.Multiplicand) + assert.Equal(t, multiplier, mulTerm.Multiplier) + } +} From b2542c29655073522c651c9b8925466916437ffc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Wed, 8 Mar 2023 11:06:35 -0300 Subject: [PATCH 099/118] Refactor old structure --- gnark_backend_ffi/structs/add_term.go | 46 ------- gnark_backend_ffi/structs/add_term_test.go | 47 -------- gnark_backend_ffi/structs/helpers.go | 133 --------------------- gnark_backend_ffi/structs/mul_term.go | 57 --------- gnark_backend_ffi/structs/mul_term_test.go | 51 -------- gnark_backend_ffi/structs/raw_gate.go | 75 ------------ gnark_backend_ffi/structs/raw_gate_test.go | 60 ---------- gnark_backend_ffi/structs/raw_r1cs.go | 96 --------------- gnark_backend_ffi/structs/raw_r1cs_test.go | 39 ------ 9 files changed, 604 deletions(-) delete mode 100644 gnark_backend_ffi/structs/add_term.go delete mode 100644 gnark_backend_ffi/structs/add_term_test.go delete mode 100644 gnark_backend_ffi/structs/helpers.go delete mode 100644 gnark_backend_ffi/structs/mul_term.go delete mode 100644 gnark_backend_ffi/structs/mul_term_test.go delete mode 100644 gnark_backend_ffi/structs/raw_gate.go delete mode 100644 gnark_backend_ffi/structs/raw_gate_test.go delete mode 100644 gnark_backend_ffi/structs/raw_r1cs.go delete mode 100644 gnark_backend_ffi/structs/raw_r1cs_test.go diff --git a/gnark_backend_ffi/structs/add_term.go b/gnark_backend_ffi/structs/add_term.go deleted file mode 100644 index e9a98e0..0000000 --- a/gnark_backend_ffi/structs/add_term.go +++ /dev/null @@ -1,46 +0,0 @@ -package structs - -import ( - "encoding/json" - "log" - - fr_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/fr" -) - -type AddTerm struct { - Coefficient fr_bn254.Element - Sum Witness -} - -func (m *AddTerm) UnmarshalJSON(data []byte) error { - var add_term_map map[string]interface{} - err := json.Unmarshal(data, &add_term_map) - if err != nil { - log.Fatal(err) - return err - } - - var coefficient fr_bn254.Element - var sum Witness - - // Deserialize coefficient. - if encodedCoefficient, ok := add_term_map["coefficient"].(string); ok { - coefficient = DeserializeFelt(encodedCoefficient) - } else { - log.Fatal("Error: couldn't deserialize coefficient.") - return &json.UnmarshalTypeError{} - } - - // Deserialize sum. - if m, ok := add_term_map["sum"].(float64); ok { - sum = Witness(m) - } else { - log.Fatal("Error: couldn't deserialize sum.") - return &json.UnmarshalTypeError{} - } - - m.Coefficient = coefficient - m.Sum = sum - - return nil -} diff --git a/gnark_backend_ffi/structs/add_term_test.go b/gnark_backend_ffi/structs/add_term_test.go deleted file mode 100644 index 38285f0..0000000 --- a/gnark_backend_ffi/structs/add_term_test.go +++ /dev/null @@ -1,47 +0,0 @@ -package structs - -import ( - "encoding/json" - "fmt" - "log" - "math/rand" - "testing" - - "github.com/stretchr/testify/assert" -) - -// TODO: Test error cases. - -func TestAddTermUnmarshalJSON(t *testing.T) { - encodedCoefficient, nonEncodedCoefficient := SampleEncodedFelt() - sum := rand.Uint32() - addTerm := fmt.Sprintf(`{"coefficient":"%s","sum":%d}`, encodedCoefficient, sum) - - var a AddTerm - err := json.Unmarshal([]byte(addTerm), &a) - if err != nil { - log.Fatal(err) - } - - assert.NoError(t, err) - assert.Equal(t, nonEncodedCoefficient, a.Coefficient) - assert.Equal(t, sum, a.Sum) -} - -func TestAddTermsUnmarshalJSON(t *testing.T) { - encodedCoefficient, nonEncodedCoefficient := SampleEncodedFelt() - sum := rand.Uint32() - addTerms := fmt.Sprintf(`[{"coefficient":"%s","sum":%d},{"coefficient":"%s","sum":%d}]`, encodedCoefficient, sum, encodedCoefficient, sum) - - var a []AddTerm - err := json.Unmarshal([]byte(addTerms), &a) - if err != nil { - log.Fatal(err) - } - - assert.NoError(t, err) - for _, addTerm := range a { - assert.Equal(t, nonEncodedCoefficient, addTerm.Coefficient) - assert.Equal(t, sum, addTerm.Sum) - } -} diff --git a/gnark_backend_ffi/structs/helpers.go b/gnark_backend_ffi/structs/helpers.go deleted file mode 100644 index dc760dd..0000000 --- a/gnark_backend_ffi/structs/helpers.go +++ /dev/null @@ -1,133 +0,0 @@ -package structs - -import ( - "encoding/hex" - "encoding/json" - "log" - - fr_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/fr" -) - -type Witness = uint32 -type Witnesses = []Witness - -func DeserializeFelt(encodedFelt string) fr_bn254.Element { - // Decode the received felt. - decodedFelt, err := hex.DecodeString(encodedFelt) - if err != nil { - log.Fatal(err) - } - - // Deserialize the decoded felt. - var deserializedFelt fr_bn254.Element - deserializedFelt.SetBytes(decodedFelt) - - return deserializedFelt -} - -func DeserializeFelts(encodedFelts string) fr_bn254.Vector { - // Decode the received felts. - decodedFelts, err := hex.DecodeString(encodedFelts) - if err != nil { - log.Fatal(err) - } - - // Unpack and deserialize the decoded felts. - var deserializedFelts fr_bn254.Vector - deserializedFelts.UnmarshalBinary(decodedFelts) - - return deserializedFelts -} - -func UncheckedDeserializeAddTerm(addTerm string) AddTerm { - var a AddTerm - err := json.Unmarshal([]byte(addTerm), &a) - if err != nil { - log.Fatal(err) - } - - return a -} - -func UncheckedDeserializeAddTerms(addTerms string) []AddTerm { - var a []AddTerm - err := json.Unmarshal([]byte(addTerms), &a) - if err != nil { - log.Fatal(err) - } - - return a -} - -func UncheckedDeserializeMulTerm(mulTerm string) MulTerm { - var m MulTerm - err := json.Unmarshal([]byte(mulTerm), &m) - if err != nil { - log.Fatal(err) - } - - return m -} - -func UncheckedDeserializeMulTerms(mulTerms string) []MulTerm { - var m []MulTerm - err := json.Unmarshal([]byte(mulTerms), &m) - if err != nil { - log.Fatal(err) - } - - return m -} - -func UncheckedDeserializeRawGate(rawGate string) RawGate { - var r RawGate - err := json.Unmarshal([]byte(rawGate), &r) - if err != nil { - log.Fatal(err) - } - - return r -} - -func UncheckedDeserializeRawGates(rawGates string) []RawGate { - var r []RawGate - err := json.Unmarshal([]byte(rawGates), &r) - if err != nil { - log.Fatal(err) - } - - return r -} - -func UncheckedDeserializeRawR1CS(rawR1CS string) RawR1CS { - var r RawR1CS - err := json.Unmarshal([]byte(rawR1CS), &r) - if err != nil { - log.Fatal(err) - } - - return r -} - -// Samples a felt and returns the encoded felt and the non-encoded felt. -func SampleEncodedFelt() (string, fr_bn254.Element) { - var felt fr_bn254.Element - felt.SetRandom() - - return hex.EncodeToString(felt.Marshal()), felt -} - -// Samples a felts vector and returns the encoded felts and the non-encoded felts vector. -func SampleEncodedFelts() (string, fr_bn254.Vector) { - var felt1 fr_bn254.Element - felt1.SetRandom() - - var felt2 fr_bn254.Element - felt2.SetRandom() - - felts := fr_bn254.Vector{felt1, felt2} - - binaryFelts, _ := felts.MarshalBinary() - - return hex.EncodeToString(binaryFelts), felts -} diff --git a/gnark_backend_ffi/structs/mul_term.go b/gnark_backend_ffi/structs/mul_term.go deleted file mode 100644 index 4e065d6..0000000 --- a/gnark_backend_ffi/structs/mul_term.go +++ /dev/null @@ -1,57 +0,0 @@ -package structs - -import ( - "encoding/json" - "log" - - fr_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/fr" -) - -type MulTerm struct { - Coefficient fr_bn254.Element - Multiplicand Witness - Multiplier Witness -} - -func (m *MulTerm) UnmarshalJSON(data []byte) error { - var mul_term_map map[string]interface{} - err := json.Unmarshal(data, &mul_term_map) - if err != nil { - log.Fatal(err) - return err - } - - var coefficient fr_bn254.Element - var multiplicand Witness - var multiplier Witness - - // Deserialize coefficient. - if encodedCoefficient, ok := mul_term_map["coefficient"].(string); ok { - coefficient = DeserializeFelt(encodedCoefficient) - } else { - log.Fatal("Error: couldn't deserialize coefficient.") - return &json.UnmarshalTypeError{} - } - - // Deserialize multiplicand. - if m, ok := mul_term_map["multiplicand"].(float64); ok { - multiplicand = Witness(m) - } else { - log.Fatal("Error: couldn't deserialize multiplicand.") - return &json.UnmarshalTypeError{} - } - - // Deserialize multiplier. - if m, ok := mul_term_map["multiplier"].(float64); ok { - multiplier = Witness(m) - } else { - log.Fatal("Error: couldn't deserialize multiplier.") - return &json.UnmarshalTypeError{} - } - - m.Coefficient = coefficient - m.Multiplicand = multiplicand - m.Multiplier = multiplier - - return nil -} diff --git a/gnark_backend_ffi/structs/mul_term_test.go b/gnark_backend_ffi/structs/mul_term_test.go deleted file mode 100644 index 942ccfb..0000000 --- a/gnark_backend_ffi/structs/mul_term_test.go +++ /dev/null @@ -1,51 +0,0 @@ -package structs - -import ( - "encoding/json" - "fmt" - "log" - "math/rand" - "testing" - - "github.com/stretchr/testify/assert" -) - -// TODO: Test error cases. - -func TestMulTermUnmarshalJSON(t *testing.T) { - encodedCoefficient, nonEncodedCoefficient := SampleEncodedFelt() - multiplicand := rand.Uint32() - multiplier := rand.Uint32() - mulTerm := fmt.Sprintf(`{"coefficient":"%s","multiplicand":%d,"multiplier":%d}`, encodedCoefficient, multiplicand, multiplier) - - var m MulTerm - err := json.Unmarshal([]byte(mulTerm), &m) - if err != nil { - log.Fatal(err) - } - - assert.NoError(t, err) - assert.Equal(t, nonEncodedCoefficient, m.Coefficient) - assert.Equal(t, multiplicand, m.Multiplicand) - assert.Equal(t, multiplier, m.Multiplier) -} - -func TestMulTermsUnmarshalJSON(t *testing.T) { - encodedCoefficient, nonEncodedCoefficient := SampleEncodedFelt() - multiplicand := rand.Uint32() - multiplier := rand.Uint32() - mulTerms := fmt.Sprintf(`[{"coefficient":"%s","multiplicand":%d,"multiplier":%d},{"coefficient":"%s","multiplicand":%d,"multiplier":%d}]`, encodedCoefficient, multiplicand, multiplier, encodedCoefficient, multiplicand, multiplier) - - var m []MulTerm - err := json.Unmarshal([]byte(mulTerms), &m) - if err != nil { - log.Fatal(err) - } - - assert.NoError(t, err) - for _, mulTerm := range m { - assert.Equal(t, nonEncodedCoefficient, mulTerm.Coefficient) - assert.Equal(t, multiplicand, mulTerm.Multiplicand) - assert.Equal(t, multiplier, mulTerm.Multiplier) - } -} diff --git a/gnark_backend_ffi/structs/raw_gate.go b/gnark_backend_ffi/structs/raw_gate.go deleted file mode 100644 index d70301c..0000000 --- a/gnark_backend_ffi/structs/raw_gate.go +++ /dev/null @@ -1,75 +0,0 @@ -package structs - -import ( - "encoding/json" - "log" - - fr_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/fr" -) - -type RawGate struct { - MulTerms []MulTerm - AddTerms []AddTerm - ConstantTerm fr_bn254.Element -} - -func (g *RawGate) UnmarshalJSON(data []byte) error { - var rawGateMap map[string]interface{} - err := json.Unmarshal(data, &rawGateMap) - if err != nil { - log.Fatal(err) - return err - } - - var mulTerms []MulTerm - var addTerms []AddTerm - var constantTerm fr_bn254.Element - - // Deserialize mul terms. - if mulTermsValue, ok := rawGateMap["mul_terms"].([]interface{}); ok { - mulTermsJSON, err := json.Marshal(mulTermsValue) - if err != nil { - log.Fatal(err) - return err - } - err = json.Unmarshal(mulTermsJSON, &mulTerms) - if err != nil { - log.Fatal(err) - return err - } - } else { - log.Fatal("Error: couldn't deserialize mul terms.") - return &json.UnmarshalTypeError{} - } - - // Deserialize add terms. - if addTermsValue, ok := rawGateMap["add_terms"].([]interface{}); ok { - addTermsJSON, err := json.Marshal(addTermsValue) - if err != nil { - log.Fatal(err) - return err - } - err = json.Unmarshal(addTermsJSON, &addTerms) - if err != nil { - log.Fatal(err) - return err - } - } else { - log.Fatal("Error: couldn't deserialize add terms.") - return &json.UnmarshalTypeError{} - } - - // Deserialize constant term. - if encodedConstantTerm, ok := rawGateMap["constant_term"].(string); ok { - constantTerm = DeserializeFelt(encodedConstantTerm) - } else { - log.Fatal("Error: coefficient is not a felt.") - return &json.UnmarshalTypeError{} - } - - g.MulTerms = mulTerms - g.AddTerms = addTerms - g.ConstantTerm = constantTerm - - return nil -} diff --git a/gnark_backend_ffi/structs/raw_gate_test.go b/gnark_backend_ffi/structs/raw_gate_test.go deleted file mode 100644 index a95587e..0000000 --- a/gnark_backend_ffi/structs/raw_gate_test.go +++ /dev/null @@ -1,60 +0,0 @@ -package structs - -import ( - "encoding/json" - "fmt" - "log" - "math/rand" - "testing" - - "github.com/stretchr/testify/assert" -) - -// TODO: Test error cases. - -func TestRawGateTermUnmarshalJSON(t *testing.T) { - encodedCoefficient, _ := SampleEncodedFelt() - multiplicand := rand.Uint32() - multiplier := rand.Uint32() - sum := rand.Uint32() - mulTerms := fmt.Sprintf(`[{"coefficient":"%s","multiplicand":%d,"multiplier":%d},{"coefficient":"%s","multiplicand":%d,"multiplier":%d}]`, encodedCoefficient, multiplicand, multiplier, encodedCoefficient, multiplicand, multiplier) - addTerms := fmt.Sprintf(`[{"coefficient":"%s","sum":%d},{"coefficient":"%s","sum":%d}]`, encodedCoefficient, sum, encodedCoefficient, sum) - encodedConstantTerm, nonEncodedConstantTerm := SampleEncodedFelt() - rawGate := fmt.Sprintf(`{"mul_terms":%s,"add_terms":%s,"constant_term":"%s"}`, mulTerms, addTerms, encodedConstantTerm) - - var r RawGate - err := json.Unmarshal([]byte(rawGate), &r) - if err != nil { - log.Fatal(err) - } - - assert.NoError(t, err) - assert.Equal(t, UncheckedDeserializeMulTerms(mulTerms), r.MulTerms) - assert.Equal(t, UncheckedDeserializeAddTerms(addTerms), r.AddTerms) - assert.Equal(t, nonEncodedConstantTerm, r.ConstantTerm) -} - -func TestRawGatesTermUnmarshalJSON(t *testing.T) { - encodedCoefficient, _ := SampleEncodedFelt() - multiplicand := rand.Uint32() - multiplier := rand.Uint32() - sum := rand.Uint32() - mulTerms := fmt.Sprintf(`[{"coefficient":"%s","multiplicand":%d,"multiplier":%d},{"coefficient":"%s","multiplicand":%d,"multiplier":%d}]`, encodedCoefficient, multiplicand, multiplier, encodedCoefficient, multiplicand, multiplier) - addTerms := fmt.Sprintf(`[{"coefficient":"%s","sum":%d},{"coefficient":"%s","sum":%d}]`, encodedCoefficient, sum, encodedCoefficient, sum) - encodedConstantTerm, nonEncodedConstantTerm := SampleEncodedFelt() - rawGate := fmt.Sprintf(`{"mul_terms":%s,"add_terms":%s,"constant_term":"%s"}`, mulTerms, addTerms, encodedConstantTerm) - rawGates := fmt.Sprintf(`[%s,%s]`, rawGate, rawGate) - - var r []RawGate - err := json.Unmarshal([]byte(rawGates), &r) - if err != nil { - log.Fatal(err) - } - - assert.NoError(t, err) - for _, rawGate := range r { - assert.Equal(t, UncheckedDeserializeMulTerms(mulTerms), rawGate.MulTerms) - assert.Equal(t, UncheckedDeserializeAddTerms(addTerms), rawGate.AddTerms) - assert.Equal(t, nonEncodedConstantTerm, rawGate.ConstantTerm) - } -} diff --git a/gnark_backend_ffi/structs/raw_r1cs.go b/gnark_backend_ffi/structs/raw_r1cs.go deleted file mode 100644 index 8a91ea4..0000000 --- a/gnark_backend_ffi/structs/raw_r1cs.go +++ /dev/null @@ -1,96 +0,0 @@ -package structs - -import ( - "encoding/json" - "log" - - fr_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/fr" -) - -type RawR1CS struct { - Gates []RawGate - PublicInputs Witnesses - Values fr_bn254.Vector - NumVariables uint64 - NumConstraints uint64 -} - -func (r *RawR1CS) UnmarshalJSON(data []byte) error { - var rawR1CSMap map[string]interface{} - err := json.Unmarshal(data, &rawR1CSMap) - if err != nil { - log.Fatal(err) - return err - } - - var gates []RawGate - var publicInputs Witnesses - var values fr_bn254.Vector - var numVariables uint64 - var numConstraints uint64 - - // Deserialize gates. - if gatesValue, ok := rawR1CSMap["gates"].([]interface{}); ok { - gatesJSON, err := json.Marshal(gatesValue) - if err != nil { - log.Fatal(err) - return err - } - err = json.Unmarshal(gatesJSON, &gates) - if err != nil { - log.Fatal(err) - return err - } - } else { - log.Fatal("Error: couldn't deserialize raw gates.") - return &json.UnmarshalTypeError{} - } - - if publicInputsValue, ok := rawR1CSMap["public_inputs"].([]interface{}); ok { - publicInputsJSON, err := json.Marshal(publicInputsValue) - if err != nil { - log.Fatal(err) - return err - } - err = json.Unmarshal(publicInputsJSON, &publicInputs) - if err != nil { - log.Fatal(err) - return err - } - } else { - log.Fatal("Error: couldn't deserialize public inputs.") - return &json.UnmarshalTypeError{} - } - - // Deserialize values. - if encodedValues, ok := rawR1CSMap["values"].(string); ok { - values = DeserializeFelts(encodedValues) - } else { - log.Fatal("Error: couldn't deserialize values.") - return &json.UnmarshalTypeError{} - } - - // Deserialize num_variables. - if numVariablesValue, ok := rawR1CSMap["num_variables"].(float64); ok { - numVariables = uint64(numVariablesValue) - } else { - log.Fatal("Error: couldn't deserialize num_variables.") - return &json.UnmarshalTypeError{} - } - - // Deserialize num_constraints. - if numConstraintsValue, ok := rawR1CSMap["num_constraints"].(float64); ok { - numConstraints = uint64(numConstraintsValue) - } else { - log.Fatal("Error: couldn't deserialize num_constraints.") - return &json.UnmarshalTypeError{} - } - - r.Gates = gates - r.PublicInputs = publicInputs - r.Values = values - r.NumVariables = numVariables - r.NumConstraints = numConstraints - - return nil -} diff --git a/gnark_backend_ffi/structs/raw_r1cs_test.go b/gnark_backend_ffi/structs/raw_r1cs_test.go deleted file mode 100644 index 30228d7..0000000 --- a/gnark_backend_ffi/structs/raw_r1cs_test.go +++ /dev/null @@ -1,39 +0,0 @@ -package structs - -import ( - "encoding/json" - "fmt" - "math/rand" - "testing" - - "github.com/stretchr/testify/assert" -) - -// TODO: Test error cases. - -func TestRawR1CSTermUnmarshalJSON(t *testing.T) { - encodedCoefficient, _ := SampleEncodedFelt() - multiplicand := rand.Uint32() - multiplier := rand.Uint32() - sum := rand.Uint32() - mulTerms := fmt.Sprintf(`[{"coefficient":"%s","multiplicand":%d,"multiplier":%d},{"coefficient":"%s","multiplicand":%d,"multiplier":%d}]`, encodedCoefficient, multiplicand, multiplier, encodedCoefficient, multiplicand, multiplier) - addTerms := fmt.Sprintf(`[{"coefficient":"%s","sum":%d},{"coefficient":"%s","sum":%d}]`, encodedCoefficient, sum, encodedCoefficient, sum) - encodedConstantTerm, _ := SampleEncodedFelt() - rawGate := fmt.Sprintf(`{"mul_terms":%s,"add_terms":%s,"constant_term":"%s"}`, mulTerms, addTerms, encodedConstantTerm) - rawGates := fmt.Sprintf(`[%s,%s]`, rawGate, rawGate) - publicInputs := fmt.Sprintf("[%d,%d,%d]", multiplicand, multiplier, sum) - encodedValues, nonEncodedValues := SampleEncodedFelts() - numVariables := uint64(10) - numConstraints := uint64(10) - rawR1CS := fmt.Sprintf(`{"gates":%s,"public_inputs":%s,"values":"%s","num_variables":%d,"num_constraints":%d}`, rawGates, publicInputs, encodedValues, numVariables, numConstraints) - - var r RawR1CS - err := json.Unmarshal([]byte(rawR1CS), &r) - - assert.NoError(t, err) - assert.Equal(t, UncheckedDeserializeRawGates(rawGates), r.Gates) - assert.Equal(t, Witnesses{multiplicand, multiplier, sum}, r.PublicInputs) - assert.Equal(t, nonEncodedValues, r.Values) - assert.Equal(t, numConstraints, r.NumConstraints) - assert.Equal(t, numVariables, r.NumVariables) -} From 5ec2b78bc8b8aaeaf952eaac635cd387d09aeed3 Mon Sep 17 00:00:00 2001 From: matias-gonz Date: Wed, 8 Mar 2023 11:31:01 -0300 Subject: [PATCH 100/118] Refactor plonk structs using interfaces --- .../structs/black_box_function_call_opcode.go | 9 ++++----- .../backend/plonk/structs/directive_opcode.go | 14 +------------- .../backend/plonk/structs/opcode.go | 15 +-------------- gnark_backend_ffi/main.go | 17 +++++++++-------- 4 files changed, 15 insertions(+), 40 deletions(-) diff --git a/gnark_backend_ffi/backend/plonk/structs/black_box_function_call_opcode.go b/gnark_backend_ffi/backend/plonk/structs/black_box_function_call_opcode.go index a21077d..a83c579 100644 --- a/gnark_backend_ffi/backend/plonk/structs/black_box_function_call_opcode.go +++ b/gnark_backend_ffi/backend/plonk/structs/black_box_function_call_opcode.go @@ -2,10 +2,10 @@ package structs import "gnark_backend_ffi/backend" -type BlackBoxFunction = int +type BlackBoxFunctionName = int const ( - AES BlackBoxFunction = iota + AES BlackBoxFunctionName = iota AND XOR RANGE @@ -27,9 +27,8 @@ type FunctionInput struct { NumBits uint32 } -type BlackBoxFunctionFields struct { - Opcode Opcode - Name BlackBoxFunction +type BlackBoxFunction struct { + Name BlackBoxFunctionName Inputs []FunctionInput Outputs backend.Witnesses } diff --git a/gnark_backend_ffi/backend/plonk/structs/directive_opcode.go b/gnark_backend_ffi/backend/plonk/structs/directive_opcode.go index 3c36632..266bcbb 100644 --- a/gnark_backend_ffi/backend/plonk/structs/directive_opcode.go +++ b/gnark_backend_ffi/backend/plonk/structs/directive_opcode.go @@ -2,19 +2,7 @@ package structs import "gnark_backend_ffi/backend" -type DirectiveOpcode = int - -const ( - // Inverts the value of x and stores it in the result variable - Invert DirectiveOpcode = iota -) - -type InvertFields struct { +type DirectiveInvert struct { X backend.Witness Result backend.Witness } - -type DirectiveFields struct { - Opcode DirectiveOpcode - Invert InvertFields -} diff --git a/gnark_backend_ffi/backend/plonk/structs/opcode.go b/gnark_backend_ffi/backend/plonk/structs/opcode.go index e6297fb..ddb5979 100644 --- a/gnark_backend_ffi/backend/plonk/structs/opcode.go +++ b/gnark_backend_ffi/backend/plonk/structs/opcode.go @@ -1,16 +1,3 @@ package structs -type Opcode = int - -const ( - Arithmetic Opcode = iota - BlackBoxFunctionCall - Directive -) - -type OpcodeFields struct { - Opcode Opcode - Arithmetic GateTerms - BlackBoxFunctionCall BlackBoxFunctionFields - Directive DirectiveFields -} +type Opcode interface{} diff --git a/gnark_backend_ffi/main.go b/gnark_backend_ffi/main.go index cbf46d2..3346d70 100644 --- a/gnark_backend_ffi/main.go +++ b/gnark_backend_ffi/main.go @@ -8,7 +8,8 @@ import ( "fmt" "log" - "gnark_backend_ffi/structs" + "gnark_backend_ffi/backend" + "gnark_backend_ffi/backend/groth16/structs" fr_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/fr" "github.com/consensys/gnark/backend/groth16" @@ -302,7 +303,7 @@ func Preprocess(rawR1CS string) (*C.char, *C.char) { //export IntegrationTestFeltSerialization func IntegrationTestFeltSerialization(encodedFelt string) *C.char { - deserializedFelt := structs.DeserializeFelt(encodedFelt) + deserializedFelt := backend.DeserializeFelt(encodedFelt) fmt.Printf("| GO |n%vn", deserializedFelt) // Serialize the felt. @@ -316,7 +317,7 @@ func IntegrationTestFeltSerialization(encodedFelt string) *C.char { //export IntegrationTestFeltsSerialization func IntegrationTestFeltsSerialization(encodedFelts string) *C.char { - deserializedFelts := structs.DeserializeFelts(encodedFelts) + deserializedFelts := backend.DeserializeFelts(encodedFelts) // Serialize the felt. serializedFelts, err := deserializedFelts.MarshalBinary() @@ -338,7 +339,7 @@ func IntegrationTestU64Serialization(number uint64) uint64 { //export IntegrationTestMulTermSerialization func IntegrationTestMulTermSerialization(mulTermJSON string) *C.char { - var deserializedMulTerm structs.MulTerm + var deserializedMulTerm backend.MulTerm err := json.Unmarshal([]byte(mulTermJSON), &deserializedMulTerm) if err != nil { log.Fatal(err) @@ -359,7 +360,7 @@ func IntegrationTestMulTermSerialization(mulTermJSON string) *C.char { //export IntegrationTestMulTermsSerialization func IntegrationTestMulTermsSerialization(mulTermsJSON string) *C.char { - var deserializedMulTerms []structs.MulTerm + var deserializedMulTerms []backend.MulTerm err := json.Unmarshal([]byte(mulTermsJSON), &deserializedMulTerms) if err != nil { log.Fatal(err) @@ -383,7 +384,7 @@ func IntegrationTestMulTermsSerialization(mulTermsJSON string) *C.char { //export IntegrationTestAddTermSerialization func IntegrationTestAddTermSerialization(addTermJSON string) *C.char { - var deserializedAddTerm structs.AddTerm + var deserializedAddTerm backend.AddTerm err := json.Unmarshal([]byte(addTermJSON), &deserializedAddTerm) if err != nil { log.Fatal(err) @@ -403,7 +404,7 @@ func IntegrationTestAddTermSerialization(addTermJSON string) *C.char { //export IntegrationTestAddTermsSerialization func IntegrationTestAddTermsSerialization(addTermsJSON string) *C.char { - var deserializedAddTerms []structs.AddTerm + var deserializedAddTerms []backend.AddTerm err := json.Unmarshal([]byte(addTermsJSON), &deserializedAddTerms) if err != nil { log.Fatal(err) @@ -575,7 +576,7 @@ func main() { // // Invalid // invalidRawR1CS := `{"gates":[{"add_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","sum":1},{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":2},{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":3}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[]},{"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":5}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","multiplicand":3,"multiplier":4}]},{"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":3}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","multiplicand":3,"multiplier":5}]},{"add_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","sum":5}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[]}],"num_constraints":11,"num_variables":7,"public_inputs":[2],"values":"00000006000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}` - // var r structs.RawR1CS + // var r backend.RawR1CS // err := json.Unmarshal([]byte(rawR1CS), &r) // if err != nil { // log.Fatal(err) From 1c4021a4cb160dbac7e4e6c20866a62cc3497474 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=ADas=20Ignacio=20Gonz=C3=A1lez?= Date: Wed, 8 Mar 2023 13:12:24 -0300 Subject: [PATCH 101/118] Arithmetic opcode (#52) * Add OpcodeArithmetic unmarshal * Change OpcodeArithmetic to ArithmeticOpcode * Update target test-go * Update gnark_backend_ffi/backend/plonk/structs/arithmetic_opcode_test.go Co-authored-by: Ivan Litteri <67517699+ilitteri@users.noreply.github.com> --------- Co-authored-by: Ivan Litteri <67517699+ilitteri@users.noreply.github.com> --- Makefile | 3 +- .../backend/groth16/structs/helpers.go | 26 -------- .../backend/groth16/structs/raw_gate_test.go | 8 +-- .../backend/groth16/structs/raw_r1cs_test.go | 6 +- .../plonk/structs/arithmetic_opcode.go | 65 ++++++++++++++++++- .../plonk/structs/arithmetic_opcode_test.go | 61 +++++++++++++++++ 6 files changed, 134 insertions(+), 35 deletions(-) create mode 100644 gnark_backend_ffi/backend/plonk/structs/arithmetic_opcode_test.go diff --git a/Makefile b/Makefile index 031f3c3..14c6079 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,8 @@ build-go: # Temporary solution for testing the only tests we have. We should test recurively. test-go: $ cd ${FFI_LIB_PATH}; \ - go test -run '' gnark_backend_ffi/structs + go test -run '' gnark_backend_ffi/backend/groth16/structs; \ + go test -run '' gnark_backend_ffi/backend/plonk/structs build: build-go $ RUSTFLAGS="-L${FFI_LIB_PATH}" cargo build diff --git a/gnark_backend_ffi/backend/groth16/structs/helpers.go b/gnark_backend_ffi/backend/groth16/structs/helpers.go index d525d5e..035d182 100644 --- a/gnark_backend_ffi/backend/groth16/structs/helpers.go +++ b/gnark_backend_ffi/backend/groth16/structs/helpers.go @@ -1,11 +1,8 @@ package structs import ( - "encoding/hex" "encoding/json" "log" - - fr_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/fr" ) func UncheckedDeserializeRawGate(rawGate string) RawGate { @@ -37,26 +34,3 @@ func UncheckedDeserializeRawR1CS(rawR1CS string) RawR1CS { return r } - -// Samples a felt and returns the encoded felt and the non-encoded felt. -func SampleEncodedFelt() (string, fr_bn254.Element) { - var felt fr_bn254.Element - felt.SetRandom() - - return hex.EncodeToString(felt.Marshal()), felt -} - -// Samples a felts vector and returns the encoded felts and the non-encoded felts vector. -func SampleEncodedFelts() (string, fr_bn254.Vector) { - var felt1 fr_bn254.Element - felt1.SetRandom() - - var felt2 fr_bn254.Element - felt2.SetRandom() - - felts := fr_bn254.Vector{felt1, felt2} - - binaryFelts, _ := felts.MarshalBinary() - - return hex.EncodeToString(binaryFelts), felts -} diff --git a/gnark_backend_ffi/backend/groth16/structs/raw_gate_test.go b/gnark_backend_ffi/backend/groth16/structs/raw_gate_test.go index 93447e4..887edd0 100644 --- a/gnark_backend_ffi/backend/groth16/structs/raw_gate_test.go +++ b/gnark_backend_ffi/backend/groth16/structs/raw_gate_test.go @@ -14,13 +14,13 @@ import ( // TODO: Test error cases. func TestRawGateTermUnmarshalJSON(t *testing.T) { - encodedCoefficient, _ := SampleEncodedFelt() + encodedCoefficient, _ := backend.SampleEncodedFelt() multiplicand := rand.Uint32() multiplier := rand.Uint32() sum := rand.Uint32() mulTerms := fmt.Sprintf(`[{"coefficient":"%s","multiplicand":%d,"multiplier":%d},{"coefficient":"%s","multiplicand":%d,"multiplier":%d}]`, encodedCoefficient, multiplicand, multiplier, encodedCoefficient, multiplicand, multiplier) addTerms := fmt.Sprintf(`[{"coefficient":"%s","sum":%d},{"coefficient":"%s","sum":%d}]`, encodedCoefficient, sum, encodedCoefficient, sum) - encodedConstantTerm, nonEncodedConstantTerm := SampleEncodedFelt() + encodedConstantTerm, nonEncodedConstantTerm := backend.SampleEncodedFelt() rawGate := fmt.Sprintf(`{"mul_terms":%s,"add_terms":%s,"constant_term":"%s"}`, mulTerms, addTerms, encodedConstantTerm) var r RawGate @@ -36,13 +36,13 @@ func TestRawGateTermUnmarshalJSON(t *testing.T) { } func TestRawGatesTermUnmarshalJSON(t *testing.T) { - encodedCoefficient, _ := SampleEncodedFelt() + encodedCoefficient, _ := backend.SampleEncodedFelt() multiplicand := rand.Uint32() multiplier := rand.Uint32() sum := rand.Uint32() mulTerms := fmt.Sprintf(`[{"coefficient":"%s","multiplicand":%d,"multiplier":%d},{"coefficient":"%s","multiplicand":%d,"multiplier":%d}]`, encodedCoefficient, multiplicand, multiplier, encodedCoefficient, multiplicand, multiplier) addTerms := fmt.Sprintf(`[{"coefficient":"%s","sum":%d},{"coefficient":"%s","sum":%d}]`, encodedCoefficient, sum, encodedCoefficient, sum) - encodedConstantTerm, nonEncodedConstantTerm := SampleEncodedFelt() + encodedConstantTerm, nonEncodedConstantTerm := backend.SampleEncodedFelt() rawGate := fmt.Sprintf(`{"mul_terms":%s,"add_terms":%s,"constant_term":"%s"}`, mulTerms, addTerms, encodedConstantTerm) rawGates := fmt.Sprintf(`[%s,%s]`, rawGate, rawGate) diff --git a/gnark_backend_ffi/backend/groth16/structs/raw_r1cs_test.go b/gnark_backend_ffi/backend/groth16/structs/raw_r1cs_test.go index 6a63e08..0ddd624 100644 --- a/gnark_backend_ffi/backend/groth16/structs/raw_r1cs_test.go +++ b/gnark_backend_ffi/backend/groth16/structs/raw_r1cs_test.go @@ -13,17 +13,17 @@ import ( // TODO: Test error cases. func TestRawR1CSTermUnmarshalJSON(t *testing.T) { - encodedCoefficient, _ := SampleEncodedFelt() + encodedCoefficient, _ := backend.SampleEncodedFelt() multiplicand := rand.Uint32() multiplier := rand.Uint32() sum := rand.Uint32() mulTerms := fmt.Sprintf(`[{"coefficient":"%s","multiplicand":%d,"multiplier":%d},{"coefficient":"%s","multiplicand":%d,"multiplier":%d}]`, encodedCoefficient, multiplicand, multiplier, encodedCoefficient, multiplicand, multiplier) addTerms := fmt.Sprintf(`[{"coefficient":"%s","sum":%d},{"coefficient":"%s","sum":%d}]`, encodedCoefficient, sum, encodedCoefficient, sum) - encodedConstantTerm, _ := SampleEncodedFelt() + encodedConstantTerm, _ := backend.SampleEncodedFelt() rawGate := fmt.Sprintf(`{"mul_terms":%s,"add_terms":%s,"constant_term":"%s"}`, mulTerms, addTerms, encodedConstantTerm) rawGates := fmt.Sprintf(`[%s,%s]`, rawGate, rawGate) publicInputs := fmt.Sprintf("[%d,%d,%d]", multiplicand, multiplier, sum) - encodedValues, nonEncodedValues := SampleEncodedFelts() + encodedValues, nonEncodedValues := backend.SampleEncodedFelts() numVariables := uint64(10) numConstraints := uint64(10) rawR1CS := fmt.Sprintf(`{"gates":%s,"public_inputs":%s,"values":"%s","num_variables":%d,"num_constraints":%d}`, rawGates, publicInputs, encodedValues, numVariables, numConstraints) diff --git a/gnark_backend_ffi/backend/plonk/structs/arithmetic_opcode.go b/gnark_backend_ffi/backend/plonk/structs/arithmetic_opcode.go index 1bffad5..347024f 100644 --- a/gnark_backend_ffi/backend/plonk/structs/arithmetic_opcode.go +++ b/gnark_backend_ffi/backend/plonk/structs/arithmetic_opcode.go @@ -1,13 +1,76 @@ package structs import ( + "encoding/json" "gnark_backend_ffi/backend" + "log" fr_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/fr" ) -type GateTerms struct { +type ArithmeticOpcode struct { MulTerms []backend.MulTerm AddTerms []backend.AddTerm qM fr_bn254.Element } + +func (g *ArithmeticOpcode) UnmarshalJSON(data []byte) error { + var gateMap map[string]interface{} + err := json.Unmarshal(data, &gateMap) + if err != nil { + log.Print(err) + return err + } + + var mulTerms []backend.MulTerm + var addTerms []backend.AddTerm + var constantTerm fr_bn254.Element + + // Deserialize mul terms. + if mulTermsValue, ok := gateMap["mul_terms"].([]interface{}); ok { + mulTermsJSON, err := json.Marshal(mulTermsValue) + if err != nil { + log.Print(err) + return err + } + err = json.Unmarshal(mulTermsJSON, &mulTerms) + if err != nil { + log.Print(err) + return err + } + } else { + log.Print("Error: couldn't deserialize mul terms.") + return &json.UnmarshalTypeError{} + } + + // Deserialize add terms. + if addTermsValue, ok := gateMap["add_terms"].([]interface{}); ok { + addTermsJSON, err := json.Marshal(addTermsValue) + if err != nil { + log.Print(err) + return err + } + err = json.Unmarshal(addTermsJSON, &addTerms) + if err != nil { + log.Print(err) + return err + } + } else { + log.Print("Error: couldn't deserialize add terms.") + return &json.UnmarshalTypeError{} + } + + // Deserialize constant term. + if encodedConstantTerm, ok := gateMap["constant_term"].(string); ok { + constantTerm = backend.DeserializeFelt(encodedConstantTerm) + } else { + log.Print("Error: coefficient is not a felt.") + return &json.UnmarshalTypeError{} + } + + g.MulTerms = mulTerms + g.AddTerms = addTerms + g.qM = constantTerm + + return nil +} diff --git a/gnark_backend_ffi/backend/plonk/structs/arithmetic_opcode_test.go b/gnark_backend_ffi/backend/plonk/structs/arithmetic_opcode_test.go new file mode 100644 index 0000000..fcf3853 --- /dev/null +++ b/gnark_backend_ffi/backend/plonk/structs/arithmetic_opcode_test.go @@ -0,0 +1,61 @@ +package structs + +import ( + "encoding/json" + "fmt" + "gnark_backend_ffi/backend" + "log" + "math/rand" + "testing" + + "github.com/stretchr/testify/assert" +) + +// TODO: Test error cases. + +func TestArithmeticOpcodeUnmarshalJSON(t *testing.T) { + encodedCoefficient, _ := backend.SampleEncodedFelt() + multiplicand := rand.Uint32() + multiplier := rand.Uint32() + sum := rand.Uint32() + mulTerms := fmt.Sprintf(`[{"coefficient":"%s","multiplicand":%d,"multiplier":%d},{"coefficient":"%s","multiplicand":%d,"multiplier":%d}]`, encodedCoefficient, multiplicand, multiplier, encodedCoefficient, multiplicand, multiplier) + addTerms := fmt.Sprintf(`[{"coefficient":"%s","sum":%d},{"coefficient":"%s","sum":%d}]`, encodedCoefficient, sum, encodedCoefficient, sum) + encodedConstantTerm, nonEncodedConstantTerm := backend.SampleEncodedFelt() + arithmetic_opcode := fmt.Sprintf(`{"mul_terms":%s,"add_terms":%s,"constant_term":"%s"}`, mulTerms, addTerms, encodedConstantTerm) + + var r ArithmeticOpcode + err := json.Unmarshal([]byte(arithmetic_opcode), &r) + if err != nil { + log.Fatal(err) + } + + assert.NoError(t, err) + assert.Equal(t, backend.UncheckedDeserializeMulTerms(mulTerms), r.MulTerms) + assert.Equal(t, backend.UncheckedDeserializeAddTerms(addTerms), r.AddTerms) + assert.Equal(t, nonEncodedConstantTerm, r.qM) +} + +func TestArithmeticOpcodesTermUnmarshalJSON(t *testing.T) { + encodedCoefficient, _ := backend.SampleEncodedFelt() + multiplicand := rand.Uint32() + multiplier := rand.Uint32() + sum := rand.Uint32() + mulTerms := fmt.Sprintf(`[{"coefficient":"%s","multiplicand":%d,"multiplier":%d},{"coefficient":"%s","multiplicand":%d,"multiplier":%d}]`, encodedCoefficient, multiplicand, multiplier, encodedCoefficient, multiplicand, multiplier) + addTerms := fmt.Sprintf(`[{"coefficient":"%s","sum":%d},{"coefficient":"%s","sum":%d}]`, encodedCoefficient, sum, encodedCoefficient, sum) + encodedConstantTerm, nonEncodedConstantTerm := backend.SampleEncodedFelt() + arithmetic_opcode := fmt.Sprintf(`{"mul_terms":%s,"add_terms":%s,"constant_term":"%s"}`, mulTerms, addTerms, encodedConstantTerm) + arithmetic_opcodes := fmt.Sprintf(`[%s,%s]`, arithmetic_opcode, arithmetic_opcode) + + var r []ArithmeticOpcode + err := json.Unmarshal([]byte(arithmetic_opcodes), &r) + if err != nil { + log.Fatal(err) + } + + assert.NoError(t, err) + for _, op := range r { + assert.Equal(t, backend.UncheckedDeserializeMulTerms(mulTerms), op.MulTerms) + assert.Equal(t, backend.UncheckedDeserializeAddTerms(addTerms), op.AddTerms) + assert.Equal(t, nonEncodedConstantTerm, op.qM) + } +} From af76c56b1125f3ef25b72d31f475b2aad6814f42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=ADas=20Ignacio=20Gonz=C3=A1lez?= Date: Wed, 8 Mar 2023 13:26:42 -0300 Subject: [PATCH 102/118] Directive opcode (#53) * Add OpcodeArithmetic unmarshal * Change OpcodeArithmetic to ArithmeticOpcode * Update target test-go * Update gnark_backend_ffi/backend/plonk/structs/arithmetic_opcode_test.go Co-authored-by: Ivan Litteri <67517699+ilitteri@users.noreply.github.com> * Add directive_opcode --------- Co-authored-by: Ivan Litteri <67517699+ilitteri@users.noreply.github.com> --- .../backend/plonk/structs/directive_opcode.go | 84 ++++++++++++++++++- .../plonk/structs/directive_opcode_test.go | 46 ++++++++++ 2 files changed, 128 insertions(+), 2 deletions(-) create mode 100644 gnark_backend_ffi/backend/plonk/structs/directive_opcode_test.go diff --git a/gnark_backend_ffi/backend/plonk/structs/directive_opcode.go b/gnark_backend_ffi/backend/plonk/structs/directive_opcode.go index 266bcbb..9927f99 100644 --- a/gnark_backend_ffi/backend/plonk/structs/directive_opcode.go +++ b/gnark_backend_ffi/backend/plonk/structs/directive_opcode.go @@ -1,8 +1,88 @@ package structs -import "gnark_backend_ffi/backend" +import ( + "encoding/json" + "gnark_backend_ffi/backend" + "log" +) -type DirectiveInvert struct { +type DirectiveName = int + +const ( + Invert DirectiveName = iota +) + +type DirectiveOpcode struct { + Name DirectiveName + Directive Directive +} + +type Directive interface{} + +type InvertDirective struct { X backend.Witness Result backend.Witness } + +func (d *InvertDirective) UnmarshalJSON(data []byte) error { + var invertDirectiveMap map[string]interface{} + err := json.Unmarshal(data, &invertDirectiveMap) + if err != nil { + log.Print(err) + return err + } + + var X backend.Witness + var Result backend.Witness + + // Deserialize X. + if XValue, ok := invertDirectiveMap["x"].(float64); ok { + X = backend.Witness(XValue) + } else { + log.Fatal("Error: couldn't deserialize X.") + return &json.UnmarshalTypeError{} + } + + // Deserialize Result. + if ResultValue, ok := invertDirectiveMap["result"].(float64); ok { + Result = backend.Witness(ResultValue) + } else { + log.Fatal("Error: couldn't deserialize Result.") + return &json.UnmarshalTypeError{} + } + + d.X = X + d.Result = Result + + return nil +} + +func (d *DirectiveOpcode) UnmarshalJSON(data []byte) error { + var directiveMap map[string]interface{} + err := json.Unmarshal(data, &directiveMap) + if err != nil { + log.Fatal(err) + return err + } + + if invertDirectiveValue, ok := directiveMap["Invert"]; ok { + var dir InvertDirective + invertDirectiveJSON, err := json.Marshal(invertDirectiveValue) + if err != nil { + log.Print(err) + return err + } + err = json.Unmarshal(invertDirectiveJSON, &dir) + if err != nil { + log.Print(err) + return err + } + d.Name = Invert + d.Directive = dir + } else { + log.Print("Error: couldn't deserialize directive.") + return &json.UnmarshalTypeError{} + } + + return nil +} diff --git a/gnark_backend_ffi/backend/plonk/structs/directive_opcode_test.go b/gnark_backend_ffi/backend/plonk/structs/directive_opcode_test.go new file mode 100644 index 0000000..adaf037 --- /dev/null +++ b/gnark_backend_ffi/backend/plonk/structs/directive_opcode_test.go @@ -0,0 +1,46 @@ +package structs + +import ( + "encoding/json" + "fmt" + "log" + "math/rand" + "testing" + + "github.com/stretchr/testify/assert" +) + +// TODO: Test error cases. + +func TestInvertDirectiveUnmarshalJSON(t *testing.T) { + x := rand.Uint32() + result := rand.Uint32() + invertDirectiveJSON := fmt.Sprintf(`{"x":%d,"result":%d}`, x, result) + + var d InvertDirective + err := json.Unmarshal([]byte(invertDirectiveJSON), &d) + if err != nil { + log.Fatal(err) + } + + assert.NoError(t, err) + assert.Equal(t, x, d.X) + assert.Equal(t, result, d.Result) +} + +func TestDirectiveUnmarshalJSONInvertDirective(t *testing.T) { + x := rand.Uint32() + result := rand.Uint32() + invertDirectiveJSON := fmt.Sprintf(`{"Invert": {"x":%d,"result":%d}}`, x, result) + + var d DirectiveOpcode + err := json.Unmarshal([]byte(invertDirectiveJSON), &d) + if err != nil { + log.Fatal(err) + } + + assert.NoError(t, err) + assert.Equal(t, Invert, d.Name) + assert.Equal(t, x, d.Directive.(InvertDirective).X) + assert.Equal(t, result, d.Directive.(InvertDirective).Result) +} From 5dbf68cb839536da273843d6f590e3005ade5f95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=ADas=20Ignacio=20Gonz=C3=A1lez?= Date: Wed, 8 Mar 2023 15:43:39 -0300 Subject: [PATCH 103/118] Acir unmarshal (#54) * Add acit unmarshal * Add acir unmarshal test * Finish acir test --- .../backend/plonk/structs/acir.go | 66 ++++++++++++++++++- .../backend/plonk/structs/acir_test.go | 39 +++++++++++ .../backend/plonk/structs/helpers.go | 16 +++++ 3 files changed, 119 insertions(+), 2 deletions(-) create mode 100644 gnark_backend_ffi/backend/plonk/structs/acir_test.go create mode 100644 gnark_backend_ffi/backend/plonk/structs/helpers.go diff --git a/gnark_backend_ffi/backend/plonk/structs/acir.go b/gnark_backend_ffi/backend/plonk/structs/acir.go index b65be04..43f50f1 100644 --- a/gnark_backend_ffi/backend/plonk/structs/acir.go +++ b/gnark_backend_ffi/backend/plonk/structs/acir.go @@ -1,9 +1,71 @@ package structs -import "gnark_backend_ffi/backend" +import ( + "encoding/json" + "gnark_backend_ffi/backend" + "log" +) type ACIR struct { - CurrentWitness uint32 + CurrentWitness backend.Witness Opcodes []Opcode PublicInputs backend.Witnesses } + +func (a *ACIR) UnmarshalJSON(data []byte) error { + var acirMap map[string]interface{} + err := json.Unmarshal(data, &acirMap) + if err != nil { + log.Print(err) + return err + } + + var opcodes []Opcode + var publicInputs backend.Witnesses + var currentWitness uint32 + + if opcodesValue, ok := acirMap["opcodes"]; ok { + opcodesJSON, err := json.Marshal(opcodesValue) + if err != nil { + log.Print(err) + return err + } + err = json.Unmarshal(opcodesJSON, &opcodes) + if err != nil { + log.Print(err) + return err + } + } else { + log.Print("Error: couldn't deserialize opcodes.") + return &json.UnmarshalTypeError{} + } + + if publicInputsValue, ok := acirMap["public_inputs"].([]interface{}); ok { + publicInputsJSON, err := json.Marshal(publicInputsValue) + if err != nil { + log.Print(err) + return err + } + err = json.Unmarshal(publicInputsJSON, &publicInputs) + if err != nil { + log.Print(err) + return err + } + } else { + log.Print("Error: couldn't deserialize public inputs.") + return &json.UnmarshalTypeError{} + } + + if currentWitnessValue, ok := acirMap["current_witness_index"].(float64); ok { + currentWitness = uint32(currentWitnessValue) + } else { + log.Print("Error: couldn't deserialize current witness.") + return &json.UnmarshalTypeError{} + } + + a.CurrentWitness = currentWitness + a.Opcodes = opcodes + a.PublicInputs = publicInputs + + return nil +} diff --git a/gnark_backend_ffi/backend/plonk/structs/acir_test.go b/gnark_backend_ffi/backend/plonk/structs/acir_test.go new file mode 100644 index 0000000..3eedab8 --- /dev/null +++ b/gnark_backend_ffi/backend/plonk/structs/acir_test.go @@ -0,0 +1,39 @@ +package structs + +import ( + "encoding/json" + "fmt" + "gnark_backend_ffi/backend" + "math/rand" + "testing" + + "github.com/stretchr/testify/assert" +) + +// TODO: Test error cases. + +func TestACIRUnmarshalJSON(t *testing.T) { + encodedCoefficient, _ := backend.SampleEncodedFelt() + multiplicand := rand.Uint32() + multiplier := rand.Uint32() + sum := rand.Uint32() + mulTerms := fmt.Sprintf(`[{"coefficient":"%s","multiplicand":%d,"multiplier":%d},{"coefficient":"%s","multiplicand":%d,"multiplier":%d}]`, encodedCoefficient, multiplicand, multiplier, encodedCoefficient, multiplicand, multiplier) + addTerms := fmt.Sprintf(`[{"coefficient":"%s","sum":%d},{"coefficient":"%s","sum":%d}]`, encodedCoefficient, sum, encodedCoefficient, sum) + encodedConstantTerm, _ := backend.SampleEncodedFelt() + arithmetic_opcode := fmt.Sprintf(`{"mul_terms":%s,"add_terms":%s,"constant_term":"%s"}`, mulTerms, addTerms, encodedConstantTerm) + x := rand.Uint32() + result := rand.Uint32() + invertDirective := fmt.Sprintf(`{"Invert": {"x":%d,"result":%d}}`, x, result) + opcodes := fmt.Sprintf(`[%s,%s]`, arithmetic_opcode, invertDirective) + publicInputs := fmt.Sprintf("[%d,%d,%d]", multiplicand, multiplier, sum) + currentWitness := uint32(1) + acirJson := fmt.Sprintf(`{"current_witness_index": %d, "opcodes": %s, "public_inputs": %s}`, currentWitness, opcodes, publicInputs) + + var a ACIR + err := json.Unmarshal([]byte(acirJson), &a) + + assert.NoError(t, err) + assert.Equal(t, currentWitness, a.CurrentWitness) + assert.Equal(t, UncheckedDeserializeOpcodes(opcodes), a.Opcodes) + assert.Equal(t, backend.Witnesses{multiplicand, multiplier, sum}, a.PublicInputs) +} diff --git a/gnark_backend_ffi/backend/plonk/structs/helpers.go b/gnark_backend_ffi/backend/plonk/structs/helpers.go new file mode 100644 index 0000000..66bd85e --- /dev/null +++ b/gnark_backend_ffi/backend/plonk/structs/helpers.go @@ -0,0 +1,16 @@ +package structs + +import ( + "encoding/json" + "log" +) + +func UncheckedDeserializeOpcodes(opcodes string) []Opcode { + var o []Opcode + err := json.Unmarshal([]byte(opcodes), &o) + if err != nil { + log.Fatal(err) + } + + return o +} From 9dc228721129fe495910b91db0c798d6c2db5f87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Wed, 8 Mar 2023 16:35:44 -0300 Subject: [PATCH 104/118] Update Makefile --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 14c6079..86acd22 100644 --- a/Makefile +++ b/Makefile @@ -9,8 +9,8 @@ build-go: # Temporary solution for testing the only tests we have. We should test recurively. test-go: $ cd ${FFI_LIB_PATH}; \ - go test -run '' gnark_backend_ffi/backend/groth16/structs; \ - go test -run '' gnark_backend_ffi/backend/plonk/structs + go test -run '' gnark_backend_ffi/backend/groth16; \ + go test -run '' gnark_backend_ffi/backend/plonk build: build-go $ RUSTFLAGS="-L${FFI_LIB_PATH}" cargo build From cbdade7424e8e2bfdfe69679eda9b136854b68dd Mon Sep 17 00:00:00 2001 From: Ivan Litteri <67517699+ilitteri@users.noreply.github.com> Date: Wed, 8 Mar 2023 16:54:05 -0300 Subject: [PATCH 105/118] Refactor backend package (#56) * Refactor backend package * Update Makefile --- .../backend/groth16/{structs => }/helpers.go | 2 +- .../backend/groth16/{structs => }/raw_gate.go | 2 +- .../groth16/{structs => }/raw_gate_test.go | 2 +- .../backend/groth16/{structs => }/raw_r1cs.go | 2 +- .../groth16/{structs => }/raw_r1cs_test.go | 2 +- .../backend/plonk/{structs => }/acir.go | 2 +- .../backend/plonk/{structs => }/acir_test.go | 2 +- .../plonk/{structs => }/arithmetic_opcode.go | 2 +- .../{structs => }/arithmetic_opcode_test.go | 2 +- .../black_box_function_call_opcode.go | 2 +- .../plonk/{structs => }/directive_opcode.go | 2 +- .../{structs => }/directive_opcode_test.go | 2 +- .../backend/plonk/{structs => }/helpers.go | 2 +- .../backend/plonk/{structs => }/opcode.go | 2 +- gnark_backend_ffi/main.go | 20 +++++++++---------- 15 files changed, 24 insertions(+), 24 deletions(-) rename gnark_backend_ffi/backend/groth16/{structs => }/helpers.go (97%) rename gnark_backend_ffi/backend/groth16/{structs => }/raw_gate.go (99%) rename gnark_backend_ffi/backend/groth16/{structs => }/raw_gate_test.go (99%) rename gnark_backend_ffi/backend/groth16/{structs => }/raw_r1cs.go (99%) rename gnark_backend_ffi/backend/groth16/{structs => }/raw_r1cs_test.go (99%) rename gnark_backend_ffi/backend/plonk/{structs => }/acir.go (98%) rename gnark_backend_ffi/backend/plonk/{structs => }/acir_test.go (99%) rename gnark_backend_ffi/backend/plonk/{structs => }/arithmetic_opcode.go (99%) rename gnark_backend_ffi/backend/plonk/{structs => }/arithmetic_opcode_test.go (99%) rename gnark_backend_ffi/backend/plonk/{structs => }/black_box_function_call_opcode.go (97%) rename gnark_backend_ffi/backend/plonk/{structs => }/directive_opcode.go (99%) rename gnark_backend_ffi/backend/plonk/{structs => }/directive_opcode_test.go (98%) rename gnark_backend_ffi/backend/plonk/{structs => }/helpers.go (92%) rename gnark_backend_ffi/backend/plonk/{structs => }/opcode.go (60%) diff --git a/gnark_backend_ffi/backend/groth16/structs/helpers.go b/gnark_backend_ffi/backend/groth16/helpers.go similarity index 97% rename from gnark_backend_ffi/backend/groth16/structs/helpers.go rename to gnark_backend_ffi/backend/groth16/helpers.go index 035d182..7d72a2a 100644 --- a/gnark_backend_ffi/backend/groth16/structs/helpers.go +++ b/gnark_backend_ffi/backend/groth16/helpers.go @@ -1,4 +1,4 @@ -package structs +package groth16 import ( "encoding/json" diff --git a/gnark_backend_ffi/backend/groth16/structs/raw_gate.go b/gnark_backend_ffi/backend/groth16/raw_gate.go similarity index 99% rename from gnark_backend_ffi/backend/groth16/structs/raw_gate.go rename to gnark_backend_ffi/backend/groth16/raw_gate.go index dc7bef7..34d561c 100644 --- a/gnark_backend_ffi/backend/groth16/structs/raw_gate.go +++ b/gnark_backend_ffi/backend/groth16/raw_gate.go @@ -1,4 +1,4 @@ -package structs +package groth16 import ( "encoding/json" diff --git a/gnark_backend_ffi/backend/groth16/structs/raw_gate_test.go b/gnark_backend_ffi/backend/groth16/raw_gate_test.go similarity index 99% rename from gnark_backend_ffi/backend/groth16/structs/raw_gate_test.go rename to gnark_backend_ffi/backend/groth16/raw_gate_test.go index 887edd0..34233fb 100644 --- a/gnark_backend_ffi/backend/groth16/structs/raw_gate_test.go +++ b/gnark_backend_ffi/backend/groth16/raw_gate_test.go @@ -1,4 +1,4 @@ -package structs +package groth16 import ( "encoding/json" diff --git a/gnark_backend_ffi/backend/groth16/structs/raw_r1cs.go b/gnark_backend_ffi/backend/groth16/raw_r1cs.go similarity index 99% rename from gnark_backend_ffi/backend/groth16/structs/raw_r1cs.go rename to gnark_backend_ffi/backend/groth16/raw_r1cs.go index 92aa2d5..f368387 100644 --- a/gnark_backend_ffi/backend/groth16/structs/raw_r1cs.go +++ b/gnark_backend_ffi/backend/groth16/raw_r1cs.go @@ -1,4 +1,4 @@ -package structs +package groth16 import ( "encoding/json" diff --git a/gnark_backend_ffi/backend/groth16/structs/raw_r1cs_test.go b/gnark_backend_ffi/backend/groth16/raw_r1cs_test.go similarity index 99% rename from gnark_backend_ffi/backend/groth16/structs/raw_r1cs_test.go rename to gnark_backend_ffi/backend/groth16/raw_r1cs_test.go index 0ddd624..b2ca76d 100644 --- a/gnark_backend_ffi/backend/groth16/structs/raw_r1cs_test.go +++ b/gnark_backend_ffi/backend/groth16/raw_r1cs_test.go @@ -1,4 +1,4 @@ -package structs +package groth16 import ( "encoding/json" diff --git a/gnark_backend_ffi/backend/plonk/structs/acir.go b/gnark_backend_ffi/backend/plonk/acir.go similarity index 98% rename from gnark_backend_ffi/backend/plonk/structs/acir.go rename to gnark_backend_ffi/backend/plonk/acir.go index 43f50f1..895839a 100644 --- a/gnark_backend_ffi/backend/plonk/structs/acir.go +++ b/gnark_backend_ffi/backend/plonk/acir.go @@ -1,4 +1,4 @@ -package structs +package groth16 import ( "encoding/json" diff --git a/gnark_backend_ffi/backend/plonk/structs/acir_test.go b/gnark_backend_ffi/backend/plonk/acir_test.go similarity index 99% rename from gnark_backend_ffi/backend/plonk/structs/acir_test.go rename to gnark_backend_ffi/backend/plonk/acir_test.go index 3eedab8..a5ef0d8 100644 --- a/gnark_backend_ffi/backend/plonk/structs/acir_test.go +++ b/gnark_backend_ffi/backend/plonk/acir_test.go @@ -1,4 +1,4 @@ -package structs +package groth16 import ( "encoding/json" diff --git a/gnark_backend_ffi/backend/plonk/structs/arithmetic_opcode.go b/gnark_backend_ffi/backend/plonk/arithmetic_opcode.go similarity index 99% rename from gnark_backend_ffi/backend/plonk/structs/arithmetic_opcode.go rename to gnark_backend_ffi/backend/plonk/arithmetic_opcode.go index 347024f..a19383b 100644 --- a/gnark_backend_ffi/backend/plonk/structs/arithmetic_opcode.go +++ b/gnark_backend_ffi/backend/plonk/arithmetic_opcode.go @@ -1,4 +1,4 @@ -package structs +package groth16 import ( "encoding/json" diff --git a/gnark_backend_ffi/backend/plonk/structs/arithmetic_opcode_test.go b/gnark_backend_ffi/backend/plonk/arithmetic_opcode_test.go similarity index 99% rename from gnark_backend_ffi/backend/plonk/structs/arithmetic_opcode_test.go rename to gnark_backend_ffi/backend/plonk/arithmetic_opcode_test.go index fcf3853..4adafc0 100644 --- a/gnark_backend_ffi/backend/plonk/structs/arithmetic_opcode_test.go +++ b/gnark_backend_ffi/backend/plonk/arithmetic_opcode_test.go @@ -1,4 +1,4 @@ -package structs +package groth16 import ( "encoding/json" diff --git a/gnark_backend_ffi/backend/plonk/structs/black_box_function_call_opcode.go b/gnark_backend_ffi/backend/plonk/black_box_function_call_opcode.go similarity index 97% rename from gnark_backend_ffi/backend/plonk/structs/black_box_function_call_opcode.go rename to gnark_backend_ffi/backend/plonk/black_box_function_call_opcode.go index a83c579..3bb8b81 100644 --- a/gnark_backend_ffi/backend/plonk/structs/black_box_function_call_opcode.go +++ b/gnark_backend_ffi/backend/plonk/black_box_function_call_opcode.go @@ -1,4 +1,4 @@ -package structs +package groth16 import "gnark_backend_ffi/backend" diff --git a/gnark_backend_ffi/backend/plonk/structs/directive_opcode.go b/gnark_backend_ffi/backend/plonk/directive_opcode.go similarity index 99% rename from gnark_backend_ffi/backend/plonk/structs/directive_opcode.go rename to gnark_backend_ffi/backend/plonk/directive_opcode.go index 9927f99..80e4590 100644 --- a/gnark_backend_ffi/backend/plonk/structs/directive_opcode.go +++ b/gnark_backend_ffi/backend/plonk/directive_opcode.go @@ -1,4 +1,4 @@ -package structs +package groth16 import ( "encoding/json" diff --git a/gnark_backend_ffi/backend/plonk/structs/directive_opcode_test.go b/gnark_backend_ffi/backend/plonk/directive_opcode_test.go similarity index 98% rename from gnark_backend_ffi/backend/plonk/structs/directive_opcode_test.go rename to gnark_backend_ffi/backend/plonk/directive_opcode_test.go index adaf037..3584a99 100644 --- a/gnark_backend_ffi/backend/plonk/structs/directive_opcode_test.go +++ b/gnark_backend_ffi/backend/plonk/directive_opcode_test.go @@ -1,4 +1,4 @@ -package structs +package groth16 import ( "encoding/json" diff --git a/gnark_backend_ffi/backend/plonk/structs/helpers.go b/gnark_backend_ffi/backend/plonk/helpers.go similarity index 92% rename from gnark_backend_ffi/backend/plonk/structs/helpers.go rename to gnark_backend_ffi/backend/plonk/helpers.go index 66bd85e..8b287b2 100644 --- a/gnark_backend_ffi/backend/plonk/structs/helpers.go +++ b/gnark_backend_ffi/backend/plonk/helpers.go @@ -1,4 +1,4 @@ -package structs +package groth16 import ( "encoding/json" diff --git a/gnark_backend_ffi/backend/plonk/structs/opcode.go b/gnark_backend_ffi/backend/plonk/opcode.go similarity index 60% rename from gnark_backend_ffi/backend/plonk/structs/opcode.go rename to gnark_backend_ffi/backend/plonk/opcode.go index ddb5979..c27faa3 100644 --- a/gnark_backend_ffi/backend/plonk/structs/opcode.go +++ b/gnark_backend_ffi/backend/plonk/opcode.go @@ -1,3 +1,3 @@ -package structs +package groth16 type Opcode interface{} diff --git a/gnark_backend_ffi/main.go b/gnark_backend_ffi/main.go index 3346d70..89b0eab 100644 --- a/gnark_backend_ffi/main.go +++ b/gnark_backend_ffi/main.go @@ -9,7 +9,7 @@ import ( "log" "gnark_backend_ffi/backend" - "gnark_backend_ffi/backend/groth16/structs" + groth16_backend "gnark_backend_ffi/backend/groth16" fr_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/fr" "github.com/consensys/gnark/backend/groth16" @@ -18,7 +18,7 @@ import ( cs_bn254 "github.com/consensys/gnark/constraint/bn254" ) -func buildR1CS(r structs.RawR1CS) (*cs_bn254.R1CS, fr_bn254.Vector, fr_bn254.Vector) { +func buildR1CS(r groth16_backend.RawR1CS) (*cs_bn254.R1CS, fr_bn254.Vector, fr_bn254.Vector) { // Create R1CS. r1cs := cs_bn254.NewR1CS(int(r.NumConstraints)) @@ -110,7 +110,7 @@ func buildWitnesses(r1cs *cs_bn254.R1CS, publicVariables fr_bn254.Vector, privat //export ProveWithMeta func ProveWithMeta(rawR1CS string) *C.char { // Deserialize rawR1CS. - var r structs.RawR1CS + var r groth16_backend.RawR1CS err := json.Unmarshal([]byte(rawR1CS), &r) if err != nil { log.Fatal(err) @@ -143,7 +143,7 @@ func ProveWithMeta(rawR1CS string) *C.char { //export ProveWithPK func ProveWithPK(rawR1CS string, encodedProvingKey string) *C.char { // Deserialize rawR1CS. - var r structs.RawR1CS + var r groth16_backend.RawR1CS err := json.Unmarshal([]byte(rawR1CS), &r) if err != nil { log.Fatal(err) @@ -181,7 +181,7 @@ func ProveWithPK(rawR1CS string, encodedProvingKey string) *C.char { //export VerifyWithMeta func VerifyWithMeta(rawR1CS string, encodedProof string) bool { // Deserialize rawR1CS. - var r structs.RawR1CS + var r groth16_backend.RawR1CS err := json.Unmarshal([]byte(rawR1CS), &r) if err != nil { log.Fatal(err) @@ -225,7 +225,7 @@ func VerifyWithMeta(rawR1CS string, encodedProof string) bool { //export VerifyWithVK func VerifyWithVK(rawR1CS string, encodedProof string, encodedVerifyingKey string) bool { // Deserialize rawR1CS. - var r structs.RawR1CS + var r groth16_backend.RawR1CS err := json.Unmarshal([]byte(rawR1CS), &r) if err != nil { log.Fatal(err) @@ -274,7 +274,7 @@ func VerifyWithVK(rawR1CS string, encodedProof string, encodedVerifyingKey strin //export Preprocess func Preprocess(rawR1CS string) (*C.char, *C.char) { // Deserialize rawR1CS. - var r structs.RawR1CS + var r groth16_backend.RawR1CS err := json.Unmarshal([]byte(rawR1CS), &r) if err != nil { log.Fatal(err) @@ -427,7 +427,7 @@ func IntegrationTestAddTermsSerialization(addTermsJSON string) *C.char { //export IntegrationTestRawGateSerialization func IntegrationTestRawGateSerialization(rawGateJSON string) *C.char { - var deserializedRawGate structs.RawGate + var deserializedRawGate groth16_backend.RawGate err := json.Unmarshal([]byte(rawGateJSON), &deserializedRawGate) if err != nil { log.Fatal(err) @@ -449,7 +449,7 @@ func IntegrationTestRawGateSerialization(rawGateJSON string) *C.char { //export IntegrationTestRawGatesSerialization func IntegrationTestRawGatesSerialization(rawGatesJSON string) *C.char { - var deserializedRawGates []structs.RawGate + var deserializedRawGates []groth16_backend.RawGate err := json.Unmarshal([]byte(rawGatesJSON), &deserializedRawGates) if err != nil { log.Fatal(err) @@ -473,7 +473,7 @@ func IntegrationTestRawGatesSerialization(rawGatesJSON string) *C.char { //export IntegrationTestRawR1CSSerialization func IntegrationTestRawR1CSSerialization(rawR1CSJSON string) *C.char { - var deserializedRawR1CS structs.RawR1CS + var deserializedRawR1CS groth16_backend.RawR1CS err := json.Unmarshal([]byte(rawR1CSJSON), &deserializedRawR1CS) if err != nil { log.Fatal(err) From 8192777a0dc5f76dc33aac319607c08b5e2eb50e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Wed, 8 Mar 2023 18:55:13 -0300 Subject: [PATCH 106/118] Add ACIR JSON example --- gnark_backend_ffi/main.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gnark_backend_ffi/main.go b/gnark_backend_ffi/main.go index 89b0eab..726e45a 100644 --- a/gnark_backend_ffi/main.go +++ b/gnark_backend_ffi/main.go @@ -576,6 +576,8 @@ func main() { // // Invalid // invalidRawR1CS := `{"gates":[{"add_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","sum":1},{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":2},{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":3}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[]},{"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":5}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","multiplicand":3,"multiplier":4}]},{"add_terms":[{"coefficient":"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000","sum":3}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","multiplicand":3,"multiplier":5}]},{"add_terms":[{"coefficient":"0000000000000000000000000000000000000000000000000000000000000001","sum":5}],"constant_term":"0000000000000000000000000000000000000000000000000000000000000000","mul_terms":[]}],"num_constraints":11,"num_variables":7,"public_inputs":[2],"values":"00000006000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}` + // acir := `{"current_witness_index":6,"opcodes":[{"Arithmetic":{"linear_combinations":[["0000000000000000000000000000000000000000000000000000000000000001",1],["30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000",2],["30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000",3]],"mul_terms":[],"q_c":"0000000000000000000000000000000000000000000000000000000000000000"}},{"Directive":{"Invert":{"result":4,"x":3}}},{"Arithmetic":{"linear_combinations":[["30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000",5]],"mul_terms":[["0000000000000000000000000000000000000000000000000000000000000001",3,4]],"q_c":"0000000000000000000000000000000000000000000000000000000000000000"}},{"Arithmetic":{"linear_combinations":[["30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000",3]],"mul_terms":[["0000000000000000000000000000000000000000000000000000000000000001",3,5]],"q_c":"0000000000000000000000000000000000000000000000000000000000000000"}},{"Arithmetic":{"linear_combinations":[["0000000000000000000000000000000000000000000000000000000000000001",5]],"mul_terms":[],"q_c":"0000000000000000000000000000000000000000000000000000000000000000"}}],"public_inputs":[2]}` + // var r backend.RawR1CS // err := json.Unmarshal([]byte(rawR1CS), &r) // if err != nil { From 827a189971729b043603707d39f831ef30eb8902 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Wed, 8 Mar 2023 18:55:39 -0300 Subject: [PATCH 107/118] Implement buildSparseR1CS function --- gnark_backend_ffi/main.go | 73 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/gnark_backend_ffi/main.go b/gnark_backend_ffi/main.go index 726e45a..8f499c4 100644 --- a/gnark_backend_ffi/main.go +++ b/gnark_backend_ffi/main.go @@ -18,6 +18,79 @@ import ( cs_bn254 "github.com/consensys/gnark/constraint/bn254" ) +// qL⋅xa + qR⋅xb + qO⋅xc + qM⋅(xa⋅xb) + qC == 0 +func buildSparseR1CS(a plonk_backend.ACIR) { + sparseR1CS := cs_bn254.NewSparseR1CS(int(a.CurrentWitness) - 1) + + for _, opcode := range a.Opcodes { + if gate, ok := opcode.(plonk_backend.ArithmeticOpcode); ok { + var xa, xb, xc int + var qL, qR, qO, qC, qM constraint.Coeff + + // Case qM⋅(xa⋅xb) + if len(gate.MulTerms) == 0 { + mulTerm := gate.MulTerms[0] + qM = sparseR1CS.FromInterface(mulTerm.Coefficient) + xa = int(mulTerm.Multiplicand) + xb = int(mulTerm.Multiplier) + } + + // Case qO⋅xc + if len(gate.AddTerms) == 1 { + qOwOTerm := gate.AddTerms[0] + qO = sparseR1CS.FromInterface(qOwOTerm.Coefficient) + xc = int(qOwOTerm.Sum) + } + + // Case qL⋅xa + qR⋅xb + if len(gate.AddTerms) == 2 { + // qL⋅xa + qLwLTerm := gate.AddTerms[0] + qL = sparseR1CS.FromInterface(qLwLTerm.Coefficient) + xa = int(qLwLTerm.Sum) + // qR⋅xb + qRwRTerm := gate.AddTerms[1] + qR = sparseR1CS.FromInterface(qRwRTerm.Coefficient) + xb = int(qRwRTerm.Sum) + // qO⋅xc + qOwOTerm := gate.AddTerms[2] + qO = sparseR1CS.FromInterface(qOwOTerm.Coefficient) + xc = int(qOwOTerm.Sum) + } + + // Case qL⋅xa + qR⋅xb + qO⋅xc + if len(gate.AddTerms) == 2 { + // qL⋅xa + qLwLTerm := gate.AddTerms[0] + qL = sparseR1CS.FromInterface(qLwLTerm.Coefficient) + xa = int(qLwLTerm.Sum) + // qR⋅xb + qRwRTerm := gate.AddTerms[1] + qR = sparseR1CS.FromInterface(qRwRTerm.Coefficient) + xb = int(qRwRTerm.Sum) + } + + // Add the qC term + qC = sparseR1CS.FromInterface(gate.QC) + + K := sparseR1CS.MakeTerm(&qC, 0) + K.MarkConstant() + + constraint := constraint.SparseR1C{ + L: sparseR1CS.MakeTerm(&qL, xa), + R: sparseR1CS.MakeTerm(&qR, xb), + O: sparseR1CS.MakeTerm(&qO, xc), + M: [2]constraint.Term{sparseR1CS.MakeTerm(&qM, xa), sparseR1CS.MakeTerm(&qM, xb)}, + K: K.CoeffID(), + } + + sparseR1CS.AddConstraint(constraint) + } else { + log.Fatal("unhandled opcode") + } + } +} + func buildR1CS(r groth16_backend.RawR1CS) (*cs_bn254.R1CS, fr_bn254.Vector, fr_bn254.Vector) { // Create R1CS. r1cs := cs_bn254.NewR1CS(int(r.NumConstraints)) From 10e557f9900e373f0defbd1a5ad6d4f5afd04cb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Wed, 8 Mar 2023 18:55:53 -0300 Subject: [PATCH 108/118] Import plonk_backend --- gnark_backend_ffi/main.go | 1 + 1 file changed, 1 insertion(+) diff --git a/gnark_backend_ffi/main.go b/gnark_backend_ffi/main.go index 8f499c4..1af7d83 100644 --- a/gnark_backend_ffi/main.go +++ b/gnark_backend_ffi/main.go @@ -10,6 +10,7 @@ import ( "gnark_backend_ffi/backend" groth16_backend "gnark_backend_ffi/backend/groth16" + plonk_backend "gnark_backend_ffi/backend/plonk" fr_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/fr" "github.com/consensys/gnark/backend/groth16" From af74672a4da963de542a30361fd6decc63c02689 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Wed, 8 Mar 2023 18:56:03 -0300 Subject: [PATCH 109/118] Fix field visibility --- gnark_backend_ffi/backend/plonk/arithmetic_opcode.go | 4 ++-- gnark_backend_ffi/backend/plonk/arithmetic_opcode_test.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/gnark_backend_ffi/backend/plonk/arithmetic_opcode.go b/gnark_backend_ffi/backend/plonk/arithmetic_opcode.go index a19383b..7d5fcc7 100644 --- a/gnark_backend_ffi/backend/plonk/arithmetic_opcode.go +++ b/gnark_backend_ffi/backend/plonk/arithmetic_opcode.go @@ -11,7 +11,7 @@ import ( type ArithmeticOpcode struct { MulTerms []backend.MulTerm AddTerms []backend.AddTerm - qM fr_bn254.Element + QC fr_bn254.Element } func (g *ArithmeticOpcode) UnmarshalJSON(data []byte) error { @@ -70,7 +70,7 @@ func (g *ArithmeticOpcode) UnmarshalJSON(data []byte) error { g.MulTerms = mulTerms g.AddTerms = addTerms - g.qM = constantTerm + g.QC = constantTerm return nil } diff --git a/gnark_backend_ffi/backend/plonk/arithmetic_opcode_test.go b/gnark_backend_ffi/backend/plonk/arithmetic_opcode_test.go index 4adafc0..009a2d6 100644 --- a/gnark_backend_ffi/backend/plonk/arithmetic_opcode_test.go +++ b/gnark_backend_ffi/backend/plonk/arithmetic_opcode_test.go @@ -32,7 +32,7 @@ func TestArithmeticOpcodeUnmarshalJSON(t *testing.T) { assert.NoError(t, err) assert.Equal(t, backend.UncheckedDeserializeMulTerms(mulTerms), r.MulTerms) assert.Equal(t, backend.UncheckedDeserializeAddTerms(addTerms), r.AddTerms) - assert.Equal(t, nonEncodedConstantTerm, r.qM) + assert.Equal(t, nonEncodedConstantTerm, r.QC) } func TestArithmeticOpcodesTermUnmarshalJSON(t *testing.T) { @@ -56,6 +56,6 @@ func TestArithmeticOpcodesTermUnmarshalJSON(t *testing.T) { for _, op := range r { assert.Equal(t, backend.UncheckedDeserializeMulTerms(mulTerms), op.MulTerms) assert.Equal(t, backend.UncheckedDeserializeAddTerms(addTerms), op.AddTerms) - assert.Equal(t, nonEncodedConstantTerm, op.qM) + assert.Equal(t, nonEncodedConstantTerm, op.QC) } } From 11c07248dd498be21ed6ca26bb555f8b9fb558a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=ADas=20Ignacio=20Gonz=C3=A1lez?= Date: Thu, 9 Mar 2023 11:00:32 -0300 Subject: [PATCH 110/118] Plonk backend wrapper (#55) * Move errors * Move c_go_structures * Add prove with meta * Add prove_with_pk * Add verify_with_meta * Add verify_with_vk * Add preprocess * Add feature plonk * Move EC config * Remove unused config * Expose num_constraints() * Fix value serialization * Fix map from_felt --- Cargo.toml | 1 + .../{groth16 => }/c_go_structures.rs | 2 +- .../{groth16 => }/errors.rs | 0 .../groth16/acir_to_r1cs.rs | 24 +- src/gnark_backend_wrapper/groth16/mod.rs | 34 +-- src/gnark_backend_wrapper/mod.rs | 59 ++++- src/gnark_backend_wrapper/plonk/mod.rs | 228 ++++++++++++++++++ 7 files changed, 295 insertions(+), 53 deletions(-) rename src/gnark_backend_wrapper/{groth16 => }/c_go_structures.rs (89%) rename src/gnark_backend_wrapper/{groth16 => }/errors.rs (100%) create mode 100644 src/gnark_backend_wrapper/plonk/mod.rs diff --git a/Cargo.toml b/Cargo.toml index 2b1f83b..e10769b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,5 +32,6 @@ debug-assertions = true [features] default = ["bn254", "groth16"] groth16 = [] +plonk = [] bn254 = ["acvm/bn254"] bls12_381 = ["acvm/bls12_381"] diff --git a/src/gnark_backend_wrapper/groth16/c_go_structures.rs b/src/gnark_backend_wrapper/c_go_structures.rs similarity index 89% rename from src/gnark_backend_wrapper/groth16/c_go_structures.rs rename to src/gnark_backend_wrapper/c_go_structures.rs index 0509ee2..6c850a5 100644 --- a/src/gnark_backend_wrapper/groth16/c_go_structures.rs +++ b/src/gnark_backend_wrapper/c_go_structures.rs @@ -1,4 +1,4 @@ -use crate::gnark_backend_wrapper::groth16::GnarkBackendError; +use crate::gnark_backend_wrapper::GnarkBackendError; use std::ffi::CString; use std::os::raw::c_char; diff --git a/src/gnark_backend_wrapper/groth16/errors.rs b/src/gnark_backend_wrapper/errors.rs similarity index 100% rename from src/gnark_backend_wrapper/groth16/errors.rs rename to src/gnark_backend_wrapper/errors.rs diff --git a/src/gnark_backend_wrapper/groth16/acir_to_r1cs.rs b/src/gnark_backend_wrapper/groth16/acir_to_r1cs.rs index e5c455b..86012d2 100644 --- a/src/gnark_backend_wrapper/groth16/acir_to_r1cs.rs +++ b/src/gnark_backend_wrapper/groth16/acir_to_r1cs.rs @@ -1,9 +1,10 @@ -use super::{from_felt, Fr}; +use super::super::{from_felt, Fr}; use crate::acvm; use crate::gnark_backend_wrapper::groth16::serialize::{ deserialize_felt, deserialize_felts, serialize_felt, serialize_felts, }; use crate::gnark_backend_wrapper::groth16::GnarkBackendError; +use crate::gnark_backend_wrapper::num_constraints; use std::num::TryFromIntError; // AcirCircuit and AcirArithGate are R1CS-friendly structs. @@ -66,7 +67,7 @@ impl RawR1CS { acir: acvm::Circuit, values: Vec, ) -> Result { - let num_constraints: u64 = Self::num_constraints(&acir)? + let num_constraints: u64 = num_constraints(&acir)? .try_into() .map_err(|e: TryFromIntError| GnarkBackendError::Error(e.to_string()))?; // Currently non-arithmetic gates are not supported @@ -93,25 +94,6 @@ impl RawR1CS { num_constraints, }) } - - pub fn num_constraints(acir: &acvm::Circuit) -> Result { - // each multiplication term adds an extra constraint - let mut num_opcodes = acir.opcodes.len(); - - for opcode in acir.opcodes.iter() { - match opcode { - acvm::Opcode::Arithmetic(arith) => num_opcodes += arith.num_mul_terms() + 1, // plus one for the linear combination gate - acvm::Opcode::Directive(_) => (), - _ => { - return Err(GnarkBackendError::UnsupportedOpcodeError( - opcode.to_string(), - )) - } - } - } - - Ok(num_opcodes) - } } impl RawGate { diff --git a/src/gnark_backend_wrapper/groth16/mod.rs b/src/gnark_backend_wrapper/groth16/mod.rs index 328d6f2..0c13ea4 100644 --- a/src/gnark_backend_wrapper/groth16/mod.rs +++ b/src/gnark_backend_wrapper/groth16/mod.rs @@ -5,40 +5,14 @@ use std::num::TryFromIntError; use std::os::raw::{c_char, c_uchar}; mod acir_to_r1cs; -mod c_go_structures; -mod errors; mod serialize; +use crate::gnark_backend_wrapper::c_go_structures::{GoString, KeyPair}; +use crate::gnark_backend_wrapper::errors::GnarkBackendError; pub use crate::gnark_backend_wrapper::groth16::acir_to_r1cs::{AddTerm, MulTerm, RawGate, RawR1CS}; -pub use crate::gnark_backend_wrapper::groth16::c_go_structures::GoString; -use crate::gnark_backend_wrapper::groth16::c_go_structures::KeyPair; -use crate::gnark_backend_wrapper::groth16::errors::GnarkBackendError; +use crate::gnark_backend_wrapper::num_constraints; use crate::Gnark; -// Arkworks's types are generic for `Field` but Noir's types are concrete and -// its value depends on the feature flag. -cfg_if::cfg_if! { - if #[cfg(feature = "bn254")] { - pub use ark_bn254::{Bn254 as Curve, Fr}; - - // Converts a FieldElement to a Fr - // noir_field uses arkworks for bn254 - pub fn from_felt(felt: acvm::FieldElement) -> Fr { - felt.into_repr() - } - } else if #[cfg(feature = "bls12_381")] { - pub use ark_bls12_381::{Bls12_381 as Curve, Fr}; - - // Converts a FieldElement to a Fr - // noir_field uses arkworks for bls12_381 - pub fn from_felt(felt: FieldElement) -> Fr { - felt.into_repr() - } - } else { - compile_error!("please specify a field to compile with"); - } -} - extern "C" { fn VerifyWithMeta(rawr1cs: GoString, proof: GoString) -> c_uchar; fn ProveWithMeta(rawr1cs: GoString) -> *const c_char; @@ -164,7 +138,7 @@ pub fn verify_with_vk( } pub fn get_exact_circuit_size(circuit: &acvm::Circuit) -> Result { - let size: u32 = RawR1CS::num_constraints(circuit)? + let size: u32 = num_constraints(circuit)? .try_into() .map_err(|e: TryFromIntError| GnarkBackendError::Error(e.to_string()))?; Ok(size) diff --git a/src/gnark_backend_wrapper/mod.rs b/src/gnark_backend_wrapper/mod.rs index ca2c7bb..5e939a3 100644 --- a/src/gnark_backend_wrapper/mod.rs +++ b/src/gnark_backend_wrapper/mod.rs @@ -1,12 +1,69 @@ +mod errors; +pub use errors::GnarkBackendError; +mod c_go_structures; +use crate::acvm; +pub use c_go_structures::{GoString, KeyPair}; + +// Arkworks's types are generic for `Field` but Noir's types are concrete and +// its value depends on the feature flag. +cfg_if::cfg_if! { + if #[cfg(feature = "bn254")] { + pub use ark_bn254::{Bn254 as Curve, Fr}; + + // Converts a FieldElement to a Fr + // noir_field uses arkworks for bn254 + pub fn from_felt(felt: acvm::FieldElement) -> Fr { + felt.into_repr() + } + } else if #[cfg(feature = "bls12_381")] { + pub use ark_bls12_381::{Bls12_381 as Curve, Fr}; + + // Converts a FieldElement to a Fr + // noir_field uses arkworks for bls12_381 + pub fn from_felt(felt: FieldElement) -> Fr { + felt.into_repr() + } + } else { + compile_error!("please specify a field to compile with"); + } +} + cfg_if::cfg_if! { if #[cfg(feature = "groth16")] { mod groth16; - pub use groth16::{AddTerm, Fr, GoString, MulTerm, RawGate, RawR1CS}; + pub use groth16::{AddTerm, MulTerm, RawGate, RawR1CS}; pub use groth16::verify_with_meta; pub use groth16::prove_with_meta; pub use groth16::verify_with_vk; pub use groth16::prove_with_pk; pub use groth16::get_exact_circuit_size; pub use groth16::preprocess; + } else if #[cfg(feature = "plonk")] { + mod plonk; + pub use plonk::verify_with_meta; + pub use plonk::prove_with_meta; + pub use plonk::verify_with_vk; + pub use plonk::prove_with_pk; + pub use plonk::get_exact_circuit_size; + pub use plonk::preprocess; + } +} + +pub fn num_constraints(acir: &acvm::Circuit) -> Result { + // each multiplication term adds an extra constraint + let mut num_opcodes = acir.opcodes.len(); + + for opcode in acir.opcodes.iter() { + match opcode { + acvm::Opcode::Arithmetic(arith) => num_opcodes += arith.num_mul_terms() + 1, // plus one for the linear combination gate + acvm::Opcode::Directive(_) => (), + _ => { + return Err(GnarkBackendError::UnsupportedOpcodeError( + opcode.to_string(), + )) + } + } } + + Ok(num_opcodes) } diff --git a/src/gnark_backend_wrapper/plonk/mod.rs b/src/gnark_backend_wrapper/plonk/mod.rs new file mode 100644 index 0000000..dd91a8b --- /dev/null +++ b/src/gnark_backend_wrapper/plonk/mod.rs @@ -0,0 +1,228 @@ +use crate::acvm; +use std::collections::BTreeMap; +use std::ffi::{CStr, CString}; +use std::num::TryFromIntError; +use std::os::raw::{c_char, c_uchar}; + +use crate::gnark_backend_wrapper::c_go_structures::{GoString, KeyPair}; +use crate::gnark_backend_wrapper::errors::GnarkBackendError; +use crate::Gnark; + +extern "C" { + fn PlonkVerifyWithMeta(circuit: GoString, values: GoString, proof: GoString) -> c_uchar; + fn PlonkProveWithMeta(circuit: GoString, values: GoString) -> *const c_char; + fn PlonkVerifyWithVK(rawr1cs: GoString, proof: GoString, verifying_key: GoString) -> c_uchar; + fn PlonkProveWithPK( + circuit: GoString, + values: GoString, + proving_key: GoString, + ) -> *const c_char; + fn PlonkPreprocess(circuit: GoString, values: GoString) -> KeyPair; +} + +pub fn prove_with_meta( + circuit: acvm::Circuit, + values: Vec, +) -> Result, GnarkBackendError> { + // Serialize to json and then convert to GoString + let acir_json = serde_json::to_string(&circuit) + .map_err(|e| GnarkBackendError::SerializeCircuitError(e.to_string()))?; + let acir_c_str = CString::new(acir_json) + .map_err(|e| GnarkBackendError::SerializeCircuitError(e.to_string()))?; + let acir_go_string = GoString::try_from(&acir_c_str)?; + + let felts = values.iter().map(from_felt).collect(); + let felts_serialized = serialize_felts(felts).to_string(); + let felts_c_str = CString::new(felts_serialized) + .map_err(|e| GnarkBackendError::SerializeCircuitError(e.to_string()))?; + let values_go_string = GoString::try_from(&felts_c_str)?; + + let result: *const c_char = unsafe { PlonkProveWithMeta(acir_go_string, values_go_string) }; + let c_str = unsafe { CStr::from_ptr(result) }; + let bytes = c_str + .to_str() + .map_err(|e| GnarkBackendError::DeserializeProofError(e.to_string()))? + .as_bytes(); + + Ok(bytes.to_vec()) +} + +pub fn prove_with_pk( + circuit: &acvm::Circuit, + values: Vec, + proving_key: &[u8], +) -> Result, GnarkBackendError> { + // Serialize to json and then convert to GoString + let acir_json = serde_json::to_string(&circuit) + .map_err(|e| GnarkBackendError::SerializeCircuitError(e.to_string()))?; + let acir_c_str = CString::new(acir_json) + .map_err(|e| GnarkBackendError::SerializeCircuitError(e.to_string()))?; + let acir_go_string = GoString::try_from(&acir_c_str)?; + + let felts = values.iter().map(from_felt).collect(); + let felts_serialized = serialize_felts(felts).to_string(); + let felts_c_str = CString::new(felts_serialized) + .map_err(|e| GnarkBackendError::SerializeCircuitError(e.to_string()))?; + let values_go_string = GoString::try_from(&felts_c_str)?; + + let proving_key_serialized = hex::encode(proving_key); + let proving_key_c_str = CString::new(proving_key_serialized) + .map_err(|e| GnarkBackendError::SerializeKeyError(e.to_string()))?; + let proving_key_go_string = GoString::try_from(&proving_key_c_str) + .map_err(|e| GnarkBackendError::SerializeKeyError(e.to_string()))?; + + let proof: *const c_char = + unsafe { PlonkProveWithPK(circuit_go_string, values_go_string, proving_key_go_string) }; + let proof_c_str = unsafe { CStr::from_ptr(proof) }; + let proof_str = proof_c_str + .to_str() + .map_err(|e| GnarkBackendError::DeserializeProofError(e.to_string()))?; + let decoded_proof = hex::decode(proof_str) + .map_err(|e| GnarkBackendError::DeserializeProofError(e.to_string()))?; + + Ok(decoded_proof) +} + +pub fn verify_with_meta( + circuit: acvm::Circuit, + proof: &[u8], + public_inputs: &[acvm::FieldElement], +) -> Result { + // Serialize to json and then convert to GoString + let acir_json = serde_json::to_string(&circuit) + .map_err(|e| GnarkBackendError::SerializeCircuitError(e.to_string()))?; + let acir_c_str = CString::new(acir_json) + .map_err(|e| GnarkBackendError::SerializeCircuitError(e.to_string()))?; + let acir_go_string = GoString::try_from(&acir_c_str)?; + + let felts = values.iter().map(from_felt).collect(); + let felts_serialized = serialize_felts(felts).to_string(); + let felts_c_str = CString::new(felts_serialized) + .map_err(|e| GnarkBackendError::SerializeCircuitError(e.to_string()))?; + let values_go_string = GoString::try_from(&felts_c_str)?; + + let serialized_proof = String::from_utf8(proof.to_vec()) + .map_err(|e| GnarkBackendError::SerializeProofError(e.to_string()))?; + let c_str = CString::new(serialized_proof) + .map_err(|e| GnarkBackendError::SerializeProofError(e.to_string()))?; + let go_string_proof = GoString::try_from(&c_str)?; + + let result = + unsafe { PlonkVerifyWithMeta(circuit_go_string, values_go_string, go_string_proof) }; + match result { + 0 => Ok(false), + 1 => Ok(true), + _ => Err(GnarkBackendError::VerifyInvalidBoolError), + } +} + +pub fn verify_with_vk( + circuit: &acvm::Circuit, + proof: &[u8], + public_inputs: &[acvm::FieldElement], + verifying_key: &[u8], +) -> Result { + // Serialize to json and then convert to GoString + let acir_json = serde_json::to_string(&circuit) + .map_err(|e| GnarkBackendError::SerializeCircuitError(e.to_string()))?; + let acir_c_str = CString::new(acir_json) + .map_err(|e| GnarkBackendError::SerializeCircuitError(e.to_string()))?; + let acir_go_string = GoString::try_from(&acir_c_str)?; + + let felts = values.iter().map(from_felt).collect(); + let felts_serialized = serialize_felts(felts).to_string(); + let felts_c_str = CString::new(felts_serialized) + .map_err(|e| GnarkBackendError::SerializeCircuitError(e.to_string()))?; + let values_go_string = GoString::try_from(&felts_c_str)?; + + let proof_serialized = hex::encode(proof); + let proof_c_str = CString::new(proof_serialized) + .map_err(|e| GnarkBackendError::SerializeProofError(e.to_string()))?; + let proof_go_string = GoString::try_from(&proof_c_str)?; + + let verifying_key_serialized = hex::encode(verifying_key); + let verifying_key_c_str = CString::new(verifying_key_serialized) + .map_err(|e| GnarkBackendError::SerializeKeyError(e.to_string()))?; + let verifying_key_go_string = GoString::try_from(&verifying_key_c_str)?; + + let verifies = unsafe { + PlonkVerifyWithVK( + circuit_go_string, + values_go_string, + proof_go_string, + verifying_key_go_string, + ) + }; + match verifies { + 0 => Ok(false), + 1 => Ok(true), + _ => Err(GnarkBackendError::VerifyInvalidBoolError), + } +} + +pub fn get_exact_circuit_size(circuit: &acvm::Circuit) -> Result { + let size: u32 = num_constraints(circuit)? + .try_into() + .map_err(|e: TryFromIntError| GnarkBackendError::Error(e.to_string()))?; + Ok(size) +} + +pub fn preprocess(circuit: &acvm::Circuit) -> Result<(Vec, Vec), GnarkBackendError> { + let num_witnesses: usize = circuit + .num_vars() + .try_into() + .map_err(|e: TryFromIntError| GnarkBackendError::Error(e.to_string()))?; + let values = vec![acvm::FieldElement::from(rand::random::()); num_witnesses - 1]; + + // Serialize to json and then convert to GoString + let acir_json = serde_json::to_string(&circuit) + .map_err(|e| GnarkBackendError::SerializeCircuitError(e.to_string()))?; + let acir_c_str = CString::new(acir_json) + .map_err(|e| GnarkBackendError::SerializeCircuitError(e.to_string()))?; + let acir_go_string = GoString::try_from(&acir_c_str)?; + + let felts = values.iter().map(from_felt).collect(); + let felts_serialized = serialize_felts(felts).to_string(); + let felts_c_str = CString::new(felts_serialized) + .map_err(|e| GnarkBackendError::SerializeCircuitError(e.to_string()))?; + let values_go_string = GoString::try_from(&felts_c_str)?; + + let key_pair: KeyPair = unsafe { PlonkPreprocess(circuit_go_string, values_go_string) }; + + let proving_key_c_str = unsafe { CStr::from_ptr(key_pair.proving_key) }; + let proving_key_str = proving_key_c_str + .to_str() + .map_err(|e| GnarkBackendError::DeserializeKeyError(e.to_string()))?; + let decoded_proving_key = hex::decode(proving_key_str) + .map_err(|e| GnarkBackendError::DeserializeKeyError(e.to_string()))?; + + let verifying_key_c_str = unsafe { CStr::from_ptr(key_pair.verifying_key) }; + let verifying_key_str = verifying_key_c_str + .to_str() + .map_err(|e| GnarkBackendError::DeserializeKeyError(e.to_string()))?; + let decoded_verifying_key = hex::decode(verifying_key_str) + .map_err(|e| GnarkBackendError::DeserializeKeyError(e.to_string()))?; + + Ok((decoded_proving_key, decoded_verifying_key)) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_go_string_from_cstring() { + let string = "This works".to_owned(); + let c_str = CString::new(string.clone()).unwrap(); + let go_string = GoString::try_from(&c_str).unwrap(); + let deserialized_c_str = unsafe { CStr::from_ptr(go_string.ptr) }; + let deserialized_string = deserialized_c_str.to_str().unwrap().to_owned(); + assert_eq!(string, deserialized_string); + } + + #[test] + fn get_exact_circuit_size_should_return_zero_with_an_empty_circuit() { + let size = get_exact_circuit_size(&acvm::Circuit::default()).unwrap(); + assert_eq!(size, 0); + } +} From 0ce03a0e4e2d1a24b06762b40929269319f43ef5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Thu, 9 Mar 2023 11:15:28 -0300 Subject: [PATCH 111/118] Fix `buildSparseR1CS` --- gnark_backend_ffi/main.go | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/gnark_backend_ffi/main.go b/gnark_backend_ffi/main.go index 1af7d83..b621e89 100644 --- a/gnark_backend_ffi/main.go +++ b/gnark_backend_ffi/main.go @@ -20,7 +20,7 @@ import ( ) // qL⋅xa + qR⋅xb + qO⋅xc + qM⋅(xa⋅xb) + qC == 0 -func buildSparseR1CS(a plonk_backend.ACIR) { +func buildSparseR1CS(a plonk_backend.ACIR) *cs_bn254.SparseR1CS { sparseR1CS := cs_bn254.NewSparseR1CS(int(a.CurrentWitness) - 1) for _, opcode := range a.Opcodes { @@ -53,14 +53,10 @@ func buildSparseR1CS(a plonk_backend.ACIR) { qRwRTerm := gate.AddTerms[1] qR = sparseR1CS.FromInterface(qRwRTerm.Coefficient) xb = int(qRwRTerm.Sum) - // qO⋅xc - qOwOTerm := gate.AddTerms[2] - qO = sparseR1CS.FromInterface(qOwOTerm.Coefficient) - xc = int(qOwOTerm.Sum) } // Case qL⋅xa + qR⋅xb + qO⋅xc - if len(gate.AddTerms) == 2 { + if len(gate.AddTerms) == 3 { // qL⋅xa qLwLTerm := gate.AddTerms[0] qL = sparseR1CS.FromInterface(qLwLTerm.Coefficient) @@ -69,6 +65,10 @@ func buildSparseR1CS(a plonk_backend.ACIR) { qRwRTerm := gate.AddTerms[1] qR = sparseR1CS.FromInterface(qRwRTerm.Coefficient) xb = int(qRwRTerm.Sum) + // qO⋅xc + qOwOTerm := gate.AddTerms[2] + qO = sparseR1CS.FromInterface(qOwOTerm.Coefficient) + xc = int(qOwOTerm.Sum) } // Add the qC term @@ -87,9 +87,11 @@ func buildSparseR1CS(a plonk_backend.ACIR) { sparseR1CS.AddConstraint(constraint) } else { - log.Fatal("unhandled opcode") + log.Print("unhandled opcode:", opcode) } } + + return sparseR1CS } func buildR1CS(r groth16_backend.RawR1CS) (*cs_bn254.R1CS, fr_bn254.Vector, fr_bn254.Vector) { From 455d19a788637311318cc67251d1592fa73eb613 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=ADas=20Ignacio=20Gonz=C3=A1lez?= Date: Thu, 9 Mar 2023 11:29:29 -0300 Subject: [PATCH 112/118] Fix Arithmetic unmarshal (#57) --- gnark_backend_ffi/backend/plonk/acir_test.go | 3 +-- .../backend/plonk/arithmetic_opcode.go | 26 ++++++++++++++++--- .../backend/plonk/arithmetic_opcode_test.go | 11 ++------ 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/gnark_backend_ffi/backend/plonk/acir_test.go b/gnark_backend_ffi/backend/plonk/acir_test.go index a5ef0d8..30f4cd3 100644 --- a/gnark_backend_ffi/backend/plonk/acir_test.go +++ b/gnark_backend_ffi/backend/plonk/acir_test.go @@ -20,7 +20,7 @@ func TestACIRUnmarshalJSON(t *testing.T) { mulTerms := fmt.Sprintf(`[{"coefficient":"%s","multiplicand":%d,"multiplier":%d},{"coefficient":"%s","multiplicand":%d,"multiplier":%d}]`, encodedCoefficient, multiplicand, multiplier, encodedCoefficient, multiplicand, multiplier) addTerms := fmt.Sprintf(`[{"coefficient":"%s","sum":%d},{"coefficient":"%s","sum":%d}]`, encodedCoefficient, sum, encodedCoefficient, sum) encodedConstantTerm, _ := backend.SampleEncodedFelt() - arithmetic_opcode := fmt.Sprintf(`{"mul_terms":%s,"add_terms":%s,"constant_term":"%s"}`, mulTerms, addTerms, encodedConstantTerm) + arithmetic_opcode := fmt.Sprintf(`{"Arithmetic": {"mul_terms":%s,"linear_combinations":%s,"q_c":"%s"}}`, mulTerms, addTerms, encodedConstantTerm) x := rand.Uint32() result := rand.Uint32() invertDirective := fmt.Sprintf(`{"Invert": {"x":%d,"result":%d}}`, x, result) @@ -31,7 +31,6 @@ func TestACIRUnmarshalJSON(t *testing.T) { var a ACIR err := json.Unmarshal([]byte(acirJson), &a) - assert.NoError(t, err) assert.Equal(t, currentWitness, a.CurrentWitness) assert.Equal(t, UncheckedDeserializeOpcodes(opcodes), a.Opcodes) diff --git a/gnark_backend_ffi/backend/plonk/arithmetic_opcode.go b/gnark_backend_ffi/backend/plonk/arithmetic_opcode.go index 7d5fcc7..71359e8 100644 --- a/gnark_backend_ffi/backend/plonk/arithmetic_opcode.go +++ b/gnark_backend_ffi/backend/plonk/arithmetic_opcode.go @@ -15,12 +15,32 @@ type ArithmeticOpcode struct { } func (g *ArithmeticOpcode) UnmarshalJSON(data []byte) error { + var opcodeMap map[string]interface{} var gateMap map[string]interface{} - err := json.Unmarshal(data, &gateMap) + err := json.Unmarshal(data, &opcodeMap) if err != nil { log.Print(err) return err } + for k := range opcodeMap { + log.Print(k) + } + + if gateValue, ok := opcodeMap["Arithmetic"]; ok { + gateJSON, err := json.Marshal(gateValue) + if err != nil { + log.Print(err) + return err + } + err = json.Unmarshal(gateJSON, &gateMap) + if err != nil { + log.Print(err) + return err + } + } else { + log.Print("Error: couldn't deserialize gate.") + return &json.UnmarshalTypeError{} + } var mulTerms []backend.MulTerm var addTerms []backend.AddTerm @@ -44,7 +64,7 @@ func (g *ArithmeticOpcode) UnmarshalJSON(data []byte) error { } // Deserialize add terms. - if addTermsValue, ok := gateMap["add_terms"].([]interface{}); ok { + if addTermsValue, ok := gateMap["linear_combinations"].([]interface{}); ok { addTermsJSON, err := json.Marshal(addTermsValue) if err != nil { log.Print(err) @@ -61,7 +81,7 @@ func (g *ArithmeticOpcode) UnmarshalJSON(data []byte) error { } // Deserialize constant term. - if encodedConstantTerm, ok := gateMap["constant_term"].(string); ok { + if encodedConstantTerm, ok := gateMap["q_c"].(string); ok { constantTerm = backend.DeserializeFelt(encodedConstantTerm) } else { log.Print("Error: coefficient is not a felt.") diff --git a/gnark_backend_ffi/backend/plonk/arithmetic_opcode_test.go b/gnark_backend_ffi/backend/plonk/arithmetic_opcode_test.go index 009a2d6..59f699c 100644 --- a/gnark_backend_ffi/backend/plonk/arithmetic_opcode_test.go +++ b/gnark_backend_ffi/backend/plonk/arithmetic_opcode_test.go @@ -4,7 +4,6 @@ import ( "encoding/json" "fmt" "gnark_backend_ffi/backend" - "log" "math/rand" "testing" @@ -21,13 +20,10 @@ func TestArithmeticOpcodeUnmarshalJSON(t *testing.T) { mulTerms := fmt.Sprintf(`[{"coefficient":"%s","multiplicand":%d,"multiplier":%d},{"coefficient":"%s","multiplicand":%d,"multiplier":%d}]`, encodedCoefficient, multiplicand, multiplier, encodedCoefficient, multiplicand, multiplier) addTerms := fmt.Sprintf(`[{"coefficient":"%s","sum":%d},{"coefficient":"%s","sum":%d}]`, encodedCoefficient, sum, encodedCoefficient, sum) encodedConstantTerm, nonEncodedConstantTerm := backend.SampleEncodedFelt() - arithmetic_opcode := fmt.Sprintf(`{"mul_terms":%s,"add_terms":%s,"constant_term":"%s"}`, mulTerms, addTerms, encodedConstantTerm) + arithmetic_opcode := fmt.Sprintf(`{"Arithmetic": {"mul_terms":%s,"linear_combinations":%s,"q_c":"%s"}}`, mulTerms, addTerms, encodedConstantTerm) var r ArithmeticOpcode err := json.Unmarshal([]byte(arithmetic_opcode), &r) - if err != nil { - log.Fatal(err) - } assert.NoError(t, err) assert.Equal(t, backend.UncheckedDeserializeMulTerms(mulTerms), r.MulTerms) @@ -43,14 +39,11 @@ func TestArithmeticOpcodesTermUnmarshalJSON(t *testing.T) { mulTerms := fmt.Sprintf(`[{"coefficient":"%s","multiplicand":%d,"multiplier":%d},{"coefficient":"%s","multiplicand":%d,"multiplier":%d}]`, encodedCoefficient, multiplicand, multiplier, encodedCoefficient, multiplicand, multiplier) addTerms := fmt.Sprintf(`[{"coefficient":"%s","sum":%d},{"coefficient":"%s","sum":%d}]`, encodedCoefficient, sum, encodedCoefficient, sum) encodedConstantTerm, nonEncodedConstantTerm := backend.SampleEncodedFelt() - arithmetic_opcode := fmt.Sprintf(`{"mul_terms":%s,"add_terms":%s,"constant_term":"%s"}`, mulTerms, addTerms, encodedConstantTerm) + arithmetic_opcode := fmt.Sprintf(`{"Arithmetic": {"mul_terms":%s,"linear_combinations":%s,"q_c":"%s"}}`, mulTerms, addTerms, encodedConstantTerm) arithmetic_opcodes := fmt.Sprintf(`[%s,%s]`, arithmetic_opcode, arithmetic_opcode) var r []ArithmeticOpcode err := json.Unmarshal([]byte(arithmetic_opcodes), &r) - if err != nil { - log.Fatal(err) - } assert.NoError(t, err) for _, op := range r { From f07a171216edfa38bad3641e5fa2c64163319ef4 Mon Sep 17 00:00:00 2001 From: matias-gonz Date: Thu, 9 Mar 2023 11:31:00 -0300 Subject: [PATCH 113/118] Remove unused print --- gnark_backend_ffi/backend/plonk/arithmetic_opcode.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/gnark_backend_ffi/backend/plonk/arithmetic_opcode.go b/gnark_backend_ffi/backend/plonk/arithmetic_opcode.go index 71359e8..6ea2728 100644 --- a/gnark_backend_ffi/backend/plonk/arithmetic_opcode.go +++ b/gnark_backend_ffi/backend/plonk/arithmetic_opcode.go @@ -22,9 +22,6 @@ func (g *ArithmeticOpcode) UnmarshalJSON(data []byte) error { log.Print(err) return err } - for k := range opcodeMap { - log.Print(k) - } if gateValue, ok := opcodeMap["Arithmetic"]; ok { gateJSON, err := json.Marshal(gateValue) From 9b8f5a804c107bd68442d292cc9e0ff5f8bfbcf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Litteri?= Date: Thu, 9 Mar 2023 11:33:05 -0300 Subject: [PATCH 114/118] Fix mul term condition --- gnark_backend_ffi/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gnark_backend_ffi/main.go b/gnark_backend_ffi/main.go index b621e89..ed4d4fa 100644 --- a/gnark_backend_ffi/main.go +++ b/gnark_backend_ffi/main.go @@ -29,7 +29,7 @@ func buildSparseR1CS(a plonk_backend.ACIR) *cs_bn254.SparseR1CS { var qL, qR, qO, qC, qM constraint.Coeff // Case qM⋅(xa⋅xb) - if len(gate.MulTerms) == 0 { + if len(gate.MulTerms) != 0 { mulTerm := gate.MulTerms[0] qM = sparseR1CS.FromInterface(mulTerm.Coefficient) xa = int(mulTerm.Multiplicand) From 0349e58cdc57b465a5bad8f351fdf99b09f1ffe1 Mon Sep 17 00:00:00 2001 From: matias-gonz Date: Thu, 9 Mar 2023 13:49:15 -0300 Subject: [PATCH 115/118] Add IntegrationTestCircuitSerialization --- gnark_backend_ffi/main.go | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/gnark_backend_ffi/main.go b/gnark_backend_ffi/main.go index b621e89..7ffb247 100644 --- a/gnark_backend_ffi/main.go +++ b/gnark_backend_ffi/main.go @@ -571,6 +571,28 @@ func IntegrationTestRawR1CSSerialization(rawR1CSJSON string) *C.char { return C.CString(string(serializedRawR1CS)) } +//export IntegrationTestCircuitSerialization +func IntegrationTestCircuitSerialization(acirJSON string) *C.char { + var acir plonk_backend.ACIR + err := json.Unmarshal([]byte(acirJSON), &acir) + if err != nil { + log.Fatal(err) + } + + fmt.Println("| GO |") + fmt.Println("Current Witness: ", acir.CurrentWitness) + fmt.Println("Opcodes: ", acir.Opcodes) + fmt.Println("Public Inputs: ", acir.PublicInputs) + fmt.Println() + + serializedAcir, err := json.Marshal(acir) + if err != nil { + log.Fatal(err) + } + + return C.CString(string(serializedAcir)) +} + func ExampleSimpleCircuit() { publicVariables := []fr_bn254.Element{fr_bn254.NewElement(2), fr_bn254.NewElement(6)} secretVariables := []fr_bn254.Element{fr_bn254.NewElement(3)} From 7f269f007b75dd2720f524699c54c5b88f9a2d99 Mon Sep 17 00:00:00 2001 From: matias-gonz Date: Thu, 9 Mar 2023 15:31:38 -0300 Subject: [PATCH 116/118] Add test_acir_serialization --- tests/serialization_tests.rs | 42 +++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/tests/serialization_tests.rs b/tests/serialization_tests.rs index d350481..22222d5 100644 --- a/tests/serialization_tests.rs +++ b/tests/serialization_tests.rs @@ -1,6 +1,7 @@ +use ::acvm::{acir::circuit::directives::Directive, pwg::arithmetic}; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use noir_backend_using_gnark::{ - acvm, + acvm::{self, Circuit, Expression, Opcode, PublicInputs}, gnark_backend_wrapper::{self, AddTerm, MulTerm, RawGate, RawR1CS}, }; use std::ffi; @@ -34,6 +35,9 @@ extern "C" { fn IntegrationTestRawR1CSSerialization( raw_r1cs: gnark_backend_wrapper::GoString, ) -> *const ffi::c_char; + fn IntegrationTestCircuitSerialization( + circuit: gnark_backend_wrapper::GoString, + ) -> *const ffi::c_char; } fn serialize_felt(felt: &gnark_backend_wrapper::Fr) -> Vec { @@ -414,3 +418,39 @@ fn test_raw_r1cs_serialization() { // * Assert that add_terms and go_add_terms are the same (go_add_terms is // the pong's deserialization) } + +#[test] +fn test_acir_serialization() { + let current_witness_index: u32 = rand::random(); + let arithmetic_expression = Expression::default(); + let arithmetic_opcode = Opcode::Arithmetic(arithmetic_expression); + let directive = Directive::Invert { + x: acvm::Witness::new(rand::random()), + result: acvm::Witness::new(rand::random()), + }; + let directive_opcode = Opcode::Directive(directive); + + let opcodes = vec![arithmetic_opcode, directive_opcode]; + let public_inputs = PublicInputs::default(); + + let acir = Circuit { + current_witness_index, + opcodes, + public_inputs, + }; + + // Serialize the raw gate. + let serialized_acir = serde_json::to_string(&acir).unwrap(); + + // Prepare ping for Go. + let pre_ping = ffi::CString::new(serialized_acir).unwrap(); + let ping = gnark_backend_wrapper::GoString::try_from(&pre_ping).unwrap(); + + // Send and receive pong from Go. + let _pong: *const ffi::c_char = unsafe { IntegrationTestCircuitSerialization(ping) }; + + // TODO: + // * Prepare pong for Rust. + // * Assert that add_terms and go_add_terms are the same (go_add_terms is + // the pong's deserialization) +} From a4492d75148107dac26149c6a79d900654308f11 Mon Sep 17 00:00:00 2001 From: matias-gonz Date: Thu, 9 Mar 2023 15:43:54 -0300 Subject: [PATCH 117/118] Update test_acir_serialization --- tests/serialization_tests.rs | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/tests/serialization_tests.rs b/tests/serialization_tests.rs index 22222d5..250c558 100644 --- a/tests/serialization_tests.rs +++ b/tests/serialization_tests.rs @@ -1,9 +1,10 @@ use ::acvm::{acir::circuit::directives::Directive, pwg::arithmetic}; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use noir_backend_using_gnark::{ - acvm::{self, Circuit, Expression, Opcode, PublicInputs}, + acvm::{self, Circuit, Expression, FieldElement, Opcode, PublicInputs}, gnark_backend_wrapper::{self, AddTerm, MulTerm, RawGate, RawR1CS}, }; +use std::collections::BTreeSet; use std::ffi; extern "C" { @@ -422,7 +423,21 @@ fn test_raw_r1cs_serialization() { #[test] fn test_acir_serialization() { let current_witness_index: u32 = rand::random(); - let arithmetic_expression = Expression::default(); + let mul_terms = vec![( + acvm::FieldElement::zero(), + acvm::Witness::new(rand::random()), + acvm::Witness::new(rand::random()), + )]; + let linear_combinations = vec![( + acvm::FieldElement::zero(), + acvm::Witness::new(rand::random()), + )]; + let q_c = acvm::FieldElement::zero(); + let arithmetic_expression = Expression { + mul_terms, + linear_combinations, + q_c, + }; let arithmetic_opcode = Opcode::Arithmetic(arithmetic_expression); let directive = Directive::Invert { x: acvm::Witness::new(rand::random()), @@ -431,7 +446,10 @@ fn test_acir_serialization() { let directive_opcode = Opcode::Directive(directive); let opcodes = vec![arithmetic_opcode, directive_opcode]; - let public_inputs = PublicInputs::default(); + let mut public_inputs_tree = BTreeSet::new(); + public_inputs_tree.insert(acvm::Witness::new(rand::random())); + public_inputs_tree.insert(acvm::Witness::new(rand::random())); + let public_inputs = PublicInputs(public_inputs_tree); let acir = Circuit { current_witness_index, From 55f11457887c9d6962d42e365f6f19f514dafaae Mon Sep 17 00:00:00 2001 From: matias-gonz Date: Thu, 9 Mar 2023 15:58:34 -0300 Subject: [PATCH 118/118] Fix linter --- tests/serialization_tests.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/serialization_tests.rs b/tests/serialization_tests.rs index 250c558..43f86f6 100644 --- a/tests/serialization_tests.rs +++ b/tests/serialization_tests.rs @@ -1,7 +1,7 @@ -use ::acvm::{acir::circuit::directives::Directive, pwg::arithmetic}; +use ::acvm::acir::circuit::directives::Directive; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use noir_backend_using_gnark::{ - acvm::{self, Circuit, Expression, FieldElement, Opcode, PublicInputs}, + acvm::{self, Circuit, Expression, Opcode, PublicInputs}, gnark_backend_wrapper::{self, AddTerm, MulTerm, RawGate, RawR1CS}, }; use std::collections::BTreeSet;