Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add GPU Acceleration Support for KZG Commitments #486

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
200 changes: 200 additions & 0 deletions ecc/bn254/kzg/icicle.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
package kzg

import (
"fmt"
"hash"
"sync"
"unsafe"

"github.com/consensys/gnark-crypto/ecc/bn254"
"github.com/consensys/gnark-crypto/ecc/bn254/fr"
"github.com/consensys/gnark-crypto/internal/parallel"
iciclegnark "github.com/ingonyama-zk/iciclegnark/curves/bn254"
)

// Commit commits to a polynomial using a multi exponentiation with the SRS.
// It is assumed that the polynomial is in canonical form, in Montgomery form.
func OnDeviceCommit(p []fr.Element, G1 unsafe.Pointer, nbTasks ...int) (Digest, error) {
// Size of the polynomial
np := len(p)

// Size of the polynomial in bytes
sizeBytesScalars := np * fr.Bytes

// Initialize Scalar channels
copyCpDone := make(chan unsafe.Pointer, 1)
cpDeviceData := make(chan iciclegnark.OnDeviceData, 1)

// Copy Scalar to device
go func() {
// Perform copy operation
iciclegnark.CopyToDevice(p, sizeBytesScalars, copyCpDone)

// Receive result once copy operation is done
cpDevice := <-copyCpDone

// Create OnDeviceData
cpDeviceValue := iciclegnark.OnDeviceData{
P: cpDevice,
Size: sizeBytesScalars,
}

// Send OnDeviceData to respective channel
cpDeviceData <- cpDeviceValue

// Close channels
close(copyCpDone)
close(cpDeviceData)
}()

// Wait for copy operation to finish
cpDeviceValue := <-cpDeviceData

// KZG Committment on device
var wg sync.WaitGroup

// Perform multi exponentiation on device
wg.Add(1)
tmpChan := make(chan bn254.G1Affine, 1)
go func() {
defer wg.Done()
tmp, _, err := iciclegnark.MsmOnDevice(cpDeviceValue.P, G1, np, true)
//fmt.Println("tmp", tmp)
if err != nil {
fmt.Print("error", err)
}
var res bn254.G1Affine
res.FromJacobian(&tmp)
tmpChan <- res
}()
wg.Wait()

// Receive result once copy operation is done
res := <-tmpChan

// Free device memory
go func() {
iciclegnark.FreeDevicePointer(unsafe.Pointer(&cpDeviceValue))
}()

return res, nil
}

// Open computes an opening proof of polynomial p at given point.
// fft.Domain Cardinality must be larger than p.Degree()
func OnDeviceOpen(p []fr.Element, point fr.Element, G1 unsafe.Pointer) (OpeningProof, error) {
// build the proof
res := OpeningProof{
ClaimedValue: eval(p, point),
}

// compute H
// h reuses memory from _p
_p := make([]fr.Element, len(p))
copy(_p, p)
h := dividePolyByXminusA(_p, res.ClaimedValue, point)

// commit to H
hCommit, err := OnDeviceCommit(h, G1)
if err != nil {
return OpeningProof{}, err
}
res.H.Set(&hCommit)

return res, nil
}

// BatchOpenSinglePoint creates a batch opening proof at point of a list of polynomials.
// It's an interactive protocol, made non-interactive using Fiat Shamir.
//
// * point is the point at which the polynomials are opened.
// * digests is the list of committed polynomials to open, need to derive the challenge using Fiat Shamir.
// * polynomials is the list of polynomials to open, they are supposed to be of the same size.
// * dataTranscript extra data that might be needed to derive the challenge used for folding
func OnDeviceBatchOpenSinglePoint(polynomials [][]fr.Element, digests []Digest, point fr.Element, hf hash.Hash, pk ProvingKey, G1 unsafe.Pointer, dataTranscript ...[]byte) (BatchOpeningProof, error) {

// check for invalid sizes
nbDigests := len(digests)
if nbDigests != len(polynomials) {
return BatchOpeningProof{}, ErrInvalidNbDigests
}

// TODO ensure the polynomials are of the same size
largestPoly := -1
for _, p := range polynomials {
if len(p) == 0 || len(p) > len(pk.G1) {
return BatchOpeningProof{}, ErrInvalidPolynomialSize
}
if len(p) > largestPoly {
largestPoly = len(p)
}
}

var res BatchOpeningProof

// compute the purported values
res.ClaimedValues = make([]fr.Element, len(polynomials))
var wg sync.WaitGroup
wg.Add(len(polynomials))
for i := 0; i < len(polynomials); i++ {
go func(_i int) {
res.ClaimedValues[_i] = eval(polynomials[_i], point)
wg.Done()
}(i)
}

// wait for polynomial evaluations to be completed (res.ClaimedValues)
wg.Wait()

// derive the challenge γ, binded to the point and the commitments
gamma, err := deriveGamma(point, digests, res.ClaimedValues, hf, dataTranscript...)
if err != nil {
return BatchOpeningProof{}, err
}

// ∑ᵢγⁱf(a)
var foldedEvaluations fr.Element
chSumGammai := make(chan struct{}, 1)
go func() {
foldedEvaluations = res.ClaimedValues[nbDigests-1]
for i := nbDigests - 2; i >= 0; i-- {
foldedEvaluations.Mul(&foldedEvaluations, &gamma).
Add(&foldedEvaluations, &res.ClaimedValues[i])
}
close(chSumGammai)
}()

// compute ∑ᵢγⁱfᵢ
// note: if we are willing to parallelize that, we could clone the poly and scale them by
// gamma n in parallel, before reducing into foldedPolynomials
foldedPolynomials := make([]fr.Element, largestPoly)
copy(foldedPolynomials, polynomials[0])
gammas := make([]fr.Element, len(polynomials))
gammas[0] = gamma
for i := 1; i < len(polynomials); i++ {
gammas[i].Mul(&gammas[i-1], &gamma)
}

for i := 1; i < len(polynomials); i++ {
i := i
parallel.Execute(len(polynomials[i]), func(start, end int) {
var pj fr.Element
for j := start; j < end; j++ {
pj.Mul(&polynomials[i][j], &gammas[i-1])
foldedPolynomials[j].Add(&foldedPolynomials[j], &pj)
}
})
}

// compute H
<-chSumGammai
h := dividePolyByXminusA(foldedPolynomials, foldedEvaluations, point)
foldedPolynomials = nil // same memory as h

res.H, err = OnDeviceCommit(h, G1)
if err != nil {
return BatchOpeningProof{}, err
}

return res, nil
}
3 changes: 3 additions & 0 deletions ecc/bn254/kzg/kzg.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

36 changes: 36 additions & 0 deletions ecc/bn254/kzg/kzg_test.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ go 1.18
require (
github.com/bits-and-blooms/bitset v1.7.0
github.com/consensys/bavard v0.1.13
github.com/ingonyama-zk/iciclegnark v0.1.0
github.com/leanovate/gopter v0.2.9
github.com/mmcloughlin/addchain v0.4.0
github.com/spf13/cobra v1.5.0
github.com/stretchr/testify v1.8.2
github.com/stretchr/testify v1.8.3
golang.org/x/crypto v0.10.0
golang.org/x/sys v0.9.0
gopkg.in/yaml.v2 v2.4.0
Expand All @@ -17,6 +18,7 @@ require (
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/ingonyama-zk/icicle v0.1.0 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
Expand Down
15 changes: 6 additions & 9 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,15 @@ github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/Yj
github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
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/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/ingonyama-zk/icicle v0.1.0 h1:9zbHaYv8/4g3HWRabBCpeH+64U8GJ99K1qeqE2jO6LM=
github.com/ingonyama-zk/icicle v0.1.0/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/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
Expand All @@ -32,13 +35,8 @@ github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU=
github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM=
golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I=
golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s=
Expand All @@ -48,7 +46,6 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
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.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
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=
Expand Down