Skip to content

feat(circuit-dsl): annotation-based circuit authoring API#6

Open
satran004 wants to merge 24 commits into
mainfrom
feat/annotation_circuit
Open

feat(circuit-dsl): annotation-based circuit authoring API#6
satran004 wants to merge 24 commits into
mainfrom
feat/annotation_circuit

Conversation

@satran004
Copy link
Copy Markdown
Member

@satran004 satran004 commented May 18, 2026

Summary

Adds a Java annotation–based authoring style for ZK circuits on top of the existing CircuitSpec / SignalBuilder stack. Removes the duplicate declaration of input names (once in CircuitBuilder, once in define()), introduces typed symbolic values (ZkUInt, ZkBool, ZkField, ZkArray, ZkBits, ZkBytes), and generates *Circuit companion classes with typed build() / schema() / inputs() / circuitId() / metadata() / publicInputValues() surfaces.

Strictly additive — does not change CircuitSpec, CircuitBuilder, SignalBuilder, Signal, or ConstraintGraph. Generated code targets the existing builder API, so every existing example, test, and proving path continues to work unchanged.

ADR: docs/adr/circuit-annotation/README.md. Implementation broken into 9 phases with one commit per phase; phase docs live alongside the ADR.

What the new API looks like

Parametric Merkle membership (full equivalent of NWayMerkleCircuit):

@ZKCircuit(
        name = "membership-proof",
        nameTemplate = "membership-proof-d{depth}-{hashType}")
public class AnnotatedMerkleMembership {

    public AnnotatedMerkleMembership(@CircuitParam("depth") int depth,
                                     @CircuitParam("hashType") ZkMerkle.HashType hashType) { ... }

    @Prove
    ZkBool prove(ZkContext zk,
                 @Secret ZkField leaf,
                 @Public ZkField root,
                 @Secret @FixedSize(param = "depth") ZkArray<ZkField> siblings,
                 @Secret @FixedSize(param = "depth") ZkArray<ZkBool> pathBits) {
        return ZkMerkle.isMember(zk, leaf, root, siblings, pathBits, hashType);
    }
}

// Usage
var circuit  = AnnotatedMerkleMembershipCircuit.build(32, POSEIDON);
var schema   = AnnotatedMerkleMembershipCircuit.schema(32, POSEIDON);
var witness  = AnnotatedMerkleMembershipCircuit
        .inputs(32, POSEIDON) 
        .leaf(leafValue)
        .root(rootValue)
        .sibling(0, ...) ... .pathBit(0, ...) ...
        .toWitnessMap();

Range proof (field-style, the simplest case):

@ZKCircuit(name = "range-proof")
public class RangeProof {
    @Secret @UInt(bits = 64) ZkUInt secret;
    @Public @UInt(bits = 64) ZkUInt lo;
    @Public @UInt(bits = 64) ZkUInt hi;

    @Prove
    ZkBool inRange() {
        return secret.gte(lo).and(secret.lte(hi));
    }
}

New modules

  • zeroj-circuit-annotation-api — annotations, symbolic Zk* types, ZkContext,
    ZkCircuitSchema, ZkCircuitMetadata. Depends only on zeroj-circuit-dsl.
  • zeroj-circuit-annotation-processor — javac annotation processor that emits
    *Circuit companion classes. Registered via META-INF/services/javax.annotation.processing.Processor.

Symbolic gadget adapters live in zeroj-circuit-lib under com.bloxbean.cardano.zeroj.circuit.lib.zk.* so the annotation API stays independent of optional gadgets:

  • ZkMiMC, ZkPoseidon, ZkMerkle (Phase 3 — first usable slice)
  • ZkPedersen, ZkJubjubPoint, ZkEdDSAJubjub (Phase 8)

All adapters are thin wrappers over existing Signal* gadgets with
differential tests.

Both new modules are included in zeroj-bom-core and zeroj-bom-all.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant