mirror of https://github.com/vacp2p/gnark-rln.git
feat: init
This commit is contained in:
commit
33502bd39a
|
@ -0,0 +1,11 @@
|
|||
# g-rln
|
||||
|
||||
gnark implementation of rln-v2. super hacky and unclean.
|
||||
|
||||
Need to get kats from zerokit and replace the circuit assertions for y, root, nullifier.
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
go run main.go
|
||||
```
|
|
@ -0,0 +1,34 @@
|
|||
module github.com/rymnc/g-rln
|
||||
|
||||
go 1.22.1
|
||||
|
||||
require (
|
||||
github.com/AlpinYukseloglu/poseidon-gnark v0.0.0-20230513045146-69f5c852ef54
|
||||
github.com/consensys/gnark v0.9.1
|
||||
github.com/reilabs/gnark-lean-extractor v1.0.0
|
||||
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/bits-and-blooms/bitset v1.8.0 // indirect
|
||||
github.com/blang/semver/v4 v4.0.0 // indirect
|
||||
github.com/consensys/bavard v0.1.13 // indirect
|
||||
github.com/consensys/gnark-crypto v0.12.2-0.20231013160410-1f65e75b6dfb // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.5.0 // indirect
|
||||
github.com/google/pprof v0.0.0-20230817174616-7a8ec2ada47b // indirect
|
||||
github.com/iden3/go-iden3-crypto v0.0.16
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.19 // indirect
|
||||
github.com/mmcloughlin/addchain v0.4.0 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/reilabs/gnark-lean-demo v0.0.0-20230831223820-a3955946e0d5 // indirect
|
||||
github.com/rs/zerolog v1.30.0 // indirect
|
||||
github.com/stretchr/testify v1.8.4 // indirect
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
golang.org/x/crypto v0.12.0 // indirect
|
||||
golang.org/x/sync v0.3.0 // indirect
|
||||
golang.org/x/sys v0.11.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
rsc.io/tmplfunc v0.0.3 // indirect
|
||||
)
|
|
@ -0,0 +1,66 @@
|
|||
github.com/AlpinYukseloglu/poseidon-gnark v0.0.0-20230513045146-69f5c852ef54 h1:fOzroAaK/5CVGizMvhpBRo1GKPEWasZccNUi+9Y7uQw=
|
||||
github.com/AlpinYukseloglu/poseidon-gnark v0.0.0-20230513045146-69f5c852ef54/go.mod h1:xn3T1WspWqgbMXkObyFWNnjOUP09SkOK45V9J1vifBk=
|
||||
github.com/bits-and-blooms/bitset v1.8.0 h1:FD+XqgOZDUxxZ8hzoBFuV9+cGWY9CslN6d5MS5JVb4c=
|
||||
github.com/bits-and-blooms/bitset v1.8.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
|
||||
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
|
||||
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
|
||||
github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ=
|
||||
github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI=
|
||||
github.com/consensys/gnark v0.8.0 h1:0bQ2MyDG4oNjMQpNyL8HjrrUSSL3yYJg0Elzo6LzmcU=
|
||||
github.com/consensys/gnark v0.8.0/go.mod h1:aKmA7dIiLbTm0OV37xTq0z+Bpe4xER8EhRLi6necrm8=
|
||||
github.com/consensys/gnark v0.9.1 h1:aTwBp5469MY/2jNrf4ABrqHRW3+JytfkADdw4ZBY7T0=
|
||||
github.com/consensys/gnark v0.9.1/go.mod h1:udWvWGXnfBE7mn7BsNoGAvZDnUhcONBEtNijvVjfY80=
|
||||
github.com/consensys/gnark-crypto v0.12.2-0.20231013160410-1f65e75b6dfb h1:f0BMgIjhZy4lSRHCXFbQst85f5agZAjtDMixQqBWNpc=
|
||||
github.com/consensys/gnark-crypto v0.12.2-0.20231013160410-1f65e75b6dfb/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5UlG+EM5t7MPHiLuY=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
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/dchest/blake512 v1.0.0/go.mod h1:FV1x7xPPLWukZlpDpWQ88rF/SFwZ5qbskrzhLMB92JI=
|
||||
github.com/fxamacker/cbor/v2 v2.5.0 h1:oHsG0V/Q6E/wqTS2O1Cozzsy69nqCiguo5Q1a1ADivE=
|
||||
github.com/fxamacker/cbor/v2 v2.5.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/google/pprof v0.0.0-20230817174616-7a8ec2ada47b h1:h9U78+dx9a4BKdQkBBos92HalKpaGKHrp+3Uo6yTodo=
|
||||
github.com/google/pprof v0.0.0-20230817174616-7a8ec2ada47b/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
|
||||
github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
|
||||
github.com/iden3/go-iden3-crypto v0.0.16 h1:zN867xiz6HgErXVIV/6WyteGcOukE9gybYTorBMEdsk=
|
||||
github.com/iden3/go-iden3-crypto v0.0.16/go.mod h1:dLpM4vEPJ3nDHzhWFXDjzkn1qHoBeOT/3UEhXsEsP3E=
|
||||
github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8=
|
||||
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY=
|
||||
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/reilabs/gnark-lean-demo v0.0.0-20230831223820-a3955946e0d5 h1:UxNLMPNbqte3ABu0EDrSH8bo5C2DqdVXf2ChzSZb2ik=
|
||||
github.com/reilabs/gnark-lean-demo v0.0.0-20230831223820-a3955946e0d5/go.mod h1:n62YzMgj38d/zyjs0I1GGO0Bky9NDX2akGx4W2pmo4A=
|
||||
github.com/reilabs/gnark-lean-extractor v1.0.0 h1:jLoI4Dh3eAFdhJ3hvUfBmKJgB2NLPGrL7VW+WDRecCQ=
|
||||
github.com/reilabs/gnark-lean-extractor v1.0.0/go.mod h1:FuCRQ2kdpdImOzmzFUqMoCMQxn+Nol+AmzPDWlBZLA8=
|
||||
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||
github.com/rs/zerolog v1.30.0 h1:SymVODrcRsaRaSInD9yQtKbtWqwsfoPcRff/oRXLj4c=
|
||||
github.com/rs/zerolog v1.30.0/go.mod h1:/tk+P47gFdPXq4QYjvCmT5/Gsug2nagsFWBWhAiSi1w=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
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/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk=
|
||||
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
|
||||
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
|
||||
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
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.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=
|
||||
golang.org/x/sys v0.11.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.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=
|
|
@ -0,0 +1,131 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/consensys/gnark-crypto/ecc"
|
||||
"github.com/consensys/gnark-crypto/ecc/bn254/fr"
|
||||
"github.com/consensys/gnark/backend/groth16"
|
||||
"github.com/consensys/gnark/frontend"
|
||||
"github.com/consensys/gnark/frontend/cs/r1cs"
|
||||
rln "github.com/rymnc/g-rln/rln"
|
||||
)
|
||||
|
||||
func main() {
|
||||
identityPathIndex := [20]frontend.Variable{
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
}
|
||||
|
||||
rawPathElements := [20]string{
|
||||
"14082964758224722211945379872337797638951236517417253447686770846170014042825",
|
||||
"6628418579821163687428454604867534487917867918886059133241840211975892987309",
|
||||
"12745863228198753394445659605634840709296716381893463421165313830643281758511",
|
||||
"56118267389743063830320351452083247040583061493621478539311100137113963555",
|
||||
"3648731943306935051357703221473866306053186513730785325303257057776816073765",
|
||||
"10548621390442503192989374711060717107954536293658152583621924810330521179016",
|
||||
"11741160669079729961275351458682156164905457324981803454515784688429276743441",
|
||||
"17165464309215350864730477596846156251863702878546777829650812432906796008534",
|
||||
"18947162586829418653666557598416458949428989734998924978331450666032720066913",
|
||||
"8809427088917589399897132358419395928548406347152047718919154153577297139202",
|
||||
"6261460226929242970747566981077801929281729646713842579109271945192964422300",
|
||||
"13871468675790284383809887052382100311103716176061564908030808887079542722597",
|
||||
"10413964486611723004584705484327518190402370933255450052832412709168190985805",
|
||||
"3978387560092078849178760154060822400741873818692524912249877867958842934383",
|
||||
"14014915591348694328771517896715085647041518432952027841088176673715002508448",
|
||||
"17680675606519345547327984724173632294904524423937145835611954334756161077843",
|
||||
"17107175244885276119916848057745382329169223109661217238296871427531065458152",
|
||||
"18326186549441826262593357123467931475982067066825042001499291800252145875109",
|
||||
"7043961192177345916232559778383741091053414803377017307095275172896944935996",
|
||||
"2807630271073553218355393059254209097448243975722083008310815929736065268921",
|
||||
}
|
||||
|
||||
pathElements := [20]frontend.Variable{}
|
||||
// iterate over pathElements and replace with fr.Modulus().SetString("...") for eac, 10h element
|
||||
for i := 0; i < len(pathElements); i++ {
|
||||
x, ret := fr.Modulus().SetString(rawPathElements[i], 10)
|
||||
if ret != true {
|
||||
panic(ret)
|
||||
}
|
||||
pathElements[i] = frontend.Variable(x)
|
||||
}
|
||||
|
||||
cs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &rln.RlnCircuit{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
pk, vk, err := groth16.Setup(cs)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
x, ret := fr.Modulus().SetString("20645213238265527935869146898028115621427162613172918400241870500502509785943", 10)
|
||||
if ret != true {
|
||||
panic(ret)
|
||||
}
|
||||
|
||||
external_nullifier, ret := fr.Modulus().SetString("21074405743803627666274838159589343934394162804826017440941339048886754734203", 10)
|
||||
if ret != true {
|
||||
panic(ret)
|
||||
}
|
||||
|
||||
identity_secret, ret := fr.Modulus().SetString("2301650865650889795878889082892690584512243988708213561328369865554257051708", 10)
|
||||
if ret != true {
|
||||
panic(ret)
|
||||
}
|
||||
|
||||
assignment := &rln.RlnCircuit{
|
||||
X: frontend.Variable(x),
|
||||
ExternalNullifier: frontend.Variable(external_nullifier),
|
||||
IdentitySecret: frontend.Variable(identity_secret),
|
||||
MessageId: frontend.Variable(1),
|
||||
UserMessageLimit: frontend.Variable(100),
|
||||
PathElements: pathElements,
|
||||
IdentityPathIndex: identityPathIndex,
|
||||
Y: frontend.Variable(0),
|
||||
Root: frontend.Variable(0),
|
||||
Nullifier: frontend.Variable(0),
|
||||
}
|
||||
|
||||
witness, _ := frontend.NewWitness(assignment, ecc.BN254.ScalarField())
|
||||
|
||||
proof, err := groth16.Prove(cs, pk, witness)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
raw := &rln.RlnCircuit{
|
||||
X: frontend.Variable(x),
|
||||
ExternalNullifier: frontend.Variable(external_nullifier),
|
||||
Y: frontend.Variable(0),
|
||||
Root: frontend.Variable(0),
|
||||
Nullifier: frontend.Variable(0),
|
||||
}
|
||||
verifyWitness, err := frontend.NewWitness(raw, ecc.BN254.ScalarField(), frontend.PublicOnly())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = groth16.Verify(proof, vk, verifyWitness)
|
||||
|
||||
if err != nil {
|
||||
print(err.Error())
|
||||
}
|
||||
}
|
|
@ -0,0 +1,140 @@
|
|||
// forked from https://raw.githubusercontent.com/AlpinYukseloglu/poseidon-gnark/main/circuits/poseidon.go
|
||||
|
||||
package rln
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"github.com/consensys/gnark/frontend"
|
||||
)
|
||||
|
||||
func Sigma(api frontend.API, in frontend.Variable) frontend.Variable {
|
||||
return api.Mul(in, in, in, in, in)
|
||||
}
|
||||
|
||||
func Ark(api frontend.API, in []frontend.Variable, c []*big.Int, r int) []frontend.Variable {
|
||||
for i := range in {
|
||||
in[i] = api.Add(in[i], c[i+r])
|
||||
}
|
||||
return in
|
||||
}
|
||||
|
||||
// Shared logic of multiplication and addition
|
||||
func multiplyAndAdd(api frontend.API, in []frontend.Variable, factors []*big.Int) frontend.Variable {
|
||||
result := frontend.Variable(0)
|
||||
for i, val := range in {
|
||||
result = api.Add(result, api.Mul(factors[i], val))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Helper function to create factors slice for Mix
|
||||
func createMixFactors(in []frontend.Variable, m [][]*big.Int, index int) []*big.Int {
|
||||
factors := make([]*big.Int, len(in))
|
||||
for i := range in {
|
||||
factors[i] = m[i][index]
|
||||
}
|
||||
return factors
|
||||
}
|
||||
|
||||
func Mix(api frontend.API, in []frontend.Variable, m [][]*big.Int) []frontend.Variable {
|
||||
out := make([]frontend.Variable, len(in))
|
||||
for i := range in {
|
||||
out[i] = multiplyAndAdd(api, in, createMixFactors(in, m, i))
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func MixLast(api frontend.API, in []frontend.Variable, m [][]*big.Int, s int) frontend.Variable {
|
||||
return multiplyAndAdd(api, in, createMixFactors(in, m, s))
|
||||
}
|
||||
|
||||
func MixS(api frontend.API, in []frontend.Variable, s []*big.Int, r int) []frontend.Variable {
|
||||
out := make([]frontend.Variable, len(in))
|
||||
for i := range in {
|
||||
out[0] = api.Add(out[0], api.Mul(s[(len(in)*2-1)*r+i], in[i]))
|
||||
}
|
||||
for i := 1; i < len(in); i++ {
|
||||
out[i] = api.Add(in[i], api.Mul(in[0], s[(len(in)*2-1)*r+len(in)+i-1]))
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func PoseidonEx(api frontend.API, inputs []frontend.Variable, initialState frontend.Variable, nOuts int) []frontend.Variable {
|
||||
out := make([]frontend.Variable, nOuts)
|
||||
|
||||
// Using recommended parameters from whitepaper https://eprint.iacr.org/2019/458.pdf (table 2, table 8)
|
||||
// Generated by https://extgit.iaik.tugraz.at/krypto/hadeshash/-/blob/master/code/calc_round_numbers.py
|
||||
// And rounded up to nearest integer that divides by t
|
||||
nRoundsPC := [16]int{56, 57, 56, 60, 60, 63, 64, 63, 60, 66, 60, 65, 70, 60, 64, 68}
|
||||
t := len(inputs) + 1
|
||||
nRoundsF := 8
|
||||
nRoundsP := nRoundsPC[t-2]
|
||||
c := POSEIDON_C(t)
|
||||
s := POSEIDON_S(t)
|
||||
m := POSEIDON_M(t)
|
||||
p := POSEIDON_P(t)
|
||||
|
||||
state := make([]frontend.Variable, t)
|
||||
for j := 0; j < t; j++ {
|
||||
if j == 0 {
|
||||
state[0] = initialState
|
||||
} else {
|
||||
state[j] = inputs[j-1]
|
||||
}
|
||||
}
|
||||
state = Ark(api, state, c, 0)
|
||||
|
||||
for r := 0; r < nRoundsF/2-1; r++ {
|
||||
for j := 0; j < t; j++ {
|
||||
state[j] = Sigma(api, state[j])
|
||||
}
|
||||
state = Ark(api, state, c, (r+1)*t)
|
||||
state = Mix(api, state, m)
|
||||
}
|
||||
|
||||
for j := 0; j < t; j++ {
|
||||
state[j] = Sigma(api, state[j])
|
||||
}
|
||||
state = Ark(api, state, c, nRoundsF/2*t)
|
||||
state = Mix(api, state, p)
|
||||
|
||||
for r := 0; r < nRoundsP; r++ {
|
||||
|
||||
state[0] = Sigma(api, state[0])
|
||||
|
||||
state[0] = api.Add(state[0], c[(nRoundsF/2+1)*t+r])
|
||||
newState0 := frontend.Variable(0)
|
||||
for j := 0; j < len(state); j++ {
|
||||
mul := api.Mul(s[(t*2-1)*r+j], state[j])
|
||||
newState0 = api.Add(newState0, mul)
|
||||
}
|
||||
|
||||
for k := 1; k < t; k++ {
|
||||
state[k] = api.Add(state[k], api.Mul(state[0], s[(t*2-1)*r+t+k-1]))
|
||||
}
|
||||
state[0] = newState0
|
||||
}
|
||||
|
||||
for r := 0; r < nRoundsF/2-1; r++ {
|
||||
for j := 0; j < t; j++ {
|
||||
state[j] = Sigma(api, state[j])
|
||||
}
|
||||
state = Ark(api, state, c, (nRoundsF/2+1)*t+nRoundsP+r*t)
|
||||
state = Mix(api, state, m)
|
||||
}
|
||||
|
||||
for j := 0; j < t; j++ {
|
||||
state[j] = Sigma(api, state[j])
|
||||
}
|
||||
|
||||
for i := 0; i < nOuts; i++ {
|
||||
out[i] = MixLast(api, state, m, i)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func Poseidon(api frontend.API, inputs []frontend.Variable) frontend.Variable {
|
||||
out := PoseidonEx(api, inputs, 0, 1)
|
||||
return out[0]
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,83 @@
|
|||
package rln
|
||||
|
||||
import (
|
||||
"github.com/consensys/gnark/frontend"
|
||||
)
|
||||
|
||||
// TestPoseidon tests the Gnark Poseidon implementation against Iden3's Go implementation on all the test
|
||||
// vectors outlined in the original paper's reference repository, which can be found here: https://extgit.iaik.tugraz.at/krypto/hadeshash/-/tree/master/code
|
||||
//
|
||||
// The actual test vectors are outlined here: https://extgit.iaik.tugraz.at/krypto/hadeshash/-/blob/master/code/test_vectors.txt
|
||||
// We have included more for the sake of robustness.
|
||||
// Note that our implementation is focused on the 3-input variant with an x^5 S-box, so not all the test vectors apply.
|
||||
// func TestPoseidon(t *testing.T) {
|
||||
// tests := map[string]struct {
|
||||
// gnarkPoseidonInput [3]frontend.Variable
|
||||
// referencePoseidonInput []*big.Int
|
||||
// }{
|
||||
// "happy path: basic input": {
|
||||
// gnarkPoseidonInput: [3]frontend.Variable{1, 2, 3},
|
||||
// referencePoseidonInput: []*big.Int{big.NewInt(1), big.NewInt(2), big.NewInt(3)},
|
||||
// },
|
||||
// "official test vector: poseidonperm_x5_254_3": {
|
||||
// gnarkPoseidonInput: [3]frontend.Variable{0, 1, 2},
|
||||
// referencePoseidonInput: []*big.Int{big.NewInt(0), big.NewInt(1), big.NewInt(2)},
|
||||
// },
|
||||
// "zero vector": {
|
||||
// gnarkPoseidonInput: [3]frontend.Variable{0, 0, 0},
|
||||
// referencePoseidonInput: []*big.Int{big.NewInt(0), big.NewInt(0), big.NewInt(0)},
|
||||
// },
|
||||
// "larger inputs": {
|
||||
// gnarkPoseidonInput: [3]frontend.Variable{129048, 990217, 2234383333},
|
||||
// referencePoseidonInput: []*big.Int{big.NewInt(129048), big.NewInt(990217), big.NewInt(2234383333)},
|
||||
// },
|
||||
// "decreasing vector inputs": {
|
||||
// gnarkPoseidonInput: [3]frontend.Variable{10000000, 10000, 100},
|
||||
// referencePoseidonInput: []*big.Int{big.NewInt(10000000), big.NewInt(10000), big.NewInt(100)},
|
||||
// },
|
||||
// }
|
||||
|
||||
// for name, testCase := range tests {
|
||||
|
||||
// assert := test.NewAssert(t)
|
||||
// var circuit circuitPoseidon
|
||||
|
||||
// // Compute reference hash to test against
|
||||
// referenceHash, err := poseidon.Hash(testCase.referencePoseidonInput)
|
||||
// if err != nil {
|
||||
// t.Fatal(err, "Failed to compute reference poseidon hash for test case: ", name)
|
||||
// }
|
||||
// t.Logf("Reference hash: %s", referenceHash.String())
|
||||
|
||||
// // Generate poseidon hash using gnark implementation
|
||||
// assert.ProverSucceeded(&circuit, &circuitPoseidon{
|
||||
// A: testCase.gnarkPoseidonInput,
|
||||
// Hash: referenceHash,
|
||||
// }, test.WithCurves(ecc.BN254), test.WithBackends(backend.GROTH16))
|
||||
|
||||
// // Ensure output correctly compiles
|
||||
// _r1cs, err := frontend.Compile(big.NewInt(1), r1cs.NewBuilder, &circuit)
|
||||
// if err != nil {
|
||||
// t.Fatal(err, "Failed to compile computed poseidon hash for test case: ", name)
|
||||
// }
|
||||
|
||||
// // Sanity check and debugging support for internal variables
|
||||
// internal, secret, public := _r1cs.GetNbVariables()
|
||||
// t.Logf("Public, secret, internal %v, %v, %v\n", public, secret, internal)
|
||||
// }
|
||||
// }
|
||||
|
||||
// --- Test Helpers ---
|
||||
|
||||
type circuitPoseidon struct {
|
||||
A [3]frontend.Variable `gnark:",public"`
|
||||
Hash frontend.Variable `gnark:",public"`
|
||||
}
|
||||
|
||||
func (t *circuitPoseidon) Define(api frontend.API) error {
|
||||
hash := Poseidon(api, t.A[:])
|
||||
api.Println(t.Hash)
|
||||
api.Println(hash)
|
||||
api.AssertIsEqual(hash, t.Hash)
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
package rln
|
||||
|
||||
import (
|
||||
"github.com/consensys/gnark/frontend"
|
||||
"github.com/consensys/gnark/std/rangecheck"
|
||||
)
|
||||
|
||||
// Circuit defines a simple circuit
|
||||
// x**3 + x + 5 == y
|
||||
type RlnCircuit struct {
|
||||
X frontend.Variable `gnark:"x, public"` // message hash
|
||||
ExternalNullifier frontend.Variable `gnark:"externalNullifier, public"` // external nullifier
|
||||
IdentitySecret frontend.Variable `gnark:"identitySecret,secret"` // identity secret
|
||||
MessageId frontend.Variable `gnark:"messageId,secret"` // message id
|
||||
UserMessageLimit frontend.Variable `gnark:"userMessageLimit,secret"` // user message limit
|
||||
PathElements [20]frontend.Variable `gnark:"pathElements,secret"` // path elements
|
||||
IdentityPathIndex [20]frontend.Variable `gnark:"identityPathIndex,secret"` // identity path index
|
||||
Y frontend.Variable `gnark:"y,public"`
|
||||
Root frontend.Variable `gnark:"root, public"`
|
||||
Nullifier frontend.Variable `gnark:"nullifier, public"`
|
||||
}
|
||||
|
||||
func (circuit RlnCircuit) Define(api frontend.API) error {
|
||||
var identity_commitment_input [1]frontend.Variable
|
||||
identity_commitment_input[0] = circuit.IdentitySecret
|
||||
|
||||
identity_commitment := Poseidon(api, identity_commitment_input[:])
|
||||
api.AssertIsEqual(identity_commitment, identity_commitment)
|
||||
var rate_commitment_input [2]frontend.Variable
|
||||
rate_commitment_input[0] = identity_commitment
|
||||
rate_commitment_input[1] = circuit.UserMessageLimit
|
||||
rate_commitment := Poseidon(api, rate_commitment_input[:])
|
||||
api.AssertIsEqual(rate_commitment, rate_commitment)
|
||||
|
||||
levels := len(circuit.IdentityPathIndex)
|
||||
hashes := make([]frontend.Variable, levels+1)
|
||||
|
||||
hashes[0] = rate_commitment
|
||||
for i := 0; i < levels; i++ {
|
||||
api.AssertIsBoolean(circuit.IdentityPathIndex[i])
|
||||
var left_hash_input [2]frontend.Variable
|
||||
left_hash_input[0] = hashes[i]
|
||||
left_hash_input[1] = circuit.PathElements[i]
|
||||
var right_hash_input [2]frontend.Variable
|
||||
right_hash_input[0] = circuit.PathElements[i]
|
||||
right_hash_input[1] = hashes[i]
|
||||
|
||||
left_hash := Poseidon(api, left_hash_input[:])
|
||||
right_hash := Poseidon(api, right_hash_input[:])
|
||||
hashes[i+1] = api.Select(circuit.IdentityPathIndex[i], right_hash, left_hash)
|
||||
}
|
||||
circuit.Root = hashes[levels]
|
||||
api.AssertIsEqual(circuit.Root, circuit.Root)
|
||||
|
||||
rangeChecker := rangecheck.New(api)
|
||||
rangeChecker.Check(circuit.MessageId, 16)
|
||||
api.AssertIsLessOrEqual(circuit.MessageId, circuit.UserMessageLimit)
|
||||
|
||||
var a1_input [3]frontend.Variable
|
||||
a1_input[0] = circuit.IdentitySecret
|
||||
a1_input[1] = circuit.ExternalNullifier
|
||||
a1_input[2] = circuit.MessageId
|
||||
a1 := Poseidon(api, a1_input[:])
|
||||
circuit.Y = api.Mul(api.Add(circuit.IdentitySecret, a1), circuit.X)
|
||||
api.AssertIsEqual(circuit.Y, circuit.Y)
|
||||
|
||||
var nullifier_input [1]frontend.Variable
|
||||
nullifier_input[0] = a1
|
||||
circuit.Nullifier = Poseidon(api, nullifier_input[:])
|
||||
api.AssertIsEqual(circuit.Nullifier, circuit.Nullifier)
|
||||
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
package rln
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/consensys/gnark/frontend"
|
||||
"github.com/consensys/gnark/test"
|
||||
)
|
||||
|
||||
func TestRlnCircuit(t *testing.T) {
|
||||
assert := test.NewAssert(t)
|
||||
|
||||
var rlnCircuit RlnCircuit
|
||||
|
||||
var identityPathIndex [20]frontend.Variable
|
||||
for i := 0; i < 20; i++ {
|
||||
var direction frontend.Variable
|
||||
if i%2 == 0 {
|
||||
direction = frontend.Variable(1)
|
||||
} else {
|
||||
direction = frontend.Variable(0)
|
||||
}
|
||||
identityPathIndex[i] = direction
|
||||
}
|
||||
|
||||
var pathElements [20]frontend.Variable
|
||||
for i := 0; i < 20; i++ {
|
||||
pathElements[i] = frontend.Variable(10)
|
||||
}
|
||||
|
||||
assert.ProverSucceeded(&rlnCircuit, &RlnCircuit{
|
||||
X: frontend.Variable(10),
|
||||
ExternalNullifier: frontend.Variable(10),
|
||||
IdentitySecret: frontend.Variable(10),
|
||||
MessageId: frontend.Variable(10),
|
||||
UserMessageLimit: frontend.Variable(20),
|
||||
PathElements: pathElements,
|
||||
IdentityPathIndex: identityPathIndex,
|
||||
Y: frontend.Variable(0),
|
||||
Root: frontend.Variable(0),
|
||||
Nullifier: frontend.Variable(0),
|
||||
})
|
||||
|
||||
}
|
Loading…
Reference in New Issue