Skip to content

Commit

Permalink
Merge pull request #12 from reclaimprotocol/oprf
Browse files Browse the repository at this point in the history
OPRF support
  • Loading branch information
adiwajshing authored Nov 9, 2024
2 parents cea243f + 4da0e8c commit 4fe79d4
Show file tree
Hide file tree
Showing 70 changed files with 3,330 additions and 537 deletions.
12 changes: 7 additions & 5 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}

Expand Down Expand Up @@ -51,7 +51,7 @@ jobs:
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}

Expand All @@ -75,16 +75,18 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
go-version: [1.23] # Specify the Go versions you want to test with
go-version: ['stable'] # Specify the Go versions you want to test with

steps:
- name: Checkout code
uses: actions/checkout@v3
uses: actions/checkout@v4

- name: Setup Go
uses: actions/setup-go@v4
uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go-version }}
check-latest: true
cache-dependency-path: "**/go.sum"

- name: Install dependencies
working-directory: ./gnark
Expand Down
Binary file modified bin/gnark/darwin-arm64-libprove.so
Binary file not shown.
Binary file modified bin/gnark/darwin-arm64-libverify.so
Binary file not shown.
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.
25 changes: 21 additions & 4 deletions circom/circuits/chacha20/chacha20-bits.circom
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,24 @@ template ChaCha20(N, BITS_PER_WORD) {
counter,
nonce[0], nonce[1], nonce[2]
];

// 1 in 32-bit words
signal one[BITS_PER_WORD];
one <== [
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1
];

var i = 0;
var j = 0;

// do the ChaCha20 rounds
component rounds[N/16];
component xors[N];
component counter_adder[N/16 - 1];

for(i = 0; i < N/16; i++) {
rounds[i] = Round(BITS_PER_WORD);
rounds[i].in <== tmp;
Expand All @@ -67,9 +79,14 @@ template ChaCha20(N, BITS_PER_WORD) {
xors[i*16 + j].b <== rounds[i].out[j];
out[i*16 + j] <== xors[i*16 + j].out;
}
// increment the counter
// TODO: we only use one block
// at a time, so isn't required
// tmp[12] = tmp[12] + 1;

if(i < N/16 - 1) {
counter_adder[i] = AddBits(BITS_PER_WORD);
counter_adder[i].a <== tmp[12];
counter_adder[i].b <== one;

// increment the counter
tmp[12] = counter_adder[i].out;
}
}
}
2 changes: 1 addition & 1 deletion circom/circuits/chacha20/circuit.circom
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ pragma circom 2.0.0;

include "./chacha20-bits.circom";

component main{public [in, nonce, counter]} = ChaCha20(16, 32);
component main{public [in, nonce, counter]} = ChaCha20(32, 32);
5 changes: 5 additions & 0 deletions circom/circuits/tests/chacha20_2.circom
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pragma circom 2.0.0;

include "../chacha20/chacha20-bits.circom";

component main = ChaCha20(32, 32);
4 changes: 2 additions & 2 deletions circom/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ Official Ptau file for bn128 with 256k max constraints can be downloaded by runn
npm run download:ptau
```

Build the circuits via `ALG={alg} npm run build:circuit`.
For eg. `ALG=chacha20 npm run build:circuit`
Build the circuits via `ALG={alg} npm run build`.
For eg. `ALG=chacha20 npm run build`
Note: `ALG` is the same as mentioned in the first section of this readme.

### Regenerating the Verification Key
Expand Down
82 changes: 82 additions & 0 deletions circom/tests/chacha-circuits.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { describe, it } from 'node:test'
import { loadCircuit, toUint32Array, uintArray32ToBits } from './utils.ts'
import { createCipheriv, createDecipheriv } from 'node:crypto'

describe('ChaCha Circuits Tests', () => {

Expand Down Expand Up @@ -262,6 +263,87 @@ describe('ChaCha Circuits Tests', () => {
}
})

it('should encrypt 2 chacha20 blocks', async() => {
const circuit = await loadCircuit('chacha20_2')

const vectors = [
{
keyBytes: Buffer.from(
[
0x00, 0x01, 0x02, 0x03,
0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b,
0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13,
0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1a, 0x1b,
0x1c, 0x1d, 0x1e, 0x1f
]
),
nonceBytes: Buffer.from(
[
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x4a,
0x00, 0x00, 0x00, 0x00
]
),
counter: 1,
plaintextBytes: Buffer.from(
[
0x4c, 0x61, 0x64, 0x69, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x47, 0x65, 0x6e, 0x74, 0x6c,
0x65, 0x6d, 0x65, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x61, 0x73,
0x73, 0x20, 0x6f, 0x66, 0x20, 0x27, 0x39, 0x39, 0x3a, 0x20, 0x49, 0x66, 0x20, 0x49, 0x20, 0x63,
0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6f, 0x66, 0x66, 0x65, 0x72, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x6f,
0x7, 0x88, 0x41, 0x5, 0x1a, 0xb, 0xf6, 0xc1, 0x63, 0x70, 0xf9, 0x0, 0x31, 0x40, 0xad, 0xff,
0xcf, 0xaa, 0x4e, 0x81, 0x6d, 0xfa, 0xec, 0xb1, 0xf9, 0xce, 0x6a, 0xf6, 0x39, 0x93, 0xf7, 0x4e,
0xc0, 0x90, 0xb, 0x1f, 0x48, 0xc4, 0x1f, 0x22, 0x4e, 0x3e, 0xd7, 0x66, 0x5d, 0x7f, 0xcd, 0x7c,
0xe5, 0x5a, 0xa2, 0x27, 0x95, 0x71, 0x48, 0xa, 0x7, 0xa8, 0xb0, 0xdd, 0xa6, 0x99, 0xa5, 0x35
]
),
ciphertextBytes: Buffer.from(
[
0x6e, 0x2e, 0x35, 0x9a, 0x25, 0x68, 0xf9, 0x80, 0x41, 0xba, 0x07, 0x28, 0xdd, 0x0d, 0x69, 0x81,
0xe9, 0x7e, 0x7a, 0xec, 0x1d, 0x43, 0x60, 0xc2, 0x0a, 0x27, 0xaf, 0xcc, 0xfd, 0x9f, 0xae, 0x0b,
0xf9, 0x1b, 0x65, 0xc5, 0x52, 0x47, 0x33, 0xab, 0x8f, 0x59, 0x3d, 0xab, 0xcd, 0x62, 0xb3, 0x57,
0x16, 0x39, 0xd6, 0x24, 0xe6, 0x51, 0x52, 0xab, 0x8f, 0x53, 0x0c, 0x35, 0x9f, 0x08, 0x61, 0xd8,
0x6e, 0x2e, 0x35, 0x9a, 0x25, 0x68, 0xf9, 0x80, 0x41, 0xba, 0x07, 0x28, 0xdd, 0x0d, 0x69, 0x81,
0xe9, 0x7e, 0x7a, 0xec, 0x1d, 0x43, 0x60, 0xc2, 0x0a, 0x27, 0xaf, 0xcc, 0xfd, 0x9f, 0xae, 0x0b,
0xf9, 0x1b, 0x65, 0xc5, 0x52, 0x47, 0x33, 0xab, 0x8f, 0x59, 0x3d, 0xab, 0xcd, 0x62, 0xb3, 0x57,
0x16, 0x39, 0xd6, 0x24, 0xe6, 0x51, 0x52, 0xab, 0x8f, 0x53, 0x0c, 0x35, 0x9f, 0x08, 0x61, 0xd8
]
)
}
]

for(const { keyBytes, nonceBytes, counter, plaintextBytes, ciphertextBytes } of vectors) {
const ciphertextBits = uintArray32ToBits(toUint32Array(ciphertextBytes))
const plaintextBits = uintArray32ToBits(toUint32Array(plaintextBytes))
const counterBits = uintArray32ToBits([counter])[0]
const w = await circuit.calculateWitness({
key: uintArray32ToBits(toUint32Array(keyBytes)),
nonce: uintArray32ToBits(toUint32Array(nonceBytes)),
counter: counterBits,
in: plaintextBits,
})

await circuit.checkConstraints(w)
await circuit.assertOut(w, {
out: ciphertextBits
})

// check decryption
const w2 = await circuit.calculateWitness({
key: uintArray32ToBits(toUint32Array(keyBytes)),
nonce: uintArray32ToBits(toUint32Array(nonceBytes)),
counter: counterBits,
in: ciphertextBits,
})

await circuit.checkConstraints(w2)
await circuit.assertOut(w2, { out: plaintextBits })
}
})

function rotl32(v, c) {
return (v << c) | (v >>> (32 - c));
}
Expand Down
2 changes: 2 additions & 0 deletions gnark/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ For Linux:
GOARCH=arm64 sh scripts/build.sh
# linux x86
GOARCH=x86_64 sh scripts/build.sh
# macos arm64
GOOS=darwin GOARCH=arm64 sh scripts/build.sh

# Android x86 & arm64
CC=android/ndk-bundle/toolchains/llvm/prebuilt/linux-x86_64/bin/x86_64-linux-android30-clang CXX=android/ndk-bundle/toolchains/llvm/prebuilt/linux-x86_64/bin/x86_64-linux-android30-clang++ GOOS=android GOARCH=amd64 sh scripts/build.sh
Expand Down
2 changes: 1 addition & 1 deletion gnark/circuits/aesV2/aes128.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func (circuit *AES128Wrapper) Define(api frontend.API) error {
keystream := aes.Encrypt(circuit.Key, counterBlock)

for i := 0; i < 16; i++ {
api.AssertIsEqual(circuit.Ciphertext[b*16+i], aes.VariableXor(keystream[i], circuit.Plaintext[b*16+i], 8))
api.AssertIsEqual(circuit.Out[b*16+i], aes.VariableXor(keystream[i], circuit.In[b*16+i], 8))
}
counter = api.Add(counter, 1)
api.AssertIsLessOrEqual(counter, math.MaxUint32)
Expand Down
24 changes: 12 additions & 12 deletions gnark/circuits/aesV2/aes128_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,11 @@ func TestAES128(t *testing.T) {
// witness values preparation
assignment := AES128Wrapper{
AESWrapper{
Key: make([]frontend.Variable, 16),
Counter: Counter,
Nonce: [12]frontend.Variable{},
Plaintext: [BLOCKS * 16]frontend.Variable{},
Ciphertext: [BLOCKS * 16]frontend.Variable{},
Key: make([]frontend.Variable, 16),
Counter: Counter,
Nonce: [12]frontend.Variable{},
In: [BLOCKS * 16]frontend.Variable{},
Out: [BLOCKS * 16]frontend.Variable{},
},
}

Expand All @@ -69,10 +69,10 @@ func TestAES128(t *testing.T) {
assignment.Key[i] = keyAssign[i]
}
for i := 0; i < len(ptAssign); i++ {
assignment.Plaintext[i] = ptAssign[i]
assignment.In[i] = ptAssign[i]
}
for i := 0; i < len(ctAssign); i++ {
assignment.Ciphertext[i] = ctAssign[i]
assignment.Out[i] = ctAssign[i]
}

for i := 0; i < len(nonceAssign); i++ {
Expand All @@ -81,11 +81,11 @@ func TestAES128(t *testing.T) {

assert.CheckCircuit(&AES128Wrapper{
AESWrapper{
Key: make([]frontend.Variable, 16),
Counter: Counter,
Nonce: [12]frontend.Variable{},
Plaintext: [BLOCKS * 16]frontend.Variable{},
Ciphertext: [BLOCKS * 16]frontend.Variable{},
Key: make([]frontend.Variable, 16),
Counter: Counter,
Nonce: [12]frontend.Variable{},
In: [BLOCKS * 16]frontend.Variable{},
Out: [BLOCKS * 16]frontend.Variable{},
},
}, test.WithValidAssignment(&assignment))
}
Expand Down
2 changes: 1 addition & 1 deletion gnark/circuits/aesV2/aes256.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func (circuit *AES256Wrapper) Define(api frontend.API) error {
keystream := aes.Encrypt(circuit.Key, counterBlock)

for i := 0; i < 16; i++ {
api.AssertIsEqual(circuit.Ciphertext[b*16+i], aes.VariableXor(keystream[i], circuit.Plaintext[b*16+i], 8))
api.AssertIsEqual(circuit.Out[b*16+i], aes.VariableXor(keystream[i], circuit.In[b*16+i], 8))
}
counter = api.Add(counter, 1)
api.AssertIsLessOrEqual(counter, math.MaxUint32)
Expand Down
24 changes: 12 additions & 12 deletions gnark/circuits/aesV2/aes256_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,11 @@ func TestAES256(t *testing.T) {
// witness values preparation
assignment := AES256Wrapper{
AESWrapper{
Key: make([]frontend.Variable, 32),
Counter: Counter,
Nonce: [12]frontend.Variable{},
Plaintext: [BLOCKS * 16]frontend.Variable{},
Ciphertext: [BLOCKS * 16]frontend.Variable{},
Key: make([]frontend.Variable, 32),
Counter: Counter,
Nonce: [12]frontend.Variable{},
In: [BLOCKS * 16]frontend.Variable{},
Out: [BLOCKS * 16]frontend.Variable{},
},
}

Expand All @@ -69,10 +69,10 @@ func TestAES256(t *testing.T) {
assignment.Key[i] = keyAssign[i]
}
for i := 0; i < len(ptAssign); i++ {
assignment.Plaintext[i] = ptAssign[i]
assignment.In[i] = ptAssign[i]
}
for i := 0; i < len(ciphertext); i++ {
assignment.Ciphertext[i] = ciphertext[i]
assignment.Out[i] = ciphertext[i]
}

for i := 0; i < len(nonceAssign); i++ {
Expand All @@ -81,11 +81,11 @@ func TestAES256(t *testing.T) {

assert.CheckCircuit(&AES256Wrapper{
AESWrapper{
Key: make([]frontend.Variable, 32),
Counter: Counter,
Nonce: [12]frontend.Variable{},
Plaintext: [BLOCKS * 16]frontend.Variable{},
Ciphertext: [BLOCKS * 16]frontend.Variable{},
Key: make([]frontend.Variable, 32),
Counter: Counter,
Nonce: [12]frontend.Variable{},
In: [BLOCKS * 16]frontend.Variable{},
Out: [BLOCKS * 16]frontend.Variable{},
},
}, test.WithValidAssignment(&assignment))
}
Expand Down
10 changes: 5 additions & 5 deletions gnark/circuits/aesV2/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ import (
const BLOCKS = 4

type AESWrapper struct {
Key []frontend.Variable
Nonce [12]frontend.Variable `gnark:",public"`
Counter frontend.Variable `gnark:",public"`
Plaintext [BLOCKS * 16]frontend.Variable `gnark:",public"`
Ciphertext [BLOCKS * 16]frontend.Variable `gnark:",public"`
Key []frontend.Variable
Nonce [12]frontend.Variable `gnark:",public"`
Counter frontend.Variable `gnark:",public"`
In [BLOCKS * 16]frontend.Variable `gnark:",public"`
Out [BLOCKS * 16]frontend.Variable `gnark:",public"`
}

type AESGadget struct {
Expand Down
17 changes: 13 additions & 4 deletions gnark/circuits/chacha/chacha_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package chacha
import (
"crypto/rand"
"encoding/binary"
"gnark-symmetric-crypto/utils"
"testing"

"github.com/consensys/gnark-crypto/ecc"
Expand Down Expand Up @@ -87,7 +86,7 @@ func TestRound(t *testing.T) {
0x13121110, 0x17161514, 0x1b1a1918, 0x1f1e1d1c,
0x00000001, 0x09000000, 0x4a000000, 0x00000000})

out := utils.BytesToUint32BE([]uint8{
out := BytesToUint32BE([]uint8{
0x10, 0xf1, 0xe7, 0xe4, 0xd1, 0x3b, 0x59, 0x15, 0x50, 0x0f, 0xdd, 0x1f, 0xa3, 0x20, 0x71, 0xc4,
0xc7, 0xd1, 0xf4, 0xc7, 0x33, 0xc0, 0x68, 0x03, 0x04, 0x22, 0xaa, 0x9a, 0xc3, 0xd4, 0x6c, 0x4e,
0xd2, 0x82, 0x64, 0x46, 0x07, 0x9f, 0xaa, 0x09, 0x14, 0xc2, 0xd7, 0x05, 0xd9, 0x8b, 0x02, 0xa2,
Expand Down Expand Up @@ -129,8 +128,8 @@ func TestCipher(t *testing.T) {
fmt.Println(hex.EncodeToString(bPt))
fmt.Println(hex.EncodeToString(bCt))*/

plaintext := utils.BytesToUint32BE(bPt)
ciphertext := utils.BytesToUint32BE(bCt)
plaintext := BytesToUint32BE(bPt)
ciphertext := BytesToUint32BE(bCt)

witness := ChaChaCircuit{}
copy(witness.Key[:], BytesToUint32LE(bKey))
Expand All @@ -153,3 +152,13 @@ func BytesToUint32LE(in []uint8) []uints.U32 {
}
return res
}

func BytesToUint32BE(in []uint8) []uints.U32 {

var res []uints.U32
for i := 0; i < len(in); i += 4 {
t := binary.BigEndian.Uint32(in[i:])
res = append(res, uints.NewU32(t))
}
return res
}
3 changes: 1 addition & 2 deletions gnark/circuits/chachaV3/chacha_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@ package chachaV3

import (
"crypto/rand"
"testing"

"gnark-symmetric-crypto/utils"
"testing"

"github.com/consensys/gnark-crypto/ecc"
"github.com/consensys/gnark/frontend"
Expand Down
Loading

0 comments on commit 4fe79d4

Please sign in to comment.