Skip to content

Commit

Permalink
Merge branch 'master' into si/goblin-without-dummies
Browse files Browse the repository at this point in the history
  • Loading branch information
iakovenkos authored Sep 26, 2024
2 parents 8755b6f + 951ce6d commit 4e6a2ed
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 52 deletions.
1 change: 1 addition & 0 deletions barretenberg/ts/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ export {
UltraHonkBackend,
} from './barretenberg/index.js';
export { RawBuffer, Fr } from './types/index.js';
export { splitHonkProof, reconstructHonkProof } from './proof/index.js';
64 changes: 64 additions & 0 deletions barretenberg/ts/src/proof/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Buffers are prepended with their size. The size takes 4 bytes.
const serializedBufferSize = 4;
const fieldByteSize = 32;
const publicInputOffset = 3;
const publicInputsOffsetBytes = publicInputOffset * fieldByteSize;

export function splitHonkProof(proofWithPublicInputs: Uint8Array): { publicInputs: Uint8Array; proof: Uint8Array } {
const proofAsStrings = deflattenFields(proofWithPublicInputs.slice(4));

const numPublicInputs = Number(proofAsStrings[1]);

// Account for the serialized buffer size at start
const publicInputsOffset = publicInputsOffsetBytes + serializedBufferSize;
// Get the part before and after the public inputs
const proofStart = proofWithPublicInputs.slice(0, publicInputsOffset);
const publicInputsSplitIndex = numPublicInputs * fieldByteSize;
const proofEnd = proofWithPublicInputs.slice(publicInputsOffset + publicInputsSplitIndex);
// Construct the proof without the public inputs
const proof = new Uint8Array([...proofStart, ...proofEnd]);

// Fetch the number of public inputs out of the proof string
const publicInputs = proofWithPublicInputs.slice(publicInputsOffset, publicInputsOffset + publicInputsSplitIndex);

return {
proof,
publicInputs,
};
}

export function reconstructHonkProof(publicInputs: Uint8Array, proof: Uint8Array): Uint8Array {
const proofStart = proof.slice(0, publicInputsOffsetBytes + serializedBufferSize);
const proofEnd = proof.slice(publicInputsOffsetBytes + serializedBufferSize);

// Concatenate publicInputs and proof
const proofWithPublicInputs = Uint8Array.from([...proofStart, ...publicInputs, ...proofEnd]);

return proofWithPublicInputs;
}

function deflattenFields(flattenedFields: Uint8Array): string[] {
const publicInputSize = 32;
const chunkedFlattenedPublicInputs: Uint8Array[] = [];

for (let i = 0; i < flattenedFields.length; i += publicInputSize) {
const publicInput = flattenedFields.slice(i, i + publicInputSize);
chunkedFlattenedPublicInputs.push(publicInput);
}

return chunkedFlattenedPublicInputs.map(uint8ArrayToHex);
}

function uint8ArrayToHex(buffer: Uint8Array): string {
const hex: string[] = [];

buffer.forEach(function (i) {
let h = i.toString(16);
if (h.length % 2) {
h = '0' + h;
}
hex.push(h);
});

return '0x' + hex.join('');
}
49 changes: 17 additions & 32 deletions noir/noir-repo/tooling/noir_js_backend_barretenberg/src/backend.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
import { acirToUint8Array } from './serialize.js';
import { Backend, CompiledCircuit, ProofData, VerifierBackend } from '@noir-lang/types';
import { deflattenFields } from './public_inputs.js';
import { reconstructProofWithPublicInputs, reconstructProofWithPublicInputsHonk } from './verifier.js';
import { BackendOptions, UltraPlonkBackend, UltraHonkBackend as UltraHonkBackendInternal } from '@aztec/bb.js';
import { deflattenFields, flattenFieldsAsArray } from './public_inputs.js';
import { reconstructProofWithPublicInputs } from './verifier.js';
import {
BackendOptions,
reconstructHonkProof,
splitHonkProof,
UltraPlonkBackend,
UltraHonkBackend as UltraHonkBackendInternal,
} from '@aztec/bb.js';
import { decompressSync as gunzip } from 'fflate';

// This is the number of bytes in a UltraPlonk proof
Expand Down Expand Up @@ -74,12 +80,6 @@ export class BarretenbergBackend implements Backend, VerifierBackend {
}
}

// Buffers are prepended with their size. The size takes 4 bytes.
const serializedBufferSize = 4;
const fieldByteSize = 32;
const publicInputOffset = 3;
const publicInputsOffsetBytes = publicInputOffset * fieldByteSize;

export class UltraHonkBackend implements Backend, VerifierBackend {
// These type assertions are used so that we don't
// have to initialize `api` in the constructor.
Expand All @@ -96,32 +96,16 @@ export class UltraHonkBackend implements Backend, VerifierBackend {

async generateProof(compressedWitness: Uint8Array): Promise<ProofData> {
const proofWithPublicInputs = await this.backend.generateProof(gunzip(compressedWitness));
const proofAsStrings = deflattenFields(proofWithPublicInputs.slice(4));

const numPublicInputs = Number(proofAsStrings[1]);

// Account for the serialized buffer size at start
const publicInputsOffset = publicInputsOffsetBytes + serializedBufferSize;
// Get the part before and after the public inputs
const proofStart = proofWithPublicInputs.slice(0, publicInputsOffset);
const publicInputsSplitIndex = numPublicInputs * fieldByteSize;
const proofEnd = proofWithPublicInputs.slice(publicInputsOffset + publicInputsSplitIndex);
// Construct the proof without the public inputs
const proof = new Uint8Array([...proofStart, ...proofEnd]);

// Fetch the number of public inputs out of the proof string
const publicInputsConcatenated = proofWithPublicInputs.slice(
publicInputsOffset,
publicInputsOffset + publicInputsSplitIndex,
);
const publicInputs = deflattenFields(publicInputsConcatenated);

const { proof, publicInputs: flatPublicInputs } = splitHonkProof(proofWithPublicInputs);
const publicInputs = deflattenFields(flatPublicInputs);

return { proof, publicInputs };
}

async verifyProof(proofData: ProofData): Promise<boolean> {
const proof = reconstructProofWithPublicInputsHonk(proofData);

const flattenedPublicInputs = flattenFieldsAsArray(proofData.publicInputs);
const proof = reconstructHonkProof(flattenedPublicInputs, proofData.proof);
return this.backend.verifyProof(proof);
}

Expand All @@ -134,8 +118,9 @@ export class UltraHonkBackend implements Backend, VerifierBackend {
proofData: ProofData,
numOfPublicInputs: number,
): Promise<{ proofAsFields: string[]; vkAsFields: string[]; vkHash: string }> {
const proof = reconstructProofWithPublicInputsHonk(proofData);
return this.backend.generateRecursiveProofArtifacts(proof, numOfPublicInputs)
const flattenedPublicInputs = flattenFieldsAsArray(proofData.publicInputs);
const proof = reconstructHonkProof(flattenedPublicInputs, proofData.proof);
return this.backend.generateRecursiveProofArtifacts(proof, numOfPublicInputs);
}

async destroy(): Promise<void> {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { ProofData } from '@noir-lang/types';
import { flattenFieldsAsArray } from './public_inputs.js';
import { BackendOptions, BarretenbergVerifier as BarretenbergVerifierInternal } from '@aztec/bb.js';
import {
BackendOptions,
BarretenbergVerifier as BarretenbergVerifierInternal,
reconstructHonkProof,
} from '@aztec/bb.js';

export class BarretenbergVerifier {
private verifier!: BarretenbergVerifierInternal;
Expand Down Expand Up @@ -39,29 +43,12 @@ export class UltraHonkVerifier {

/** @description Verifies a proof */
async verifyProof(proofData: ProofData, verificationKey: Uint8Array): Promise<boolean> {
const proof = reconstructProofWithPublicInputsHonk(proofData);
const flattenedPublicInputs = flattenFieldsAsArray(proofData.publicInputs);
const proof = reconstructHonkProof(flattenedPublicInputs, proofData.proof);
return this.verifier.verifyUltrahonkProof(proof, verificationKey);
}

async destroy(): Promise<void> {
await this.verifier.destroy();
}
}

const serializedBufferSize = 4;
const fieldByteSize = 32;
const publicInputOffset = 3;
const publicInputsOffsetBytes = publicInputOffset * fieldByteSize;

export function reconstructProofWithPublicInputsHonk(proofData: ProofData): Uint8Array {
// Flatten publicInputs
const publicInputsConcatenated = flattenFieldsAsArray(proofData.publicInputs);

const proofStart = proofData.proof.slice(0, publicInputsOffsetBytes + serializedBufferSize);
const proofEnd = proofData.proof.slice(publicInputsOffsetBytes + serializedBufferSize);

// Concatenate publicInputs and proof
const proofWithPublicInputs = Uint8Array.from([...proofStart, ...publicInputsConcatenated, ...proofEnd]);

return proofWithPublicInputs;
}

0 comments on commit 4e6a2ed

Please sign in to comment.