diff --git a/go.mod b/go.mod index 0655839..3b48d50 100644 --- a/go.mod +++ b/go.mod @@ -3,24 +3,32 @@ module tutorial/sumcheck-verifier-circuit go 1.22.5 require ( - github.com/consensys/gnark v0.10.0 - github.com/consensys/gnark-crypto v0.13.0 + github.com/consensys/gnark v0.11.0 + github.com/consensys/gnark-crypto v0.14.0 github.com/vocdoni/gnark-crypto-primitives v0.0.1 ) require ( - github.com/bits-and-blooms/bitset v1.8.0 // indirect + github.com/iden3/go-iden3-crypto v0.0.17 // indirect + github.com/ronanh/intcomp v1.1.0 // indirect + golang.org/x/crypto v0.27.0 // indirect + golang.org/x/sync v0.8.0 // indirect +) + +require ( + github.com/bits-and-blooms/bitset v1.14.3 // indirect github.com/blang/semver/v4 v4.0.0 // indirect - github.com/consensys/bavard v0.1.13 // indirect - github.com/fxamacker/cbor/v2 v2.5.0 // indirect - github.com/google/pprof v0.0.0-20230817174616-7a8ec2ada47b // indirect - github.com/ingonyama-zk/icicle v0.0.0-20230928131117-97f0079e5c71 // indirect - github.com/ingonyama-zk/iciclegnark v0.1.0 // indirect + github.com/consensys/bavard v0.1.22 // indirect + github.com/fxamacker/cbor/v2 v2.7.0 // indirect + github.com/google/pprof v0.0.0-20241001023024-f4c0cfd0cf1d // indirect + github.com/ingonyama-zk/icicle v1.1.0 // indirect + github.com/ingonyama-zk/iciclegnark v0.1.1 // indirect github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.19 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect github.com/mmcloughlin/addchain v0.4.0 // indirect - github.com/rs/zerolog v1.30.0 // indirect + github.com/rs/zerolog v1.33.0 // indirect github.com/x448/float16 v0.8.4 // indirect - golang.org/x/sys v0.15.0 // indirect + golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 + golang.org/x/sys v0.25.0 // indirect rsc.io/tmplfunc v0.0.3 // indirect ) diff --git a/go.sum b/go.sum index c41f1f4..1a04f73 100644 --- a/go.sum +++ b/go.sum @@ -1,64 +1,66 @@ -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/bits-and-blooms/bitset v1.14.3 h1:Gd2c8lSNf9pKXom5JtD7AaKO8o7fGQ2LtFj1436qilA= +github.com/bits-and-blooms/bitset v1.14.3/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.10.0 h1:yhi6ThoeFP7WrH8zQDaO56WVXe9iJEBSkfrZ9PZxabw= -github.com/consensys/gnark v0.10.0/go.mod h1:VJU5JrrhZorbfDH+EUjcuFWr2c5z19tHPh8D6KVQksU= -github.com/consensys/gnark-crypto v0.13.0 h1:VPULb/v6bbYELAPTDFINEVaMTTybV5GLxDdcjnS+4oc= -github.com/consensys/gnark-crypto v0.13.0/go.mod h1:wKqwsieaKPThcFkHe0d0zMsbHEUWFmZcG7KBCse210o= +github.com/consensys/bavard v0.1.22 h1:Uw2CGvbXSZWhqK59X0VG/zOjpTFuOMcPLStrp1ihI0A= +github.com/consensys/bavard v0.1.22/go.mod h1:k/zVjHHC4B+PQy1Pg7fgvG3ALicQw540Crag8qx+dZs= +github.com/consensys/gnark v0.11.0 h1:YlndnlbRAoIEA+aIIHzNIW4P0dCIOM9/jCVzsXf356c= +github.com/consensys/gnark v0.11.0/go.mod h1:2LbheIOxsBI1a9Ck1XxUoy6PRnH28mSI9qrvtN2HwDY= +github.com/consensys/gnark-crypto v0.14.0 h1:DDBdl4HaBtdQsq/wfMwJvZNE80sHidrK3Nfrefatm0E= +github.com/consensys/gnark-crypto v0.14.0/go.mod h1:CU4UijNPsHawiVGNxe9co07FkzCeWHHrb1li/n1XoU0= 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/fxamacker/cbor/v2 v2.5.0 h1:oHsG0V/Q6E/wqTS2O1Cozzsy69nqCiguo5Q1a1ADivE= -github.com/fxamacker/cbor/v2 v2.5.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= +github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= +github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -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/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/pprof v0.0.0-20241001023024-f4c0cfd0cf1d h1:Jaz2JzpQaQXyET0AjLBXShrthbpqMkhGiEfkcQAiAUs= +github.com/google/pprof v0.0.0-20241001023024-f4c0cfd0cf1d/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= -github.com/iden3/go-iden3-crypto v0.0.15 h1:4MJYlrot1l31Fzlo2sF56u7EVFeHHJkxGXXZCtESgK4= -github.com/iden3/go-iden3-crypto v0.0.15/go.mod h1:dLpM4vEPJ3nDHzhWFXDjzkn1qHoBeOT/3UEhXsEsP3E= -github.com/ingonyama-zk/icicle v0.0.0-20230928131117-97f0079e5c71 h1:YxI1RTPzpFJ3MBmxPl3Bo0F7ume7CmQEC1M9jL6CT94= -github.com/ingonyama-zk/icicle v0.0.0-20230928131117-97f0079e5c71/go.mod h1:kAK8/EoN7fUEmakzgZIYdWy1a2rBnpCaZLqSHwZWxEk= -github.com/ingonyama-zk/iciclegnark v0.1.0 h1:88MkEghzjQBMjrYRJFxZ9oR9CTIpB8NG2zLeCJSvXKQ= -github.com/ingonyama-zk/iciclegnark v0.1.0/go.mod h1:wz6+IpyHKs6UhMMoQpNqz1VY+ddfKqC/gRwR/64W6WU= -github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= -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/iden3/go-iden3-crypto v0.0.17 h1:NdkceRLJo/pI4UpcjVah4lN/a3yzxRUGXqxbWcYh9mY= +github.com/iden3/go-iden3-crypto v0.0.17/go.mod h1:dLpM4vEPJ3nDHzhWFXDjzkn1qHoBeOT/3UEhXsEsP3E= +github.com/ingonyama-zk/icicle v1.1.0 h1:a2MUIaF+1i4JY2Lnb961ZMvaC8GFs9GqZgSnd9e95C8= +github.com/ingonyama-zk/icicle v1.1.0/go.mod h1:kAK8/EoN7fUEmakzgZIYdWy1a2rBnpCaZLqSHwZWxEk= +github.com/ingonyama-zk/iciclegnark v0.1.1 h1:BugVGAkKFu2uy02cRsgQdsE18VaFIJz55dBeZQJl4R0= +github.com/ingonyama-zk/iciclegnark v0.1.1/go.mod h1:g17CDuMfNBiN4hhZ4aA0rGF24Abv5GBFHJqE7aLxaZQ= +github.com/leanovate/gopter v0.2.11 h1:vRjThO1EKPb/1NsDXuDrzldR28RLkBflWYcU9CvzWu4= +github.com/leanovate/gopter v0.2.11/go.mod h1:aK3tzZP/C+p1m3SPRE4SYZFGP7jjkuSI4f7Xvpt0S9c= 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/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/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/ronanh/intcomp v1.1.0 h1:i54kxmpmSoOZFcWPMWryuakN0vLxLswASsGa07zkvLU= +github.com/ronanh/intcomp v1.1.0/go.mod h1:7FOLy3P3Zj3er/kVrU/pl+Ql7JFZj7bwliMGketo0IU= 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/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= +github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/vocdoni/gnark-crypto-primitives v0.0.1 h1:RmxfYvHCFI1lnSPs07ZSTVNpoj0qrQSaNXwkh6vqcRg= github.com/vocdoni/gnark-crypto-primitives v0.0.1/go.mod h1:0rxBVlF+OY7EnoDatCPMTxrY6FzxNkyc4c4sweIvTRQ= 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.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= -golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= -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/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= +golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= +golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk= +golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 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.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/hashmanager/hashmanager.go b/hashmanager/hashmanager.go new file mode 100644 index 0000000..5a7557a --- /dev/null +++ b/hashmanager/hashmanager.go @@ -0,0 +1,32 @@ +package hashmanager + +import ( + "github.com/consensys/gnark/frontend" + "github.com/vocdoni/gnark-crypto-primitives/poseidon" +) + +type HashManager struct { + poseidonInstance poseidon.Poseidon + HashCollector []frontend.Variable + api frontend.API +} + +func NewHashManager(api frontend.API) *HashManager { + manager := new(HashManager) + manager.poseidonInstance = poseidon.NewPoseidon(api) + manager.HashCollector = []frontend.Variable{} + return manager +} + +func (manager *HashManager) WriteInput(inputs ...frontend.Variable) { + manager.poseidonInstance.Write(inputs...) +} + +func (manager *HashManager) WriteInputAndCollectAndReturnHash(inputs ...frontend.Variable) frontend.Variable { + manager.poseidonInstance.Write(inputs...) + hashUntilNow := manager.poseidonInstance.Sum() + // manager.HashCollector = append(manager.HashCollector, hashUntilNow) + // manager.poseidonInstance.Write(hashUntilNow) + manager.poseidonInstance.Reset() + return hashUntilNow +} diff --git a/main.go b/main.go index 2c7dc2b..42d937c 100644 --- a/main.go +++ b/main.go @@ -1,62 +1,96 @@ package main -import( - "github.com/vocdoni/gnark-crypto-primitives/poseidon" - "github.com/consensys/gnark/frontend/cs/r1cs" - "github.com/consensys/gnark/backend/groth16" +import ( + "math/big" + "tutorial/sumcheck-verifier-circuit/hashmanager" + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark/backend/groth16" "github.com/consensys/gnark/frontend" - "tutorial/sumcheck-verifier-circuit/polynomials" - // "github.com/kr/pretty" - "math/big" + "github.com/consensys/gnark/frontend/cs/r1cs" ) -type Circuit struct { - Seed frontend.Variable `gnark:"Seed"` - C1 frontend.Variable `gnark:"C1"` - R1 frontend.Variable `gnark:"R1"` - R2 frontend.Variable `gnark:"R2"` - G_Coeffs [4]frontend.Variable `gnark:"G Coefficients"` - G1_Coeffs [2]frontend.Variable `gnark:"G1 Coefficients"` - G2_Coeffs [2]frontend.Variable `gnark:"G2 Coefficients"` +type VerifyMerkleProofCircuit struct { + // Inputs + Leaves []frontend.Variable + LeafIndexes []frontend.Variable + LeafSiblingHashes []frontend.Variable + AuthPaths [][]frontend.Variable + // Public Input + RootHash frontend.Variable `gnark:",public"` } -func (circuit *Circuit) Define (api frontend.API) error { - g1_0 := polynomials.CircUniPoly(circuit.G1_Coeffs[:], 0, api) - g1_1 := polynomials.CircUniPoly(circuit.G1_Coeffs[:], 1, api) - api.AssertIsEqual(circuit.C1, api.Add(g1_0, g1_1)) - api.AssertIsEqual(circuit.R1, poseidon.Hash(api, circuit.Seed)) - g2_0 := polynomials.CircUniPoly(circuit.G2_Coeffs[:], 0, api) - g2_1 := polynomials.CircUniPoly(circuit.G2_Coeffs[:], 1, api) - g1_r1 := polynomials.CircUniPoly(circuit.G1_Coeffs[:], circuit.R1, api) - api.AssertIsEqual(api.Add(g2_0, g2_1), g1_r1) - api.AssertIsEqual(poseidon.Hash(api, circuit.R1), circuit.R2) - g2_r2 := polynomials.CircUniPoly(circuit.G2_Coeffs[:], circuit.R2, api) - g_eval := polynomials.CircMultPoly(circuit.G_Coeffs[:], []frontend.Variable{circuit.R1, circuit.R2}, api) - api.AssertIsEqual(g2_r2, g_eval) +func (circuit *VerifyMerkleProofCircuit) Define(api frontend.API) error { + var manager = hashmanager.NewHashManager(api) + numLeaves := len(circuit.Leaves) + // ``treeHeight := len(circuit.AuthPathSuffixes[0]) + 2 + + for i := 0; i < numLeaves; i++ { + leaf := circuit.Leaves[i] + leafIndex := circuit.LeafIndexes[i] + leafSiblingHash := circuit.LeafSiblingHashes[i] + + authPath := circuit.AuthPaths[i] + + claimedLeafHash := manager.WriteInputAndCollectAndReturnHash(leaf) + + dir := api.And(leafIndex, 1) + leftChild := api.Select(dir, leafSiblingHash, claimedLeafHash) + rightChild := api.Select(dir, claimedLeafHash, leafSiblingHash) + + currentHash := manager.WriteInputAndCollectAndReturnHash(leftChild, rightChild) + + index := api.Div(leafIndex, 2) + + for level := 0; level < len(authPath); level++ { + siblingHash := authPath[level] + + dir := api.And(index, 1) + left := api.Select(dir, siblingHash, currentHash) + right := api.Select(dir, currentHash, siblingHash) + + currentHash = manager.WriteInputAndCollectAndReturnHash(left, right) + + index = api.Div(index, 2) + } + + api.AssertIsEqual(currentHash, circuit.RootHash) + } + return nil } func main() { - var circuit Circuit + var number_of_variables = 2 + + var authPaths = make([][]frontend.Variable, number_of_variables) + for i := 0; i < number_of_variables; i++ { + authPaths[i] = make([]frontend.Variable, 3) + } + + var leaves = make([]frontend.Variable, 3) + var leaf_indexes = make([]frontend.Variable, 3) + var leaf_sibling_hashes = make([]frontend.Variable, 3) + var root_hash = big.NewInt(1) + + var circuit = VerifyMerkleProofCircuit{ + Leaves: leaves, + LeafIndexes: leaf_indexes, + LeafSiblingHashes: leaf_sibling_hashes, + AuthPaths: authPaths, + RootHash: root_hash, + } + ccs, _ := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &circuit) pk, vk, _ := groth16.Setup(ccs) - // ------ - R1, _ := new(big.Int).SetString("9256297558679035993185603119224026483248878132105160101344427504900917382708", 10) - R2, _ := new(big.Int).SetString("1501086694344315373207989466448958625613689647511317698257372243506299745486", 10) - G2_0, _ := new(big1Int).SetString("5880649804197832757310403612414804361198269995899445960335078328126943652508", 10) - G2_1, _ := new(big.Int).SetString("5010004099433259042870408211211164478295323719387463638651458302705939844619", 10) - - assignment := Circuit{ - Seed: 47, - C1: 34, - R1: R1, - R2: R2, - G_Coeffs: [4]frontend.Variable{1,3,7,10}, //g(x, y) := 1 + 3x + 7y + 10xy - G1_Coeffs: [2]frontend.Variable{9,16}, - G2_Coeffs: [2]frontend.Variable{G2_0, G2_1}, + + assignment := VerifyMerkleProofCircuit{ + Leaves: leaves, + LeafIndexes: leaf_indexes, + LeafSiblingHashes: leaf_sibling_hashes, + AuthPaths: authPaths, + RootHash: root_hash, } - // ------ witness, _ := frontend.NewWitness(&assignment, ecc.BN254.ScalarField()) publicWitness, _ := witness.Public() proof, _ := groth16.Prove(ccs, pk, witness) diff --git a/main_spartan.go b/main_spartan.go new file mode 100644 index 0000000..b357790 --- /dev/null +++ b/main_spartan.go @@ -0,0 +1,251 @@ +package main + +import ( + "fmt" + "math/big" + "tutorial/sumcheck-verifier-circuit/hashmanager" + + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark/backend/groth16" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/frontend/cs/r1cs" + "github.com/iden3/go-iden3-crypto/poseidon" +) + +const NUMBER_OF_COEFFS_IN_LINEAR = 2 +const NUMBER_OF_COEFFS_IN_QUADRATIC = 3 +const NUMBER_OF_COEFFS_IN_CUBIC = 4 + +var MOD *big.Int +var ONE_HALF_CONSTANT *big.Int + +func Init_Spartan() { + var success bool + MOD, _ = new(big.Int).SetString("21888242871839275222246405745257275088548364400416034343698204186575808495617", 10) + ONE_HALF_CONSTANT, success = new(big.Int).SetString("10944121435919637611123202872628637544274182200208017171849102093287904247809", 10) + if !success { + fmt.Println("Error: Failed to set big.Int value") + } +} + +type Circuit struct { + // Alleged computed sum of all the evaluations + ExpectedSum frontend.Variable `gnark:"ExpectedSum"` + ValueAtChallengeVector frontend.Variable `gnark:"ValueAtChallengeVector"` + // Array of elements representing the values of p0, p1 in each of the rounds + GPolynomials [][]frontend.Variable `gnark:"GPolynomials"` +} + +func (circuit *Circuit) Define(api frontend.API) error { + var manager = hashmanager.NewHashManager(api) + g_length := len(circuit.GPolynomials) + e := circuit.ExpectedSum + for i := 0; i < g_length; i++ { + api.AssertIsEqual(len(circuit.GPolynomials[i]), NUMBER_OF_COEFFS_IN_CUBIC) + + // Equivalent constraint to the one below it, doesn't require GPoly[i][0] + // e = api.Add(api.Mul(ONE_HALF_CONSTANT, api.Add(e, api.Neg(circuit.GPolynomials[i][1]))), api.Mul(circuit.ChallengeVector[i], circuit.GPolynomials[i][1])) + api.Println(circuit.GPolynomials[i][0], circuit.GPolynomials[i][1]) + r_i := manager.WriteInputAndCollectAndReturnHash(circuit.GPolynomials[i]...) + api.Println(r_i) + cumulative := circuit.GPolynomials[i][NUMBER_OF_COEFFS_IN_CUBIC-1] + for j := NUMBER_OF_COEFFS_IN_CUBIC - 2; j >= 1; j-- { + cumulative = api.Add(circuit.GPolynomials[i][j], api.Mul(cumulative, r_i)) + } + e = api.Add(circuit.GPolynomials[i][0], api.Mul(cumulative, r_i)) + } + api.AssertIsEqual(e, circuit.ValueAtChallengeVector) + return nil +} + +func calculateCubic(e []*big.Int, a_z []*big.Int, b_z []*big.Int, c_z []*big.Int) *big.Int { + result := big.NewInt(0) + for i := 0; i < len(e); i++ { + tmp := new(big.Int).Mul(a_z[i], b_z[i]) + tmp.Sub(tmp, c_z[i]) + tmp.Mul(tmp, e[i]) + result.Add(result, tmp) + } + return result +} + +func replace_r_in_f(f []*big.Int, r *big.Int) []*big.Int { + n := len(f) / 2 + for i := 0; i < n; i++ { + diff := new(big.Int).Sub(f[n+i], f[i]) // diff = f[n+i] - f[i] + scaled := new(big.Int).Mul(r, diff) // scaled = r * diff + f[i].Add(f[i], scaled) // f[i] += scaled + } + return f[:n] +} + +func main_spartan() { + Init_Spartan() + + // START R1CS case + // Sum_x e(x) * (a(x) * b(x) - c(x)) + var number_of_variables = 2 + + // initialize coefficients + var coeffs_univariate_polynomials = make([][]frontend.Variable, number_of_variables) + for i := 0; i < number_of_variables; i++ { + coeffs_univariate_polynomials[i] = make([]frontend.Variable, NUMBER_OF_COEFFS_IN_CUBIC) + } + var circuit = Circuit{ + GPolynomials: coeffs_univariate_polynomials, + } + + ccs, _ := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &circuit) + pk, vk, _ := groth16.Setup(ccs) + // proof for some random values of e, Az, Bz, Cz + // still to validate for real A,B,C and its witness vector + + // Commented out since VerifyR1CS() is not defined in the provided code + // VerifyR1CS() + + // Initialize arrays with *big.Int + var e = []*big.Int{ + big.NewInt(1), + big.NewInt(4), + big.NewInt(3), + big.NewInt(6), + big.NewInt(3), + big.NewInt(5), + big.NewInt(0), + big.NewInt(0), + } + + var a_z = []*big.Int{ + big.NewInt(3), + big.NewInt(9), + big.NewInt(30), + big.NewInt(25), + big.NewInt(5), + big.NewInt(25), + big.NewInt(0), + big.NewInt(0), + } + + var b_z = []*big.Int{ + big.NewInt(3), + big.NewInt(3), + big.NewInt(1), + big.NewInt(1), + big.NewInt(5), + big.NewInt(1), + big.NewInt(0), + big.NewInt(0), + } + + var c_z = []*big.Int{ + big.NewInt(9), + big.NewInt(27), + big.NewInt(30), + big.NewInt(25), + big.NewInt(25), + big.NewInt(25), + big.NewInt(0), + big.NewInt(0), + } + + var initial_expected_sum = calculateCubic(e, a_z, b_z, c_z) + var expected_sum = new(big.Int).Set(initial_expected_sum) + var challenge_vector []frontend.Variable + + fmt.Println("Initial Expected Sum:", expected_sum) + + for i := 0; i < number_of_variables; i++ { + p_0 := big.NewInt(0) + p_tmp := big.NewInt(0) + p_3 := big.NewInt(0) + offset := len(e) / 2 + for j := 0; j < len(e)/2; j++ { + // p_0 += e[j] * (a_z[j]*b_z[j] - c_z[j]) + temp1 := new(big.Int).Mul(a_z[j], b_z[j]) // a_z[j]*a_z[j] + temp1.Sub(temp1, c_z[j]) // temp1 = temp1 - c_z[j] + temp1.Mul(temp1, e[j]) // temp1 = e[j] * (a_z[j]*b_z[j] - c_z[j]) + p_0.Add(p_0, temp1) + p_0.Mod(temp1, MOD) + + // p_tmp += (2*e[j] - e[j+offset]) * ((2*a_z[j]-a_z[j+offset])*(2*b_z[j]-b_z[j+offset]) - (2*c_z[j] - c_z[j+offset])) + temp2 := new(big.Int).Mul(big.NewInt(2), e[j]) // 2*e[j] + temp2.Sub(temp2, e[j+offset]) // temp2 = (2*e[j] - e[j+offset]) + + temp3 := new(big.Int).Mul(big.NewInt(2), a_z[j]) // 2*a_z[j] + temp3.Sub(temp3, a_z[j+offset]) // temp3 = (2*a_z[j] - a_z[j+offset]) + + temp4 := new(big.Int).Mul(big.NewInt(2), b_z[j]) // 2*b_z[j] + temp4.Sub(temp4, b_z[j+offset]) // temp4 = (2*b_z[j] - b_z[j+offset]) + + temp5 := new(big.Int).Mul(temp3, temp4) // temp5 = temp3 * temp4 + + temp6 := new(big.Int).Mul(big.NewInt(2), c_z[j]) // 2*c_z[j] + temp6.Sub(temp6, c_z[j+offset]) // temp6 = (2*c_z[j] - c_z[j+offset]) + + temp7 := new(big.Int).Sub(temp5, temp6) // temp7 = temp5 - temp6 + + temp8 := new(big.Int).Mul(temp2, temp7) // temp8 = temp2 * temp7 + + p_tmp.Add(p_tmp, temp8) + p_tmp.Mod(p_tmp, MOD) + + // p_3 += (e[j+offset] - e[j]) * (a_z[j+offset] - a_z[j]) * (b_z[j+offset] - b_z[j]) + temp9 := new(big.Int).Sub(e[j+offset], e[j]) // temp9 = e[j+offset] - e[j] + temp10 := new(big.Int).Sub(a_z[j+offset], a_z[j]) // temp10 = a_z[j+offset] - a_z[j] + temp11 := new(big.Int).Sub(b_z[j+offset], b_z[j]) // temp11 = b_z[j+offset] - b_z[j] + + temp12 := new(big.Int).Mul(temp9, temp10) + temp12.Mul(temp12, temp11) + + p_3.Add(p_3, temp12) + p_3.Mod(p_3, MOD) + } + + // p_2 := (expected_sum + p_tmp - p_0 - p_0 - p_0) / 2 + temp13 := new(big.Int).Add(expected_sum, p_tmp) + temp13.Sub(temp13, p_0) + temp13.Sub(temp13, p_0) + temp13.Sub(temp13, p_0) + + p_2 := new(big.Int).Div(temp13, big.NewInt(2)) + p_2.Mod(p_2, MOD) + // p_1 := expected_sum - p_0 - p_0 - p_3 - p_2 + p_1 := new(big.Int).Sub(expected_sum, p_0) + p_1.Sub(p_1, p_0) + p_1.Sub(p_1, p_3) + p_1.Sub(p_1, p_2) + p_1.Mod(p_1, MOD) + + coeffs_univariate_polynomials[i] = []frontend.Variable{p_0, p_1, p_2, p_3} + hash_value, _ := poseidon.Hash([]*big.Int{p_0, p_1, p_2, p_3}) + // Generate a random *big.Int less than 11 + r := hash_value + fmt.Println("r_", i, " = ", r) + challenge_vector = append(challenge_vector, r) + + e = replace_r_in_f(e, r) + a_z = replace_r_in_f(a_z, r) + b_z = replace_r_in_f(b_z, r) + c_z = replace_r_in_f(c_z, r) + + // expected_sum = p_0 + r*(p_1 + r*(p_2 + r*p_3)) + temp14 := new(big.Int).Mul(r, p_3) // r * p_3 + temp14.Add(temp14, p_2) // p_2 + r * p_3 + temp14.Mul(temp14, r) // r * (p_2 + r * p_3) + temp14.Add(temp14, p_1) // p_1 + r * (p_2 + r * p_3) + temp14.Mul(temp14, r) // r * (p_1 + r * (p_2 + r * p_3)) + expected_sum = new(big.Int).Add(p_0, temp14) + expected_sum.Mod(expected_sum, MOD) + } + + assignment := Circuit{ + ExpectedSum: initial_expected_sum, + ValueAtChallengeVector: expected_sum, + GPolynomials: coeffs_univariate_polynomials, + } + witness, _ := frontend.NewWitness(&assignment, ecc.BN254.ScalarField()) + publicWitness, _ := witness.Public() + proof, _ := groth16.Prove(ccs, pk, witness) + groth16.Verify(proof, vk, publicWitness) + //END R1CS case +} diff --git a/r1cs.go b/r1cs.go new file mode 100644 index 0000000..a37ba36 --- /dev/null +++ b/r1cs.go @@ -0,0 +1,80 @@ +package main + +import ( + "fmt" +) + +func VerifyR1CS() { + const numConstraints = 6 + const numVariables = 8 + + //row-major order + a := []int{ + 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 1, 0, 1, 0, 0, 0, 0, + -5, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 1, 0, 0, + } + + b := []int{ + 0, 1, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + } + + c := []int{ + 0, 0, 1, 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, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1, + 0, 0, 0, 0, 0, 0, 0, 1, + } + + // Witness + z := []int{ + 1, + 3, + 9, + 27, + 30, + 25, + 5, + 25, + } + + valid := true + for i := 0; i < numConstraints; i++ { + + Aiz := 0 + Biz := 0 + Ciz := 0 + + for j := 0; j < numVariables; j++ { + index := i*numVariables + j + Aiz += a[index] * z[j] + Biz += b[index] * z[j] + Ciz += c[index] * z[j] + } + + if Aiz*Biz != Ciz { + valid = false + fmt.Printf("Constraint %d failed: (A_i z) * (B_i z) != C_i z\n", i+1) + fmt.Printf("A_i z = %d, B_i z = %d, C_i z = %d\n", Aiz, Biz, Ciz) + } else { + fmt.Printf("Constraint %d passed: (A_i z) * (B_i z) = C_i z\n", i+1) + fmt.Printf("A_i z = %d, B_i z = %d, C_i z = %d\n", Aiz, Biz, Ciz) + } + } + + if valid { + fmt.Println("All constraints are satisfied.") + } else { + fmt.Println("Some constraints are not satisfied.") + } +} diff --git a/verify_merkle.go b/verify_merkle.go new file mode 100644 index 0000000..6cc180b --- /dev/null +++ b/verify_merkle.go @@ -0,0 +1,57 @@ +package main + +import ( + "tutorial/sumcheck-verifier-circuit/hashmanager" + + "github.com/consensys/gnark/frontend" +) + +type VerifyMerkleProofCircuit2 struct { + // Inputs + Leaves []frontend.Variable + LeafIndexes []frontend.Variable + LeafSiblingHashes []frontend.Variable + AuthPaths [][]frontend.Variable + // Public Input + RootHash frontend.Variable `gnark:",public"` +} + +func (circuit *VerifyMerkleProofCircuit) Define2(api frontend.API) error { + var manager = hashmanager.NewHashManager(api) + numLeaves := len(circuit.Leaves) + // ``treeHeight := len(circuit.AuthPathSuffixes[0]) + 2 + + for i := 0; i < numLeaves; i++ { + leaf := circuit.Leaves[i] + leafIndex := circuit.LeafIndexes[i] + leafSiblingHash := circuit.LeafSiblingHashes[i] + + authPath := circuit.AuthPaths[i] + + claimedLeafHash := manager.WriteInputAndCollectAndReturnHash(leaf) + + dir := api.And(leafIndex, 1) + leftChild := api.Select(dir, leafSiblingHash, claimedLeafHash) + rightChild := api.Select(dir, claimedLeafHash, leafSiblingHash) + + currentHash := manager.WriteInputAndCollectAndReturnHash(leftChild, rightChild) + + index := api.Div(leafIndex, 2) + + for level := 0; level < len(authPath); level++ { + siblingHash := authPath[level] + + dir := api.And(index, 1) + left := api.Select(dir, siblingHash, currentHash) + right := api.Select(dir, currentHash, siblingHash) + + currentHash = manager.WriteInputAndCollectAndReturnHash(left, right) + + index = api.Div(index, 2) + } + + api.AssertIsEqual(currentHash, circuit.RootHash) + } + + return nil +}