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

Web3 1262 gnark support #19

Merged
merged 9 commits into from
Dec 6, 2024
Merged
Show file tree
Hide file tree
Changes from 7 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
4 changes: 4 additions & 0 deletions .env.template
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,8 @@ SEED_PHRASE_4=
SEED_PHRASE_5=
SEED_PHRASE_6=
SEED_PHRASE_7=
SEED_PHRASE_8=
SEED_PHRASE_9=
SEED_PHRASE_10=
SEED_PHRASE_11=
QA_SLACK_WEBHOOK_URL=
3 changes: 3 additions & 0 deletions .github/workflows/ci-build-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ jobs:
SEED_PHRASE_6: ${{ secrets.SEED_PHRASE_6 }}
SEED_PHRASE_7: ${{ secrets.SEED_PHRASE_7 }}
SEED_PHRASE_8: ${{ secrets.SEED_PHRASE_8 }}
SEED_PHRASE_9: ${{ secrets.SEED_PHRASE_9 }}
SEED_PHRASE_10: ${{ secrets.SEED_PHRASE_10 }}
SEED_PHRASE_11: ${{ secrets.SEED_PHRASE_11 }}

steps:
- name: Checkout code
Expand Down
3 changes: 3 additions & 0 deletions .secrets
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ QA_SEED_PHRASE_5=_seed_phrase_5_
QA_SEED_PHRASE_6=_seed_phrase_6_
QA_SEED_PHRASE_7=_seed_phrase_7_
QA_SEED_PHRASE_8=_seed_phrase_8_
QA_SEED_PHRASE_9=_seed_phrase_9_
QA_SEED_PHRASE_10=_seed_phrase_10_
QA_SEED_PHRASE_11=_seed_phrase_11_
QA_SLACK_WEBHOOK_URL=_webhook_url_
RELEASES_PROD_SLACK_WEBHOOK_URL=_releases_prod_webhook_url_
NPM_TOKEN=_npm_token_
15 changes: 10 additions & 5 deletions DOCS.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Currently the following proof verifiers are supported:

* FFlonk
* Groth16 (BN128, BN254, BLS12-381 elliptic curves)
* Note - Must include `Library` and `CurveType` e.g. `.groth16(Library.gnark, CurveType.bn128)`
* Risc0
* Ultraplonk
* Space and Time
Expand Down Expand Up @@ -110,12 +111,16 @@ const { events, transactionResult } = await session
2. Frontend after establishing a session with `withWallet()`

```typescript
const { events, transactionResult } = await session.verify()
.groth16()
.execute({ proofData: {
import {CurveType} from "./index";

const {events, transactionResult} = await session.verify()
.groth16(Library.snarkjs, CurveType.bn128)
.execute({
proofData: {
vk: vk,
proof: proof,
publicSignals: publicSignals }
publicSignals: publicSignals
}
});

events.on('ErrorEvent', (eventData) => {
Expand Down Expand Up @@ -189,7 +194,7 @@ To await the final result of the transaction, use the transactionResult promise.

```typescript
const { events, transactionResult } = await session.verify()
.groth16()
.groth16(Library.gnark, CurveType.bls12381)
.execute({ proofData: {
vk: vk,
proof: proof,
Expand Down
16 changes: 11 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ The `zkverifyjs` package is a TypeScript library designed to facilitate sending
Currently the following proof verifiers are supported:
- FFlonk
- Groth16 (BN128, BN254, BLS12-381 elliptic curves)
- Note - Must include `Library` and `CurveType` e.g. `.groth16(Library.gnark, CurveType.bn128)`
- Risc0
- Ultraplonk
- Space and Time
Expand Down Expand Up @@ -126,13 +127,18 @@ const { events, transactionResult } = await session
```

2. Frontend after establishing a session with `withWallet()`

```typescript
const { events, transactionResult } = await session.verify()
.groth16()
.execute({ proofData: {
import {CurveType} from "./index";

const {events, transactionResult} = await session.verify()
.groth16(Library.snarkjs, CurveType.bn128)
.execute({
proofData: {
vk: vk,
proof: proof,
publicSignals: publicSignals }
publicSignals: publicSignals
}
});

events.on('ErrorEvent', (eventData) => {
Expand Down Expand Up @@ -206,7 +212,7 @@ To await the final result of the transaction, use the transactionResult promise.

```typescript
const { events, transactionResult } = await session.verify()
.groth16()
.groth16(Library.gnark, CurveType.bls12381)
.execute({ proofData: {
vk: vk,
proof: proof,
Expand Down
136 changes: 51 additions & 85 deletions src/api/format/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ProofProcessor } from '../../types';
import { getProofProcessor } from '../../utils/helpers';
import { ProofType } from '../../config';
import { ProofType, Library, CurveType } from '../../config';
import { format } from './index';

jest.mock('../../utils/helpers', () => ({
Expand All @@ -10,6 +10,12 @@ jest.mock('../../utils/helpers', () => ({
describe('format', () => {
let mockProcessor: ProofProcessor;

const proofOptions = {
proofType: ProofType.groth16,
library: Library.snarkjs,
curve: CurveType.bls12381,
};

beforeEach(() => {
mockProcessor = {
formatProof: jest.fn().mockReturnValue('formattedProof'),
Expand All @@ -26,29 +32,24 @@ describe('format', () => {
it('should throw an error if unsupported proofType is provided', () => {
(getProofProcessor as jest.Mock).mockReturnValue(null);

expect(() => format(ProofType.groth16, 'proof', 'signals', 'vk')).toThrow(
'Unsupported proof type: groth16',
);
expect(() =>
format(
{ ...proofOptions, proofType: 'unsupportedType' as any },
'proof',
'signals',
'vk',
),
).toThrow('Unsupported proof type: unsupportedType');
});

it('should throw an error if proof, public signals, or verification key is null, undefined, or empty', () => {
expect(() => format(ProofType.groth16, null, 'signals', 'vk')).toThrow(
expect(() => format(proofOptions, null, 'signals', 'vk')).toThrow(
'groth16: Proof is required and cannot be null, undefined, or an empty string.',
);
expect(() => format(ProofType.groth16, 'proof', null, 'vk')).toThrow(
expect(() => format(proofOptions, 'proof', null, 'vk')).toThrow(
'groth16: Public signals are required and cannot be null, undefined, or an empty string.',
);
expect(() => format(ProofType.groth16, 'proof', 'signals', null)).toThrow(
'groth16: Verification Key must be provided.',
);

expect(() => format(ProofType.groth16, '', 'signals', 'vk')).toThrow(
'groth16: Proof is required and cannot be null, undefined, or an empty string.',
);
expect(() => format(ProofType.groth16, 'proof', '', 'vk')).toThrow(
'groth16: Public signals are required and cannot be null, undefined, or an empty string.',
);
expect(() => format(ProofType.groth16, 'proof', 'signals', '')).toThrow(
expect(() => format(proofOptions, 'proof', 'signals', null)).toThrow(
'groth16: Verification Key must be provided.',
);
});
Expand All @@ -58,7 +59,7 @@ describe('format', () => {
throw new Error('Proof formatting error');
});

expect(() => format(ProofType.groth16, 'proof', 'signals', 'vk')).toThrow(
expect(() => format(proofOptions, 'proof', 'signals', 'vk')).toThrow(
'Failed to format groth16 proof: Proof formatting error. Proof snippet: "proof..."',
);
});
Expand All @@ -68,7 +69,7 @@ describe('format', () => {
throw new Error('Public signals formatting error');
});

expect(() => format(ProofType.groth16, 'proof', 'signals', 'vk')).toThrow(
expect(() => format(proofOptions, 'proof', 'signals', 'vk')).toThrow(
'Failed to format groth16 public signals: Public signals formatting error. Public signals snippet: "signals..."',
);
});
Expand All @@ -78,7 +79,7 @@ describe('format', () => {
throw new Error('Verification key formatting error');
});

expect(() => format(ProofType.groth16, 'proof', 'signals', 'vk')).toThrow(
expect(() => format(proofOptions, 'proof', 'signals', 'vk')).toThrow(
'Failed to format groth16 verification key: Verification key formatting error. Verification key snippet: "vk..."',
);
});
Expand All @@ -88,94 +89,59 @@ describe('format', () => {
throw 'Non-Error failure in proof';
});

expect(() => format(ProofType.groth16, 'proof', 'signals', 'vk')).toThrow(
expect(() => format(proofOptions, 'proof', 'signals', 'vk')).toThrow(
'Failed to format groth16 proof: Unknown error. Proof snippet: "proof..."',
);
});

it('should throw a generic error if formatting public signals fails with a non-Error type', () => {
(mockProcessor.formatPubs as jest.Mock).mockImplementation(() => {
throw 'Non-Error failure in public signals';
});

expect(() => format(ProofType.groth16, 'proof', 'signals', 'vk')).toThrow(
'Failed to format groth16 public signals: Unknown error. Public signals snippet: "signals..."',
);
});

it('should throw a generic error if formatting verification key fails with a non-Error type', () => {
(mockProcessor.formatVk as jest.Mock).mockImplementation(() => {
throw 'Non-Error failure in verification key';
});

expect(() => format(ProofType.groth16, 'proof', 'signals', 'vk')).toThrow(
'Failed to format groth16 verification key: Unknown error. Verification key snippet: "vk..."',
);
});

it('should return formatted values for non-registered verification key', () => {
const result = format(ProofType.groth16, 'proof', 'signals', 'vk');
const result = format(proofOptions, 'proof', 'signals', 'vk');

expect(result.formattedVk).toEqual({ Vk: 'formattedVk' });
expect(result.formattedProof).toBe('formattedProof');
expect(result.formattedPubs).toBe('formattedPubs');
expect(mockProcessor.formatProof).toHaveBeenCalledWith('proof');
expect(mockProcessor.formatPubs).toHaveBeenCalledWith('signals');
expect(mockProcessor.formatVk).toHaveBeenCalledWith('vk');
expect(mockProcessor.formatProof).toHaveBeenCalledWith(
'proof',
proofOptions,
);
expect(mockProcessor.formatPubs).toHaveBeenCalledWith(
'signals',
proofOptions,
);
expect(mockProcessor.formatVk).toHaveBeenCalledWith('vk', proofOptions);
});

it('should return formatted values for registered verification key', () => {
const result = format(ProofType.groth16, 'proof', 'signals', 'vk', true);
const result = format(proofOptions, 'proof', 'signals', 'vk', true);

expect(result.formattedVk).toEqual({ Hash: 'vk' });
expect(result.formattedProof).toBe('formattedProof');
expect(result.formattedPubs).toBe('formattedPubs');
expect(mockProcessor.formatProof).toHaveBeenCalledWith('proof');
expect(mockProcessor.formatPubs).toHaveBeenCalledWith('signals');
expect(mockProcessor.formatProof).toHaveBeenCalledWith(
'proof',
proofOptions,
);
expect(mockProcessor.formatPubs).toHaveBeenCalledWith(
'signals',
proofOptions,
);
expect(mockProcessor.formatVk).not.toHaveBeenCalled();
});

it('should format public signals correctly when publicSignals is an array', () => {
(mockProcessor.formatPubs as jest.Mock).mockImplementation(() => {
throw new Error('Array public signals formatting error');
});
expect(() =>
format(ProofType.groth16, 'proof', ['signal1', 'signal2'], 'vk'),
).toThrow(
'Failed to format groth16 public signals: Array public signals formatting error. Public signals snippet: "["signal1","signal2"]..."',
);
});
it('should handle arrays in publicSignals correctly', () => {
const result = format(proofOptions, 'proof', ['signal1', 'signal2'], 'vk');

it('should throw a formatted error for non-string proof, publicSignals, and vk', () => {
(mockProcessor.formatProof as jest.Mock).mockImplementation(() => {
throw new Error('Non-string proof error');
});
expect(() =>
format(ProofType.groth16, { field: 'value' }, 'signals', 'vk'),
).toThrow(
'Failed to format groth16 proof: Non-string proof error. Proof snippet: "{"field":"value"}..."',
expect(result.formattedPubs).toBe('formattedPubs');
expect(mockProcessor.formatPubs).toHaveBeenCalledWith(
['signal1', 'signal2'],
proofOptions,
);
});

it('should handle non-array, non-string publicSignals object correctly', () => {
(mockProcessor.formatPubs as jest.Mock).mockImplementation(() => {
throw new Error('Object public signals error');
});
expect(() =>
format(ProofType.groth16, 'proof', { key: 'value' }, 'vk'),
).toThrow(
'Failed to format groth16 public signals: Object public signals error. Public signals snippet: "[object Object]..."',
);
});
it('should handle non-string verification key correctly', () => {
const vkObject = { key: 'value' };
const result = format(proofOptions, 'proof', 'signals', vkObject);

it('should handle non-string vk object correctly', () => {
(mockProcessor.formatVk as jest.Mock).mockImplementation(() => {
throw new Error('Object vk formatting error');
});
expect(() =>
format(ProofType.groth16, 'proof', 'signals', { vkField: 'vkValue' }),
).toThrow(
'Failed to format groth16 verification key: Object vk formatting error. Verification key snippet: "{"vkField":"vkValue"}..."',
);
expect(mockProcessor.formatVk).toHaveBeenCalledWith(vkObject, proofOptions);
});
});
Loading
Loading