mirror of
https://github.com/arnaucube/go-snark-study.git
synced 2026-02-02 17:26:41 +01:00
r1cs to qap over finite field
This commit is contained in:
157
r1csqap/r1csqap.go
Normal file
157
r1csqap/r1csqap.go
Normal file
@@ -0,0 +1,157 @@
|
||||
package r1csqap
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"github.com/arnaucube/go-snark/fields"
|
||||
)
|
||||
|
||||
func Transpose(matrix [][]*big.Int) [][]*big.Int {
|
||||
var r [][]*big.Int
|
||||
for i := 0; i < len(matrix[0]); i++ {
|
||||
var row []*big.Int
|
||||
for j := 0; j < len(matrix); j++ {
|
||||
row = append(row, matrix[j][i])
|
||||
}
|
||||
r = append(r, row)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func ArrayOfBigZeros(num int) []*big.Int {
|
||||
bigZero := big.NewInt(int64(0))
|
||||
var r []*big.Int
|
||||
for i := 0; i < num; i++ {
|
||||
r = append(r, bigZero)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
type PolynomialField struct {
|
||||
F fields.Fq
|
||||
}
|
||||
|
||||
func NewPolynomialField(f fields.Fq) PolynomialField {
|
||||
return PolynomialField{
|
||||
f,
|
||||
}
|
||||
}
|
||||
func (pf PolynomialField) Mul(a, b []*big.Int) []*big.Int {
|
||||
r := ArrayOfBigZeros(len(a) + len(b) - 1)
|
||||
for i := 0; i < len(a); i++ {
|
||||
for j := 0; j < len(b); j++ {
|
||||
r[i+j] = pf.F.Add(
|
||||
r[i+j],
|
||||
pf.F.Mul(a[i], b[j]))
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func max(a, b int) int {
|
||||
if a > b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func (pf PolynomialField) Add(a, b []*big.Int) []*big.Int {
|
||||
r := ArrayOfBigZeros(max(len(a), len(b)))
|
||||
for i := 0; i < len(a); i++ {
|
||||
r[i] = pf.F.Add(r[i], a[i])
|
||||
}
|
||||
for i := 0; i < len(b); i++ {
|
||||
r[i] = pf.F.Add(r[i], b[i])
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func (pf PolynomialField) Sub(a, b []*big.Int) []*big.Int {
|
||||
r := ArrayOfBigZeros(max(len(a), len(b)))
|
||||
for i := 0; i < len(a); i++ {
|
||||
r[i] = pf.F.Add(r[i], a[i])
|
||||
}
|
||||
for i := 0; i < len(b); i++ {
|
||||
// bneg := pf.F.Mul(b[i], big.NewInt(int64(-1)))
|
||||
// r[i] = pf.F.Add(r[i], bneg)
|
||||
r[i] = pf.F.Sub(r[i], b[i])
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// func FloatPow(a *big.Int, e int) *big.Int {
|
||||
// if e == 0 {
|
||||
// return big.NewInt(int64(1))
|
||||
// }
|
||||
// result := new(big.Int).Copy(a)
|
||||
// for i := 0; i < e-1; i++ {
|
||||
// result = new(big.Int).Mul(result, a)
|
||||
// }
|
||||
// return result
|
||||
// }
|
||||
|
||||
func (pf PolynomialField) Eval(v []*big.Int, x *big.Int) *big.Int {
|
||||
r := big.NewInt(int64(0))
|
||||
for i := 0; i < len(v); i++ {
|
||||
// xi := FloatPow(x, i)
|
||||
xi := pf.F.Exp(x, big.NewInt(int64(i)))
|
||||
elem := pf.F.Mul(v[i], xi)
|
||||
r = pf.F.Add(r, elem)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func (pf PolynomialField) NewPolZeroAt(pointPos, totalPoints int, height *big.Int) []*big.Int {
|
||||
fac := 1
|
||||
for i := 1; i < totalPoints+1; i++ {
|
||||
if i != pointPos {
|
||||
fac = fac * (pointPos - i)
|
||||
}
|
||||
}
|
||||
facBig := big.NewInt(int64(fac))
|
||||
hf := pf.F.Div(height, facBig)
|
||||
r := []*big.Int{hf}
|
||||
for i := 1; i < totalPoints+1; i++ {
|
||||
if i != pointPos {
|
||||
ineg := big.NewInt(int64(-i))
|
||||
b1 := big.NewInt(int64(1))
|
||||
r = pf.Mul(r, []*big.Int{ineg, b1})
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
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]))
|
||||
}
|
||||
//
|
||||
return r
|
||||
}
|
||||
|
||||
func (pf PolynomialField) R1CSToQAP(a, b, c [][]*big.Int) ([][]*big.Int, [][]*big.Int, [][]*big.Int, []*big.Int) {
|
||||
aT := Transpose(a)
|
||||
bT := Transpose(b)
|
||||
cT := Transpose(c)
|
||||
var alpha [][]*big.Int
|
||||
for i := 0; i < len(aT); i++ {
|
||||
alpha = append(alpha, pf.LagrangeInterpolation(aT[i]))
|
||||
}
|
||||
var beta [][]*big.Int
|
||||
for i := 0; i < len(bT); i++ {
|
||||
beta = append(beta, pf.LagrangeInterpolation(bT[i]))
|
||||
}
|
||||
var gamma [][]*big.Int
|
||||
for i := 0; i < len(cT); i++ {
|
||||
gamma = append(gamma, 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})
|
||||
}
|
||||
return alpha, beta, gamma, z
|
||||
}
|
||||
136
r1csqap/r1csqap_test.go
Normal file
136
r1csqap/r1csqap_test.go
Normal file
@@ -0,0 +1,136 @@
|
||||
package r1csqap
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/arnaucube/go-snark/fields"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestTranspose(t *testing.T) {
|
||||
b0 := big.NewInt(int64(0))
|
||||
b1 := big.NewInt(int64(1))
|
||||
bFive := big.NewInt(int64(5))
|
||||
a := [][]*big.Int{
|
||||
[]*big.Int{b0, b1, b0, b0, b0, b0},
|
||||
[]*big.Int{b0, b0, b0, b1, b0, b0},
|
||||
[]*big.Int{b0, b1, b0, b0, b1, b0},
|
||||
[]*big.Int{bFive, b0, b0, b0, b0, b1},
|
||||
}
|
||||
aT := Transpose(a)
|
||||
assert.Equal(t, aT, [][]*big.Int{
|
||||
[]*big.Int{b0, b0, b0, bFive},
|
||||
[]*big.Int{b1, b0, b1, b0},
|
||||
[]*big.Int{b0, b0, b0, b0},
|
||||
[]*big.Int{b0, b1, b0, b0},
|
||||
[]*big.Int{b0, b0, b1, b0},
|
||||
[]*big.Int{b0, b0, b0, b1},
|
||||
})
|
||||
}
|
||||
|
||||
func TestPol(t *testing.T) {
|
||||
b0 := big.NewInt(int64(0))
|
||||
b1 := big.NewInt(int64(1))
|
||||
b3 := big.NewInt(int64(3))
|
||||
b4 := big.NewInt(int64(4))
|
||||
b5 := big.NewInt(int64(5))
|
||||
b6 := big.NewInt(int64(6))
|
||||
b16 := big.NewInt(int64(16))
|
||||
|
||||
a := []*big.Int{b1, b0, b5}
|
||||
b := []*big.Int{b3, b0, b1}
|
||||
|
||||
// new Finite Field
|
||||
r, ok := new(big.Int).SetString("21888242871839275222246405745257275088548364400416034343698204186575808495617", 10)
|
||||
assert.True(nil, ok)
|
||||
f := fields.NewFq(r)
|
||||
|
||||
// new Polynomial Field
|
||||
pf := NewPolynomialField(f)
|
||||
|
||||
// polynomial multiplication
|
||||
o := pf.Mul(a, b)
|
||||
assert.Equal(t, o, []*big.Int{b3, b0, b16, b0, b5})
|
||||
|
||||
// polynomial addition
|
||||
o = pf.Add(a, b)
|
||||
assert.Equal(t, o, []*big.Int{b4, b0, b6})
|
||||
|
||||
// polynomial subtraction
|
||||
o1 := pf.Sub(a, b)
|
||||
o2 := pf.Sub(b, a)
|
||||
o = pf.Add(o1, o2)
|
||||
assert.True(t, bytes.Equal(b0.Bytes(), o[0].Bytes()))
|
||||
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}
|
||||
o = pf.Sub(c, d)
|
||||
assert.Equal(t, o, []*big.Int{b4, b3, b1})
|
||||
|
||||
// NewPolZeroAt
|
||||
o = pf.NewPolZeroAt(3, 4, b4)
|
||||
assert.Equal(t, pf.Eval(o, big.NewInt(3)), b4)
|
||||
o = pf.NewPolZeroAt(2, 4, b3)
|
||||
assert.Equal(t, pf.Eval(o, big.NewInt(2)), b3)
|
||||
}
|
||||
|
||||
func TestLagrangeInterpolation(t *testing.T) {
|
||||
// new Finite Field
|
||||
r, ok := new(big.Int).SetString("21888242871839275222246405745257275088548364400416034343698204186575808495617", 10)
|
||||
assert.True(nil, ok)
|
||||
f := fields.NewFq(r)
|
||||
// new Polynomial Field
|
||||
pf := NewPolynomialField(f)
|
||||
|
||||
b0 := big.NewInt(int64(0))
|
||||
b5 := big.NewInt(int64(5))
|
||||
a := []*big.Int{b0, b0, b0, b5}
|
||||
alpha := pf.LagrangeInterpolation(a)
|
||||
|
||||
assert.Equal(t, pf.Eval(alpha, big.NewInt(int64(4))), b5)
|
||||
aux := pf.Eval(alpha, big.NewInt(int64(3))).Int64()
|
||||
assert.Equal(t, aux, int64(0))
|
||||
|
||||
}
|
||||
|
||||
func TestR1CSToQAP(t *testing.T) {
|
||||
// new Finite Field
|
||||
r, ok := new(big.Int).SetString("21888242871839275222246405745257275088548364400416034343698204186575808495617", 10)
|
||||
assert.True(nil, ok)
|
||||
f := fields.NewFq(r)
|
||||
// new Polynomial Field
|
||||
pf := NewPolynomialField(f)
|
||||
|
||||
b0 := big.NewInt(int64(0))
|
||||
b1 := big.NewInt(int64(1))
|
||||
b5 := big.NewInt(int64(5))
|
||||
a := [][]*big.Int{
|
||||
[]*big.Int{b0, b1, b0, b0, b0, b0},
|
||||
[]*big.Int{b0, b0, b0, b1, b0, b0},
|
||||
[]*big.Int{b0, b1, b0, b0, b1, b0},
|
||||
[]*big.Int{b5, b0, b0, b0, b0, b1},
|
||||
}
|
||||
b := [][]*big.Int{
|
||||
[]*big.Int{b0, b1, b0, b0, b0, b0},
|
||||
[]*big.Int{b0, b1, b0, b0, b0, b0},
|
||||
[]*big.Int{b1, b0, b0, b0, b0, b0},
|
||||
[]*big.Int{b1, b0, b0, b0, b0, b0},
|
||||
}
|
||||
c := [][]*big.Int{
|
||||
[]*big.Int{b0, b0, b0, b1, b0, b0},
|
||||
[]*big.Int{b0, b0, b0, b0, b1, b0},
|
||||
[]*big.Int{b0, b0, b0, b0, b0, b1},
|
||||
[]*big.Int{b0, b0, b1, b0, b0, b0},
|
||||
}
|
||||
alpha, beta, gamma, z := pf.R1CSToQAP(a, b, c)
|
||||
fmt.Println(alpha)
|
||||
fmt.Println(beta)
|
||||
fmt.Println(gamma)
|
||||
fmt.Println(z)
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user