Skip to content
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
65 changes: 65 additions & 0 deletions barretenberg/cpp/src/barretenberg/dsl/acir_proofs/c_bind.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,29 @@ WASM_EXPORT void acir_prove_ultra_starknet_honk([[maybe_unused]] uint8_t const*
#endif
}

WASM_EXPORT void acir_prove_ultra_starknet_zk_honk([[maybe_unused]] uint8_t const* acir_vec,
[[maybe_unused]] uint8_t const* witness_vec,
[[maybe_unused]] uint8_t** out)
{
#ifdef STARKNET_GARAGA_FLAVORS
// Lambda function to ensure things get freed before proving.
UltraStarknetZKProver prover = [&] {
const acir_format::ProgramMetadata metadata{ .honk_recursion = 1 };
acir_format::AcirProgram program{
acir_format::circuit_buf_to_acir_format(from_buffer<std::vector<uint8_t>>(acir_vec)),
acir_format::witness_buf_to_witness_data(from_buffer<std::vector<uint8_t>>(witness_vec))
};
auto builder = acir_format::create_circuit<UltraCircuitBuilder>(program, metadata);

return UltraStarknetZKProver(builder);
}();
auto proof = prover.construct_proof();
*out = to_heap_buffer(to_buffer(proof));
#else
throw_or_abort("bb wasm was not compiled with starknet garaga flavors!");
#endif
}

WASM_EXPORT void acir_verify_ultra_honk(uint8_t const* proof_buf, uint8_t const* vk_buf, bool* result)
{
using VerificationKey = UltraFlavor::VerificationKey;
Expand Down Expand Up @@ -359,6 +382,25 @@ WASM_EXPORT void acir_verify_ultra_starknet_honk([[maybe_unused]] uint8_t const*
#endif
}

WASM_EXPORT void acir_verify_ultra_starknet_zk_honk([[maybe_unused]] uint8_t const* proof_buf,
[[maybe_unused]] uint8_t const* vk_buf,
[[maybe_unused]] bool* result)
{
#ifdef STARKNET_GARAGA_FLAVORS
using VerificationKey = UltraStarknetZKFlavor::VerificationKey;
using Verifier = UltraVerifier_<UltraStarknetZKFlavor>;

auto proof = many_from_buffer<bb::fr>(from_buffer<std::vector<uint8_t>>(proof_buf));
auto verification_key = std::make_shared<VerificationKey>(from_buffer<VerificationKey>(vk_buf));

Verifier verifier{ verification_key };

*result = verifier.verify_proof(proof);
#else
throw_or_abort("bb wasm was not compiled with starknet garaga flavors!");
#endif
}

WASM_EXPORT void acir_write_vk_ultra_honk(uint8_t const* acir_vec, uint8_t** out)
{
using DeciderProvingKey = DeciderProvingKey_<UltraFlavor>;
Expand Down Expand Up @@ -435,6 +477,29 @@ WASM_EXPORT void acir_write_vk_ultra_starknet_honk([[maybe_unused]] uint8_t cons
#endif
}

WASM_EXPORT void acir_write_vk_ultra_starknet_zk_honk([[maybe_unused]] uint8_t const* acir_vec,
[[maybe_unused]] uint8_t** out)
{
#ifdef STARKNET_GARAGA_FLAVORS
using DeciderProvingKey = DeciderProvingKey_<UltraStarknetZKFlavor>;
using VerificationKey = UltraStarknetZKFlavor::VerificationKey;

// lambda to free the builder
DeciderProvingKey proving_key = [&] {
const acir_format::ProgramMetadata metadata{ .honk_recursion = 1 };
acir_format::AcirProgram program{ acir_format::circuit_buf_to_acir_format(
from_buffer<std::vector<uint8_t>>(acir_vec)) };
auto builder = acir_format::create_circuit<UltraCircuitBuilder>(program, metadata);
return DeciderProvingKey(builder);
}();
VerificationKey vk(proving_key.proving_key);
vinfo("Constructed UltraStarknetZKHonk verification key");
*out = to_heap_buffer(to_buffer(vk));
#else
throw_or_abort("bb wasm was not compiled with starknet garaga flavors!");
#endif
}

WASM_EXPORT void acir_honk_solidity_verifier(uint8_t const* proof_buf, uint8_t const* vk_buf, uint8_t** out)
{
using VerificationKey = UltraKeccakFlavor::VerificationKey;
Expand Down
3 changes: 3 additions & 0 deletions barretenberg/cpp/src/barretenberg/dsl/acir_proofs/c_bind.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,16 +86,19 @@ WASM_EXPORT void acir_prove_ultra_honk(uint8_t const* acir_vec, uint8_t const* w
WASM_EXPORT void acir_prove_ultra_keccak_honk(uint8_t const* acir_vec, uint8_t const* witness_vec, uint8_t** out);
WASM_EXPORT void acir_prove_ultra_keccak_zk_honk(uint8_t const* acir_vec, uint8_t const* witness_vec, uint8_t** out);
WASM_EXPORT void acir_prove_ultra_starknet_honk(uint8_t const* acir_vec, uint8_t const* witness_vec, uint8_t** out);
WASM_EXPORT void acir_prove_ultra_starknet_zk_honk(uint8_t const* acir_vec, uint8_t const* witness_vec, uint8_t** out);

WASM_EXPORT void acir_verify_ultra_honk(uint8_t const* proof_buf, uint8_t const* vk_buf, bool* result);
WASM_EXPORT void acir_verify_ultra_keccak_honk(uint8_t const* proof_buf, uint8_t const* vk_buf, bool* result);
WASM_EXPORT void acir_verify_ultra_keccak_zk_honk(uint8_t const* proof_buf, uint8_t const* vk_buf, bool* result);
WASM_EXPORT void acir_verify_ultra_starknet_honk(uint8_t const* proof_buf, uint8_t const* vk_buf, bool* result);
WASM_EXPORT void acir_verify_ultra_starknet_zk_honk(uint8_t const* proof_buf, uint8_t const* vk_buf, bool* result);

WASM_EXPORT void acir_write_vk_ultra_honk(uint8_t const* acir_vec, uint8_t** out);
WASM_EXPORT void acir_write_vk_ultra_keccak_honk(uint8_t const* acir_vec, uint8_t** out);
WASM_EXPORT void acir_write_vk_ultra_keccak_zk_honk(uint8_t const* acir_vec, uint8_t** out);
WASM_EXPORT void acir_write_vk_ultra_starknet_honk(uint8_t const* acir_vec, uint8_t** out);
WASM_EXPORT void acir_write_vk_ultra_starknet_zk_honk(uint8_t const* acir_vec, uint8_t** out);

WASM_EXPORT void acir_proof_as_fields_ultra_honk(uint8_t const* proof_buf, fr::vec_out_buf out);

Expand Down
112 changes: 112 additions & 0 deletions barretenberg/exports.json
Original file line number Diff line number Diff line change
Expand Up @@ -715,6 +715,46 @@
],
"isAsync": false
},
{
"functionName": "acir_prove_ultra_starknet_honk",
"inArgs": [
{
"name": "acir_vec",
"type": "const uint8_t *"
},
{
"name": "witness_vec",
"type": "const uint8_t *"
}
],
"outArgs": [
{
"name": "out",
"type": "uint8_t **"
}
],
"isAsync": false
},
{
"functionName": "acir_prove_ultra_starknet_zk_honk",
"inArgs": [
{
"name": "acir_vec",
"type": "const uint8_t *"
},
{
"name": "witness_vec",
"type": "const uint8_t *"
}
],
"outArgs": [
{
"name": "out",
"type": "uint8_t **"
}
],
"isAsync": false
},
{
"functionName": "acir_verify_ultra_honk",
"inArgs": [
Expand Down Expand Up @@ -775,6 +815,46 @@
],
"isAsync": false
},
{
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was missing @feltroidprime but I am not sure where it is used it at all

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a byproduct of running binding generation. did you?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a compiler output that was committed when the binding code was made, it's not used, but shows that people ran binding gen

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, I did not. I updated it manually. I will get to it then.

Copy link
Contributor Author

@raugfer raugfer May 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ludamad I ran bindgen and exports.json did not change (the manual changes matched the expected output), however, the suffix ZKHonk for the API mehods were automatically replaced by ZkHonk, as you can see on this commit:

44f40ad

Then I updated all references to also use ZkHonk:

eafe13b

Given that, I believe the PR is good to go. Let me know otherwise. Thanks!

"functionName": "acir_verify_ultra_starknet_honk",
"inArgs": [
{
"name": "proof_buf",
"type": "const uint8_t *"
},
{
"name": "vk_buf",
"type": "const uint8_t *"
}
],
"outArgs": [
{
"name": "result",
"type": "bool *"
}
],
"isAsync": false
},
{
"functionName": "acir_verify_ultra_starknet_zk_honk",
"inArgs": [
{
"name": "proof_buf",
"type": "const uint8_t *"
},
{
"name": "vk_buf",
"type": "const uint8_t *"
}
],
"outArgs": [
{
"name": "result",
"type": "bool *"
}
],
"isAsync": false
},
{
"functionName": "acir_write_vk_ultra_honk",
"inArgs": [
Expand Down Expand Up @@ -823,6 +903,38 @@
],
"isAsync": false
},
{
"functionName": "acir_write_vk_ultra_starknet_honk",
"inArgs": [
{
"name": "acir_vec",
"type": "const uint8_t *"
}
],
"outArgs": [
{
"name": "out",
"type": "uint8_t **"
}
],
"isAsync": false
},
{
"functionName": "acir_write_vk_ultra_starknet_zk_honk",
"inArgs": [
{
"name": "acir_vec",
"type": "const uint8_t *"
}
],
"outArgs": [
{
"name": "out",
"type": "uint8_t **"
}
],
"isAsync": false
},
{
"functionName": "acir_proof_as_fields_ultra_honk",
"inArgs": [
Expand Down
37 changes: 26 additions & 11 deletions barretenberg/ts/src/barretenberg/backend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,16 @@ export type UltraHonkBackendOptions = {
* Use this when you want to verify the created proof on an EVM chain.
*/
keccakZK?: boolean;
/**S electing this option will use the poseidon/stark252 hash function instead of poseidon
/** Selecting this option will use the poseidon/stark252 hash function instead of poseidon
* when generating challenges in the proof.
* Use this when you want to verify the created proof on an Starknet chain with Garaga.
*/
starknet?: boolean;
/** Selecting this option will use the poseidon/stark252 hash function instead of poseidon
* when generating challenges in the proof.
* Use this when you want to verify the created proof on an Starknet chain with Garaga.
*/
starknetZK?: boolean;
};

export class UltraHonkBackend {
Expand Down Expand Up @@ -90,21 +95,25 @@ export class UltraHonkBackend {
const proveUltraHonk = options?.keccak
? this.api.acirProveUltraKeccakHonk.bind(this.api)
: options?.keccakZK
? this.api.acirProveUltraKeccakZKHonk.bind(this.api)
? this.api.acirProveUltraKeccakZkHonk.bind(this.api)
: options?.starknet
? this.api.acirProveUltraStarknetHonk.bind(this.api)
: this.api.acirProveUltraHonk.bind(this.api);
: options?.starknetZK
? this.api.acirProveUltraStarknetZkHonk.bind(this.api)
: this.api.acirProveUltraHonk.bind(this.api);

const proofWithPublicInputs = await proveUltraHonk(this.acirUncompressedBytecode, gunzip(compressedWitness));

// Write VK to get the number of public inputs
const writeVKUltraHonk = options?.keccak
? this.api.acirWriteVkUltraKeccakHonk.bind(this.api)
: options?.keccakZK
? this.api.acirWriteVkUltraKeccakZKHonk.bind(this.api)
? this.api.acirWriteVkUltraKeccakZkHonk.bind(this.api)
: options?.starknet
? this.api.acirWriteVkUltraStarknetHonk.bind(this.api)
: this.api.acirWriteVkUltraHonk.bind(this.api);
: options?.starknetZK
? this.api.acirWriteVkUltraStarknetZkHonk.bind(this.api)
: this.api.acirWriteVkUltraHonk.bind(this.api);

const vk = await writeVKUltraHonk(this.acirUncompressedBytecode);
const vkAsFields = await this.api.acirVkAsFieldsUltraHonk(new RawBuffer(vk));
Expand All @@ -127,17 +136,21 @@ export class UltraHonkBackend {
const writeVkUltraHonk = options?.keccak
? this.api.acirWriteVkUltraKeccakHonk.bind(this.api)
: options?.keccakZK
? this.api.acirWriteVkUltraKeccakZKHonk.bind(this.api)
? this.api.acirWriteVkUltraKeccakZkHonk.bind(this.api)
: options?.starknet
? this.api.acirWriteVkUltraStarknetHonk.bind(this.api)
: this.api.acirWriteVkUltraHonk.bind(this.api);
: options?.starknetZK
? this.api.acirWriteVkUltraStarknetZkHonk.bind(this.api)
: this.api.acirWriteVkUltraHonk.bind(this.api);
const verifyUltraHonk = options?.keccak
? this.api.acirVerifyUltraKeccakHonk.bind(this.api)
: options?.keccakZK
? this.api.acirVerifyUltraKeccakZKHonk.bind(this.api)
? this.api.acirVerifyUltraKeccakZkHonk.bind(this.api)
: options?.starknet
? this.api.acirVerifyUltraStarknetHonk.bind(this.api)
: this.api.acirVerifyUltraHonk.bind(this.api);
: options?.starknetZK
? this.api.acirVerifyUltraStarknetZkHonk.bind(this.api)
: this.api.acirVerifyUltraHonk.bind(this.api);

const vkBuf = await writeVkUltraHonk(this.acirUncompressedBytecode);
return await verifyUltraHonk(proof, new RawBuffer(vkBuf));
Expand All @@ -148,10 +161,12 @@ export class UltraHonkBackend {
return options?.keccak
? await this.api.acirWriteVkUltraKeccakHonk(this.acirUncompressedBytecode)
: options?.keccakZK
? await this.api.acirWriteVkUltraKeccakZKHonk(this.acirUncompressedBytecode)
? await this.api.acirWriteVkUltraKeccakZkHonk(this.acirUncompressedBytecode)
: options?.starknet
? await this.api.acirWriteVkUltraStarknetHonk(this.acirUncompressedBytecode)
: await this.api.acirWriteVkUltraHonk(this.acirUncompressedBytecode);
: options?.starknetZK
? await this.api.acirWriteVkUltraStarknetZkHonk(this.acirUncompressedBytecode)
: await this.api.acirWriteVkUltraHonk(this.acirUncompressedBytecode);
}

/** @description Returns a solidity verifier */
Expand Down
Loading