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

adding tests to getGroth16Calldata #9

Merged
merged 1 commit into from
Nov 2, 2024
Merged
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
6 changes: 6 additions & 0 deletions tools/npm/garaga_ts/babel.config.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module.exports = {
presets: [
'@babel/preset-env',
'@babel/preset-typescript',
],
};
11 changes: 7 additions & 4 deletions tools/npm/garaga_ts/jest.config.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
export default {
module.exports= {
preset: 'ts-jest',
testEnvironment: 'node',
testMatch: ['**/tests/**/*.test.ts'],
moduleFileExtensions: ['ts', 'js'],
transform: {
'^.+\\.ts$': 'ts-jest'
},
// transform: {
// '^.+\\.ts$': 'ts-jest'
// },
collectCoverage: true,
collectCoverageFrom: ['src/**/*.ts'],
transform: {
'^.+\\.(ts|tsx|js|jsx)$': 'babel-jest',
},
};
1,838 changes: 1,566 additions & 272 deletions tools/npm/garaga_ts/package-lock.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions tools/npm/garaga_ts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
"test:watch": "jest --watch"
},
"devDependencies": {
"@babel/preset-env": "^7.26.0",
"@babel/preset-typescript": "^7.26.0",
"@rollup/plugin-typescript": "^11.1.6",
"@types/jest": "^29.5.13",
"@types/node": "^22.7.4",
Expand Down
9 changes: 1 addition & 8 deletions tools/npm/garaga_ts/src/node/api.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,9 @@
// This files provides a ts-like interface for garaga_rs

import { msm_calldata_builder, mpc_calldata_builder, to_twistededwards, to_weirstrass, get_groth16_calldata } from '../wasm/pkg/garaga_rs';
import { CurveId } from './definitions';
import { Groth16Proof, Groth16VerifyingKey } from './starknet/groth16ContractGenerator/parsingUtils';

export enum CurveId {
BN254 = 0,
BLS12_381 = 1,
SECP256K1 = 2,
SECP256R1 = 3,
X25519 = 4,
}

export type G1Point = [bigint, bigint];
export type G2Point = [[bigint, bigint], [bigint, bigint]];
export type G1G2Pair = [G1Point, G2Point];
Expand Down
13 changes: 11 additions & 2 deletions tools/npm/garaga_ts/src/node/hints/io.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,13 @@ export const bitLength = (x: bigint): number => {
}

export const split128 = (a: bigint): [bigint, bigint] => {
const MAX_UINT256 = BigInt(2) ** BigInt(256);
const MASK_128 = BigInt((1n << BigInt(128)) - 1n);
try{

console.log("a bigint", a);

const MAX_UINT256 = 115792089237316195423570985008687907853269984665640564039457584007913129639936n;

const MASK_128 = BigInt((1n << 128n) - 1n);

if (a < 0n || a >= MAX_UINT256) {
throw new Error(`Value ${a} is too large to fit in a u256`);
Expand All @@ -91,6 +96,10 @@ export const split128 = (a: bigint): [bigint, bigint] => {
const high = a >> BigInt(128);

return [low, high];
} catch(err){
console.log("ERR split 128: ", err);
throw new Error("ERROR split 128")
}
}

export const modInverse = (a: bigint, p: bigint): bigint => {
Expand Down
3 changes: 3 additions & 0 deletions tools/npm/garaga_ts/src/node/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
export * from './api'; // exports "ts" interface
export * from '../wasm/pkg/garaga_rs'; // export "raw" interface

export { CurveId } from './definitions';

import pkg_init from '../wasm/pkg/garaga_rs';
import module_or_path from '../wasm/pkg/garaga_rs_bg.wasm';


export function init(): ReturnType<typeof pkg_init> {
return pkg_init({ module_or_path });
}
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ export const parseGroth16ProofFromObject = (data: any, publicInputsData?: bigint
const imageIdBytes = hexStringToBytes(imageIdHex);
const journalBytes = hexStringToBytes(journalHex);


return createGroth16ProofFromRisc0(sealBytes, imageIdBytes, journalBytes)

} catch(err){
Expand All @@ -228,7 +229,7 @@ export const parseGroth16ProofFromObject = (data: any, publicInputsData?: bigint
try {
publicInputs = findItemFromKeyPatterns(data, ['public']);
} catch(err){
throw new Error(`Error: ${err}`);

}
}
const a = tryParseG1PointFromKey(proof, ['a'], curveId);
Expand Down Expand Up @@ -258,21 +259,26 @@ export const parseGroth16ProofFromObject = (data: any, publicInputsData?: bigint
export const createGroth16ProofFromRisc0 = (seal: Uint8Array, imageId: Uint8Array, journalBytes: Uint8Array,
controlRoot: bigint = RISC0_CONTROL_ROOT, bn254ControlId: bigint = RISC0_BN254_CONTROL_ID): Groth16Proof => {


if(imageId.length > 32){
throw new Error("imageId must be 32 bytes")
}

const [constrolRoot0, controlRoot1] = splitDigest(controlRoot);
const [controlRoot0, controlRoot1] = splitDigest(controlRoot);

const proof = seal.slice(4);



const journal = createHash("sha256").update(journalBytes).digest();

const claimDigest = digestReceiptClaim(ok(imageId, journal));


const [claim0, claim1] = splitDigest(claimDigest);



const groth16Proof: Groth16Proof = {
a: {
x: toBigInt(proof.slice(0, 32)),
Expand All @@ -282,7 +288,7 @@ export const createGroth16ProofFromRisc0 = (seal: Uint8Array, imageId: Uint8Arra
b: {
x: [
toBigInt(proof.slice(96, 128)),
toBigInt(proof.slice(64, 196))
toBigInt(proof.slice(64, 96))
],
y: [
toBigInt(proof.slice(160, 192)),
Expand All @@ -296,7 +302,7 @@ export const createGroth16ProofFromRisc0 = (seal: Uint8Array, imageId: Uint8Arra
curveId: CurveId.BN254
},
publicInputs: [
constrolRoot0,
controlRoot0,
controlRoot1,
claim0,
claim1,
Expand All @@ -311,7 +317,6 @@ export const createGroth16ProofFromRisc0 = (seal: Uint8Array, imageId: Uint8Arra

throw new Error(`Invalid Groth16 proof: ${groth16Proof}`);


}


Expand Down Expand Up @@ -344,19 +349,30 @@ export const checkGroth16VerifyingKey = (vk: Groth16VerifyingKey): boolean => {

const digestReceiptClaim = (receipt: ReceiptClaim): Uint8Array => {
const { tagDigest, input, preStateDigest, postStateDigest, output, exitCode } = receipt;

const systemExitCodeBuffer = Buffer.alloc(4);
systemExitCodeBuffer.writeUInt32BE(exitCode.system << 24);

const userExitCodeBuffer = Buffer.alloc(4);
userExitCodeBuffer.writeUInt32BE(exitCode.user << 24);

// Create a 2-byte big-endian representation of 4 << 8
const twoBytes = Buffer.alloc(2);
twoBytes.writeUInt16BE(4 << 8);


// Concatenating all parts into one Buffer
const data = Buffer.concat([
tagDigest!,
input,
preStateDigest,
postStateDigest,
output,
Buffer.alloc(4, exitCode.system << 24), // Encode exitCode.system in 4 bytes, big-endian
Buffer.alloc(4, exitCode.user << 24), // Encode exitCode.user in 4 bytes, big-endian
Buffer.alloc(2, 4 << 8) // Add the 4 << 8 equivalent to (4 << 8).to_bytes(2, 'big')
systemExitCodeBuffer,
userExitCodeBuffer,
twoBytes
]);

// Return the sha256 digest of the combined data
return createHash('sha256').update(data).digest();
}

Expand Down Expand Up @@ -390,19 +406,22 @@ function ok(imageId: Uint8Array, journalDigest: Uint8Array): ReceiptClaim {
const digestOutput = (output: Output): Uint8Array =>{
const { journalDigest, assumptionsDigest } = output;


// Compute the internal tag digest equivalent to hashlib.sha256(b"risc0.Output").digest()
const tagDigest = createHash('sha256').update(Buffer.from("risc0.Output")).digest();

// Concatenate all parts into a single Buffer
const data = Buffer.concat([
tagDigest,
journalDigest,
assumptionsDigest,
Buffer.alloc(2, 2 << 8) // Add the 2 << 8 equivalent to (2 << 8).to_bytes(2, 'big')
const twoBytes = Buffer.alloc(2);
twoBytes.writeUInt16BE(512);

const combined = Buffer.concat([
tagDigest,
Buffer.from(journalDigest),
Buffer.from(assumptionsDigest),
twoBytes // Append 2 as a 2-byte big-endian integer
]);

// Return the sha256 digest of the combined data
return createHash('sha256').update(data).digest();
return createHash('sha256').update(combined).digest();
}

const reverseByteOrderUint256 = (value: bigint | Uint8Array): bigint => {
Expand Down
45 changes: 45 additions & 0 deletions tools/npm/garaga_ts/tests/starknet/groth16Calldata.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { Groth16Proof, parseGroth16ProofFromJson, parseGroth16VerifyingKeyFromJson } from "../../src/node/starknet/groth16ContractGenerator/parsingUtils";
import * as garaga from "../../src/node/index";


const PATH = '../../../hydra/garaga/starknet/groth16_contract_generator/examples';

describe('Groth16 Getting calldata', () => {

const proofAndVkWithPublicInputs = [
[`${PATH}/proof_bn254.json`, `${PATH}/vk_bn254.json`, null],
[`${PATH}/proof_bls.json`, `${PATH}/vk_bls.json`, null],

[`${PATH}/gnark_proof_bn254.json`, `${PATH}/gnark_vk_bn254.json`, `${PATH}/gnark_public_bn254.json`],
[`${PATH}/snarkjs_proof_bn254.json`, `${PATH}/snarkjs_vk_bn254.json`, `${PATH}/snarkjs_public_bn254.json`],

[`${PATH}/proof_risc0.json`, `${PATH}/vk_risc0.json`, null],

]

test.each(proofAndVkWithPublicInputs)("should get groth16 calldata from proof %s, vk %s and pub inputs %s", async (proofPath, vkPath, pubInputsPath) => {

await garaga.init();

const vk = parseGroth16VerifyingKeyFromJson(vkPath as string);

let proof: Groth16Proof;
if(pubInputsPath == null){
proof = parseGroth16ProofFromJson(proofPath as string);
} else{
proof = parseGroth16ProofFromJson(proofPath as string, pubInputsPath);
}

const curveId: garaga.CurveId = proof.a.curveId;

console.log("proof", proof);

console.log("vk", vk);
console.log("curveId", curveId);
const groth16Calldata = garaga.getGroth16CallData(proof, vk, curveId);

console.log("groth16Calldata", groth16Calldata);

});

});
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@ describe('Groth16 Parsing Tests', () => {

const proofPaths = [
`${PATH}/proof_bn254.json`,
`${PATH}/proof_bls.json`,
`${PATH}/proof_risc0.json`
`${PATH}/proof_bls.json`
];

test.each(proofPaths)('should parse proof from %s', (proofPath) => {
Expand Down
1 change: 1 addition & 0 deletions tools/npm/garaga_ts/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"noPropertyAccessFromIndexSignature": true,
"types": ["jest", "node"],
"skipLibCheck": true, // Skipping type checks for external libraries
"esModuleInterop": true
},
"include": ["src/**/*.ts", "tests/**/*.ts"]
}
Loading