Skip to content

Commit

Permalink
Merge pull request #16 from reclaimprotocol/gnark-improvements
Browse files Browse the repository at this point in the history
Gnark improvements
  • Loading branch information
Scratch-net authored Nov 20, 2024
2 parents 9e8632e + 294621c commit 58ad00c
Show file tree
Hide file tree
Showing 19 changed files with 126 additions and 157 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ jobs:

- name: Install Circom
run: |
git clone https://github.com/iden3/circom.git -b v2.1.6 circom-lib
git clone https://github.com/iden3/circom.git -b v2.2.1 circom-lib
cd circom-lib
RUSTFLAGS="-A dead_code -A unused-imports" cargo install --path circom
Expand Down
Binary file modified bin/gnark/linux-arm64-libprove.so
Binary file not shown.
Binary file modified bin/gnark/linux-arm64-libverify.so
Binary file not shown.
Binary file modified bin/gnark/linux-x86_64-libprove.so
Binary file not shown.
Binary file modified bin/gnark/linux-x86_64-libverify.so
Binary file not shown.
132 changes: 112 additions & 20 deletions gnark/keygen/keygen.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
package main

import (
"bytes"
"crypto/sha256"
"encoding/hex"
aes_v2 "gnark-symmetric-crypto/circuits/aesV2"
"gnark-symmetric-crypto/circuits/chachaV3"
"gnark-symmetric-crypto/circuits/chachaV3_oprf"
"regexp"
"time"

"fmt"
Expand All @@ -17,26 +21,26 @@ import (

const OUT_DIR = "../resources/gnark"

func main() {

generateCircuitFiles(&chachaV3.ChaChaCircuit{}, "chacha20")
generateCircuitFiles(&chachaV3_oprf.ChachaTOPRFCircuit{TOPRF: chachaV3_oprf.TOPRFData{}}, "chacha20_oprf")
type algCircuit struct {
alg string
circuit frontend.Circuit
}

aes128 := &aes_v2.AES128Wrapper{
var algMappings = map[string]*algCircuit{
"chacha20": {"chacha20", &chachaV3.ChaChaCircuit{}},
"aes128": {"aes-128-ctr", &aes_v2.AES128Wrapper{
AESWrapper: aes_v2.AESWrapper{
Key: make([]frontend.Variable, 16),
},
}

generateCircuitFiles(aes128, "aes128")

aes256 := &aes_v2.AES256Wrapper{
Key: make([]frontend.Variable, 16)}}},
"aes256": {"aes-256-ctr", &aes_v2.AES256Wrapper{
AESWrapper: aes_v2.AESWrapper{
Key: make([]frontend.Variable, 32),
},
}
generateCircuitFiles(aes256, "aes256")
Key: make([]frontend.Variable, 32)}}},
"chacha20_oprf": {"chacha20-toprf", &chachaV3_oprf.ChachaTOPRFCircuit{TOPRF: chachaV3_oprf.TOPRFData{}}},
}

func main() {
for alg, circuit := range algMappings {
generateCircuitFiles(circuit.circuit, alg)
}
}

func generateCircuitFiles(circuit frontend.Circuit, name string) {
Expand Down Expand Up @@ -67,26 +71,44 @@ func generateCircuitFiles(circuit frontend.Circuit, name string) {
panic(err)
}

_, err = r1css.WriteTo(f)
buf := &bytes.Buffer{}
_, err = r1css.WriteTo(buf)
if err != nil {
panic(err)
}

circuitHash := hashBytes(buf.Bytes())

_, err = f.Write(buf.Bytes())
if err != nil {
{
panic(err)
}
}

err = f.Close()
if err != nil {
panic(err)
}

pk1, vk1, err := groth16.Setup(r1css)
pk, vk1, err := groth16.Setup(r1css)
if err != nil {
panic(err)
}

buf = &bytes.Buffer{}
_, err = pk.WriteTo(buf)
if err != nil {
panic(err)
}
pkHash := hashBytes(buf.Bytes())

f2, err := os.OpenFile(OUT_DIR+"/pk."+name, os.O_RDWR|os.O_CREATE, 0777)
if err != nil {
panic(err)
}

_, err = pk1.WriteTo(f2)
_, err = f2.Write(buf.Bytes())
if err != nil {
panic(err)
}
Expand All @@ -109,7 +131,77 @@ func generateCircuitFiles(circuit frontend.Circuit, name string) {
panic(err)
}

fmt.Println("generated circuit for ", name)
fmt.Println("generated circuit for", name)
updateLibraryHashes(algMappings[name].alg, pkHash, circuitHash)
fmt.Println("updated hashes for", name)
}

func hashBytes(bytes []byte) []byte {
hash := sha256.Sum256(bytes)
return []byte(hex.EncodeToString(hash[:]))
}

func updateLibraryHashes(algName string, pkHash, circuitHash []byte) {
libFile, err := os.ReadFile("libraries/prover/impl/library.go")
if err != nil {
panic(err)
}

r := regexp.MustCompile("(?si)" + algName + "\":.*?KeyHash:\\s*\"([a-z0-9]{64})\".*?CircuitHash:\\s+\"([a-z0-9]{64})\"")
libFile = replaceAllSubmatchFunc(r, libFile, func(groups [][]byte) [][]byte {
groups[0] = pkHash
groups[1] = circuitHash
return groups
}, 1)
err = os.WriteFile("libraries/prover/impl/library.go", libFile, 0777)
if err != nil {
panic(err)
}
}

// from https://gist.github.com/slimsag/14c66b88633bd52b7fa710349e4c6749
func replaceAllSubmatchFunc(re *regexp.Regexp, src []byte, repl func([][]byte) [][]byte, n int) []byte {
var (
result = make([]byte, 0, len(src))
matches = re.FindAllSubmatchIndex(src, n)
last = 0
)
for _, match := range matches {
// Append bytes between our last match and this one (i.e. non-matched bytes).
matchStart := match[0]
matchEnd := match[1]
result = append(result, src[last:matchStart]...)
last = matchEnd

// Determine the groups / submatch bytes and indices.
groups := [][]byte{}
groupIndices := [][2]int{}
for i := 2; i < len(match); i += 2 {
start := match[i]
end := match[i+1]
groups = append(groups, src[start:end])
groupIndices = append(groupIndices, [2]int{start, end})
}

// Replace the groups as desired.
groups = repl(groups)

// Append match data.
lastGroup := matchStart
for i, newValue := range groups {
// Append bytes between our last group match and this one (i.e. non-group-matched bytes)
groupStart := groupIndices[i][0]
groupEnd := groupIndices[i][1]
result = append(result, src[lastGroup:groupStart]...)
lastGroup = groupEnd

// Append the new group value.
result = append(result, newValue...)
}
result = append(result, src[lastGroup:matchEnd]...) // remaining
}
result = append(result, src[last:]...) // remaining
return result
}

/**
Expand Down
126 changes: 2 additions & 124 deletions gnark/libraries/core_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import (
"math"
"math/big"
"os"
"sync"
"testing"

"github.com/consensys/gnark-crypto/ecc/bn254/twistededwards"
Expand Down Expand Up @@ -41,127 +40,7 @@ func TestInit(t *testing.T) {
assert.True(prover.InitAlgorithm(prover.CHACHA20, chachaKey, chachaR1CS))
assert.True(prover.InitAlgorithm(prover.AES_128, aes128Key, aes128r1cs))
assert.True(prover.InitAlgorithm(prover.AES_256, aes256Key, aes256r1cs))
// assert.True(prover.InitAlgorithm(prover.CHACHA20_OPRF, chachaOprfKey, chachaOprfr1cs))

}

func TestProveVerify(t *testing.T) {
assert := test.NewAssert(t)

proofs := make([][]byte, 0, 4)

wg := new(sync.WaitGroup)
wg.Add(4)
go func() {
assert.True(prover.InitAlgorithm(prover.CHACHA20, chachaKey, chachaR1CS))
params_struct := prover.InputParams{
Cipher: "chacha20",
Key: []byte{2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2},
Nonce: []byte{3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3},
Counter: 3,
Input: make([]uint8, 64*CHACHA20_BLOCKS),
}
params, err := json.Marshal(&params_struct)
assert.NoError(err)

res := prover.Prove(params)

assert.NotNil(res)
var outParams *prover.OutputParams
json.Unmarshal(res, &outParams)

var inParams *prover.InputParams
json.Unmarshal(params, &inParams)

signals := outParams.PublicSignals
signals = append(signals, inParams.Nonce...)
bCounter := make([]byte, 4)
binary.LittleEndian.PutUint32(bCounter, inParams.Counter)
signals = append(signals, bCounter...)
signals = append(signals, inParams.Input...)

inParams2 := &verifier.InputVerifyParams{
Cipher: "chacha20",
Proof: outParams.Proof.ProofJson,
PublicSignals: signals,
}
inBuf, _ := json.Marshal(inParams2)
proofs = append(proofs, inBuf)
wg.Done()
}()

go func() {
assert.True(prover.InitAlgorithm(prover.AES_128, aes128Key, aes128r1cs))
params := `{"cipher":"aes-128-ctr","key":[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2],"nonce":[3,3,3,3,3,3,3,3,3,3,3,3],"counter":2,"input":[183,4,206,60,254,21,117,9,150,227,246,245,71,101,56,67,79,93,44,163,22,89,128,55,214,254,228,214,89,253,176,112,138,115,93,140,194,222,104,252,49,144,91,252,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}`
res := prover.Prove([]byte(params))
assert.NotNil(res)

var outParams *prover.OutputParams
json.Unmarshal(res, &outParams)

var inParams *prover.InputParams
json.Unmarshal([]byte(params), &inParams)

signals := outParams.PublicSignals
signals = append(signals, inParams.Nonce...)
bCounter := make([]byte, 4)
binary.BigEndian.PutUint32(bCounter, inParams.Counter)
signals = append(signals, bCounter...)
signals = append(signals, inParams.Input...)

inParams2 := &verifier.InputVerifyParams{
Cipher: "aes-128-ctr",
Proof: outParams.Proof.ProofJson,
PublicSignals: signals,
}
inBuf, _ := json.Marshal(inParams2)
proofs = append(proofs, inBuf)
wg.Done()
}()

go func() {
assert.True(prover.InitAlgorithm(prover.AES_256, aes256Key, aes256r1cs))
params := `{"cipher":"aes-256-ctr","key":[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2],"nonce":[3,3,3,3,3,3,3,3,3,3,3,3],"counter":10,"input":[189,250,225,242,6,46,173,203,7,166,62,139,67,150,1,155,64,122,211,198,184,203,124,194,99,34,127,29,236,17,232,214,154,146,78,217,254,224,208,196,55,200,23,93,90,175,240,31,31,225,26,15,219,156,123,21,103,98,205,87,197,22,245,158]}`
res := prover.Prove([]byte(params))
assert.NotNil(res)

var outParams *prover.OutputParams
json.Unmarshal(res, &outParams)

var inParams *prover.InputParams
json.Unmarshal([]byte(params), &inParams)
signals := outParams.PublicSignals
signals = append(signals, inParams.Nonce...)
bCounter := make([]byte, 4)
binary.BigEndian.PutUint32(bCounter, inParams.Counter)
signals = append(signals, bCounter...)
signals = append(signals, inParams.Input...)

inParams2 := &verifier.InputVerifyParams{
Cipher: "aes-256-ctr",
Proof: outParams.Proof.ProofJson,
PublicSignals: signals,
}
inBuf, _ := json.Marshal(inParams2)
proofs = append(proofs, inBuf)
wg.Done()
}()

go func() {
assert.True(prover.InitAlgorithm(prover.CHACHA20_OPRF, chachaOprfKey, chachaOprfr1cs))
params := `{"cipher":"chacha20-toprf","key":"cmTjtxcDYzMlAMqtmjhQq2yxxN1syhocwhK3iOAOd34=","nonce":"KIDzQFfJemUYKf2r","counter":38538388,"input":"wJwt+53oiXWmev7LPuPR/nNVaLknXp83Y/zkg4R3NDE7tmmx+LEbiC97IpAryMpMpg2+XXAwrp/6EP17zmS9ywjBsq8kUjAlmILM9z3a3QlN2/k6UILaYWfhH73/Mxjjt44zYb+Sl7n95wMHMx/2e65awMUfi3F9TbmfT+Ez7lA=","toprf":{"pos":59,"len":14,"mask":"pxXilBb2iX9ayGvl9PUIsaLQ0gXQ217kqCOEtW3NCg==","domainSeparator":"cmVjbGFpbQ==","output":"Evt2a6W9F/kFC9i/TBVHDjvAhUIzq07q+Ug0Ky9Wq74=","responses":[{"index":0,"publicKeyShare":"xP7+zxUAQV3NXAIxGH1snWFy8ZuouuTZT8P/Tz178ao=","evaluated":"zRcJ2TLzWoMoMAb9xWkqXy7c1yXQvgdM0HDTcUqZ3q0=","c":"KMQFGM3WFCBS3Ds91sQkiRajWY5JhNg6Y1OiQU4KRR0=","r":"A7bEbIuK1zjaQJdCNrehfDU2XXZ+v2cul7KzXBbCPR0="}]}}`
res := prover.Prove([]byte(params))
assert.NotNil(res)
wg.Done()
}()

wg.Wait()

assert.Equal(3, len(proofs))

for _, proof := range proofs {
assert.True(verifier.Verify(proof))
}
assert.True(prover.InitAlgorithm(prover.CHACHA20_OPRF, chachaOprfKey, chachaOprfr1cs))
}

func TestPanic(t *testing.T) {
Expand Down Expand Up @@ -341,8 +220,7 @@ func TestFullChaCha20OPRF(t *testing.T) {
nodes := threshold + 1

tParams := &oprf.InputGenerateParams{
Total: uint8(nodes),
Threshold: uint8(threshold),
Total: uint8(nodes),
}

btParams, err := json.Marshal(tParams)
Expand Down
12 changes: 6 additions & 6 deletions gnark/libraries/prover/impl/library.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,22 +31,22 @@ var algorithmNames = map[uint8]string{

var provers = map[string]*ProverParams{
"chacha20": {
KeyHash: "967e55bd35f1333735fb62b9bda363dd307a294979c543bfc400c859b5f45fe5",
KeyHash: "c873216b53f0e8b65cfdb2e1e306e3423596166794067a0fa5b406b215000396",
CircuitHash: "4aa80775a6721404bf8f82fd2d78d335fabbdf517762b82a7d13e6d2446c49bf",
Prover: &ChaChaProver{},
},
"aes-128-ctr": {
KeyHash: "70a67f30e706a5ac91e231f23c936c3b06c4a34a7e7b578b74c70ec61473d13a",
CircuitHash: "396128ea72136960c8a0cfddf36e2888f398116a210904745c7ed62dfcd9b115",
KeyHash: "a312a67df74f1a173f5860b4b4f3d67e53ac24fc4121ca25e0e99a62595c9202",
CircuitHash: "f51d0f2166119d6113aff0152163de9cfc87e93b09a151b4167004787098c582",
Prover: &AESProver{},
},
"aes-256-ctr": {
KeyHash: "b78c3e0b5c28c000e5338cf16e6745b8a8f2c3613d20898e88659e39c82f7de8",
CircuitHash: "7b03be9e28a5c6de19da34cfd9fad9e7dab62cda8873fada4e916b1978bbf692",
KeyHash: "659ed771c9e4d6ad835c3db02e44034f7e30138309e8fd8a188c0f2371987c9f",
CircuitHash: "fe603e94c6a8d3254a5a9703c265aeade34b8f2e4f621c2f75a48e33e912b145",
Prover: &AESProver{},
},
"chacha20-toprf": {
KeyHash: "e12b7ffc6fec577fb0191967ebb93fe5f9a18b597f2a59637bdcb55f0a9b27e4",
KeyHash: "4d5dbd24724f544abf81c9d4c11bc853484571fcb2f4c2c5ec0d8d8fb9aa782e",
CircuitHash: "4770df06bb04cf64ea19549834a6ff2e32772ee0b81336d6e6eddb81e8947c12",
Prover: &ChaChaOPRFProver{},
},
Expand Down
Binary file modified gnark/libraries/verifier/impl/generated/vk.aes128
100644 → 100755
Binary file not shown.
Binary file modified gnark/libraries/verifier/impl/generated/vk.aes256
100644 → 100755
Binary file not shown.
Binary file modified gnark/libraries/verifier/impl/generated/vk.chacha20
Binary file not shown.
Binary file modified gnark/libraries/verifier/impl/generated/vk.chacha20_oprf
Binary file not shown.
Loading

0 comments on commit 58ad00c

Please sign in to comment.