Browse Source

snark trusted setup + generate proof + verify proof working. Added test to bn128 pairing

pull/5/head
arnaucube 6 years ago
parent
commit
f555ae4b18
10 changed files with 187 additions and 161 deletions
  1. +17
    -10
      README.md
  2. +10
    -11
      bn128/bn128.go
  3. +25
    -6
      bn128/bn128_test.go
  4. +7
    -0
      compiler/circuit.go
  5. +21
    -0
      fields/fq.go
  6. +3
    -0
      go.mod
  7. +6
    -0
      go.sum
  8. +0
    -1
      r1csqap/r1csqap.go
  9. +81
    -119
      snark.go
  10. +17
    -14
      snark_test.go

+ 17
- 10
README.md

@ -5,6 +5,7 @@ zkSNARK library implementation in Go
`Succinct Non-Interactive Zero Knowledge for a von Neumann Architecture`, Eli Ben-Sasson, Alessandro Chiesa, Eran Tromer, Madars Virza https://eprint.iacr.org/2013/879.pdf `Succinct Non-Interactive Zero Knowledge for a von Neumann Architecture`, Eli Ben-Sasson, Alessandro Chiesa, Eran Tromer, Madars Virza https://eprint.iacr.org/2013/879.pdf
`Pinocchio: Nearly practical verifiable computation`, Bryan Parno, Craig Gentry, Jon Howell, Mariana Raykova https://eprint.iacr.org/2013/279.pdf
### Usage ### Usage
- [![GoDoc](https://godoc.org/github.com/arnaucube/go-snark?status.svg)](https://godoc.org/github.com/arnaucube/go-snark) zkSnark - [![GoDoc](https://godoc.org/github.com/arnaucube/go-snark?status.svg)](https://godoc.org/github.com/arnaucube/go-snark) zkSnark
@ -18,7 +19,7 @@ bn, err := bn128.NewBn128()
assert.Nil(t, err) assert.Nil(t, err)
// new Finite Field // new Finite Field
f := fields.NewFq(bn.R)
fqR := fields.NewFq(bn.R)
// new Polynomial Field // new Polynomial Field
pf := r1csqap.NewPolynomialField(f) pf := r1csqap.NewPolynomialField(f)
@ -34,6 +35,13 @@ w = [1, 3, 35, 9, 27, 30]
alphas, betas, gammas, zx := pf.R1CSToQAP(a, b, c) alphas, betas, gammas, zx := pf.R1CSToQAP(a, b, c)
// wittness = 1, 3, 35, 9, 27, 30
w := []*big.Int{b1, b3, b35, b9, b27, b30}
circuit := compiler.Circuit{
NVars: 6,
NPublic: 0,
NSignals: len(w),
}
ax, bx, cx, px := pf.CombinePolynomials(w, alphas, betas, gammas) ax, bx, cx, px := pf.CombinePolynomials(w, alphas, betas, gammas)
hx := pf.DivisorPolinomial(px, zx) hx := pf.DivisorPolinomial(px, zx)
@ -46,22 +54,21 @@ abc := pf.Sub(pf.Mul(ax, bx), cx)
assert.Equal(t, abc, px) assert.Equal(t, abc, px)
hz := pf.Mul(hx, zx) hz := pf.Mul(hx, zx)
assert.Equal(t, abc, hz) assert.Equal(t, abc, hz)
div, rem := pf.Div(px, zx)
assert.Equal(t, hx, div)
assert.Equal(t, rem, r1csqap.ArrayOfBigZeros(4))
// calculate trusted setup // calculate trusted setup
setup, err := GenerateTrustedSetup(bn, len(ax))
setup, err := GenerateTrustedSetup(bn, fqR, pf, len(w), circuit, alphas, betas, gammas, zx)
assert.Nil(t, err) assert.Nil(t, err)
fmt.Println("trusted setup:")
fmt.Println(setup.G1T)
fmt.Println(setup.G2T)
fmt.Println("t", setup.Toxic.T)
// piA = g1 * A(t), piB = g2 * B(t), piC = g1 * C(t), piH = g1 * H(t) // piA = g1 * A(t), piB = g2 * B(t), piC = g1 * C(t), piH = g1 * H(t)
proof, err := GenerateProofs(bn, f, setup, ax, bx, cx, hx, zx)
proof, err := GenerateProofs(bn, fqR, circuit, setup, hx, w)
assert.Nil(t, err) assert.Nil(t, err)
// verify the proofs with the bn128 pairing
verified := VerifyProof(bn, publicSetup, proof)
assert.True(t, verified)
assert.True(t, VerifyProof(bn, circuit, setup, proof))
``` ```
### Test ### Test

+ 10
- 11
bn128/bn128.go

@ -105,7 +105,7 @@ func NewBn128() (Bn128, error) {
return b, nil return b, nil
} }
func NewFqR() (fields.Fq, error){
func NewFqR() (fields.Fq, error) {
r, ok := new(big.Int).SetString("21888242871839275222246405745257275088548364400416034343698204186575808495617", 10) r, ok := new(big.Int).SetString("21888242871839275222246405745257275088548364400416034343698204186575808495617", 10)
if !ok { if !ok {
return fields.Fq{}, errors.New("err parsing R") return fields.Fq{}, errors.New("err parsing R")
@ -172,16 +172,13 @@ func (bn128 *Bn128) preparePairing() error {
} }
func (bn128 Bn128) Pairing(p1 [3]*big.Int, p2 [3][2]*big.Int) ([2][3][2]*big.Int, error) {
func (bn128 Bn128) Pairing(p1 [3]*big.Int, p2 [3][2]*big.Int) [2][3][2]*big.Int {
pre1 := bn128.PreComputeG1(p1) pre1 := bn128.PreComputeG1(p1)
pre2, err := bn128.PreComputeG2(p2)
if err != nil {
return [2][3][2]*big.Int{}, err
}
pre2 := bn128.PreComputeG2(p2)
r1 := bn128.MillerLoop(pre1, pre2) r1 := bn128.MillerLoop(pre1, pre2)
res := bn128.FinalExponentiation(r1) res := bn128.FinalExponentiation(r1)
return res, nil
return res
} }
type AteG1Precomp struct { type AteG1Precomp struct {
@ -209,7 +206,7 @@ type AteG2Precomp struct {
Coeffs []EllCoeffs Coeffs []EllCoeffs
} }
func (bn128 Bn128) PreComputeG2(p [3][2]*big.Int) (AteG2Precomp, error) {
func (bn128 Bn128) PreComputeG2(p [3][2]*big.Int) AteG2Precomp {
qCopy := bn128.G2.Affine(p) qCopy := bn128.G2.Affine(p)
res := AteG2Precomp{ res := AteG2Precomp{
qCopy[0], qCopy[0],
@ -235,11 +232,13 @@ func (bn128 Bn128) PreComputeG2(p [3][2]*big.Int) (AteG2Precomp, error) {
q1 := bn128.G2.Affine(bn128.G2MulByQ(qCopy)) q1 := bn128.G2.Affine(bn128.G2MulByQ(qCopy))
if !bn128.Fq2.Equal(q1[2], bn128.Fq2.One()) { if !bn128.Fq2.Equal(q1[2], bn128.Fq2.One()) {
return res, errors.New("q1[2] != Fq2.One")
// return res, errors.New("q1[2] != Fq2.One")
panic(errors.New("q1[2] != Fq2.One()"))
} }
q2 := bn128.G2.Affine(bn128.G2MulByQ(q1)) q2 := bn128.G2.Affine(bn128.G2MulByQ(q1))
if !bn128.Fq2.Equal(q2[2], bn128.Fq2.One()) { if !bn128.Fq2.Equal(q2[2], bn128.Fq2.One()) {
return res, errors.New("q2[2] != Fq2.One")
// return res, errors.New("q2[2] != Fq2.One")
panic(errors.New("q2[2] != Fq2.One()"))
} }
if bn128.LoopCountNeg { if bn128.LoopCountNeg {
@ -253,7 +252,7 @@ func (bn128 Bn128) PreComputeG2(p [3][2]*big.Int) (AteG2Precomp, error) {
c, r = bn128.MixedAdditionStep(q2, r) c, r = bn128.MixedAdditionStep(q2, r)
res.Coeffs = append(res.Coeffs, c) res.Coeffs = append(res.Coeffs, c)
return res, nil
return res
} }
func (bn128 Bn128) DoublingStep(current [3][2]*big.Int) (EllCoeffs, [3][2]*big.Int) { func (bn128 Bn128) DoublingStep(current [3][2]*big.Int) (EllCoeffs, [3][2]*big.Int) {

+ 25
- 6
bn128/bn128_test.go

@ -22,10 +22,10 @@ func TestBN128(t *testing.T) {
g2b := bn128.G2.MulScalar(bn128.G2.G, bn128.Fq1.Copy(big40)) g2b := bn128.G2.MulScalar(bn128.G2.G, bn128.Fq1.Copy(big40))
pre1a := bn128.PreComputeG1(g1a) pre1a := bn128.PreComputeG1(g1a)
pre2a, err := bn128.PreComputeG2(g2a)
pre2a := bn128.PreComputeG2(g2a)
assert.Nil(t, err) assert.Nil(t, err)
pre1b := bn128.PreComputeG1(g1b) pre1b := bn128.PreComputeG1(g1b)
pre2b, err := bn128.PreComputeG2(g2b)
pre2b := bn128.PreComputeG2(g2b)
assert.Nil(t, err) assert.Nil(t, err)
r1 := bn128.MillerLoop(pre1a, pre2a) r1 := bn128.MillerLoop(pre1a, pre2a)
@ -55,10 +55,8 @@ func TestBN128Pairing(t *testing.T) {
g1b := bn128.G1.MulScalar(bn128.G1.G, big30) g1b := bn128.G1.MulScalar(bn128.G1.G, big30)
g2b := bn128.G2.MulScalar(bn128.G2.G, big25) g2b := bn128.G2.MulScalar(bn128.G2.G, big25)
pA, err := bn128.Pairing(g1a, g2a)
assert.Nil(t, err)
pB, err := bn128.Pairing(g1b, g2b)
assert.Nil(t, err)
pA := bn128.Pairing(g1a, g2a)
pB := bn128.Pairing(g1b, g2b)
assert.True(t, bn128.Fq12.Equal(pA, pB)) assert.True(t, bn128.Fq12.Equal(pA, pB))
@ -67,3 +65,24 @@ func TestBN128Pairing(t *testing.T) {
// assert.Equal(t, pA[0][0][0].String(), "73680848340331011700282047627232219336104151861349893575958589557226556635706") // assert.Equal(t, pA[0][0][0].String(), "73680848340331011700282047627232219336104151861349893575958589557226556635706")
// assert.Equal(t, bn128.Fq12.Affine(pA)[0][0][0].String(), "8016119724813186033542830391460394070015218389456422587891475873290878009957") // assert.Equal(t, bn128.Fq12.Affine(pA)[0][0][0].String(), "8016119724813186033542830391460394070015218389456422587891475873290878009957")
} }
func TestBN128Pairing2(t *testing.T) {
// test idea from https://bplib.readthedocs.io/en/latest/ by George Danezis
bn, err := NewBn128()
assert.Nil(t, err)
gt := bn.Pairing(bn.G1.G, bn.G2.G)
gt6 := bn.Fq12.Exp(gt, big.NewInt(int64(6)))
// e(g1, g2)^6 == e(g1, 6*g2)
assert.True(t, bn.Fq12.Equal(gt6, bn.Pairing(bn.G1.G, bn.G2.MulScalar(bn.G2.G, big.NewInt(int64(6))))))
// e(g1, g2)^6 == e(6* g1, g2)
assert.True(t, bn.Fq12.Equal(gt6, bn.Pairing(bn.G1.MulScalar(bn.G1.G, big.NewInt(int64(6))), bn.G2.G)))
// e(g1, g2)^6 == e(3*g1, 2*g2)
assert.True(t, bn.Fq12.Equal(gt6, bn.Pairing(bn.G1.MulScalar(bn.G1.G, big.NewInt(int64(3))), bn.G2.MulScalar(bn.G2.G, big.NewInt(int64(2))))))
// e(g1, g2)^6 == e(2*g1, 3*g2)
assert.True(t, bn.Fq12.Equal(gt6, bn.Pairing(bn.G1.MulScalar(bn.G1.G, big.NewInt(int64(2))), bn.G2.MulScalar(bn.G2.G, big.NewInt(int64(3))))))
}

+ 7
- 0
compiler/circuit.go

@ -0,0 +1,7 @@
package compiler
type Circuit struct {
NVars int
NPublic int
NSignals int
}

+ 21
- 0
fields/fq.go

@ -2,6 +2,7 @@ package fields
import ( import (
"bytes" "bytes"
"crypto/rand"
"math/big" "math/big"
) )
@ -117,6 +118,26 @@ func (fq Fq) Exp(base *big.Int, e *big.Int) *big.Int {
return res return res
} }
func (fq Fq) Rand() (*big.Int, error) {
// twoexp := new(big.Int).Exp(big.NewInt(2), big.NewInt(int64(maxbits)), nil)
// max := new(big.Int).Sub(twoexp, big.NewInt(1))
maxbits := fq.Q.BitLen()
b := make([]byte, (maxbits/8)-1)
// b := make([]byte, 3)
// b := make([]byte, 3)
_, err := rand.Read(b)
if err != nil {
return nil, err
}
r := new(big.Int).SetBytes(b)
rq := new(big.Int).Mod(r, fq.Q)
// return r over q, nil
return rq, nil
}
func (fq Fq) IsZero(a *big.Int) bool { func (fq Fq) IsZero(a *big.Int) bool {
return bytes.Equal(a.Bytes(), fq.Zero().Bytes()) return bytes.Equal(a.Bytes(), fq.Zero().Bytes())
} }

+ 3
- 0
go.mod

@ -2,5 +2,8 @@ module github.com/arnaucube/go-snark
require ( require (
github.com/arnaucube/cryptofun v0.0.0-20181124004321-9b11ae8280bd github.com/arnaucube/cryptofun v0.0.0-20181124004321-9b11ae8280bd
github.com/fatih/color v1.7.0
github.com/mattn/go-colorable v0.0.9 // indirect
github.com/mattn/go-isatty v0.0.4 // indirect
github.com/stretchr/testify v1.2.2 github.com/stretchr/testify v1.2.2
) )

+ 6
- 0
go.sum

@ -2,6 +2,12 @@ github.com/arnaucube/cryptofun v0.0.0-20181124004321-9b11ae8280bd h1:NDpNBTFeHNE
github.com/arnaucube/cryptofun v0.0.0-20181124004321-9b11ae8280bd/go.mod h1:PZE8kKpHPD1UMrS3mTfAMmEEinGtijSwjxLRqRcD64A= github.com/arnaucube/cryptofun v0.0.0-20181124004321-9b11ae8280bd/go.mod h1:PZE8kKpHPD1UMrS3mTfAMmEEinGtijSwjxLRqRcD64A=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 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/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 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/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=

+ 0
- 1
r1csqap/r1csqap.go

@ -95,7 +95,6 @@ func (pf PolynomialField) Sub(a, b []*big.Int) []*big.Int {
func (pf PolynomialField) Eval(v []*big.Int, x *big.Int) *big.Int { func (pf PolynomialField) Eval(v []*big.Int, x *big.Int) *big.Int {
r := big.NewInt(int64(0)) r := big.NewInt(int64(0))
for i := 0; i < len(v); i++ { for i := 0; i < len(v); i++ {
// xi := FloatPow(x, i)
xi := pf.F.Exp(x, big.NewInt(int64(i))) xi := pf.F.Exp(x, big.NewInt(int64(i)))
elem := pf.F.Mul(v[i], xi) elem := pf.F.Mul(v[i], xi)
r = pf.F.Add(r, elem) r = pf.F.Add(r, elem)

+ 81
- 119
snark.go

@ -1,11 +1,12 @@
package snark package snark
import ( import (
"crypto/rand"
"fmt" "fmt"
"math/big" "math/big"
"os"
"github.com/arnaucube/go-snark/bn128" "github.com/arnaucube/go-snark/bn128"
"github.com/arnaucube/go-snark/compiler"
"github.com/arnaucube/go-snark/fields" "github.com/arnaucube/go-snark/fields"
"github.com/arnaucube/go-snark/r1csqap" "github.com/arnaucube/go-snark/r1csqap"
) )
@ -36,9 +37,10 @@ type Setup struct {
Cp [][3]*big.Int Cp [][3]*big.Int
} }
Vk struct { Vk struct {
A [3][2]*big.Int
B [3]*big.Int
C [3][2]*big.Int
Vka [3][2]*big.Int
Vkb [3]*big.Int
Vkc [3][2]*big.Int
A [][3]*big.Int
G1Kbg [3]*big.Int // g1 * Kbeta * Kgamma G1Kbg [3]*big.Int // g1 * Kbeta * Kgamma
G2Kbg [3][2]*big.Int // g2 * Kbeta * Kgamma G2Kbg [3][2]*big.Int // g2 * Kbeta * Kgamma
G2Kg [3][2]*big.Int // g2 * Kgamma G2Kg [3][2]*big.Int // g2 * Kgamma
@ -47,67 +49,66 @@ type Setup struct {
} }
type Proof struct { type Proof struct {
PiA [3]*big.Int
PiAp [3]*big.Int
PiB [3][2]*big.Int
PiBp [3]*big.Int
PiC [3]*big.Int
PiCp [3]*big.Int
PiH [3]*big.Int
PiKp [3]*big.Int
PiA [3]*big.Int
PiAp [3]*big.Int
PiB [3][2]*big.Int
PiBp [3]*big.Int
PiC [3]*big.Int
PiCp [3]*big.Int
PiH [3]*big.Int
PiKp [3]*big.Int
PublicSignals []*big.Int
} }
const bits = 512
func GenerateTrustedSetup(bn bn128.Bn128, pf r1csqap.PolynomialField, witnessLength int, alphas, betas, gammas [][]*big.Int, ax, bx, cx, hx, zx []*big.Int) (Setup, error) {
func GenerateTrustedSetup(bn bn128.Bn128, fqR fields.Fq, pf r1csqap.PolynomialField, witnessLength int, circuit compiler.Circuit, alphas, betas, gammas [][]*big.Int, zx []*big.Int) (Setup, error) {
var setup Setup var setup Setup
var err error var err error
// generate random t value // generate random t value
setup.Toxic.T, err = rand.Prime(rand.Reader, bits)
setup.Toxic.T, err = fqR.Rand()
if err != nil { if err != nil {
return Setup{}, err return Setup{}, err
} }
// k for calculating pi' and Vk // k for calculating pi' and Vk
setup.Toxic.Ka, err = rand.Prime(rand.Reader, bits)
setup.Toxic.Ka, err = fqR.Rand()
if err != nil { if err != nil {
return Setup{}, err return Setup{}, err
} }
setup.Toxic.Kb, err = rand.Prime(rand.Reader, bits)
setup.Toxic.Kb, err = fqR.Rand()
if err != nil { if err != nil {
return Setup{}, err return Setup{}, err
} }
setup.Toxic.Kc, err = rand.Prime(rand.Reader, bits)
setup.Toxic.Kc, err = fqR.Rand()
if err != nil { if err != nil {
return Setup{}, err return Setup{}, err
} }
// generate Kβ (Kbeta) and Kγ (Kgamma) // generate Kβ (Kbeta) and Kγ (Kgamma)
setup.Toxic.Kbeta, err = rand.Prime(rand.Reader, bits)
setup.Toxic.Kbeta, err = fqR.Rand()
if err != nil { if err != nil {
return Setup{}, err return Setup{}, err
} }
setup.Toxic.Kgamma, err = rand.Prime(rand.Reader, bits)
setup.Toxic.Kgamma, err = fqR.Rand()
if err != nil { if err != nil {
return Setup{}, err return Setup{}, err
} }
// generate ρ (Rho): ρA, ρB, ρC // generate ρ (Rho): ρA, ρB, ρC
setup.Toxic.RhoA, err = rand.Prime(rand.Reader, bits)
setup.Toxic.RhoA, err = fqR.Rand()
if err != nil { if err != nil {
return Setup{}, err return Setup{}, err
} }
setup.Toxic.RhoB, err = rand.Prime(rand.Reader, bits)
setup.Toxic.RhoB, err = fqR.Rand()
if err != nil { if err != nil {
return Setup{}, err return Setup{}, err
} }
setup.Toxic.RhoC = bn.Fq1.Mul(setup.Toxic.RhoA, setup.Toxic.RhoB)
setup.Toxic.RhoC = fqR.Mul(setup.Toxic.RhoA, setup.Toxic.RhoB)
// encrypt t values with curve generators // encrypt t values with curve generators
var gt1 [][3]*big.Int var gt1 [][3]*big.Int
var gt2 [][3][2]*big.Int var gt2 [][3][2]*big.Int
for i := 0; i < witnessLength; i++ { for i := 0; i < witnessLength; i++ {
tPow := bn.Fq1.Exp(setup.Toxic.T, big.NewInt(int64(i)))
tPow := fqR.Exp(setup.Toxic.T, big.NewInt(int64(i)))
tEncr1 := bn.G1.MulScalar(bn.G1.G, tPow) tEncr1 := bn.G1.MulScalar(bn.G1.G, tPow)
gt1 = append(gt1, tEncr1) gt1 = append(gt1, tEncr1)
tEncr2 := bn.G2.MulScalar(bn.G2.G, tPow) tEncr2 := bn.G2.MulScalar(bn.G2.G, tPow)
@ -118,9 +119,9 @@ func GenerateTrustedSetup(bn bn128.Bn128, pf r1csqap.PolynomialField, witnessLen
setup.G1T = gt1 setup.G1T = gt1
setup.G2T = gt2 setup.G2T = gt2
setup.Vk.A = bn.G2.MulScalar(bn.G2.G, setup.Toxic.Ka)
setup.Vk.B = bn.G1.MulScalar(bn.G1.G, setup.Toxic.Kb)
setup.Vk.C = bn.G2.MulScalar(bn.G2.G, setup.Toxic.Kc)
setup.Vk.Vka = bn.G2.MulScalar(bn.G2.G, setup.Toxic.Ka)
setup.Vk.Vkb = bn.G1.MulScalar(bn.G1.G, setup.Toxic.Kb)
setup.Vk.Vkc = bn.G2.MulScalar(bn.G2.G, setup.Toxic.Kc)
/* /*
Verification keys: Verification keys:
@ -128,16 +129,19 @@ func GenerateTrustedSetup(bn bn128.Bn128, pf r1csqap.PolynomialField, witnessLen
- Vk_betagamma2: setup.G2Kbg = g2 * Kbeta*Kgamma - Vk_betagamma2: setup.G2Kbg = g2 * Kbeta*Kgamma
- Vk_gamma: setup.G2Kg = g2 * Kgamma - Vk_gamma: setup.G2Kg = g2 * Kgamma
*/ */
kbg := bn.Fq1.Mul(setup.Toxic.Kbeta, setup.Toxic.Kgamma)
kbg := fqR.Mul(setup.Toxic.Kbeta, setup.Toxic.Kgamma)
setup.Vk.G1Kbg = bn.G1.MulScalar(bn.G1.G, kbg) setup.Vk.G1Kbg = bn.G1.MulScalar(bn.G1.G, kbg)
setup.Vk.G2Kbg = bn.G2.MulScalar(bn.G2.G, kbg) setup.Vk.G2Kbg = bn.G2.MulScalar(bn.G2.G, kbg)
setup.Vk.G2Kg = bn.G2.MulScalar(bn.G2.G, setup.Toxic.Kgamma) setup.Vk.G2Kg = bn.G2.MulScalar(bn.G2.G, setup.Toxic.Kgamma)
for i := 0; i < witnessLength; i++ {
// A[i] = g1 * ax[t]
// for i := 0; i < circuit.NSignals; i++ {
for i := 0; i < circuit.NVars; i++ {
at := pf.Eval(alphas[i], setup.Toxic.T) at := pf.Eval(alphas[i], setup.Toxic.T)
a := bn.G1.MulScalar(bn.G1.G, at) a := bn.G1.MulScalar(bn.G1.G, at)
setup.Pk.A = append(setup.Pk.A, a) setup.Pk.A = append(setup.Pk.A, a)
if i <= circuit.NPublic {
setup.Vk.A = append(setup.Vk.A, a)
}
bt := pf.Eval(betas[i], setup.Toxic.T) bt := pf.Eval(betas[i], setup.Toxic.T)
bg1 := bn.G1.MulScalar(bn.G1.G, bt) bg1 := bn.G1.MulScalar(bn.G1.G, bt)
@ -148,20 +152,27 @@ func GenerateTrustedSetup(bn bn128.Bn128, pf r1csqap.PolynomialField, witnessLen
c := bn.G1.MulScalar(bn.G1.G, ct) c := bn.G1.MulScalar(bn.G1.G, ct)
setup.Pk.C = append(setup.Pk.C, c) setup.Pk.C = append(setup.Pk.C, c)
kt := bn.Fq1.Add(bn.Fq1.Add(at, bt), ct)
k := bn.G1.MulScalar(bn.G1.G, kt)
kt := fqR.Add(fqR.Add(at, bt), ct)
k := bn.G1.Affine(bn.G1.MulScalar(bn.G1.G, kt))
ktest := bn.G1.Affine(bn.G1.Add(bn.G1.Add(a, bg1), c))
if !bn.Fq2.Equal(k, ktest) {
os.Exit(1)
return setup, err
}
setup.Pk.Ap = append(setup.Pk.Ap, bn.G1.MulScalar(a, setup.Toxic.Ka)) setup.Pk.Ap = append(setup.Pk.Ap, bn.G1.MulScalar(a, setup.Toxic.Ka))
setup.Pk.Bp = append(setup.Pk.Bp, bn.G1.MulScalar(bg1, setup.Toxic.Kb)) setup.Pk.Bp = append(setup.Pk.Bp, bn.G1.MulScalar(bg1, setup.Toxic.Kb))
setup.Pk.Cp = append(setup.Pk.Cp, bn.G1.MulScalar(c, setup.Toxic.Kc)) setup.Pk.Cp = append(setup.Pk.Cp, bn.G1.MulScalar(c, setup.Toxic.Kc))
setup.Pk.Kp = append(setup.Pk.Kp, bn.G1.MulScalar(k, setup.Toxic.Kbeta))
k_ := bn.G1.MulScalar(bn.G1.G, kt)
setup.Pk.Kp = append(setup.Pk.Kp, bn.G1.MulScalar(k_, setup.Toxic.Kbeta))
} }
setup.Vk.Vkz = bn.G2.MulScalar(bn.G2.G, pf.Eval(zx, setup.Toxic.T)) setup.Vk.Vkz = bn.G2.MulScalar(bn.G2.G, pf.Eval(zx, setup.Toxic.T))
return setup, nil return setup, nil
} }
func GenerateProofs(bn bn128.Bn128, f fields.Fq, setup Setup, hx []*big.Int, w []*big.Int) (Proof, error) {
func GenerateProofs(bn bn128.Bn128, f fields.Fq, circuit compiler.Circuit, setup Setup, hx []*big.Int, w []*big.Int) (Proof, error) {
var proof Proof var proof Proof
proof.PiA = [3]*big.Int{bn.G1.F.Zero(), bn.G1.F.Zero(), bn.G1.F.Zero()} proof.PiA = [3]*big.Int{bn.G1.F.Zero(), bn.G1.F.Zero(), bn.G1.F.Zero()}
proof.PiAp = [3]*big.Int{bn.G1.F.Zero(), bn.G1.F.Zero(), bn.G1.F.Zero()} proof.PiAp = [3]*big.Int{bn.G1.F.Zero(), bn.G1.F.Zero(), bn.G1.F.Zero()}
@ -172,12 +183,12 @@ func GenerateProofs(bn bn128.Bn128, f fields.Fq, setup Setup, hx []*big.Int, w [
proof.PiH = [3]*big.Int{bn.G1.F.Zero(), bn.G1.F.Zero(), bn.G1.F.Zero()} proof.PiH = [3]*big.Int{bn.G1.F.Zero(), bn.G1.F.Zero(), bn.G1.F.Zero()}
proof.PiKp = [3]*big.Int{bn.G1.F.Zero(), bn.G1.F.Zero(), bn.G1.F.Zero()} proof.PiKp = [3]*big.Int{bn.G1.F.Zero(), bn.G1.F.Zero(), bn.G1.F.Zero()}
for i := 0; i < len(w); i++ {
for i := circuit.NPublic + 1; i < circuit.NVars; i++ {
proof.PiA = bn.G1.Add(proof.PiA, bn.G1.MulScalar(setup.Pk.A[i], w[i])) proof.PiA = bn.G1.Add(proof.PiA, bn.G1.MulScalar(setup.Pk.A[i], w[i]))
proof.PiAp = bn.G1.Add(proof.PiAp, bn.G1.MulScalar(setup.Pk.Ap[i], w[i])) proof.PiAp = bn.G1.Add(proof.PiAp, bn.G1.MulScalar(setup.Pk.Ap[i], w[i]))
} }
for i := 0; i < len(w); i++ {
for i := 0; i < circuit.NVars; i++ {
proof.PiB = bn.G2.Add(proof.PiB, bn.G2.MulScalar(setup.Pk.B[i], w[i])) proof.PiB = bn.G2.Add(proof.PiB, bn.G2.MulScalar(setup.Pk.B[i], w[i]))
proof.PiBp = bn.G1.Add(proof.PiBp, bn.G1.MulScalar(setup.Pk.Bp[i], w[i])) proof.PiBp = bn.G1.Add(proof.PiBp, bn.G1.MulScalar(setup.Pk.Bp[i], w[i]))
@ -186,122 +197,73 @@ func GenerateProofs(bn bn128.Bn128, f fields.Fq, setup Setup, hx []*big.Int, w [
proof.PiKp = bn.G1.Add(proof.PiKp, bn.G1.MulScalar(setup.Pk.Kp[i], w[i])) proof.PiKp = bn.G1.Add(proof.PiKp, bn.G1.MulScalar(setup.Pk.Kp[i], w[i]))
} }
for i := 0; i < len(hx); i++ { for i := 0; i < len(hx); i++ {
proof.PiH = bn.G1.Add(proof.PiH, bn.G1.MulScalar(setup.G1T[i], hx[i])) proof.PiH = bn.G1.Add(proof.PiH, bn.G1.MulScalar(setup.G1T[i], hx[i]))
} }
proof.PublicSignals = w[1 : circuit.NPublic+1]
return proof, nil return proof, nil
} }
func VerifyProof(bn bn128.Bn128, setup Setup, proof Proof) bool {
func VerifyProof(bn bn128.Bn128, circuit compiler.Circuit, setup Setup, proof Proof) bool {
// e(piA, Va) == e(piA', g2) // e(piA, Va) == e(piA', g2)
pairingPiaVa, err := bn.Pairing(proof.PiA, setup.Vk.A)
if err != nil {
return false
}
pairingPiapG2, err := bn.Pairing(proof.PiAp, bn.G2.G)
if err != nil {
return false
}
pairingPiaVa := bn.Pairing(proof.PiA, setup.Vk.Vka)
pairingPiapG2 := bn.Pairing(proof.PiAp, bn.G2.G)
if !bn.Fq12.Equal(pairingPiaVa, pairingPiapG2) { if !bn.Fq12.Equal(pairingPiaVa, pairingPiapG2) {
return false return false
} else { } else {
fmt.Println("valid knowledge commitment for A")
fmt.Println("✓ e(piA, Va) == e(piA', g2), valid knowledge commitment for A")
} }
// e(Vb, piB) == e(piB', g2) // e(Vb, piB) == e(piB', g2)
pairingVbPib, err := bn.Pairing(setup.Vk.B, proof.PiB)
if err != nil {
return false
}
pairingPibpG2, err := bn.Pairing(proof.PiBp, bn.G2.G)
if err != nil {
return false
}
pairingVbPib := bn.Pairing(setup.Vk.Vkb, proof.PiB)
pairingPibpG2 := bn.Pairing(proof.PiBp, bn.G2.G)
if !bn.Fq12.Equal(pairingVbPib, pairingPibpG2) { if !bn.Fq12.Equal(pairingVbPib, pairingPibpG2) {
return false return false
} else { } else {
fmt.Println("valid knowledge commitment for B")
fmt.Println("✓ e(Vb, piB) == e(piB', g2), valid knowledge commitment for B")
} }
// e(piC, Vc) == e(piC', g2) // e(piC, Vc) == e(piC', g2)
pairingPicVc, err := bn.Pairing(proof.PiC, setup.Vk.C)
if err != nil {
return false
}
pairingPicpG2, err := bn.Pairing(proof.PiCp, bn.G2.G)
if err != nil {
return false
}
pairingPicVc := bn.Pairing(proof.PiC, setup.Vk.Vkc)
pairingPicpG2 := bn.Pairing(proof.PiCp, bn.G2.G)
if !bn.Fq12.Equal(pairingPicVc, pairingPicpG2) { if !bn.Fq12.Equal(pairingPicVc, pairingPicpG2) {
return false return false
} else { } else {
fmt.Println("valid knowledge commitment for C")
fmt.Println("✓ e(piC, Vc) == e(piC', g2), valid knowledge commitment for C")
} }
// Vkx, to then calculate Vkx+piA // Vkx, to then calculate Vkx+piA
vkxpia := setup.Vk.A[0]
for i := 0; i < circuit.NPublic; i++ {
vkxpia = bn.G1.Add(vkxpia, bn.G1.MulScalar(setup.Vk.A[i+1], proof.PublicSignals[i]))
}
// e(Vkx+piA, piB) == e(piH, Vkz) * e(piC, g2) // e(Vkx+piA, piB) == e(piH, Vkz) * e(piC, g2)
pairingPiaPib, err := bn.Pairing(proof.PiA, proof.PiB)
if err != nil {
return false
}
pairingPihVkz, err := bn.Pairing(proof.PiH, setup.Vk.Vkz)
if err != nil {
return false
}
pairingPicG2, err := bn.Pairing(proof.PiC, bn.G2.G)
if err != nil {
return false
}
pairingR := bn.Fq12.Mul(pairingPihVkz, pairingPicG2)
if !bn.Fq12.Equal(pairingPiaPib, pairingR) {
fmt.Println("p4")
if !bn.Fq12.Equal(
bn.Pairing(bn.G1.Add(vkxpia, proof.PiA), proof.PiB),
bn.Fq12.Mul(
bn.Pairing(proof.PiH, setup.Vk.Vkz),
bn.Pairing(proof.PiC, bn.G2.G))) {
return false return false
} else { } else {
fmt.Println("QAP disibility checked")
fmt.Println("✓ e(Vkx+piA, piB) == e(piH, Vkz) * e(piC, g2), QAP disibility checked")
} }
// e(piA+piC, g2KbetaKgamma) * e(g1KbetaKgamma, piB)
// e(Vkx+piA+piC, g2KbetaKgamma) * e(g1KbetaKgamma, piB)
// == e(piK, g2Kgamma) // == e(piK, g2Kgamma)
// piApiC := bn.G1.Add(proof.PiA, proof.PiC)
// pairingPiACG2Kbg, err := bn.Pairing(piApiC, setup.Vk.G2Kbg)
// if err != nil {
// return false
// }
// pairingG1KbgPiB, err := bn.Pairing(setup.Vk.G1Kbg, proof.PiB)
// if err != nil {
// return false
// }
// pairingL := bn.Fq12.Mul(pairingPiACG2Kbg, pairingG1KbgPiB)
// pairingR, err := bn.Pairing(proof.PiKp, setup.Vk.G2Kg)
// if err != nil {
// return false
// }
// if !bn.Fq12.Equal(pairingL, pairingR) {
// fmt.Println("p5")
// return false
// }
//
// e(piA, piB) == e(piH, Vz) * e(piC, g2)
// pairingPiaPib, err := bn.Pairing(proof.PiA, proof.PiB)
// if err != nil {
// return false
// }
// pairingPihVz, err := bn.Pairing(proof.PiH, setup.Vk.Vkz)
// if err != nil {
// return false
// }
// pairingPicG2, err := bn.Pairing(proof.PiC, bn.G2.G)
// if err != nil {
// return false
// }
// if !bn.Fq12.Equal(pairingPiaPib, bn.Fq12.Mul(pairingPihVz, pairingPicG2)) {
// return false
// }
piApiC := bn.G1.Add(bn.G1.Add(vkxpia, proof.PiA), proof.PiC)
pairingPiACG2Kbg := bn.Pairing(piApiC, setup.Vk.G2Kbg)
pairingG1KbgPiB := bn.Pairing(setup.Vk.G1Kbg, proof.PiB)
pairingL := bn.Fq12.Mul(pairingPiACG2Kbg, pairingG1KbgPiB)
pairingR := bn.Pairing(proof.PiKp, setup.Vk.G2Kg)
if !bn.Fq12.Equal(pairingL, pairingR) {
return false
} else {
fmt.Println("✓ e(Vkx+piA+piC, g2KbetaKgamma) * e(g1KbetaKgamma, piB) == e(piK, g2Kgamma)")
}
return true return true
} }

+ 17
- 14
snark_test.go

@ -6,6 +6,7 @@ import (
"testing" "testing"
"github.com/arnaucube/go-snark/bn128" "github.com/arnaucube/go-snark/bn128"
"github.com/arnaucube/go-snark/compiler"
"github.com/arnaucube/go-snark/fields" "github.com/arnaucube/go-snark/fields"
"github.com/arnaucube/go-snark/r1csqap" "github.com/arnaucube/go-snark/r1csqap"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -16,10 +17,10 @@ func TestZk(t *testing.T) {
assert.Nil(t, err) assert.Nil(t, err)
// new Finite Field // new Finite Field
f := fields.NewFq(bn.R)
fqR := fields.NewFq(bn.R)
// new Polynomial Field // new Polynomial Field
pf := r1csqap.NewPolynomialField(f)
pf := r1csqap.NewPolynomialField(fqR)
b0 := big.NewInt(int64(0)) b0 := big.NewInt(int64(0))
b1 := big.NewInt(int64(1)) b1 := big.NewInt(int64(1))
@ -49,7 +50,13 @@ func TestZk(t *testing.T) {
} }
alphas, betas, gammas, zx := pf.R1CSToQAP(a, b, c) alphas, betas, gammas, zx := pf.R1CSToQAP(a, b, c)
// wittness = 1, 3, 35, 9, 27, 30
w := []*big.Int{b1, b3, b35, b9, b27, b30} w := []*big.Int{b1, b3, b35, b9, b27, b30}
circuit := compiler.Circuit{
NVars: 6,
NPublic: 0,
NSignals: len(w),
}
ax, bx, cx, px := pf.CombinePolynomials(w, alphas, betas, gammas) ax, bx, cx, px := pf.CombinePolynomials(w, alphas, betas, gammas)
hx := pf.DivisorPolinomial(px, zx) hx := pf.DivisorPolinomial(px, zx)
@ -62,23 +69,19 @@ func TestZk(t *testing.T) {
assert.Equal(t, abc, px) assert.Equal(t, abc, px)
hz := pf.Mul(hx, zx) hz := pf.Mul(hx, zx)
assert.Equal(t, abc, hz) assert.Equal(t, abc, hz)
div, rem := pf.Div(px, zx)
assert.Equal(t, hx, div)
assert.Equal(t, rem, r1csqap.ArrayOfBigZeros(4))
// calculate trusted setup // calculate trusted setup
setup, err := GenerateTrustedSetup(bn, pf, len(w), alphas, betas, gammas, ax, bx, cx, hx, zx)
setup, err := GenerateTrustedSetup(bn, fqR, pf, len(w), circuit, alphas, betas, gammas, zx)
assert.Nil(t, err) assert.Nil(t, err)
fmt.Println("trusted setup:")
fmt.Println(setup.G1T)
fmt.Println(setup.G2T)
fmt.Println("t", setup.Toxic.T)
// piA = g1 * A(t), piB = g2 * B(t), piC = g1 * C(t), piH = g1 * H(t) // piA = g1 * A(t), piB = g2 * B(t), piC = g1 * C(t), piH = g1 * H(t)
proof, err := GenerateProofs(bn, f, setup, hx, w)
proof, err := GenerateProofs(bn, fqR, circuit, setup, hx, w)
assert.Nil(t, err) assert.Nil(t, err)
fmt.Println("proofs:")
fmt.Println(proof.PiA)
fmt.Println(proof.PiB)
fmt.Println(proof.PiC)
fmt.Println(proof.PiH)
// fmt.Println(proof.Vz)
assert.True(t, VerifyProof(bn, setup, proof))
assert.True(t, VerifyProof(bn, circuit, setup, proof))
} }

Loading…
Cancel
Save