I have developed a **functional Proof of Concept (PoC/MVP)** that performs this conversion **natively in node.js (Backend) and in the browser (Frontend)**, allowing proofs to be submitted directly to ZKVerify without manual CLI steps.
npm install olivmath-ultraplonk-zk-verify-nodejsCurrently, developers using the Noir/Nargo stack with the UltraPlonk backend face a critical limitation: the lack of tools to convert zk-SNARK proofs generated via CLI (bb) into a format compatible with ZKVerify. This prevents direct frontend integrations with modern verifiers.
I have developed a functional Proof of Concept (PoC/MVP) that performs this conversion natively in node.js (Backend) and in the browser (Frontend), allowing proofs to be submitted directly to ZKVerify without manual CLI steps.
---
Developers working with UltraPlonk face the following barriers:
- Proofs generated by bb prove are binary (.bin) and incompatible with ZKVerify.
- Conversion to hex format is only possible via CLI, preventing frontend/browser usage.
- There is no official solution for runtime conversion via JavaScript.
---
Creation of an open-source JavaScript/TypeScript library that:
- Converts proofs and Uint8Array keys generated by @aztec/bb.js to hex in Node.js or browser environments.
- Generates the proof format accepted by ZKVerify from the UltraPlonk structure.
- Provides a user-friendly API for Web3 developers, DApps, and ZK tools.
> This library is already functional as a PoC, with successful proof submissions to ZKVerify.
---
The developed PoC already demonstrates that:
- Conversion can be done entirely in Node.js without CLI.
- The converted format is accepted by ZKVerify's API.
- It can run in Node.js backend.
``js`
import ultraplonk from "olivmath-zkverify";
Apply in your flow:
`js
// POST
app.post("/", async (req, res) => {
// 1. Receive proof, public inputs and vk
// 2. Convertendo proof e vk para Uint8Array
// 3. Load ZK circuit
// 4. Instantiate UltraPlonkBackend from @aztec/bb.js;
// 5. Verify proofs + public inputs locally with UltraPlonkBackend
// 6. Convert proofs & vk to ZkVerify compatible format
const convertedProof = ultraplonk.convert_proof(proof, 1); // <- 1 is the number of public inputs
const convertedVk = ultraplonk.convert_verification_key(vk);
// 7. Submit to ZkVerify
const session = await zkVerifySession
.start()
.Volta()
.withAccount("your seed here");
const { events } = await session
.verify()
.ultraplonk()
.execute({
proofData: {
publicSignals: publicInputs,
proof: convertedProof,
vk: convertedVk,
},
});
await new Promise((resolve) => {
events.on(ZkVerifyEvents.Finalized, (data) => {
console.log("Proof finalized on zkVerify. ✅", data);
resolve(data);
});
});
});
``
Comingo soon