Browse Source

fixing Z(x), VkIC, Vkz, piH calculations

pull/5/head
arnaucube 5 years ago
parent
commit
7d0c2ad53c
7 changed files with 160 additions and 99 deletions
  1. +1
    -0
      .gitignore
  2. +3
    -1
      README.md
  3. +1
    -0
      circuitcompiler/circuit.go
  4. +8
    -4
      r1csqap/r1csqap.go
  5. +28
    -13
      r1csqap/r1csqap_test.go
  6. +46
    -23
      snark.go
  7. +73
    -58
      snark_test.go

+ 1
- 0
.gitignore

@ -5,3 +5,4 @@ cli/proofs.json
cli/test.circuit
cli/trustedsetup.json
tmp
tmpBackup

+ 3
- 1
README.md

@ -24,7 +24,7 @@ Current implementation status:
- [x] generate trusted setup
- [x] generate proofs
- [x] verify proofs with BN128 pairing
- [ ] fix 4th pairing proofs generation & verification
- [ ] fix 4th pairing proofs generation & verification: ê(Vkx+piA, piB) == ê(piH, Vkz) * ê(piC, g2)
- [ ] WASM implementation to run on browsers
@ -36,6 +36,8 @@ Current implementation status:
- [![GoDoc](https://godoc.org/github.com/arnaucube/go-snark/circuitcompiler?status.svg)](https://godoc.org/github.com/arnaucube/go-snark/circuitcompiler) Circuit Compiler
### Library usage
Warning: not finished.
Example:
```go
// compile circuit and get the R1CS

+ 1
- 0
circuitcompiler/circuit.go

@ -153,6 +153,7 @@ type Inputs struct {
}
// CalculateWitness calculates the Witness of a Circuit based on the given inputs
// witness = [ one, output, publicInputs, privateInputs, ...]
func (circ *Circuit) CalculateWitness(inputs []*big.Int) ([]*big.Int, error) {
if len(inputs) != len(circ.Inputs) {
return []*big.Int{}, errors.New("given inputs != circuit.Inputs")

+ 8
- 4
r1csqap/r1csqap.go

@ -175,10 +175,14 @@ func (pf PolynomialField) R1CSToQAP(a, b, c [][]*big.Int) ([][]*big.Int, [][]*bi
gammas = append(gammas, pf.LagrangeInterpolation(cT[i]))
}
z := []*big.Int{big.NewInt(int64(1))}
for i := 1; i < len(aT[0])+1; i++ {
ineg := big.NewInt(int64(-i))
b1 := big.NewInt(int64(1))
z = pf.Mul(z, []*big.Int{ineg, b1})
for i := 1; i < len(alphas)-1; i++ {
z = pf.Mul(
z,
[]*big.Int{
pf.F.Neg(
big.NewInt(int64(i))),
big.NewInt(int64(1)),
})
}
return alphas, betas, gammas, z
}

+ 28
- 13
r1csqap/r1csqap_test.go

@ -2,7 +2,6 @@ package r1csqap
import (
"bytes"
"fmt"
"math/big"
"testing"
@ -31,9 +30,14 @@ func TestTranspose(t *testing.T) {
})
}
func neg(a *big.Int) *big.Int {
return new(big.Int).Neg(a)
}
func TestPol(t *testing.T) {
b0 := big.NewInt(int64(0))
b1 := big.NewInt(int64(1))
b2 := big.NewInt(int64(2))
b3 := big.NewInt(int64(3))
b4 := big.NewInt(int64(4))
b5 := big.NewInt(int64(5))
@ -55,6 +59,17 @@ func TestPol(t *testing.T) {
o := pf.Mul(a, b)
assert.Equal(t, o, []*big.Int{b3, b0, b16, b0, b5})
// polynomial division
quo, rem := pf.Div(a, b)
assert.Equal(t, quo[0].Int64(), int64(5))
assert.Equal(t, new(big.Int).Sub(rem[0], r).Int64(), int64(-14)) // check the rem result without modulo
c := []*big.Int{neg(b4), b0, neg(b2), b1}
d := []*big.Int{neg(b3), b1}
quo2, rem2 := pf.Div(c, d)
assert.Equal(t, quo2, []*big.Int{b3, b1, b1})
assert.Equal(t, rem2[0].Int64(), int64(5))
// polynomial addition
o = pf.Add(a, b)
assert.Equal(t, o, []*big.Int{b4, b0, b6})
@ -67,8 +82,8 @@ func TestPol(t *testing.T) {
assert.True(t, bytes.Equal(b0.Bytes(), o[1].Bytes()))
assert.True(t, bytes.Equal(b0.Bytes(), o[2].Bytes()))
c := []*big.Int{b5, b6, b1}
d := []*big.Int{b1, b3}
c = []*big.Int{b5, b6, b1}
d = []*big.Int{b1, b3}
o = pf.Sub(c, d)
assert.Equal(t, o, []*big.Int{b4, b3, b1})
@ -133,21 +148,21 @@ func TestR1CSToQAP(t *testing.T) {
[]*big.Int{b0, b0, b1, b0, b0, b0},
}
alphas, betas, gammas, zx := pf.R1CSToQAP(a, b, c)
fmt.Println(alphas)
fmt.Println(betas)
fmt.Println(gammas)
fmt.Print("Z(x): ")
fmt.Println(zx)
// fmt.Println(alphas)
// fmt.Println(betas)
// fmt.Println(gammas)
// fmt.Print("Z(x): ")
// fmt.Println(zx)
w := []*big.Int{b1, b3, b35, b9, b27, b30}
ax, bx, cx, px := pf.CombinePolynomials(w, alphas, betas, gammas)
fmt.Println(ax)
fmt.Println(bx)
fmt.Println(cx)
fmt.Println(px)
// fmt.Println(ax)
// fmt.Println(bx)
// fmt.Println(cx)
// fmt.Println(px)
hx := pf.DivisorPolynomial(px, zx)
fmt.Println(hx)
// fmt.Println(hx)
// hx==px/zx so px==hx*zx
assert.Equal(t, px, pf.Mul(hx, zx))

+ 46
- 23
snark.go

@ -27,7 +27,7 @@ type Setup struct {
}
// public
G1T [][3]*big.Int // t encrypted in G1 curve
G1T [][3]*big.Int // t encrypted in G1 curve, G1T == Pk.H
G2T [][3][2]*big.Int // t encrypted in G2 curve
Pk struct { // Proving Key pk:=(pkA, pkB, pkC, pkH)
A [][3]*big.Int
@ -37,6 +37,7 @@ type Setup struct {
Ap [][3]*big.Int
Bp [][3]*big.Int
Cp [][3]*big.Int
Z []*big.Int
}
Vk struct {
Vka [3][2]*big.Int
@ -90,7 +91,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, circuit circuitcompiler.Circuit, alphas, betas, gammas [][]*big.Int, zx []*big.Int) (Setup, error) {
func GenerateTrustedSetup(witnessLength int, circuit circuitcompiler.Circuit, alphas, betas, gammas [][]*big.Int) (Setup, error) {
var setup Setup
var err error
@ -146,15 +147,7 @@ func GenerateTrustedSetup(witnessLength int, circuit circuitcompiler.Circuit, al
}
setup.Toxic.RhoC = Utils.FqR.Mul(setup.Toxic.RhoA, setup.Toxic.RhoB)
// encrypt t values with curve generators
var gt1 [][3]*big.Int
var gt2 [][3][2]*big.Int
gt1 = append(gt1, Utils.Bn.G1.G)
tEncr := setup.Toxic.T
for i := 1; i < witnessLength; i++ {
gt1 = append(gt1, Utils.Bn.G1.MulScalar(Utils.Bn.G1.G, tEncr))
tEncr = Utils.Bn.Fq1.Mul(tEncr, setup.Toxic.T)
}
// calculated more down
// for i := 0; i < witnessLength; i++ {
// tPow := Utils.FqR.Exp(setup.Toxic.T, big.NewInt(int64(i)))
// tEncr1 := Utils.Bn.G1.MulScalar(Utils.Bn.G1.G, tPow)
@ -164,8 +157,6 @@ func GenerateTrustedSetup(witnessLength int, circuit circuitcompiler.Circuit, al
// }
// gt1: g1, g1*t, g1*t^2, g1*t^3, ...
// gt2: g2, g2*t, g2*t^2, ...
setup.G1T = gt1
setup.G2T = gt2
setup.Vk.Vka = Utils.Bn.G2.MulScalar(Utils.Bn.G2.G, setup.Toxic.Ka)
setup.Vk.Vkb = Utils.Bn.G1.MulScalar(Utils.Bn.G1.G, setup.Toxic.Kb)
@ -182,7 +173,8 @@ func GenerateTrustedSetup(witnessLength int, circuit circuitcompiler.Circuit, al
setup.Vk.G2Kbg = Utils.Bn.G2.MulScalar(Utils.Bn.G2.G, kbg)
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 < circuit.NVars; i++ {
for i := 0; i < len(circuit.Signals); i++ {
at := Utils.PF.Eval(alphas[i], setup.Toxic.T)
rhoAat := Utils.Bn.Fq1.Mul(setup.Toxic.RhoA, at)
a := Utils.Bn.G1.MulScalar(Utils.Bn.G1.G, rhoAat)
@ -217,15 +209,41 @@ func GenerateTrustedSetup(witnessLength int, circuit circuitcompiler.Circuit, al
k_ := Utils.Bn.G1.MulScalar(Utils.Bn.G1.G, kt)
setup.Pk.Kp = append(setup.Pk.Kp, Utils.Bn.G1.MulScalar(k_, setup.Toxic.Kbeta))
}
zt := Utils.PF.Eval(zx, setup.Toxic.T)
// z pol
zpol := []*big.Int{big.NewInt(int64(1))}
// for i := 1; i < len(circuit.Constraints); i++ {
for i := 1; i <= circuit.NPublic; i++ { // circuit.NPublic == d
zpol = Utils.PF.Mul(
zpol,
[]*big.Int{
Utils.FqR.Neg( // neg over R
big.NewInt(int64(i))),
big.NewInt(int64(1)),
})
}
setup.Pk.Z = zpol
zt := Utils.PF.Eval(zpol, setup.Toxic.T)
rhoCzt := Utils.Bn.Fq1.Mul(setup.Toxic.RhoC, zt)
setup.Vk.Vkz = Utils.Bn.G2.MulScalar(Utils.Bn.G2.G, rhoCzt)
// encrypt t values with curve generators
var gt1 [][3]*big.Int
gt1 = append(gt1, Utils.Bn.G1.G) // the first is t**0 * G1 = 1 * G1 = G1
tEncr := setup.Toxic.T
for i := 1; i < len(zpol); i++ { //should be G1T = pkH = (tau**i * G1) from i=0 to d, where d is degree of pol Z(x)
gt1 = append(gt1, Utils.Bn.G1.MulScalar(Utils.Bn.G1.G, tEncr))
tEncr = Utils.Bn.Fq1.Mul(tEncr, setup.Toxic.T)
}
fmt.Println("len(G1T)", len(gt1))
setup.G1T = gt1
return setup, nil
}
// GenerateProofs generates all the parameters to proof the zkSNARK from the Circuit, Setup and the Witness
func GenerateProofs(circuit circuitcompiler.Circuit, setup Setup, hx []*big.Int, w []*big.Int) (Proof, error) {
func GenerateProofs(circuit circuitcompiler.Circuit, setup Setup, w []*big.Int, px []*big.Int) (Proof, error) {
var proof Proof
proof.PiA = [3]*big.Int{Utils.Bn.G1.F.Zero(), Utils.Bn.G1.F.Zero(), Utils.Bn.G1.F.Zero()}
proof.PiAp = [3]*big.Int{Utils.Bn.G1.F.Zero(), Utils.Bn.G1.F.Zero(), Utils.Bn.G1.F.Zero()}
@ -251,7 +269,11 @@ func GenerateProofs(circuit circuitcompiler.Circuit, setup Setup, hx []*big.Int,
proof.PiKp = Utils.Bn.G1.Add(proof.PiKp, Utils.Bn.G1.MulScalar(setup.Pk.Kp[i], w[i]))
}
for i := 0; i < len(hx); i++ {
hx := Utils.PF.DivisorPolynomial(px, setup.Pk.Z) // maybe move this calculation to a previous step
// piH = pkH,0 + sum ( hi * pk H,i ), where pkH = G1T, hi=hx
proof.PiH = Utils.Bn.G1.Add(proof.PiH, setup.G1T[0])
for i := 1; i < len(setup.Pk.Z); i++ {
proof.PiH = Utils.Bn.G1.Add(proof.PiH, Utils.Bn.G1.MulScalar(setup.G1T[i], hx[i]))
}
@ -259,14 +281,14 @@ func GenerateProofs(circuit circuitcompiler.Circuit, setup Setup, hx []*big.Int,
}
// VerifyProof verifies over the BN128 the Pairings of the Proof
func VerifyProof(circuit circuitcompiler.Circuit, setup Setup, proof Proof, publicSignals []*big.Int, printVer bool) bool {
func VerifyProof(circuit circuitcompiler.Circuit, setup Setup, proof Proof, publicSignals []*big.Int, debug bool) bool {
// e(piA, Va) == e(piA', g2)
pairingPiaVa := Utils.Bn.Pairing(proof.PiA, setup.Vk.Vka)
pairingPiapG2 := Utils.Bn.Pairing(proof.PiAp, Utils.Bn.G2.G)
if !Utils.Bn.Fq12.Equal(pairingPiaVa, pairingPiapG2) {
return false
}
if printVer {
if debug {
fmt.Println("✓ e(piA, Va) == e(piA', g2), valid knowledge commitment for A")
}
@ -276,7 +298,7 @@ func VerifyProof(circuit circuitcompiler.Circuit, setup Setup, proof Proof, publ
if !Utils.Bn.Fq12.Equal(pairingVbPib, pairingPibpG2) {
return false
}
if printVer {
if debug {
fmt.Println("✓ e(Vb, piB) == e(piB', g2), valid knowledge commitment for B")
}
@ -286,13 +308,14 @@ func VerifyProof(circuit circuitcompiler.Circuit, setup Setup, proof Proof, publ
if !Utils.Bn.Fq12.Equal(pairingPicVc, pairingPicpG2) {
return false
}
if printVer {
if debug {
fmt.Println("✓ e(piC, Vc) == e(piC', g2), valid knowledge commitment for C")
}
// Vkx, to then calculate Vkx+piA
vkxpia := setup.Vk.IC[0]
for i := 0; i < len(publicSignals); i++ {
fmt.Println("pub sig", publicSignals[i])
vkxpia = Utils.Bn.G1.Add(vkxpia, Utils.Bn.G1.MulScalar(setup.Vk.IC[i+1], publicSignals[i]))
}
@ -304,7 +327,7 @@ func VerifyProof(circuit circuitcompiler.Circuit, setup Setup, proof Proof, publ
Utils.Bn.Pairing(proof.PiC, Utils.Bn.G2.G))) {
return false
}
if printVer {
if debug {
fmt.Println("✓ e(Vkx+piA, piB) == e(piH, Vkz) * e(piC, g2), QAP disibility checked")
}
@ -318,7 +341,7 @@ func VerifyProof(circuit circuitcompiler.Circuit, setup Setup, proof Proof, publ
if !Utils.Bn.Fq12.Equal(pairingL, pairingR) {
return false
}
if printVer {
if debug {
fmt.Println("✓ e(Vkx+piA+piC, g2KbetaKgamma) * e(g1KbetaKgamma, piB) == e(piK, g2Kgamma)")
}

+ 73
- 58
snark_test.go

@ -13,31 +13,36 @@ import (
"github.com/stretchr/testify/assert"
)
/*
func TestZkMultiplication(t *testing.T) {
func TestZkFromFlatCircuitCode(t *testing.T) {
// compile circuit and get the R1CS
flatCode := `
func test(a, b):
out = a * b
func test(x):
aux = x*x
y = aux*x
z = x + y
out = z + 5
`
fmt.Print("\nflat code of the circuit:")
fmt.Println(flatCode)
// parse the code
parser := circuitcompiler.NewParser(strings.NewReader(flatCode))
circuit, err := parser.Parse()
assert.Nil(t, err)
fmt.Println("\ncircuit data:", circuit)
circuitJson, _ := json.Marshal(circuit)
fmt.Println("circuit:", string(circuitJson))
b3 := big.NewInt(int64(3))
b4 := big.NewInt(int64(4))
inputs := []*big.Int{b3, b4}
privateInputs := []*big.Int{b3}
// wittness
w, err := circuit.CalculateWitness(inputs)
w, err := circuit.CalculateWitness(privateInputs)
assert.Nil(t, err)
fmt.Println("circuit")
fmt.Println(circuit.NPublic)
fmt.Println("\nwitness", w)
// flat code to R1CS
fmt.Println("\ngenerating R1CS from flat code")
a, b, c := circuit.GenerateR1CS()
fmt.Println("\nR1CS:")
fmt.Println("a:", a)
@ -45,74 +50,99 @@ func TestZkMultiplication(t *testing.T) {
fmt.Println("c:", c)
// R1CS to QAP
alphas, betas, gammas, zx := Utils.PF.R1CSToQAP(a, b, c)
alphas, betas, gammas, zxQAP := Utils.PF.R1CSToQAP(a, b, c)
fmt.Println("qap")
fmt.Println("alphas", alphas)
fmt.Println("betas", betas)
fmt.Println("gammas", gammas)
fmt.Println("alphas", len(alphas))
fmt.Println("alphas", alphas[0])
fmt.Println("betas", len(betas))
fmt.Println("gammas", len(gammas))
fmt.Println("zx length", len(zxQAP))
ax, bx, cx, px := Utils.PF.CombinePolynomials(w, alphas, betas, gammas)
fmt.Println("ax length", len(ax))
fmt.Println("bx length", len(bx))
fmt.Println("cx length", len(cx))
fmt.Println("px length", len(px))
hx := Utils.PF.DivisorPolynomial(px, zx)
hxQAP := Utils.PF.DivisorPolynomial(px, zxQAP)
fmt.Println("hx length", len(hxQAP))
// hx==px/zx so px==hx*zx
assert.Equal(t, px, Utils.PF.Mul(hx, zx))
assert.Equal(t, px, Utils.PF.Mul(hxQAP, zxQAP))
// p(x) = a(x) * b(x) - c(x) == h(x) * z(x)
abc := Utils.PF.Sub(Utils.PF.Mul(ax, bx), cx)
assert.Equal(t, abc, px)
hz := Utils.PF.Mul(hx, zx)
assert.Equal(t, abc, hz)
hzQAP := Utils.PF.Mul(hxQAP, zxQAP)
assert.Equal(t, abc, hzQAP)
div, rem := Utils.PF.Div(px, zx)
assert.Equal(t, hx, div)
assert.Equal(t, rem, r1csqap.ArrayOfBigZeros(1))
div, rem := Utils.PF.Div(px, zxQAP)
assert.Equal(t, hxQAP, div)
assert.Equal(t, rem, r1csqap.ArrayOfBigZeros(4))
// calculate trusted setup
setup, err := GenerateTrustedSetup(len(w), *circuit, alphas, betas, gammas, zx)
setup, err := GenerateTrustedSetup(len(w), *circuit, alphas, betas, gammas)
assert.Nil(t, err)
fmt.Println("\nt:", setup.Toxic.T)
// zx and setup.Pk.Z should be the same (currently not, the correct one is the calculation used inside GenerateTrustedSetup function), the calculation is repeated. TODO avoid repeating calculation
// assert.Equal(t, zxQAP, setup.Pk.Z)
fmt.Println("hx pk.z", hxQAP)
hx := Utils.PF.DivisorPolynomial(px, setup.Pk.Z)
fmt.Println("hx pk.z", hx)
// assert.Equal(t, hxQAP, hx)
assert.Equal(t, px, Utils.PF.Mul(hxQAP, zxQAP))
assert.Equal(t, px, Utils.PF.Mul(hx, setup.Pk.Z))
assert.Equal(t, len(hx), len(px)-len(setup.Pk.Z)+1)
assert.Equal(t, len(hxQAP), len(px)-len(zxQAP)+1)
// fmt.Println("pk.Z", len(setup.Pk.Z))
// fmt.Println("zxQAP", len(zxQAP))
// piA = g1 * A(t), piB = g2 * B(t), piC = g1 * C(t), piH = g1 * H(t)
proof, err := GenerateProofs(*circuit, setup, hx, w)
proof, err := GenerateProofs(*circuit, setup, w, px)
assert.Nil(t, err)
// assert.True(t, VerifyProof(*circuit, setup, proof, false))
// fmt.Println("\n proofs:")
// fmt.Println(proof)
// fmt.Println("public signals:", proof.PublicSignals)
fmt.Println("\nwitness", w)
// b1 := big.NewInt(int64(1))
b35 := big.NewInt(int64(35))
// publicSignals := []*big.Int{b1, b35}
publicSignals := []*big.Int{b35}
before := time.Now()
assert.True(t, VerifyProof(*circuit, setup, proof, publicSignals, true))
fmt.Println("verify proof time elapsed:", time.Since(before))
}
*/
func TestZkFromFlatCircuitCode(t *testing.T) {
/*
func TestZkMultiplication(t *testing.T) {
// compile circuit and get the R1CS
flatCode := `
func test(x):
aux = x*x
y = aux*x
z = x + y
out = z + 5
func test(a, b):
out = a * b
`
fmt.Print("\nflat code of the circuit:")
fmt.Println(flatCode)
// parse the code
parser := circuitcompiler.NewParser(strings.NewReader(flatCode))
circuit, err := parser.Parse()
assert.Nil(t, err)
fmt.Println("\ncircuit data:", circuit)
circuitJson, _ := json.Marshal(circuit)
fmt.Println("circuit:", string(circuitJson))
b3 := big.NewInt(int64(3))
privateInputs := []*big.Int{b3}
b4 := big.NewInt(int64(4))
inputs := []*big.Int{b3, b4}
// wittness
w, err := circuit.CalculateWitness(privateInputs)
w, err := circuit.CalculateWitness(inputs)
assert.Nil(t, err)
fmt.Println("\nwitness", w)
fmt.Println("circuit")
fmt.Println(circuit.NPublic)
// flat code to R1CS
fmt.Println("\ngenerating R1CS from flat code")
a, b, c := circuit.GenerateR1CS()
fmt.Println("\nR1CS:")
fmt.Println("a:", a)
@ -125,13 +155,8 @@ func TestZkFromFlatCircuitCode(t *testing.T) {
fmt.Println("alphas", alphas)
fmt.Println("betas", betas)
fmt.Println("gammas", gammas)
fmt.Println("zx", zx)
ax, bx, cx, px := Utils.PF.CombinePolynomials(w, alphas, betas, gammas)
fmt.Println("ax", ax)
// fmt.Println("bx", bx)
// fmt.Println("cx", cx)
// fmt.Println("px", px)
hx := Utils.PF.DivisorPolynomial(px, zx)
@ -146,32 +171,22 @@ func TestZkFromFlatCircuitCode(t *testing.T) {
div, rem := Utils.PF.Div(px, zx)
assert.Equal(t, hx, div)
assert.Equal(t, rem, r1csqap.ArrayOfBigZeros(4))
assert.Equal(t, rem, r1csqap.ArrayOfBigZeros(1))
// calculate trusted setup
setup, err := GenerateTrustedSetup(len(w), *circuit, alphas, betas, gammas, zx)
// setup, err := GenerateTrustedSetup(len(w), *circuit, ax, bx, cx, zx)
assert.Nil(t, err)
fmt.Println("\nt:", setup.Toxic.T)
// piA = g1 * A(t), piB = g2 * B(t), piC = g1 * C(t), piH = g1 * H(t)
proof, err := GenerateProofs(*circuit, setup, hx, w)
assert.Nil(t, err)
fmt.Println("IC", setup.Vk.IC)
// fmt.Println("\n proofs:")
// fmt.Println(proof)
// fmt.Println("public signals:", proof.PublicSignals)
fmt.Println("\nwitness", w)
// assert.True(t, VerifyProof(*circuit, setup, proof, false))
b35 := big.NewInt(int64(35))
publicSignals := []*big.Int{b35}
fmt.Println("public signals:", publicSignals)
before := time.Now()
assert.True(t, VerifyProof(*circuit, setup, proof, publicSignals, true))
fmt.Println("verify proof time elapsed:", time.Since(before))
}
*/
/*
func TestZkFromHardcodedR1CS(t *testing.T) {
b0 := big.NewInt(int64(0))

Loading…
Cancel
Save