From 5c5949614436696495c8ebcb40849b06ad906b73 Mon Sep 17 00:00:00 2001 From: mottla Date: Fri, 7 Jun 2019 12:34:01 +0200 Subject: [PATCH] changed signal order : [1,inputs..,outputs...,trace...] Improved performance --- circuitcompiler/Programm.go | 23 ++++++++++++++++---- circuitcompiler/Programm_test.go | 2 +- r1csqap/r1csqap.go | 10 +++++++-- snark.go | 37 ++++---------------------------- snark_test.go | 11 ++++------ 5 files changed, 36 insertions(+), 47 deletions(-) diff --git a/circuitcompiler/Programm.go b/circuitcompiler/Programm.go index dac2006..7e02960 100644 --- a/circuitcompiler/Programm.go +++ b/circuitcompiler/Programm.go @@ -24,6 +24,7 @@ type R1CS struct { type Program struct { functions map[string]*Circuit globalInputs []string + globalOutput map[string]bool arithmeticEnvironment utils //find a better name //key 1: the hash chain indicating from where the variable is called H( H(main(a,b)) , doSomething(x,z) ), where H is a hash function. @@ -67,6 +68,10 @@ func (p *Program) BuildConstraintTrees() { for _, in := range p.getMainCircuit().Inputs { p.globalInputs = append(p.globalInputs, in) } + for key, _ := range p.globalOutput { + p.globalInputs = append(p.globalInputs, key) + } + //TODO do the same with the outputs var wg = sync.WaitGroup{} //we build the parse trees concurrently! because we can! go rocks @@ -193,8 +198,14 @@ func (p *Program) r1CSRecursiveBuild(currentCircuit *Circuit, node *gate, hashTr out := hashTogether(leftHash, rightHash) rootGate.value.V1 = rootGate.value.V1 + string(leftHash[:10]) rootGate.value.V2 = rootGate.value.V2 + string(rightHash[:10]) - rootGate.value.Out = rootGate.value.Out + string(out[:10]) + + //note we only check for existence, but not for truth. + if _, ex := p.globalOutput[rootGate.value.Out]; !ex { + rootGate.value.Out = rootGate.value.Out + string(out[:10]) + } + p.computedInContext[string(hashTraceBuildup)][node.value.Out] = rootGate.value.Out + p.computedFactors[sig] = rootGate.value.Out *orderedmGates = append(*orderedmGates, *rootGate) @@ -449,6 +460,7 @@ func NewProgram() (p *Program) { p = &Program{ functions: map[string]*Circuit{}, globalInputs: []string{"one"}, + globalOutput: map[string]bool{"main": true}, arithmeticEnvironment: prepareUtils(), } return @@ -458,7 +470,7 @@ func NewProgram() (p *Program) { func (p *Program) GenerateReducedR1CS(mGates []gate) (r1CS R1CS) { // from flat code to R1CS - offset := len(p.globalInputs) + offset := len(p.globalInputs) - len(p.globalOutput) // one + in1 +in2+... + gate1 + gate2 .. + out size := offset + len(mGates) indexMap := make(map[string]int) @@ -467,8 +479,11 @@ func (p *Program) GenerateReducedR1CS(mGates []gate) (r1CS R1CS) { indexMap[v] = i } - for i, v := range mGates { - indexMap[v.value.Out] = i + offset + for _, v := range mGates { + if _, ex := indexMap[v.value.Out]; !ex { + indexMap[v.value.Out] = len(indexMap) + } + } for _, g := range mGates { diff --git a/circuitcompiler/Programm_test.go b/circuitcompiler/Programm_test.go index 1b8960a..412e23f 100644 --- a/circuitcompiler/Programm_test.go +++ b/circuitcompiler/Programm_test.go @@ -154,7 +154,7 @@ func TestNewProgramm(t *testing.T) { w := CalculateWitness(inputs, r1cs) fmt.Println("witness") fmt.Println(w) - assert.Equal(t, io.result, w[len(w)-1]) + assert.Equal(t, io.result, w[len(program.globalInputs)-1]) } } diff --git a/r1csqap/r1csqap.go b/r1csqap/r1csqap.go index d5d668f..048f855 100644 --- a/r1csqap/r1csqap.go +++ b/r1csqap/r1csqap.go @@ -6,6 +6,8 @@ import ( "github.com/arnaucube/go-snark/fields" ) +var bigZero = big.NewInt(int64(0)) + // Transpose transposes the *big.Int matrix func Transpose(matrix [][]*big.Int) [][]*big.Int { r := make([][]*big.Int, len(matrix[0])) @@ -22,7 +24,7 @@ func Transpose(matrix [][]*big.Int) [][]*big.Int { // ArrayOfBigZeros creates a *big.Int array with n elements to zero func ArrayOfBigZeros(num int) []*big.Int { - bigZero := big.NewInt(int64(0)) + var r = make([]*big.Int, num, num) for i := 0; i < num; i++ { r[i] = bigZero @@ -155,7 +157,11 @@ func (pf PolynomialField) LagrangeInterpolation(v []*big.Int) []*big.Int { // https://en.wikipedia.org/wiki/Lagrange_polynomial var r []*big.Int for i := 0; i < len(v); i++ { - r = pf.Add(r, pf.NewPolZeroAt(i+1, len(v), v[i])) + //NOTE this comparison gives a huge performance boost + if v[i].Cmp(bigZero) != 0 { + r = pf.Add(r, pf.NewPolZeroAt(i+1, len(v), v[i])) + } + //r = pf.Mul(v[i], pf.NewPolZeroAt(i+1, len(v), v[i])) } // diff --git a/snark.go b/snark.go index 0f3f71d..135dc70 100644 --- a/snark.go +++ b/snark.go @@ -2,7 +2,6 @@ package snark import ( "fmt" - "github.com/arnaucube/go-snark/circuitcompiler" "math/big" "os" @@ -91,7 +90,7 @@ func prepareUtils() utils { } // GenerateTrustedSetup generates the Trusted Setup from a compiled Circuit. The Setup.Toxic sub data structure must be destroyed -func GenerateTrustedSetup(witnessLength int, alphas, betas, gammas [][]*big.Int) (Setup, error) { +func GenerateTrustedSetup(inputs int, alphas, betas, gammas [][]*big.Int) (Setup, error) { var setup Setup var err error @@ -174,13 +173,13 @@ func GenerateTrustedSetup(witnessLength int, alphas, betas, gammas [][]*big.Int) setup.Vk.G2Kg = Utils.Bn.G2.MulScalar(Utils.Bn.G2.G, setup.Toxic.Kgamma) // for i := 0; i < circuit.NVars; i++ { - for i := 0; i < witnessLength; i++ { + for i := 0; i < len(alphas); i++ { at := Utils.PF.Eval(alphas[i], setup.Toxic.T) // rhoAat := Utils.Bn.Fq1.Mul(setup.Toxic.RhoA, at) rhoAat := Utils.FqR.Mul(setup.Toxic.RhoA, at) a := Utils.Bn.G1.MulScalar(Utils.Bn.G1.G, rhoAat) setup.Pk.A = append(setup.Pk.A, a) - if i <= 4 { + if i < inputs { setup.Vk.IC = append(setup.Vk.IC, a) } @@ -322,7 +321,7 @@ func VerifyProof(setup Setup, proof Proof, publicSignals []*big.Int, debug bool) // Vkx, to then calculate Vkx+piA vkxpia := setup.Vk.IC[0] for i := 0; i < len(publicSignals); i++ { - vkxpia = Utils.Bn.G1.Add(vkxpia, Utils.Bn.G1.MulScalar(setup.Vk.IC[i+1], publicSignals[i])) + vkxpia = Utils.Bn.G1.Add(vkxpia, Utils.Bn.G1.MulScalar(setup.Vk.IC[i], publicSignals[i])) } // e(Vkx+piA, piB) == e(piH, Vkz) * e(piC, g2) @@ -355,31 +354,3 @@ func VerifyProof(setup Setup, proof Proof, publicSignals []*big.Int, debug bool) return true } - -//TODO this is just a workaround to place the output after the input signals. Will be removed once the handling of private variables is already considered in the lexer -func moveOutputToBegining(r1cs circuitcompiler.R1CS) (r circuitcompiler.R1CS) { - return r1cs - // activating this part, causes a huge messup I want to deal with a bit later - tmpA, tmpB, tmpC := [][]*big.Int{}, [][]*big.Int{}, [][]*big.Int{} - - tmpA = append(tmpA, r1cs.A[len(r1cs.A)-1]) - tmpA = append(tmpA, r1cs.A[:len(r1cs.A)-1]...) - - tmpB = append(tmpB, r1cs.B[len(r1cs.B)-1]) - tmpB = append(tmpB, r1cs.B[:len(r1cs.B)-1]...) - - tmpC = append(tmpC, r1cs.C[len(r1cs.C)-1]) - tmpC = append(tmpC, r1cs.C[:len(r1cs.C)-1]...) - - return circuitcompiler.R1CS{A: tmpA, B: tmpB, C: tmpC} -} - -//TODO this is just a workaround to place the output after the input signals. Will be removed once the handling of private variables is already considered in the lexer -func moveWitnessOutputAfterInputs(numberOfInputs int, witness []*big.Int) (w []*big.Int) { - return witness - // activating this part, causes a huge messup I want to deal with a bit later - wtmp := append(witness[:numberOfInputs], witness[len(witness)-1]) - wtmp = append(wtmp, witness[numberOfInputs:len(witness)-2]...) - - return wtmp -} diff --git a/snark_test.go b/snark_test.go index 5cb969c..6653899 100644 --- a/snark_test.go +++ b/snark_test.go @@ -143,7 +143,7 @@ func TestGenerateAndVerifyProof(t *testing.T) { fmt.Println("generating R1CS") //NOTE MOVE DOES NOTHING CURRENTLY - r1cs := moveOutputToBegining(program.GenerateReducedR1CS(gates)) + r1cs := program.GenerateReducedR1CS(gates) //[[0 1 0 0 0 0 0 0 0 0] [0 0 0 1 0 0 0 0 0 0] [0 0 0 0 0 1 0 0 0 0] [0 0 0 0 0 0 0 0 1 0] [0 0 0 0 0 0 0 1 0 0]] //[[0 0 1 0 0 0 0 0 0 0] [0 0 0 0 1 0 0 0 0 0] [0 0 0 0 0 0 1 0 0 0] [0 0 0 0 0 1 0 0 0 0] [0 0 0 0 0 0 0 0 5 0]] //[[0 0 0 0 0 1 0 0 0 0] [0 0 0 0 0 0 1 0 0 0] [0 0 0 0 0 0 0 1 0 0] [0 0 0 0 0 0 0 1 0 0] [0 0 0 0 0 0 0 0 0 1]] @@ -163,7 +163,7 @@ func TestGenerateAndVerifyProof(t *testing.T) { before := time.Now() //calculate trusted setup - setup, err := GenerateTrustedSetup(len(alphas[0]), alphas, betas, gammas) + setup, err := GenerateTrustedSetup(program.GlobalInputCount(), alphas, betas, gammas) fmt.Println("Generate CRS time elapsed:", time.Since(before)) assert.Nil(t, err) fmt.Println("\nt:", setup.Toxic.T) @@ -175,11 +175,8 @@ func TestGenerateAndVerifyProof(t *testing.T) { fmt.Println(inputs) w := circuitcompiler.CalculateWitness(inputs, r1cs) fmt.Println("\nwitness", w) - //NOTE MOVE DOES NOTHING - w = moveWitnessOutputAfterInputs(program.GlobalInputCount(), w) - fmt.Println("\nwitness Reordered ", w) - assert.Equal(t, io.result, w[len(w)-1]) + assert.Equal(t, io.result, w[program.GlobalInputCount()-1]) ax, bx, cx, px := Utils.PF.CombinePolynomials(w, alphas, betas, gammas) fmt.Println("ax length", len(ax)) @@ -219,7 +216,7 @@ func TestGenerateAndVerifyProof(t *testing.T) { assert.Nil(t, err) before = time.Now() - assert.True(t, VerifyProof(setup, proof, append(w[1:program.GlobalInputCount()], w[len(w)-1]), true)) + assert.True(t, VerifyProof(setup, proof, w[:program.GlobalInputCount()], true)) fmt.Println("verify proof time elapsed:", time.Since(before)) }