From 823c4227aa67892914fd7762a5344a8d2ae3a363 Mon Sep 17 00:00:00 2001
From: Satya This package will expose the public annotations and symbolic value types
+ * used by Java classes that are compiled into {@code CircuitBuilder} /
+ * {@code CircuitSpec} companions by the annotation processor. Functional processing is introduced in Phase 4. Until then, this processor
+ * deliberately claims no annotations and performs no source generation. This package will expose the public annotations and symbolic value types
- * used by Java classes that are compiled into {@code CircuitBuilder} /
+ * This package exposes the public annotations and symbolic value types used
+ * by Java classes that are compiled into {@code CircuitBuilder} /
* {@code CircuitSpec} companions by the annotation processor. Implementations that track input visibility should reject secret
+ * variables here. The default preserves compatibility with minimal
+ * implementations by falling back to {@link #var(String)}. Implementations that track input visibility should reject public
+ * variables here. The default preserves compatibility with minimal
+ * implementations by falling back to {@link #var(String)}. MiMC uses x^7 S-box with 91 rounds for BN254.
* Each round: state = (state + round_constant + key)^7.
- * Approximately 273 constraints for one hash.
Functional processing is introduced in Phase 4. Until then, this processor - * deliberately claims no annotations and performs no source generation.
+ * Annotation processor that generates Phase 4 circuit companions. */ public final class CircuitAnnotationProcessor extends AbstractProcessor { + private static final String ANNOTATION_PKG = "com.bloxbean.cardano.zeroj.circuit.annotation."; + private static final String ZK_BOOL = ANNOTATION_PKG + "ZkBool"; + private static final String ZK_FIELD = ANNOTATION_PKG + "ZkField"; + private static final String ZK_UINT = ANNOTATION_PKG + "ZkUInt"; + private static final String ZK_ARRAY = ANNOTATION_PKG + "ZkArray"; + private static final String ZK_CONTEXT = ANNOTATION_PKG + "ZkContext"; @Override public SetPublic key and signature points must be curve-valid subgroup points before + * they are bound with {@link ZkJubjubPoint#fromTrustedAffine}. This verifier + * additionally rejects the identity public key in-circuit. + */ +public final class ZkEdDSAJubjub { + + private ZkEdDSAJubjub() {} + + public record KReduction(BigInteger kModL, BigInteger kQuotient) {} + + public static void verify( + ZkContext zk, + ZkJubjubPoint publicKey, + ZkField message, + ZkJubjubPoint rPoint, + ZkUInt s, + ZkUInt kModL, + ZkUInt kQuotient) { + validateInputs(zk, publicKey, message, rPoint, s, kModL, kQuotient); + publicKey.assertNotIdentity(zk); + InCircuitEdDSAJubjub.verify( + zk.builder().api(), + publicKey.asPoint(), + message.signal().variable(), + rPoint.asPoint(), + s.signal().variable(), + kModL.signal().variable(), + kQuotient.signal().variable()); + } + + public static KReduction witnessComputeKReduction( + JubjubPoint rPoint, + JubjubPoint publicKey, + BigInteger message) { + var reduction = InCircuitEdDSAJubjub.witnessComputeKReduction(rPoint, publicKey, message); + return new KReduction(reduction.kModL(), reduction.kQuotient()); + } + + private static void validateInputs( + ZkContext zk, + ZkJubjubPoint publicKey, + ZkField message, + ZkJubjubPoint rPoint, + ZkUInt s, + ZkUInt kModL, + ZkUInt kQuotient) { + Objects.requireNonNull(zk, "zk"); + Objects.requireNonNull(publicKey, "publicKey"); + Objects.requireNonNull(message, "message"); + Objects.requireNonNull(rPoint, "rPoint"); + Objects.requireNonNull(s, "s"); + Objects.requireNonNull(kModL, "kModL"); + Objects.requireNonNull(kQuotient, "kQuotient"); + publicKey.requireSameContext(zk); + rPoint.requireSameContext(zk); + zk.requireSignal(message.signal()); + zk.requireSignal(s.signal()); + zk.requireSignal(kModL.signal()); + zk.requireSignal(kQuotient.signal()); + if (s.bits() > ZkPedersen.MAX_SCALAR_BITS || kModL.bits() > ZkPedersen.MAX_SCALAR_BITS) { + throw new IllegalArgumentException("s and kModL must use at most 252 bits"); + } + if (kQuotient.bits() > 4) { + throw new IllegalArgumentException("kQuotient must use at most 4 bits"); + } + } +} diff --git a/zeroj-circuit-lib/src/main/java/com/bloxbean/cardano/zeroj/circuit/lib/zk/ZkJubjubPoint.java b/zeroj-circuit-lib/src/main/java/com/bloxbean/cardano/zeroj/circuit/lib/zk/ZkJubjubPoint.java new file mode 100644 index 0000000..1f2f261 --- /dev/null +++ b/zeroj-circuit-lib/src/main/java/com/bloxbean/cardano/zeroj/circuit/lib/zk/ZkJubjubPoint.java @@ -0,0 +1,200 @@ +package com.bloxbean.cardano.zeroj.circuit.lib.zk; + +import com.bloxbean.cardano.zeroj.circuit.Signal; +import com.bloxbean.cardano.zeroj.circuit.annotation.ZkBool; +import com.bloxbean.cardano.zeroj.circuit.annotation.ZkContext; +import com.bloxbean.cardano.zeroj.circuit.annotation.ZkField; +import com.bloxbean.cardano.zeroj.circuit.annotation.ZkValue; +import com.bloxbean.cardano.zeroj.circuit.lib.jubjub.InCircuitJubjub; +import com.bloxbean.cardano.zeroj.circuit.lib.jubjub.JubjubPoint; +import com.bloxbean.cardano.zeroj.circuit.lib.poseidon.PoseidonParamsBLS12_381T3; + +import java.util.List; +import java.util.Objects; + +/** + * Symbolic Jubjub point backed by extended-coordinate field values. + * + *
This adapter is intentionally a thin wrapper over {@link InCircuitJubjub}.
+ * It does not add curve or subgroup checks for arbitrary witness points; callers
+ * should only bind points that were validated off-circuit or produced by a
+ * reviewed gadget.
+ */
+public final class ZkJubjubPoint implements ZkValue {
+ private final ZkField u;
+ private final ZkField v;
+ private final ZkField z;
+ private final ZkField t;
+
+ private ZkJubjubPoint(ZkField u, ZkField v, ZkField z, ZkField t) {
+ this.u = Objects.requireNonNull(u, "u");
+ this.v = Objects.requireNonNull(v, "v");
+ this.z = Objects.requireNonNull(z, "z");
+ this.t = Objects.requireNonNull(t, "t");
+ }
+
+ /**
+ * Binds an affine point whose curve validity, subgroup membership, and
+ * identity policy were checked off-circuit before the values entered the
+ * circuit.
+ */
+ public static ZkJubjubPoint fromTrustedAffine(ZkContext zk, ZkField u, ZkField v) {
+ Objects.requireNonNull(zk, "zk");
+ Objects.requireNonNull(u, "u");
+ Objects.requireNonNull(v, "v");
+ requireBls12381(zk);
+ zk.requireSignal(u.signal());
+ zk.requireSignal(v.signal());
+ return new ZkJubjubPoint(
+ u,
+ v,
+ ZkField.wrap(zk, zk.builder().constant(1)),
+ u.mul(v));
+ }
+
+ public static ZkJubjubPoint constant(ZkContext zk, JubjubPoint point) {
+ Objects.requireNonNull(zk, "zk");
+ Objects.requireNonNull(point, "point");
+ return wrap(zk, InCircuitJubjub.constant(zk.builder().api(), point));
+ }
+
+ static ZkJubjubPoint wrap(ZkContext zk, InCircuitJubjub.Point point) {
+ Objects.requireNonNull(zk, "zk");
+ Objects.requireNonNull(point, "point");
+ requireBls12381(zk);
+ return new ZkJubjubPoint(
+ ZkField.wrap(zk, zk.builder().wrap(point.u())),
+ ZkField.wrap(zk, zk.builder().wrap(point.v())),
+ ZkField.wrap(zk, zk.builder().wrap(point.z())),
+ ZkField.wrap(zk, zk.builder().wrap(point.t())));
+ }
+
+ public ZkField u() {
+ return u;
+ }
+
+ public ZkField v() {
+ return v;
+ }
+
+ public ZkField z() {
+ return z;
+ }
+
+ public ZkField t() {
+ return t;
+ }
+
+ public ZkJubjubPoint add(ZkContext zk, ZkJubjubPoint other) {
+ requireSameContext(zk);
+ other.requireSameContext(zk);
+ requireBls12381(zk);
+ return wrap(zk, InCircuitJubjub.add(zk.builder().api(), asPoint(), other.asPoint()));
+ }
+
+ public ZkJubjubPoint doubled(ZkContext zk) {
+ requireSameContext(zk);
+ requireBls12381(zk);
+ return wrap(zk, InCircuitJubjub.doubled(zk.builder().api(), asPoint()));
+ }
+
+ public static ZkJubjubPoint select(
+ ZkContext zk,
+ ZkBool condition,
+ ZkJubjubPoint ifTrue,
+ ZkJubjubPoint ifFalse) {
+ Objects.requireNonNull(zk, "zk");
+ Objects.requireNonNull(condition, "condition");
+ Objects.requireNonNull(ifTrue, "ifTrue");
+ Objects.requireNonNull(ifFalse, "ifFalse");
+ ifTrue.requireSameContext(zk);
+ ifFalse.requireSameContext(zk);
+ zk.requireSignal(condition.signal());
+ requireBls12381(zk);
+ return wrap(zk, InCircuitJubjub.select(
+ zk.builder().api(), condition.signal().variable(), ifTrue.asPoint(), ifFalse.asPoint()));
+ }
+
+ public void assertEqual(ZkContext zk, ZkJubjubPoint other) {
+ requireSameContext(zk);
+ other.requireSameContext(zk);
+ requireBls12381(zk);
+ var api = zk.builder().api();
+ api.assertEqual(api.mul(u.signal().variable(), other.z.signal().variable()),
+ api.mul(other.u.signal().variable(), z.signal().variable()));
+ api.assertEqual(api.mul(v.signal().variable(), other.z.signal().variable()),
+ api.mul(other.v.signal().variable(), z.signal().variable()));
+ }
+
+ public ZkBool isEqual(ZkContext zk, ZkJubjubPoint other) {
+ requireSameContext(zk);
+ other.requireSameContext(zk);
+ requireBls12381(zk);
+ var api = zk.builder().api();
+ var sameU = api.isEqual(
+ api.mul(u.signal().variable(), other.z.signal().variable()),
+ api.mul(other.u.signal().variable(), z.signal().variable()));
+ var sameV = api.isEqual(
+ api.mul(v.signal().variable(), other.z.signal().variable()),
+ api.mul(other.v.signal().variable(), z.signal().variable()));
+ return ZkBool.wrap(zk, zk.builder().wrap(api.and(sameU, sameV)));
+ }
+
+ public ZkBool isIdentity(ZkContext zk) {
+ requireSameContext(zk);
+ requireBls12381(zk);
+ var api = zk.builder().api();
+ return ZkBool.wrap(zk, zk.builder().wrap(api.and(
+ api.isZero(u.signal().variable()),
+ api.isEqual(v.signal().variable(), z.signal().variable()))));
+ }
+
+ public void assertNotIdentity(ZkContext zk) {
+ isIdentity(zk).assertFalse();
+ }
+
+ public void assertAffineEquals(ZkContext zk, ZkField affineU, ZkField affineV) {
+ Objects.requireNonNull(affineU, "affineU");
+ Objects.requireNonNull(affineV, "affineV");
+ requireSameContext(zk);
+ zk.requireSignal(affineU.signal());
+ zk.requireSignal(affineV.signal());
+ requireBls12381(zk);
+ var api = zk.builder().api();
+ api.assertEqual(api.mul(affineU.signal().variable(), z.signal().variable()), u.signal().variable());
+ api.assertEqual(api.mul(affineV.signal().variable(), z.signal().variable()), v.signal().variable());
+ }
+
+ @Override
+ public List This package exposes the public annotations and symbolic value types used
* by Java classes that are compiled into {@code CircuitBuilder} /
- * {@code CircuitSpec} companions by the annotation processor.
This wrapper requires explicit {@link PoseidonParams}. The lower-level + * {@link PoseidonN} no-params overload remains BN254 for backward + * compatibility, but symbolic code should make the target field visible at the + * call site. + */ +public final class ZkPoseidonN { + + private ZkPoseidonN() {} + + /** + * Hash one or more symbolic field elements using folded two-input + * Poseidon under the supplied parameters. + * + *
Single-input semantics match {@link PoseidonN}: {@code hash(x)} is
+ * {@code Poseidon(x, 0)} under the same parameters.
+ */
+ public static ZkField hash(ZkContext zk, PoseidonParams params, ZkField... inputs) {
+ Objects.requireNonNull(zk, "zk");
+ Objects.requireNonNull(params, "params");
+ Objects.requireNonNull(inputs, "inputs");
+ if (inputs.length == 0) {
+ throw new IllegalArgumentException("inputs must not be empty");
+ }
+
+ Signal[] signals = new Signal[inputs.length];
+ for (int i = 0; i < inputs.length; i++) {
+ ZkField input = Objects.requireNonNull(inputs[i], "inputs[" + i + "]");
+ zk.requireSignal(input.signal());
+ signals[i] = input.signal();
+ }
+
+ return ZkField.wrap(zk, PoseidonN.hash(zk.builder(), params, signals));
+ }
+}
diff --git a/zeroj-circuit-lib/src/test/java/com/bloxbean/cardano/zeroj/circuit/lib/zk/ZkGadgetAdaptersTest.java b/zeroj-circuit-lib/src/test/java/com/bloxbean/cardano/zeroj/circuit/lib/zk/ZkGadgetAdaptersTest.java
index cfed06f..ded69aa 100644
--- a/zeroj-circuit-lib/src/test/java/com/bloxbean/cardano/zeroj/circuit/lib/zk/ZkGadgetAdaptersTest.java
+++ b/zeroj-circuit-lib/src/test/java/com/bloxbean/cardano/zeroj/circuit/lib/zk/ZkGadgetAdaptersTest.java
@@ -9,6 +9,7 @@
import com.bloxbean.cardano.zeroj.circuit.annotation.ZkContext;
import com.bloxbean.cardano.zeroj.circuit.annotation.ZkField;
import com.bloxbean.cardano.zeroj.circuit.annotation.ZkUInt;
+import com.bloxbean.cardano.zeroj.circuit.lib.PoseidonN;
import com.bloxbean.cardano.zeroj.circuit.lib.SignalMerkle;
import com.bloxbean.cardano.zeroj.circuit.lib.SignalMiMC;
import com.bloxbean.cardano.zeroj.circuit.lib.SignalPoseidon;
@@ -88,6 +89,142 @@ void poseidonAdapterMatchesSignalAdapter() {
symbolic.calculateWitness(inputs, CurveId.BN254));
}
+ @Test
+ void poseidonNAdapterMatchesSignalAdapterForBn254() {
+ var symbolic = CircuitBuilder.create("zk-poseidon-n")
+ .secretVar("a")
+ .secretVar("b")
+ .secretVar("c")
+ .secretVar("d")
+ .defineSignals(c -> {
+ var zk = new ZkContext(c);
+ ZkPoseidonN.hash(
+ zk,
+ PoseidonParamsBN254T3.INSTANCE,
+ ZkField.secret(c, "a"),
+ ZkField.secret(c, "b"),
+ ZkField.secret(c, "c"),
+ ZkField.secret(c, "d"));
+ });
+
+ var signal = CircuitBuilder.create("signal-poseidon-n")
+ .secretVar("a")
+ .secretVar("b")
+ .secretVar("c")
+ .secretVar("d")
+ .defineSignals(c -> PoseidonN.hash(
+ c,
+ PoseidonParamsBN254T3.INSTANCE,
+ c.privateInput("a"),
+ c.privateInput("b"),
+ c.privateInput("c"),
+ c.privateInput("d")));
+
+ var inputs = Map.of(
+ "a", List.of(BigInteger.valueOf(5)),
+ "b", List.of(BigInteger.valueOf(9)),
+ "c", List.of(BigInteger.valueOf(13)),
+ "d", List.of(BigInteger.valueOf(17)));
+
+ assertEquals(signal.constraintGraph().gates().size(), symbolic.constraintGraph().gates().size());
+ assertArrayEquals(
+ signal.calculateWitness(inputs, CurveId.BN254),
+ symbolic.calculateWitness(inputs, CurveId.BN254));
+ }
+
+ @Test
+ void poseidonNExplicitParamsSupportBls12381() {
+ BigInteger a = BigInteger.valueOf(5);
+ BigInteger b = BigInteger.valueOf(9);
+ BigInteger cValue = BigInteger.valueOf(13);
+ BigInteger expected = PoseidonHash.hashN(
+ PoseidonParamsBLS12_381T3.INSTANCE,
+ a,
+ b,
+ cValue);
+
+ var circuit = CircuitBuilder.create("zk-poseidon-n-bls")
+ .secretVar("a")
+ .secretVar("b")
+ .secretVar("c")
+ .publicVar("out")
+ .defineSignals(c -> {
+ var zk = new ZkContext(c);
+ ZkPoseidonN.hash(
+ zk,
+ PoseidonParamsBLS12_381T3.INSTANCE,
+ ZkField.secret(c, "a"),
+ ZkField.secret(c, "b"),
+ ZkField.secret(c, "c"))
+ .assertEqual(ZkField.publicInput(c, "out"));
+ });
+
+ var valid = Map.of(
+ "a", List.of(a),
+ "b", List.of(b),
+ "c", List.of(cValue),
+ "out", List.of(expected));
+ assertDoesNotThrow(() -> circuit.calculateWitness(valid, CurveId.BLS12_381));
+ assertDoesNotThrow(() -> circuit.compileR1CS(CurveId.BLS12_381));
+ assertThrows(IllegalStateException.class, () -> circuit.compileR1CS(CurveId.BN254));
+
+ var invalid = Map.of(
+ "a", List.of(a),
+ "b", List.of(b),
+ "c", List.of(cValue),
+ "out", List.of(BigInteger.ONE));
+ assertThrows(ArithmeticException.class, () -> circuit.calculateWitness(invalid, CurveId.BLS12_381));
+ }
+
+ @Test
+ void poseidonNRejectsEmptyInputsAndForeignBuilderSignals() {
+ assertThrows(IllegalArgumentException.class, () -> CircuitBuilder.create("zk-poseidon-n-empty")
+ .defineSignals(c -> ZkPoseidonN.hash(
+ new ZkContext(c),
+ PoseidonParamsBLS12_381T3.INSTANCE)));
+
+ ZkField[] fieldFromOtherBuilder = new ZkField[1];
+ CircuitBuilder.create("zk-poseidon-n-other")
+ .secretVar("a")
+ .defineSignals(c -> fieldFromOtherBuilder[0] = ZkField.secret(c, "a"));
+
+ assertThrows(IllegalArgumentException.class, () -> CircuitBuilder.create("zk-poseidon-n-local")
+ .secretVar("b")
+ .defineSignals(c -> ZkPoseidonN.hash(
+ new ZkContext(c),
+ PoseidonParamsBLS12_381T3.INSTANCE,
+ fieldFromOtherBuilder[0],
+ ZkField.secret(c, "b"))));
+ }
+
+ @Test
+ void poseidonNRejectsNullArguments() {
+ CircuitBuilder.create("zk-poseidon-n-null")
+ .secretVar("a")
+ .defineSignals(c -> {
+ var zk = new ZkContext(c);
+ var input = ZkField.secret(c, "a");
+
+ assertThrows(NullPointerException.class, () -> ZkPoseidonN.hash(
+ null,
+ PoseidonParamsBLS12_381T3.INSTANCE,
+ input));
+ assertThrows(NullPointerException.class, () -> ZkPoseidonN.hash(
+ zk,
+ null,
+ input));
+ assertThrows(NullPointerException.class, () -> ZkPoseidonN.hash(
+ zk,
+ PoseidonParamsBLS12_381T3.INSTANCE,
+ (ZkField[]) null));
+ assertThrows(NullPointerException.class, () -> ZkPoseidonN.hash(
+ zk,
+ PoseidonParamsBLS12_381T3.INSTANCE,
+ input,
+ null));
+ });
+ }
+
@Test
void merkleComputeRootMatchesSignalAdapterRootBehavior() {
var symbolic = CircuitBuilder.create("zk-merkle")
diff --git a/zeroj-examples/README.md b/zeroj-examples/README.md
index db027b7..b5c01b6 100644
--- a/zeroj-examples/README.md
+++ b/zeroj-examples/README.md
@@ -37,13 +37,15 @@ See the circuit annotation support matrix:
Write circuits as annotated Java classes and use generated companions for
`build(...)`, `schema(...)`, and witness input builders.
- **Examples**: range proof, age verification, private transfer, MiMC
- commitment, sealed-bid auction, anonymous voting, parameterized Merkle
- membership, Pedersen commitment, proof-flow helper
+ commitment, [BLS12-381 PoseidonN multi-input commitment](src/main/java/com/bloxbean/cardano/zeroj/examples/annotation/AnnotatedMultiInputCommitment.java),
+ sealed-bid auction, anonymous voting, parameterized Merkle membership,
+ Pedersen commitment, proof-flow helper
- **Source**: [`examples/annotation`](src/main/java/com/bloxbean/cardano/zeroj/examples/annotation)
- **Tests**: [`AnnotatedCircuitExamplesTest.java`](src/test/java/com/bloxbean/cardano/zeroj/examples/annotation/AnnotatedCircuitExamplesTest.java)
- **Guide**: [`docs/circuit-annotation-user-guide.md`](../docs/circuit-annotation-user-guide.md)
- **Note**: MiMC-based annotation examples target BN254/off-chain. For
- Cardano/BLS12-381 circuits, use Poseidon with explicit BLS12-381 parameters.
+ Cardano/BLS12-381 circuits, use `ZkPoseidon` or `ZkPoseidonN` with explicit
+ BLS12-381 parameters.
### 1. Sealed-Bid Auction
Prove your bid exceeds a reserve price without revealing the bid amount.
diff --git a/zeroj-examples/src/main/java/com/bloxbean/cardano/zeroj/examples/annotation/AnnotatedMultiInputCommitment.java b/zeroj-examples/src/main/java/com/bloxbean/cardano/zeroj/examples/annotation/AnnotatedMultiInputCommitment.java
new file mode 100644
index 0000000..436cc05
--- /dev/null
+++ b/zeroj-examples/src/main/java/com/bloxbean/cardano/zeroj/examples/annotation/AnnotatedMultiInputCommitment.java
@@ -0,0 +1,30 @@
+package com.bloxbean.cardano.zeroj.examples.annotation;
+
+import com.bloxbean.cardano.zeroj.circuit.annotation.Prove;
+import com.bloxbean.cardano.zeroj.circuit.annotation.Public;
+import com.bloxbean.cardano.zeroj.circuit.annotation.Secret;
+import com.bloxbean.cardano.zeroj.circuit.annotation.ZKCircuit;
+import com.bloxbean.cardano.zeroj.circuit.annotation.ZkBool;
+import com.bloxbean.cardano.zeroj.circuit.annotation.ZkContext;
+import com.bloxbean.cardano.zeroj.circuit.annotation.ZkField;
+import com.bloxbean.cardano.zeroj.circuit.lib.poseidon.PoseidonParamsBLS12_381T3;
+import com.bloxbean.cardano.zeroj.circuit.lib.zk.ZkPoseidonN;
+
+@ZKCircuit(name = "annotation-multi-input-commitment", version = 1)
+public class AnnotatedMultiInputCommitment {
+ @Prove
+ ZkBool prove(
+ ZkContext zk,
+ @Secret ZkField owner,
+ @Secret ZkField assetId,
+ @Secret ZkField nonce,
+ @Public ZkField commitment) {
+ return ZkPoseidonN.hash(
+ zk,
+ PoseidonParamsBLS12_381T3.INSTANCE,
+ owner,
+ assetId,
+ nonce)
+ .isEqual(commitment);
+ }
+}
diff --git a/zeroj-examples/src/test/java/com/bloxbean/cardano/zeroj/examples/annotation/AnnotatedCircuitExamplesTest.java b/zeroj-examples/src/test/java/com/bloxbean/cardano/zeroj/examples/annotation/AnnotatedCircuitExamplesTest.java
index 40ab3df..f815b6b 100644
--- a/zeroj-examples/src/test/java/com/bloxbean/cardano/zeroj/examples/annotation/AnnotatedCircuitExamplesTest.java
+++ b/zeroj-examples/src/test/java/com/bloxbean/cardano/zeroj/examples/annotation/AnnotatedCircuitExamplesTest.java
@@ -8,6 +8,8 @@
import com.bloxbean.cardano.zeroj.circuit.FieldConfig;
import com.bloxbean.cardano.zeroj.circuit.annotation.ZkCircuitMetadata;
import com.bloxbean.cardano.zeroj.circuit.lib.jubjub.PedersenCommitment;
+import com.bloxbean.cardano.zeroj.circuit.lib.poseidon.PoseidonHash;
+import com.bloxbean.cardano.zeroj.circuit.lib.poseidon.PoseidonParamsBLS12_381T3;
import com.bloxbean.cardano.zeroj.circuit.lib.zk.ZkMerkle;
import com.bloxbean.cardano.zeroj.examples.dsl.common.MiMCHash;
import com.bloxbean.cardano.zeroj.prover.gnark.GnarkProver;
@@ -172,6 +174,44 @@ void hashCommitmentUsesSymbolicGadgetAdapter() {
() -> circuit.calculateWitness(wrong.toWitnessMap(), CurveId.BN254));
}
+ @Test
+ void multiInputCommitmentUsesBlsPoseidonNAdapter() {
+ var circuit = AnnotatedMultiInputCommitmentCircuit.build();
+ var schema = AnnotatedMultiInputCommitmentCircuit.schema();
+
+ assertEquals("annotation-multi-input-commitment", schema.name());
+ assertEquals(List.of("commitment"), schema.publicInputs().names());
+ assertEquals(List.of("owner", "assetId", "nonce"), schema.secretInputs().names());
+
+ var owner = BigInteger.valueOf(101);
+ var assetId = BigInteger.valueOf(202);
+ var nonce = BigInteger.valueOf(303);
+ var commitment = PoseidonHash.hashN(
+ PoseidonParamsBLS12_381T3.INSTANCE,
+ owner,
+ assetId,
+ nonce);
+
+ var inputs = AnnotatedMultiInputCommitmentCircuit.inputs()
+ .owner(owner)
+ .assetId(assetId)
+ .nonce(nonce)
+ .commitment(commitment);
+
+ assertEquals(List.of(commitment), inputs.publicValues());
+ assertDoesNotThrow(() -> circuit.calculateWitness(inputs.toWitnessMap(), CurveId.BLS12_381));
+ assertDoesNotThrow(() -> circuit.compileR1CS(CurveId.BLS12_381));
+ assertThrows(IllegalStateException.class, () -> circuit.compileR1CS(CurveId.BN254));
+
+ var wrong = AnnotatedMultiInputCommitmentCircuit.inputs()
+ .owner(owner)
+ .assetId(assetId)
+ .nonce(nonce)
+ .commitment(BigInteger.ONE);
+ assertThrows(ArithmeticException.class,
+ () -> circuit.calculateWitness(wrong.toWitnessMap(), CurveId.BLS12_381));
+ }
+
@Test
void annotatedSealedBidMirrorsReferenceDslCircuit() {
var circuit = AnnotatedSealedBidCircuit.build();
From 2f5b02970aff9c74b15aa0bb0df108e91f268968 Mon Sep 17 00:00:00 2001
From: Satya Circuit: {@link PrivateMultiplierCircuit} — a * b = c (a, c public; b private).
- * Uses the generic {@link Groth16BLS12381Verifier} (2 public inputs, 3 IC points). Circuit: a * x + b = c, where a, b, and c are public and x is private.
+ * Uses the generic {@link Groth16BLS12381GenericVerifier} with 3 public
+ * inputs and 4 IC points.
+ * Verification key points are baked in at deploy time. Unlike
+ * {@link Groth16BLS12381Verifier}, this verifier accepts the full IC vector as
+ * a Plutus list parameter, so it supports any public-input count.
+ *
+ * Datum: list of public input integers in verification-key schema order.
+ * Redeemer: compressed Groth16 proof points.
+ * Parameter {@code vkIc}: list of compressed G1 IC points, where
+ * {@code len(vkIc) == len(publicInputs) + 1}.
+ */
+@SpendingValidator
+public class Groth16BLS12381GenericVerifier {
+
+ @Param static byte[] vkAlpha; // G1 compressed 48 bytes
+ @Param static byte[] vkBeta; // G2 compressed 96 bytes
+ @Param static byte[] vkGamma; // G2 compressed 96 bytes
+ @Param static byte[] vkDelta; // G2 compressed 96 bytes
+ @Param static PlutusData vkIc; // List of G1 compressed 48-byte IC points
+
+ /**
+ * Groth16 proof points (compressed BLS bytes), passed as redeemer.
+ */
+ record Groth16Proof(byte[] piA, byte[] piB, byte[] piC) {}
+
+ @Entrypoint
+ public static boolean validate(PlutusData datum, Groth16Proof proof, PlutusData ctx) {
+ PlutusData inputsCursor = Builtins.unListData(datum);
+ PlutusData icCursor = Builtins.unListData(vkIc);
+
+ if (Builtins.nullList(icCursor)) {
+ return false;
+ }
+
+ byte[] vkX = BlsLib.g1Uncompress(Builtins.unBData(Builtins.headList(icCursor)));
+ return verifyWithPublicInputs(inputsCursor, Builtins.tailList(icCursor), vkX, proof);
+ }
+
+ private static boolean verifyWithPublicInputs(PlutusData inputsCursor,
+ PlutusData icCursor,
+ byte[] vkX,
+ Groth16Proof proof) {
+ if (!matchingLengths(inputsCursor, icCursor)) {
+ return false;
+ }
+
+ byte[] computedVkX = computeVkX(inputsCursor, icCursor, vkX);
+
+ byte[] a = BlsLib.g1Uncompress(proof.piA());
+ byte[] b = BlsLib.g2Uncompress(proof.piB());
+ byte[] c = BlsLib.g1Uncompress(proof.piC());
+
+ byte[] alpha = BlsLib.g1Uncompress(vkAlpha);
+ byte[] beta = BlsLib.g2Uncompress(vkBeta);
+ byte[] gamma = BlsLib.g2Uncompress(vkGamma);
+ byte[] delta = BlsLib.g2Uncompress(vkDelta);
+
+ byte[] negAlpha = BlsLib.g1Neg(alpha);
+ byte[] lhs = BlsLib.mulMlResult(
+ BlsLib.millerLoop(a, b),
+ BlsLib.millerLoop(negAlpha, beta));
+ byte[] rhs = BlsLib.mulMlResult(
+ BlsLib.millerLoop(computedVkX, gamma),
+ BlsLib.millerLoop(c, delta));
+
+ return BlsLib.finalVerify(lhs, rhs);
+ }
+
+ private static boolean matchingLengths(PlutusData inputsCursor, PlutusData icCursor) {
+ if (Builtins.nullList(inputsCursor)) {
+ return Builtins.nullList(icCursor);
+ } else if (Builtins.nullList(icCursor)) {
+ return false;
+ } else {
+ return matchingLengths(Builtins.tailList(inputsCursor), Builtins.tailList(icCursor));
+ }
+ }
+
+ private static byte[] computeVkX(PlutusData inputsCursor, PlutusData icCursor, byte[] vkX) {
+ if (Builtins.nullList(inputsCursor)) {
+ return vkX;
+ } else {
+ BigInteger publicInput = Builtins.asInteger(Builtins.headList(inputsCursor));
+ byte[] ic = BlsLib.g1Uncompress(Builtins.unBData(Builtins.headList(icCursor)));
+ byte[] scaled = BlsLib.g1ScalarMul(publicInput, ic);
+ byte[] nextVkX = BlsLib.g1Add(vkX, scaled);
+ return computeVkX(Builtins.tailList(inputsCursor), Builtins.tailList(icCursor), nextVkX);
+ }
+ }
+}
diff --git a/zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/ProverToCardano.java b/zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/ProverToCardano.java
index 38326ce..ae3c1f0 100644
--- a/zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/ProverToCardano.java
+++ b/zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/ProverToCardano.java
@@ -21,7 +21,8 @@
*
* For production: Use this to convert proofs generated by the pure Java
* prover ({@code Groth16ProverBLS381}) into the byte format expected by the
- * on-chain verifier ({@link Groth16BLS12381Verifier}).
This circuit has 2 public inputs (threshold, isAboveThreshold), matching the generic - * {@link Groth16BLS12381Verifier} (3 IC points = IC[0] + pub0*IC[1] + pub1*IC[2]).
+ *This circuit has 2 public inputs (threshold, isAboveThreshold), which can + * be verified on-chain by {@code Groth16BLS12381GenericVerifier}.
* *Uses {@code PowersOfTauBLS381.generate(8)} — for development only.
@@ -72,7 +72,7 @@ void devTau_balanceThreshold_fullStack() { System.out.println("=== BalanceThreshold E2E (dev tau): off-chain COMPLETE ==="); // On-chain Julc VM verification runs in the zeroj-onchain-julc module - // where compileValidator(Groth16BLS12381Verifier.class) can access Julc bytecode. + // where compileValidator(Groth16BLS12381GenericVerifier.class) can access Julc bytecode. // Use ProverToCardano.compressVk/compressProof to convert for on-chain submission. } diff --git a/zeroj-onchain-julc/README.md b/zeroj-onchain-julc/README.md index 390e643..5744bba 100644 --- a/zeroj-onchain-julc/README.md +++ b/zeroj-onchain-julc/README.md @@ -12,7 +12,8 @@ V3. | Validator / Helper | Status | Notes | |--------------------|--------|-------| -| `Groth16BLS12381Verifier` | Working | Production-oriented BLS12-381 Groth16 verifier using Plutus V3 BLS builtins | +| `Groth16BLS12381GenericVerifier` | Working | Default BLS12-381 Groth16 verifier using Plutus V3 BLS builtins; supports arbitrary public-input counts | +| `Groth16BLS12381Verifier` | Deprecated compatibility | Fixed two-public-input verifier retained for older callers | | `PlonkBLS12381FullVerifier` | Experimental prototype | Re-derives transcript and checks inverse constraints; KZG batch opening pairing check is deferred | | `SnarkjsToCardano` | Working helper | Converts snarkjs Groth16 JSON points to Cardano-compatible compressed bytes | | `ProverToCardano` | Working helper | Converts ZeroJ prover artifacts to on-chain data shapes | diff --git a/zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/Groth16BLS12381Verifier.java b/zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/Groth16BLS12381Verifier.java index d821d88..3062774 100644 --- a/zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/Groth16BLS12381Verifier.java +++ b/zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/Groth16BLS12381Verifier.java @@ -10,7 +10,8 @@ import java.math.BigInteger; /** - * On-chain Groth16 BLS12-381 verifier as a Plutus V3 spending validator. + * Fixed two-public-input Groth16 BLS12-381 verifier as a Plutus V3 spending + * validator. *
* Verification key points are baked in at deploy time via {@link Param}.
* The proof (piA, piB, piC) is passed as the redeemer (compressed BLS bytes).
@@ -23,8 +24,13 @@
* mulMlResult(millerLoop(vk_x, gamma), millerLoop(C, delta))
* )
*
+ *
+ * @deprecated Use {@link Groth16BLS12381GenericVerifier}. This class is kept
+ * only for compatibility with older examples that baked exactly two public
+ * inputs as three separate IC parameters.
*/
@SpendingValidator
+@Deprecated
public class Groth16BLS12381Verifier {
// VK points — compressed bytes baked at compile time
diff --git a/zeroj-onchain-julc/src/test/java/com/bloxbean/cardano/zeroj/onchain/julc/CircomToOnChainE2ETest.java b/zeroj-onchain-julc/src/test/java/com/bloxbean/cardano/zeroj/onchain/julc/CircomToOnChainE2ETest.java
index d2e6bf5..95a07be 100644
--- a/zeroj-onchain-julc/src/test/java/com/bloxbean/cardano/zeroj/onchain/julc/CircomToOnChainE2ETest.java
+++ b/zeroj-onchain-julc/src/test/java/com/bloxbean/cardano/zeroj/onchain/julc/CircomToOnChainE2ETest.java
@@ -15,6 +15,8 @@
import java.io.IOException;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
@@ -77,15 +79,13 @@ void circom_javaProve_onChainVerify() {
byte[] piC = g1Compress(proof.c());
// Compile on-chain verifier with circom VK
- var compiled = compileValidator(Groth16BLS12381Verifier.class);
+ var compiled = compileValidator(Groth16BLS12381GenericVerifier.class);
var program = compiled.program().applyParams(
PlutusData.bytes(vk.alpha()),
PlutusData.bytes(vk.beta()),
PlutusData.bytes(vk.gamma()),
PlutusData.bytes(vk.delta()),
- PlutusData.bytes(vk.ic().get(0)),
- PlutusData.bytes(vk.ic().get(1)),
- PlutusData.bytes(vk.ic().get(2)));
+ vkIcData(vk.ic()));
// Datum: public signals [c=33, a=3]
var datum = PlutusData.list(
@@ -117,15 +117,13 @@ void circom_wrongWitness_onChainRejects() {
byte[] piB = g2Compress(proof.b());
byte[] piC = g1Compress(proof.c());
- var compiled = compileValidator(Groth16BLS12381Verifier.class);
+ var compiled = compileValidator(Groth16BLS12381GenericVerifier.class);
var program = compiled.program().applyParams(
PlutusData.bytes(vk.alpha()),
PlutusData.bytes(vk.beta()),
PlutusData.bytes(vk.gamma()),
PlutusData.bytes(vk.delta()),
- PlutusData.bytes(vk.ic().get(0)),
- PlutusData.bytes(vk.ic().get(1)),
- PlutusData.bytes(vk.ic().get(2)));
+ vkIcData(vk.ic()));
// Wrong public inputs: claim c=99, a=3 (instead of c=33, a=3)
var wrongDatum = PlutusData.list(
@@ -170,6 +168,14 @@ private static void writeFp(byte[] buf, int off, BigInteger v) {
System.arraycopy(b, s, buf, off + FP - c, c);
}
+ private static PlutusData vkIcData(List Uses the generic {@link Groth16BLS12381Verifier} which requires exactly
- * 2 public inputs (3 IC points: IC[0], IC[1], IC[2]). Uses {@link Groth16BLS12381GenericVerifier}; the same verifier also
+ * supports circuits with more or fewer public inputs. Circuit: publicA * secretB = publicC (publicA and publicC are public).
* This demonstrates the full end-to-end flow:
* 1. Parse snarkjs JSON artifacts → compressed BLS12-381 bytes
@@ -20,6 +21,7 @@
* 3. Evaluate with proof redeemer and public inputs datum
* 4. Assert the pairing check passes in the Julc VM
*/
+@SuppressWarnings("deprecation")
class Groth16BLS12381VerifierTest extends ContractTest {
private static SnarkjsToCardano.VkCompressed vk;
From a9486454d759bd453166321e68601bcafe6a588e Mon Sep 17 00:00:00 2001
From: Satya
- * This is a domain-specific verifier that extends the core Groth16 pattern
- * (from {@code zeroj-onchain-julc}) with a {@code reservePriceBytes} binding
- * parameter, demonstrating how to customize the core verifier for a specific use case.
+ * This domain-specific verifier composes the reusable {@link Groth16BLS12381}
+ * on-chain library with a {@code reservePriceBytes} binding parameter.
*/
@SpendingValidator
public class ZkAuctionVerifier {
@@ -33,41 +32,22 @@ public class ZkAuctionVerifier {
@Param static byte[] vkBeta;
@Param static byte[] vkGamma;
@Param static byte[] vkDelta;
- @Param static byte[] vkIc0;
- @Param static byte[] vkIc1;
- @Param static byte[] vkIc2;
+ @Param static PlutusData vkIc;
record Groth16Proof(byte[] piA, byte[] piB, byte[] piC) {}
@Entrypoint
static boolean validate(PlutusData datum, Groth16Proof proof, PlutusData ctx) {
PlutusData inputs = Builtins.unListData(datum);
- BigInteger pub0 = Builtins.asInteger(Builtins.headList(inputs)); // bidCommitment
BigInteger pub1 = Builtins.asInteger(Builtins.headList(Builtins.tailList(inputs))); // reservePrice
// Binding: reserve price must match the auctioneer's configured reserve
BigInteger committedReserve = Builtins.byteStringToInteger(true, reservePriceBytes);
boolean reserveMatches = pub1.equals(committedReserve);
- // Groth16 verification
- byte[] a = BlsLib.g1Uncompress(proof.piA());
- byte[] b = BlsLib.g2Uncompress(proof.piB());
- byte[] c = BlsLib.g1Uncompress(proof.piC());
- byte[] alpha = BlsLib.g1Uncompress(vkAlpha);
- byte[] beta = BlsLib.g2Uncompress(vkBeta);
- byte[] gamma = BlsLib.g2Uncompress(vkGamma);
- byte[] delta = BlsLib.g2Uncompress(vkDelta);
- byte[] ic0 = BlsLib.g1Uncompress(vkIc0);
- byte[] ic1 = BlsLib.g1Uncompress(vkIc1);
- byte[] ic2 = BlsLib.g1Uncompress(vkIc2);
+ boolean proofValid = Groth16BLS12381.verify(datum, proof.piA(), proof.piB(), proof.piC(),
+ vkAlpha, vkBeta, vkGamma, vkDelta, vkIc);
- byte[] vkX = BlsLib.g1Add(ic0,
- BlsLib.g1Add(BlsLib.g1ScalarMul(pub0, ic1), BlsLib.g1ScalarMul(pub1, ic2)));
-
- byte[] negAlpha = BlsLib.g1Neg(alpha);
- byte[] lhs = BlsLib.mulMlResult(BlsLib.millerLoop(a, b), BlsLib.millerLoop(negAlpha, beta));
- byte[] rhs = BlsLib.mulMlResult(BlsLib.millerLoop(vkX, gamma), BlsLib.millerLoop(c, delta));
-
- return reserveMatches && BlsLib.finalVerify(lhs, rhs);
+ return reserveMatches && proofValid;
}
}
diff --git a/zeroj-examples/src/test/java/com/bloxbean/cardano/zeroj/examples/dsl/PureJavaProverYaciE2ETest.java b/zeroj-examples/src/test/java/com/bloxbean/cardano/zeroj/examples/dsl/PureJavaProverYaciE2ETest.java
index ec6883f..6f11697 100644
--- a/zeroj-examples/src/test/java/com/bloxbean/cardano/zeroj/examples/dsl/PureJavaProverYaciE2ETest.java
+++ b/zeroj-examples/src/test/java/com/bloxbean/cardano/zeroj/examples/dsl/PureJavaProverYaciE2ETest.java
@@ -17,7 +17,7 @@
import com.bloxbean.cardano.zeroj.crypto.setup.PowersOfTauBLS381;
import com.bloxbean.cardano.zeroj.onchain.julc.ProverToCardano;
import com.bloxbean.cardano.zeroj.examples.dsl.common.YaciHelper;
-import com.bloxbean.cardano.zeroj.onchain.julc.Groth16BLS12381GenericVerifier;
+import com.bloxbean.cardano.zeroj.onchain.julc.Groth16BLS12381Verifier;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
@@ -39,7 +39,7 @@
* Circuit: a * x + b = c, where a, b, and c are public and x is private.
- * Uses the generic {@link Groth16BLS12381GenericVerifier} with 3 public
+ * Uses {@link Groth16BLS12381Verifier} with 3 public
* inputs and 4 IC points. This circuit has 2 public inputs (threshold, isAboveThreshold), which can
- * be verified on-chain by {@code Groth16BLS12381GenericVerifier}. Uses {@code PowersOfTauBLS381.generate(8)} — for development only.
- * Verification key points are baked in at deploy time. Unlike
- * {@link Groth16BLS12381Verifier}, this verifier accepts the full IC vector as
- * a Plutus list parameter, so it supports any public-input count.
- *
- * Datum: list of public input integers in verification-key schema order.
- * Redeemer: compressed Groth16 proof points.
- * Parameter {@code vkIc}: list of compressed G1 IC points, where
- * {@code len(vkIc) == len(publicInputs) + 1}.
- */
-@SpendingValidator
-public class Groth16BLS12381GenericVerifier {
-
- @Param static byte[] vkAlpha; // G1 compressed 48 bytes
- @Param static byte[] vkBeta; // G2 compressed 96 bytes
- @Param static byte[] vkGamma; // G2 compressed 96 bytes
- @Param static byte[] vkDelta; // G2 compressed 96 bytes
- @Param static PlutusData vkIc; // List of G1 compressed 48-byte IC points
-
- /**
- * Groth16 proof points (compressed BLS bytes), passed as redeemer.
- */
- record Groth16Proof(byte[] piA, byte[] piB, byte[] piC) {}
-
- @Entrypoint
- public static boolean validate(PlutusData datum, Groth16Proof proof, PlutusData ctx) {
- PlutusData inputsCursor = Builtins.unListData(datum);
- PlutusData icCursor = Builtins.unListData(vkIc);
-
- if (Builtins.nullList(icCursor)) {
- return false;
- }
-
- byte[] vkX = BlsLib.g1Uncompress(Builtins.unBData(Builtins.headList(icCursor)));
- return verifyWithPublicInputs(inputsCursor, Builtins.tailList(icCursor), vkX, proof);
- }
-
- private static boolean verifyWithPublicInputs(PlutusData inputsCursor,
- PlutusData icCursor,
- byte[] vkX,
- Groth16Proof proof) {
- if (!matchingLengths(inputsCursor, icCursor)) {
- return false;
- }
-
- byte[] computedVkX = computeVkX(inputsCursor, icCursor, vkX);
-
- byte[] a = BlsLib.g1Uncompress(proof.piA());
- byte[] b = BlsLib.g2Uncompress(proof.piB());
- byte[] c = BlsLib.g1Uncompress(proof.piC());
-
- byte[] alpha = BlsLib.g1Uncompress(vkAlpha);
- byte[] beta = BlsLib.g2Uncompress(vkBeta);
- byte[] gamma = BlsLib.g2Uncompress(vkGamma);
- byte[] delta = BlsLib.g2Uncompress(vkDelta);
-
- byte[] negAlpha = BlsLib.g1Neg(alpha);
- byte[] lhs = BlsLib.mulMlResult(
- BlsLib.millerLoop(a, b),
- BlsLib.millerLoop(negAlpha, beta));
- byte[] rhs = BlsLib.mulMlResult(
- BlsLib.millerLoop(computedVkX, gamma),
- BlsLib.millerLoop(c, delta));
-
- return BlsLib.finalVerify(lhs, rhs);
- }
-
- private static boolean matchingLengths(PlutusData inputsCursor, PlutusData icCursor) {
- if (Builtins.nullList(inputsCursor)) {
- return Builtins.nullList(icCursor);
- } else if (Builtins.nullList(icCursor)) {
- return false;
- } else {
- return matchingLengths(Builtins.tailList(inputsCursor), Builtins.tailList(icCursor));
- }
- }
-
- private static byte[] computeVkX(PlutusData inputsCursor, PlutusData icCursor, byte[] vkX) {
- if (Builtins.nullList(inputsCursor)) {
- return vkX;
- } else {
- BigInteger publicInput = Builtins.asInteger(Builtins.headList(inputsCursor));
- byte[] ic = BlsLib.g1Uncompress(Builtins.unBData(Builtins.headList(icCursor)));
- byte[] scaled = BlsLib.g1ScalarMul(publicInput, ic);
- byte[] nextVkX = BlsLib.g1Add(vkX, scaled);
- return computeVkX(Builtins.tailList(inputsCursor), Builtins.tailList(icCursor), nextVkX);
- }
- }
-}
diff --git a/zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/Groth16BLS12381Verifier.java b/zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/Groth16BLS12381Verifier.java
index 3062774..c622c4a 100644
--- a/zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/Groth16BLS12381Verifier.java
+++ b/zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/Groth16BLS12381Verifier.java
@@ -1,87 +1,36 @@
package com.bloxbean.cardano.zeroj.onchain.julc;
import com.bloxbean.cardano.julc.core.PlutusData;
-import com.bloxbean.cardano.julc.stdlib.Builtins;
import com.bloxbean.cardano.julc.stdlib.annotation.Entrypoint;
import com.bloxbean.cardano.julc.stdlib.annotation.Param;
import com.bloxbean.cardano.julc.stdlib.annotation.SpendingValidator;
-import com.bloxbean.cardano.julc.stdlib.lib.BlsLib;
-
-import java.math.BigInteger;
/**
- * Fixed two-public-input Groth16 BLS12-381 verifier as a Plutus V3 spending
- * validator.
+ * On-chain Groth16 BLS12-381 verifier as a Plutus V3 spending validator.
*
- * Verification key points are baked in at deploy time via {@link Param}.
- * The proof (piA, piB, piC) is passed as the redeemer (compressed BLS bytes).
- * Public inputs are passed in the datum as a list of integers.
+ * Verification key points are baked in at deploy time. The full IC vector is
+ * passed as a Plutus list parameter, so this verifier supports any public-input
+ * count for Groth16 circuits over BLS12-381.
*
- * Verification equation:
- * For production: Use this to convert proofs generated by the pure Java
* prover ({@code Groth16ProverBLS381}) into the byte format expected by the
- * on-chain verifiers ({@link Groth16BLS12381Verifier} and
- * {@link Groth16BLS12381GenericVerifier}).DEV/TEST (this test)
*
- * finalVerify(
- * mulMlResult(millerLoop(A, B), millerLoop(-alpha, beta)),
- * mulMlResult(millerLoop(vk_x, gamma), millerLoop(C, delta))
- * )
- *
- *
- * @deprecated Use {@link Groth16BLS12381GenericVerifier}. This class is kept
- * only for compatibility with older examples that baked exactly two public
- * inputs as three separate IC parameters.
+ * Datum: list of public input integers in verification-key schema order.
+ * Redeemer: compressed Groth16 proof points.
+ * Parameter {@code vkIc}: list of compressed G1 IC points, where
+ * {@code len(vkIc) == len(publicInputs) + 1}.
*/
@SpendingValidator
-@Deprecated
public class Groth16BLS12381Verifier {
- // VK points — compressed bytes baked at compile time
@Param static byte[] vkAlpha; // G1 compressed 48 bytes
@Param static byte[] vkBeta; // G2 compressed 96 bytes
@Param static byte[] vkGamma; // G2 compressed 96 bytes
@Param static byte[] vkDelta; // G2 compressed 96 bytes
- @Param static byte[] vkIc0; // G1 compressed 48 bytes
- @Param static byte[] vkIc1; // G1 compressed 48 bytes
- @Param static byte[] vkIc2; // G1 compressed 48 bytes
+ @Param static PlutusData vkIc; // List of G1 compressed 48-byte IC points
- /**
- * Groth16 proof points (compressed BLS bytes), passed as redeemer.
- */
record Groth16Proof(byte[] piA, byte[] piB, byte[] piC) {}
@Entrypoint
- static boolean validate(PlutusData datum, Groth16Proof proof, PlutusData ctx) {
- // 1. Uncompress proof points
- byte[] a = BlsLib.g1Uncompress(proof.piA());
- byte[] b = BlsLib.g2Uncompress(proof.piB());
- byte[] c = BlsLib.g1Uncompress(proof.piC());
-
- // 2. Uncompress VK points
- byte[] alpha = BlsLib.g1Uncompress(vkAlpha);
- byte[] beta = BlsLib.g2Uncompress(vkBeta);
- byte[] gamma = BlsLib.g2Uncompress(vkGamma);
- byte[] delta = BlsLib.g2Uncompress(vkDelta);
- byte[] ic0 = BlsLib.g1Uncompress(vkIc0);
- byte[] ic1 = BlsLib.g1Uncompress(vkIc1);
- byte[] ic2 = BlsLib.g1Uncompress(vkIc2);
-
- // 3. Extract public inputs from datum (list of integers)
- PlutusData inputs = Builtins.unListData(datum);
- BigInteger pub0 = Builtins.asInteger(Builtins.headList(inputs));
- BigInteger pub1 = Builtins.asInteger(Builtins.headList(Builtins.tailList(inputs)));
-
- // 4. Compute vk_x = IC[0] + pub[0]*IC[1] + pub[1]*IC[2]
- byte[] s0 = BlsLib.g1ScalarMul(pub0, ic1);
- byte[] s1 = BlsLib.g1ScalarMul(pub1, ic2);
- byte[] vkX = BlsLib.g1Add(ic0, BlsLib.g1Add(s0, s1));
-
- // 5. Groth16 pairing check
- byte[] negAlpha = BlsLib.g1Neg(alpha);
- byte[] lhs = BlsLib.mulMlResult(
- BlsLib.millerLoop(a, b),
- BlsLib.millerLoop(negAlpha, beta));
- byte[] rhs = BlsLib.mulMlResult(
- BlsLib.millerLoop(vkX, gamma),
- BlsLib.millerLoop(c, delta));
-
- return BlsLib.finalVerify(lhs, rhs);
+ public static boolean validate(PlutusData datum, Groth16Proof proof, PlutusData ctx) {
+ return Groth16BLS12381.verify(datum, proof.piA(), proof.piB(), proof.piC(),
+ vkAlpha, vkBeta, vkGamma, vkDelta, vkIc);
}
}
diff --git a/zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/PlonkBLS12381FullVerifier.java b/zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/PlonkBLS12381FullVerifier.java
index e0deae2..f9bada4 100644
--- a/zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/PlonkBLS12381FullVerifier.java
+++ b/zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/PlonkBLS12381FullVerifier.java
@@ -5,7 +5,6 @@
import com.bloxbean.cardano.julc.stdlib.annotation.Entrypoint;
import com.bloxbean.cardano.julc.stdlib.annotation.Param;
import com.bloxbean.cardano.julc.stdlib.annotation.SpendingValidator;
-import com.bloxbean.cardano.julc.stdlib.lib.BlsLib;
import java.math.BigInteger;
@@ -147,31 +146,31 @@ static boolean validate(PlutusData datum, PlonkProof p, PlutusData ctx) {
BigInteger r0 = pi.subtract(l1.multiply(alpha2).mod(fr)).mod(fr).subtract(e3).mod(fr);
// ======== G1 operations ========
- byte[] qm = BlsLib.g1Uncompress(vkQm);
- byte[] ql = BlsLib.g1Uncompress(vkQl);
- byte[] qr = BlsLib.g1Uncompress(vkQr);
- byte[] qo = BlsLib.g1Uncompress(vkQo);
- byte[] qc = BlsLib.g1Uncompress(vkQc);
- byte[] s3u = BlsLib.g1Uncompress(vkS3);
- byte[] x2u = BlsLib.g2Uncompress(vkX2);
- byte[] cA = BlsLib.g1Uncompress(p.cmA());
- byte[] cB = BlsLib.g1Uncompress(p.cmB());
- byte[] cC = BlsLib.g1Uncompress(p.cmC());
- byte[] cZ = BlsLib.g1Uncompress(p.cmZ());
- byte[] t1 = BlsLib.g1Uncompress(p.cmT1());
- byte[] t2 = BlsLib.g1Uncompress(p.cmT2());
- byte[] t3 = BlsLib.g1Uncompress(p.cmT3());
- byte[] wXi = BlsLib.g1Uncompress(p.wXi());
- byte[] wXiw = BlsLib.g1Uncompress(p.wXiw());
- byte[] g1 = BlsLib.g1Uncompress(g1Gen);
- byte[] g2 = BlsLib.g2Uncompress(g2Gen);
+ byte[] qm = Builtins.bls12_381_G1_uncompress(vkQm);
+ byte[] ql = Builtins.bls12_381_G1_uncompress(vkQl);
+ byte[] qr = Builtins.bls12_381_G1_uncompress(vkQr);
+ byte[] qo = Builtins.bls12_381_G1_uncompress(vkQo);
+ byte[] qc = Builtins.bls12_381_G1_uncompress(vkQc);
+ byte[] s3u = Builtins.bls12_381_G1_uncompress(vkS3);
+ byte[] x2u = Builtins.bls12_381_G2_uncompress(vkX2);
+ byte[] cA = Builtins.bls12_381_G1_uncompress(p.cmA());
+ byte[] cB = Builtins.bls12_381_G1_uncompress(p.cmB());
+ byte[] cC = Builtins.bls12_381_G1_uncompress(p.cmC());
+ byte[] cZ = Builtins.bls12_381_G1_uncompress(p.cmZ());
+ byte[] t1 = Builtins.bls12_381_G1_uncompress(p.cmT1());
+ byte[] t2 = Builtins.bls12_381_G1_uncompress(p.cmT2());
+ byte[] t3 = Builtins.bls12_381_G1_uncompress(p.cmT3());
+ byte[] wXi = Builtins.bls12_381_G1_uncompress(p.wXi());
+ byte[] wXiw = Builtins.bls12_381_G1_uncompress(p.wXiw());
+ byte[] g1 = Builtins.bls12_381_G1_uncompress(g1Gen);
+ byte[] g2 = Builtins.bls12_381_G2_uncompress(g2Gen);
// ======== [D] ========
BigInteger ab = p.evalA().multiply(p.evalB()).mod(fr);
- byte[] d1 = BlsLib.g1Add(
- BlsLib.g1Add(BlsLib.g1ScalarMul(ab, qm), BlsLib.g1ScalarMul(p.evalA(), ql)),
- BlsLib.g1Add(BlsLib.g1ScalarMul(p.evalB(), qr),
- BlsLib.g1Add(BlsLib.g1ScalarMul(p.evalC(), qo), qc)));
+ byte[] d1 = Builtins.bls12_381_G1_add(
+ Builtins.bls12_381_G1_add(Builtins.bls12_381_G1_scalarMul(ab, qm), Builtins.bls12_381_G1_scalarMul(p.evalA(), ql)),
+ Builtins.bls12_381_G1_add(Builtins.bls12_381_G1_scalarMul(p.evalB(), qr),
+ Builtins.bls12_381_G1_add(Builtins.bls12_381_G1_scalarMul(p.evalC(), qo), qc)));
BigInteger betaxi = beta.multiply(xi).mod(fr);
BigInteger d2c = p.evalA().add(betaxi).add(gamma).mod(fr)
@@ -179,18 +178,18 @@ static boolean validate(PlutusData datum, PlonkProof p, PlutusData ctx) {
.multiply(p.evalC().add(betaxi.multiply(k2).mod(fr)).add(gamma).mod(fr)).mod(fr)
.multiply(alpha).mod(fr)
.add(l1.multiply(alpha2).mod(fr)).mod(fr);
- byte[] d2 = BlsLib.g1ScalarMul(d2c, cZ);
+ byte[] d2 = Builtins.bls12_381_G1_scalarMul(d2c, cZ);
BigInteger d3c = p.evalA().add(beta.multiply(p.evalS1()).mod(fr)).add(gamma).mod(fr)
.multiply(p.evalB().add(beta.multiply(p.evalS2()).mod(fr)).add(gamma).mod(fr)).mod(fr)
.multiply(alpha.multiply(beta).mod(fr).multiply(p.evalZw()).mod(fr)).mod(fr);
- byte[] d3 = BlsLib.g1ScalarMul(d3c, s3u);
+ byte[] d3 = Builtins.bls12_381_G1_scalarMul(d3c, s3u);
BigInteger xi4sq = xi4.multiply(xi4).mod(fr);
- byte[] d4 = BlsLib.g1ScalarMul(zh,
- BlsLib.g1Add(t1, BlsLib.g1Add(BlsLib.g1ScalarMul(xi4, t2), BlsLib.g1ScalarMul(xi4sq, t3))));
+ byte[] d4 = Builtins.bls12_381_G1_scalarMul(zh,
+ Builtins.bls12_381_G1_add(t1, Builtins.bls12_381_G1_add(Builtins.bls12_381_G1_scalarMul(xi4, t2), Builtins.bls12_381_G1_scalarMul(xi4sq, t3))));
- byte[] dPt = BlsLib.g1Add(BlsLib.g1Add(d1, d2), BlsLib.g1Neg(BlsLib.g1Add(d3, d4)));
+ byte[] dPt = Builtins.bls12_381_G1_add(Builtins.bls12_381_G1_add(d1, d2), Builtins.bls12_381_G1_neg(Builtins.bls12_381_G1_add(d3, d4)));
// ======== [F], [E], pairing ========
// (simplified — gnark's v/u challenges come from KZG fold, not PlonK transcript)
diff --git a/zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/ProverToCardano.java b/zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/ProverToCardano.java
index ae3c1f0..38326ce 100644
--- a/zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/ProverToCardano.java
+++ b/zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/ProverToCardano.java
@@ -21,8 +21,7 @@
*
*
Uses {@link Groth16BLS12381GenericVerifier}; the same verifier also + *
Uses {@link Groth16BLS12381Verifier}; the same verifier also * supports circuits with more or fewer public inputs.
* *Circuit: publicA * secretB = publicC (publicA and publicC are public).
@@ -76,7 +76,7 @@ void twoPublicInputs_pureJavaProve_onChainVerify() { assertEquals(3, compressedVk.ic().size(), "IC should have numPublic+1 = 3 entries"); // Compile on-chain verifier with VK params - var compiled = compileValidator(Groth16BLS12381GenericVerifier.class); + var compiled = compileValidator(Groth16BLS12381Verifier.class); var program = compiled.program().applyParams( PlutusData.bytes(compressedVk.alpha()), PlutusData.bytes(compressedVk.beta()), diff --git a/zeroj-onchain-julc/src/test/java/com/bloxbean/cardano/zeroj/onchain/julc/Groth16BLS12381VerifierTest.java b/zeroj-onchain-julc/src/test/java/com/bloxbean/cardano/zeroj/onchain/julc/Groth16BLS12381VerifierTest.java index 51bb52d..a1211c1 100644 --- a/zeroj-onchain-julc/src/test/java/com/bloxbean/cardano/zeroj/onchain/julc/Groth16BLS12381VerifierTest.java +++ b/zeroj-onchain-julc/src/test/java/com/bloxbean/cardano/zeroj/onchain/julc/Groth16BLS12381VerifierTest.java @@ -3,138 +3,177 @@ import com.bloxbean.cardano.julc.core.PlutusData; import com.bloxbean.cardano.julc.testkit.ContractTest; import com.bloxbean.cardano.julc.testkit.TestDataBuilder; +import com.bloxbean.cardano.zeroj.api.CurveId; +import com.bloxbean.cardano.zeroj.circuit.CircuitBuilder; +import com.bloxbean.cardano.zeroj.crypto.groth16.Groth16ProverBLS381; +import com.bloxbean.cardano.zeroj.crypto.setup.Groth16SetupBLS381; +import com.bloxbean.cardano.zeroj.crypto.setup.PowersOfTauBLS381; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import java.io.IOException; import java.math.BigInteger; +import java.nio.file.Path; import java.nio.charset.StandardCharsets; +import java.util.ArrayList; import java.util.List; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; /** - * Compatibility tests for the deprecated fixed two-public-input Groth16 - * BLS12-381 verifier using the Julc VM. - *
- * This demonstrates the full end-to-end flow:
- * 1. Parse snarkjs JSON artifacts → compressed BLS12-381 bytes
- * 2. Compile the on-chain verifier with VK params
- * 3. Evaluate with proof redeemer and public inputs datum
- * 4. Assert the pairing check passes in the Julc VM
+ * Tests the arbitrary-public-input Groth16 BLS12-381 verifier in the Julc VM.
*/
-@SuppressWarnings("deprecation")
class Groth16BLS12381VerifierTest extends ContractTest {
- private static SnarkjsToCardano.VkCompressed vk;
- private static SnarkjsToCardano.ProofCompressed proof;
- private static List
- * This domain-specific verifier composes the reusable {@link Groth16BLS12381}
+ * This domain-specific verifier composes the reusable {@link Groth16BLS12381Lib}
* on-chain library with a {@code reservePriceBytes} binding parameter.
*/
@SpendingValidator
@@ -45,7 +45,7 @@ static boolean validate(PlutusData datum, Groth16Proof proof, PlutusData ctx) {
BigInteger committedReserve = Builtins.byteStringToInteger(true, reservePriceBytes);
boolean reserveMatches = pub1.equals(committedReserve);
- boolean proofValid = Groth16BLS12381.verify(datum, proof.piA(), proof.piB(), proof.piC(),
+ boolean proofValid = Groth16BLS12381Lib.verify(datum, proof.piA(), proof.piB(), proof.piC(),
vkAlpha, vkBeta, vkGamma, vkDelta, vkIc);
return reserveMatches && proofValid;
diff --git a/zeroj-examples/src/test/java/com/bloxbean/cardano/zeroj/examples/dsl/PureJavaProverYaciE2ETest.java b/zeroj-examples/src/test/java/com/bloxbean/cardano/zeroj/examples/dsl/PureJavaProverYaciE2ETest.java
index 6f11697..a1a81fb 100644
--- a/zeroj-examples/src/test/java/com/bloxbean/cardano/zeroj/examples/dsl/PureJavaProverYaciE2ETest.java
+++ b/zeroj-examples/src/test/java/com/bloxbean/cardano/zeroj/examples/dsl/PureJavaProverYaciE2ETest.java
@@ -15,9 +15,9 @@
import com.bloxbean.cardano.zeroj.crypto.groth16.Groth16ProverBLS381;
import com.bloxbean.cardano.zeroj.crypto.setup.Groth16SetupBLS381;
import com.bloxbean.cardano.zeroj.crypto.setup.PowersOfTauBLS381;
-import com.bloxbean.cardano.zeroj.onchain.julc.ProverToCardano;
+import com.bloxbean.cardano.zeroj.onchain.julc.groth16.codec.ProverToCardano;
import com.bloxbean.cardano.zeroj.examples.dsl.common.YaciHelper;
-import com.bloxbean.cardano.zeroj.onchain.julc.Groth16BLS12381Verifier;
+import com.bloxbean.cardano.zeroj.onchain.julc.groth16.validator.Groth16BLS12381Verifier;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
diff --git a/zeroj-examples/src/test/java/com/bloxbean/cardano/zeroj/examples/dsl/common/ZkE2ETestBase.java b/zeroj-examples/src/test/java/com/bloxbean/cardano/zeroj/examples/dsl/common/ZkE2ETestBase.java
index 8af07c5..ce66be5 100644
--- a/zeroj-examples/src/test/java/com/bloxbean/cardano/zeroj/examples/dsl/common/ZkE2ETestBase.java
+++ b/zeroj-examples/src/test/java/com/bloxbean/cardano/zeroj/examples/dsl/common/ZkE2ETestBase.java
@@ -7,7 +7,7 @@
import com.bloxbean.cardano.client.function.helper.SignerProviders;
import com.bloxbean.cardano.client.quicktx.QuickTxBuilder;
import com.bloxbean.cardano.client.quicktx.Tx;
-import com.bloxbean.cardano.zeroj.onchain.julc.SnarkjsToCardano;
+import com.bloxbean.cardano.zeroj.onchain.julc.groth16.codec.SnarkjsToCardano;
import java.io.IOException;
import java.math.BigInteger;
diff --git a/zeroj-onchain-julc/README.md b/zeroj-onchain-julc/README.md
index 53fe362..bfbfbb6 100644
--- a/zeroj-onchain-julc/README.md
+++ b/zeroj-onchain-julc/README.md
@@ -10,16 +10,14 @@ V3.
## Current Status
-| Validator / Helper | Status | Notes |
-|--------------------|--------|-------|
-| `Groth16BLS12381Verifier` | Working | Default BLS12-381 Groth16 verifier using Plutus V3 BLS builtins; supports arbitrary public-input counts |
-| `Groth16BLS12381` | Working library | Reusable `@OnchainLibrary` proof verification helper for custom validators |
-| `PlonkBLS12381FullVerifier` | Experimental prototype | Re-derives transcript and checks inverse constraints; KZG batch opening pairing check is deferred |
-| `SnarkjsToCardano` | Working helper | Converts snarkjs Groth16 JSON points to Cardano-compatible compressed bytes |
-| `ProverToCardano` | Working helper | Converts ZeroJ prover artifacts to on-chain data shapes |
-| `ScriptBudgetEstimator` | Planning helper | Estimates Plutus CPU/memory budgets for supported combinations |
-| `OnChainFeasibility` | Planning helper | Matrix for proof system / curve support on Cardano |
-| `ReferenceScriptDeployer` | Config helper | Describes CIP-0033 reference-script deployment patterns; does not submit transactions |
+| Package | Contents | Status | Notes |
+|---------|----------|--------|-------|
+| `com.bloxbean.cardano.zeroj.onchain.julc.groth16.validator` | `Groth16BLS12381Verifier` | Working validator | Default BLS12-381 Groth16 spending validator using Plutus V3 BLS builtins; supports arbitrary public-input counts |
+| `com.bloxbean.cardano.zeroj.onchain.julc.groth16.lib` | `Groth16BLS12381Lib` | Working on-chain library | Reusable `@OnchainLibrary` proof verification helper for custom validators |
+| `com.bloxbean.cardano.zeroj.onchain.julc.groth16.codec` | `SnarkjsToCardano`, `ProverToCardano` | Working off-chain helpers | Convert snarkjs and ZeroJ Groth16 artifacts to Cardano-compatible compressed bytes and Plutus data shapes |
+| `com.bloxbean.cardano.zeroj.onchain.julc.plonk.validator` | `PlonkBLS12381FullVerifier` | Experimental validator prototype | Re-derives transcript and checks inverse constraints; KZG batch opening pairing check is deferred |
+| `com.bloxbean.cardano.zeroj.onchain.julc.analysis` | `ScriptBudgetEstimator`, `OnChainFeasibility` | Planning helpers | Estimate Plutus CPU/memory budgets and report proof system / curve feasibility |
+| `com.bloxbean.cardano.zeroj.onchain.julc.deployment` | `ReferenceScriptDeployer` | Config helper | Describes CIP-0033 reference-script deployment patterns; does not submit transactions |
## Why It Is Useful
@@ -40,6 +38,43 @@ The tests run validators in the Julc VM and include Groth16 positive/negative
checks, pure Java Groth16 prover to on-chain verification, budget estimation, and
the PlonK prototype transcript/inverse-check path.
+## Imports
+
+Use package names by role:
+
+```java
+import com.bloxbean.cardano.zeroj.onchain.julc.groth16.validator.Groth16BLS12381Verifier;
+import com.bloxbean.cardano.zeroj.onchain.julc.groth16.lib.Groth16BLS12381Lib;
+import com.bloxbean.cardano.zeroj.onchain.julc.groth16.codec.ProverToCardano;
+import com.bloxbean.cardano.zeroj.onchain.julc.groth16.codec.SnarkjsToCardano;
+```
+
+Custom validators should define their own local redeemer record and compose the
+shared library:
+
+```java
+@SpendingValidator
+public class MyVerifier {
+ @Param static byte[] vkAlpha;
+ @Param static byte[] vkBeta;
+ @Param static byte[] vkGamma;
+ @Param static byte[] vkDelta;
+ @Param static PlutusData vkIc;
+
+ record Groth16Proof(byte[] piA, byte[] piB, byte[] piC) {}
+
+ @Entrypoint
+ static boolean validate(PlutusData datum, Groth16Proof proof, PlutusData ctx) {
+ return Groth16BLS12381Lib.verify(datum, proof.piA(), proof.piB(), proof.piC(),
+ vkAlpha, vkBeta, vkGamma, vkDelta, vkIc);
+ }
+}
+```
+
+The proof record is kept validator-local because Julc record decoding is
+validator-local today. Sharing `Groth16BLS12381Lib` still avoids duplicating the
+pairing and public-input folding logic.
+
## Gradle
```gradle
diff --git a/zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/OnChainFeasibility.java b/zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/analysis/OnChainFeasibility.java
similarity index 98%
rename from zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/OnChainFeasibility.java
rename to zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/analysis/OnChainFeasibility.java
index fad0a08..70e7536 100644
--- a/zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/OnChainFeasibility.java
+++ b/zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/analysis/OnChainFeasibility.java
@@ -1,4 +1,4 @@
-package com.bloxbean.cardano.zeroj.onchain.julc;
+package com.bloxbean.cardano.zeroj.onchain.julc.analysis;
import com.bloxbean.cardano.zeroj.api.CurveId;
import com.bloxbean.cardano.zeroj.api.ProofSystemId;
diff --git a/zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/ScriptBudgetEstimator.java b/zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/analysis/ScriptBudgetEstimator.java
similarity index 98%
rename from zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/ScriptBudgetEstimator.java
rename to zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/analysis/ScriptBudgetEstimator.java
index e4ed253..4ed218d 100644
--- a/zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/ScriptBudgetEstimator.java
+++ b/zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/analysis/ScriptBudgetEstimator.java
@@ -1,4 +1,4 @@
-package com.bloxbean.cardano.zeroj.onchain.julc;
+package com.bloxbean.cardano.zeroj.onchain.julc.analysis;
import com.bloxbean.cardano.zeroj.api.CurveId;
import com.bloxbean.cardano.zeroj.api.ProofSystemId;
diff --git a/zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/ReferenceScriptDeployer.java b/zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/deployment/ReferenceScriptDeployer.java
similarity index 95%
rename from zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/ReferenceScriptDeployer.java
rename to zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/deployment/ReferenceScriptDeployer.java
index ee4499d..884a478 100644
--- a/zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/ReferenceScriptDeployer.java
+++ b/zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/deployment/ReferenceScriptDeployer.java
@@ -1,4 +1,4 @@
-package com.bloxbean.cardano.zeroj.onchain.julc;
+package com.bloxbean.cardano.zeroj.onchain.julc.deployment;
/**
* Structured deployment configuration for Cardano CIP-0033 reference scripts.
diff --git a/zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/ProverToCardano.java b/zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/groth16/codec/ProverToCardano.java
similarity index 96%
rename from zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/ProverToCardano.java
rename to zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/groth16/codec/ProverToCardano.java
index 38326ce..a95236a 100644
--- a/zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/ProverToCardano.java
+++ b/zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/groth16/codec/ProverToCardano.java
@@ -1,9 +1,10 @@
-package com.bloxbean.cardano.zeroj.onchain.julc;
+package com.bloxbean.cardano.zeroj.onchain.julc.groth16.codec;
import com.bloxbean.cardano.zeroj.bls12381.ec.JacobianG1BLS381;
import com.bloxbean.cardano.zeroj.bls12381.ec.JacobianG2BLS381;
import com.bloxbean.cardano.zeroj.crypto.groth16.Groth16ProofBLS381;
import com.bloxbean.cardano.zeroj.crypto.setup.Groth16SetupBLS381;
+import com.bloxbean.cardano.zeroj.onchain.julc.groth16.validator.Groth16BLS12381Verifier;
import supranational.blst.P1_Affine;
import supranational.blst.P2_Affine;
diff --git a/zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/SnarkjsToCardano.java b/zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/groth16/codec/SnarkjsToCardano.java
similarity index 99%
rename from zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/SnarkjsToCardano.java
rename to zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/groth16/codec/SnarkjsToCardano.java
index c9ef84f..72eab3e 100644
--- a/zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/SnarkjsToCardano.java
+++ b/zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/groth16/codec/SnarkjsToCardano.java
@@ -1,4 +1,4 @@
-package com.bloxbean.cardano.zeroj.onchain.julc;
+package com.bloxbean.cardano.zeroj.onchain.julc.groth16.codec;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
diff --git a/zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/Groth16BLS12381.java b/zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/groth16/lib/Groth16BLS12381Lib.java
similarity index 98%
rename from zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/Groth16BLS12381.java
rename to zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/groth16/lib/Groth16BLS12381Lib.java
index 0ae8066..d1c2af1 100644
--- a/zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/Groth16BLS12381.java
+++ b/zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/groth16/lib/Groth16BLS12381Lib.java
@@ -1,4 +1,4 @@
-package com.bloxbean.cardano.zeroj.onchain.julc;
+package com.bloxbean.cardano.zeroj.onchain.julc.groth16.lib;
import com.bloxbean.cardano.julc.core.PlutusData;
import com.bloxbean.cardano.julc.stdlib.Builtins;
@@ -10,7 +10,7 @@
* Reusable on-chain Groth16 verifier logic for BLS12-381 proofs.
*/
@OnchainLibrary
-public class Groth16BLS12381 {
+public class Groth16BLS12381Lib {
public static PlutusData publicInputs(BigInteger pub0) {
return Builtins.listData(Builtins.mkCons(
diff --git a/zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/Groth16BLS12381Verifier.java b/zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/groth16/validator/Groth16BLS12381Verifier.java
similarity index 85%
rename from zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/Groth16BLS12381Verifier.java
rename to zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/groth16/validator/Groth16BLS12381Verifier.java
index c622c4a..a42874d 100644
--- a/zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/Groth16BLS12381Verifier.java
+++ b/zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/groth16/validator/Groth16BLS12381Verifier.java
@@ -1,9 +1,10 @@
-package com.bloxbean.cardano.zeroj.onchain.julc;
+package com.bloxbean.cardano.zeroj.onchain.julc.groth16.validator;
import com.bloxbean.cardano.julc.core.PlutusData;
import com.bloxbean.cardano.julc.stdlib.annotation.Entrypoint;
import com.bloxbean.cardano.julc.stdlib.annotation.Param;
import com.bloxbean.cardano.julc.stdlib.annotation.SpendingValidator;
+import com.bloxbean.cardano.zeroj.onchain.julc.groth16.lib.Groth16BLS12381Lib;
/**
* On-chain Groth16 BLS12-381 verifier as a Plutus V3 spending validator.
@@ -30,7 +31,7 @@ record Groth16Proof(byte[] piA, byte[] piB, byte[] piC) {}
@Entrypoint
public static boolean validate(PlutusData datum, Groth16Proof proof, PlutusData ctx) {
- return Groth16BLS12381.verify(datum, proof.piA(), proof.piB(), proof.piC(),
+ return Groth16BLS12381Lib.verify(datum, proof.piA(), proof.piB(), proof.piC(),
vkAlpha, vkBeta, vkGamma, vkDelta, vkIc);
}
}
diff --git a/zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/PlonkBLS12381FullVerifier.java b/zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/plonk/validator/PlonkBLS12381FullVerifier.java
similarity index 99%
rename from zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/PlonkBLS12381FullVerifier.java
rename to zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/plonk/validator/PlonkBLS12381FullVerifier.java
index f9bada4..df4d123 100644
--- a/zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/PlonkBLS12381FullVerifier.java
+++ b/zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/plonk/validator/PlonkBLS12381FullVerifier.java
@@ -1,4 +1,4 @@
-package com.bloxbean.cardano.zeroj.onchain.julc;
+package com.bloxbean.cardano.zeroj.onchain.julc.plonk.validator;
import com.bloxbean.cardano.julc.core.PlutusData;
import com.bloxbean.cardano.julc.stdlib.Builtins;
diff --git a/zeroj-onchain-julc/src/test/java/com/bloxbean/cardano/zeroj/onchain/julc/OnChainFeasibilityTest.java b/zeroj-onchain-julc/src/test/java/com/bloxbean/cardano/zeroj/onchain/julc/analysis/OnChainFeasibilityTest.java
similarity index 96%
rename from zeroj-onchain-julc/src/test/java/com/bloxbean/cardano/zeroj/onchain/julc/OnChainFeasibilityTest.java
rename to zeroj-onchain-julc/src/test/java/com/bloxbean/cardano/zeroj/onchain/julc/analysis/OnChainFeasibilityTest.java
index d76adfb..a2bdb65 100644
--- a/zeroj-onchain-julc/src/test/java/com/bloxbean/cardano/zeroj/onchain/julc/OnChainFeasibilityTest.java
+++ b/zeroj-onchain-julc/src/test/java/com/bloxbean/cardano/zeroj/onchain/julc/analysis/OnChainFeasibilityTest.java
@@ -1,4 +1,4 @@
-package com.bloxbean.cardano.zeroj.onchain.julc;
+package com.bloxbean.cardano.zeroj.onchain.julc.analysis;
import com.bloxbean.cardano.zeroj.api.CurveId;
import com.bloxbean.cardano.zeroj.api.ProofSystemId;
diff --git a/zeroj-onchain-julc/src/test/java/com/bloxbean/cardano/zeroj/onchain/julc/ScriptBudgetEstimatorTest.java b/zeroj-onchain-julc/src/test/java/com/bloxbean/cardano/zeroj/onchain/julc/analysis/ScriptBudgetEstimatorTest.java
similarity index 96%
rename from zeroj-onchain-julc/src/test/java/com/bloxbean/cardano/zeroj/onchain/julc/ScriptBudgetEstimatorTest.java
rename to zeroj-onchain-julc/src/test/java/com/bloxbean/cardano/zeroj/onchain/julc/analysis/ScriptBudgetEstimatorTest.java
index 2d48197..4055da5 100644
--- a/zeroj-onchain-julc/src/test/java/com/bloxbean/cardano/zeroj/onchain/julc/ScriptBudgetEstimatorTest.java
+++ b/zeroj-onchain-julc/src/test/java/com/bloxbean/cardano/zeroj/onchain/julc/analysis/ScriptBudgetEstimatorTest.java
@@ -1,4 +1,4 @@
-package com.bloxbean.cardano.zeroj.onchain.julc;
+package com.bloxbean.cardano.zeroj.onchain.julc.analysis;
import com.bloxbean.cardano.zeroj.api.CurveId;
import com.bloxbean.cardano.zeroj.api.ProofSystemId;
diff --git a/zeroj-onchain-julc/src/test/java/com/bloxbean/cardano/zeroj/onchain/julc/ReferenceScriptDeployerTest.java b/zeroj-onchain-julc/src/test/java/com/bloxbean/cardano/zeroj/onchain/julc/deployment/ReferenceScriptDeployerTest.java
similarity index 96%
rename from zeroj-onchain-julc/src/test/java/com/bloxbean/cardano/zeroj/onchain/julc/ReferenceScriptDeployerTest.java
rename to zeroj-onchain-julc/src/test/java/com/bloxbean/cardano/zeroj/onchain/julc/deployment/ReferenceScriptDeployerTest.java
index fcabdcc..9512c56 100644
--- a/zeroj-onchain-julc/src/test/java/com/bloxbean/cardano/zeroj/onchain/julc/ReferenceScriptDeployerTest.java
+++ b/zeroj-onchain-julc/src/test/java/com/bloxbean/cardano/zeroj/onchain/julc/deployment/ReferenceScriptDeployerTest.java
@@ -1,4 +1,4 @@
-package com.bloxbean.cardano.zeroj.onchain.julc;
+package com.bloxbean.cardano.zeroj.onchain.julc.deployment;
import org.junit.jupiter.api.Test;
diff --git a/zeroj-onchain-julc/src/test/java/com/bloxbean/cardano/zeroj/onchain/julc/CircomToOnChainE2ETest.java b/zeroj-onchain-julc/src/test/java/com/bloxbean/cardano/zeroj/onchain/julc/groth16/validator/CircomToOnChainE2ETest.java
similarity index 98%
rename from zeroj-onchain-julc/src/test/java/com/bloxbean/cardano/zeroj/onchain/julc/CircomToOnChainE2ETest.java
rename to zeroj-onchain-julc/src/test/java/com/bloxbean/cardano/zeroj/onchain/julc/groth16/validator/CircomToOnChainE2ETest.java
index 80df154..0d9dc3f 100644
--- a/zeroj-onchain-julc/src/test/java/com/bloxbean/cardano/zeroj/onchain/julc/CircomToOnChainE2ETest.java
+++ b/zeroj-onchain-julc/src/test/java/com/bloxbean/cardano/zeroj/onchain/julc/groth16/validator/CircomToOnChainE2ETest.java
@@ -1,4 +1,4 @@
-package com.bloxbean.cardano.zeroj.onchain.julc;
+package com.bloxbean.cardano.zeroj.onchain.julc.groth16.validator;
import com.bloxbean.cardano.zeroj.bls12381.ec.JacobianG1BLS381;
import com.bloxbean.cardano.zeroj.bls12381.ec.JacobianG2BLS381;
@@ -7,6 +7,7 @@
import com.bloxbean.cardano.julc.core.PlutusData;
import com.bloxbean.cardano.julc.testkit.ContractTest;
import com.bloxbean.cardano.julc.testkit.TestDataBuilder;
+import com.bloxbean.cardano.zeroj.onchain.julc.groth16.codec.SnarkjsToCardano;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import supranational.blst.P1_Affine;
diff --git a/zeroj-onchain-julc/src/test/java/com/bloxbean/cardano/zeroj/onchain/julc/Groth16BLS12381FirstInputBindingVerifier.java b/zeroj-onchain-julc/src/test/java/com/bloxbean/cardano/zeroj/onchain/julc/groth16/validator/Groth16BLS12381FirstInputBindingVerifier.java
similarity index 82%
rename from zeroj-onchain-julc/src/test/java/com/bloxbean/cardano/zeroj/onchain/julc/Groth16BLS12381FirstInputBindingVerifier.java
rename to zeroj-onchain-julc/src/test/java/com/bloxbean/cardano/zeroj/onchain/julc/groth16/validator/Groth16BLS12381FirstInputBindingVerifier.java
index c286351..b46097d 100644
--- a/zeroj-onchain-julc/src/test/java/com/bloxbean/cardano/zeroj/onchain/julc/Groth16BLS12381FirstInputBindingVerifier.java
+++ b/zeroj-onchain-julc/src/test/java/com/bloxbean/cardano/zeroj/onchain/julc/groth16/validator/Groth16BLS12381FirstInputBindingVerifier.java
@@ -1,15 +1,16 @@
-package com.bloxbean.cardano.zeroj.onchain.julc;
+package com.bloxbean.cardano.zeroj.onchain.julc.groth16.validator;
import com.bloxbean.cardano.julc.core.PlutusData;
import com.bloxbean.cardano.julc.stdlib.Builtins;
import com.bloxbean.cardano.julc.stdlib.annotation.Entrypoint;
import com.bloxbean.cardano.julc.stdlib.annotation.Param;
import com.bloxbean.cardano.julc.stdlib.annotation.SpendingValidator;
+import com.bloxbean.cardano.zeroj.onchain.julc.groth16.lib.Groth16BLS12381Lib;
import java.math.BigInteger;
/**
- * Test-only custom validator demonstrating composition with Groth16BLS12381.
+ * Test-only custom validator demonstrating composition with Groth16BLS12381Lib.
*/
@SpendingValidator
public class Groth16BLS12381FirstInputBindingVerifier {
@@ -32,7 +33,7 @@ public static boolean validate(PlutusData datum, Groth16Proof proof, PlutusData
BigInteger firstPublicInput = Builtins.asInteger(Builtins.headList(inputs));
boolean domainRuleHolds = firstPublicInput.equals(expectedFirstPublicInput);
- boolean proofValid = Groth16BLS12381.verify(datum, proof.piA(), proof.piB(), proof.piC(),
+ boolean proofValid = Groth16BLS12381Lib.verify(datum, proof.piA(), proof.piB(), proof.piC(),
vkAlpha, vkBeta, vkGamma, vkDelta, vkIc);
return domainRuleHolds && proofValid;
diff --git a/zeroj-onchain-julc/src/test/java/com/bloxbean/cardano/zeroj/onchain/julc/Groth16BLS12381PureJavaProverTest.java b/zeroj-onchain-julc/src/test/java/com/bloxbean/cardano/zeroj/onchain/julc/groth16/validator/Groth16BLS12381PureJavaProverTest.java
similarity index 97%
rename from zeroj-onchain-julc/src/test/java/com/bloxbean/cardano/zeroj/onchain/julc/Groth16BLS12381PureJavaProverTest.java
rename to zeroj-onchain-julc/src/test/java/com/bloxbean/cardano/zeroj/onchain/julc/groth16/validator/Groth16BLS12381PureJavaProverTest.java
index 26c43fb..4f229fd 100644
--- a/zeroj-onchain-julc/src/test/java/com/bloxbean/cardano/zeroj/onchain/julc/Groth16BLS12381PureJavaProverTest.java
+++ b/zeroj-onchain-julc/src/test/java/com/bloxbean/cardano/zeroj/onchain/julc/groth16/validator/Groth16BLS12381PureJavaProverTest.java
@@ -1,4 +1,4 @@
-package com.bloxbean.cardano.zeroj.onchain.julc;
+package com.bloxbean.cardano.zeroj.onchain.julc.groth16.validator;
import com.bloxbean.cardano.zeroj.api.CurveId;
import com.bloxbean.cardano.zeroj.circuit.CircuitBuilder;
@@ -11,6 +11,7 @@
import com.bloxbean.cardano.julc.core.PlutusData;
import com.bloxbean.cardano.julc.testkit.ContractTest;
import com.bloxbean.cardano.julc.testkit.TestDataBuilder;
+import com.bloxbean.cardano.zeroj.onchain.julc.groth16.codec.SnarkjsToCardano;
import org.junit.jupiter.api.Test;
import supranational.blst.P1_Affine;
import supranational.blst.P2_Affine;
diff --git a/zeroj-onchain-julc/src/test/java/com/bloxbean/cardano/zeroj/onchain/julc/Groth16BLS12381VerifierTest.java b/zeroj-onchain-julc/src/test/java/com/bloxbean/cardano/zeroj/onchain/julc/groth16/validator/Groth16BLS12381VerifierTest.java
similarity index 97%
rename from zeroj-onchain-julc/src/test/java/com/bloxbean/cardano/zeroj/onchain/julc/Groth16BLS12381VerifierTest.java
rename to zeroj-onchain-julc/src/test/java/com/bloxbean/cardano/zeroj/onchain/julc/groth16/validator/Groth16BLS12381VerifierTest.java
index a1211c1..6ea3cce 100644
--- a/zeroj-onchain-julc/src/test/java/com/bloxbean/cardano/zeroj/onchain/julc/Groth16BLS12381VerifierTest.java
+++ b/zeroj-onchain-julc/src/test/java/com/bloxbean/cardano/zeroj/onchain/julc/groth16/validator/Groth16BLS12381VerifierTest.java
@@ -1,4 +1,4 @@
-package com.bloxbean.cardano.zeroj.onchain.julc;
+package com.bloxbean.cardano.zeroj.onchain.julc.groth16.validator;
import com.bloxbean.cardano.julc.core.PlutusData;
import com.bloxbean.cardano.julc.testkit.ContractTest;
@@ -8,6 +8,8 @@
import com.bloxbean.cardano.zeroj.crypto.groth16.Groth16ProverBLS381;
import com.bloxbean.cardano.zeroj.crypto.setup.Groth16SetupBLS381;
import com.bloxbean.cardano.zeroj.crypto.setup.PowersOfTauBLS381;
+import com.bloxbean.cardano.zeroj.onchain.julc.groth16.codec.ProverToCardano;
+import com.bloxbean.cardano.zeroj.onchain.julc.groth16.codec.SnarkjsToCardano;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
diff --git a/zeroj-onchain-julc/src/test/java/com/bloxbean/cardano/zeroj/onchain/julc/PlonkBLS12381FullVerifierTest.java b/zeroj-onchain-julc/src/test/java/com/bloxbean/cardano/zeroj/onchain/julc/plonk/validator/PlonkBLS12381FullVerifierTest.java
similarity index 99%
rename from zeroj-onchain-julc/src/test/java/com/bloxbean/cardano/zeroj/onchain/julc/PlonkBLS12381FullVerifierTest.java
rename to zeroj-onchain-julc/src/test/java/com/bloxbean/cardano/zeroj/onchain/julc/plonk/validator/PlonkBLS12381FullVerifierTest.java
index e41cfc1..e77a503 100644
--- a/zeroj-onchain-julc/src/test/java/com/bloxbean/cardano/zeroj/onchain/julc/PlonkBLS12381FullVerifierTest.java
+++ b/zeroj-onchain-julc/src/test/java/com/bloxbean/cardano/zeroj/onchain/julc/plonk/validator/PlonkBLS12381FullVerifierTest.java
@@ -1,4 +1,4 @@
-package com.bloxbean.cardano.zeroj.onchain.julc;
+package com.bloxbean.cardano.zeroj.onchain.julc.plonk.validator;
import com.bloxbean.cardano.julc.core.PlutusData;
import com.bloxbean.cardano.julc.testkit.ContractTest;
From 029cd505fad5b9fbe9c5a61808fb447236de446e Mon Sep 17 00:00:00 2001
From: Satya Cardano-facing hash examples use explicit BLS12-381 Poseidon params
+ * instead. This class remains as the small MiMC symbolic adapter example. The bidder commits to their bid: {@code bidCommitment = MiMC(bidAmount, salt)}.
+ * The bidder commits to their bid:
+ * {@code bidCommitment = PoseidonBLS12_381(bidAmount, salt)}.
* The circuit proves two things: Signals: Wire layout (iden3 convention): [1, reservePrice, bidCommitment, isAboveReserve, bidAmount, salt, ...] Wire layout (iden3 convention): [1, bidCommitment, reservePrice, bidAmount, salt, ...] Handles the full lifecycle: Computes bidCommitment and isAboveReserve internally. Computes bidCommitment internally. Bids below reserve fail witness
+ * calculation because the reserve check is constrained inside the circuit. Produces the same output as the circuit-based {@code SignalMiMC.hash()} / {@code MiMC.hash()},
* allowing the prover to compute hash values before constructing the witness. MiMC-7 parameters: 91 rounds, S-box x^7, round constants = SHA-256("mimc_round_N"). The in-circuit MiMC gadget is BN254-only. Cardano-facing examples should
+ * use BLS12-381 Poseidon instead. Proves knowledge of N secret inputs whose sequential MiMC hash produces a
+ * Proves knowledge of N secret inputs whose sequential BLS12-381 Poseidon hash produces a
* known public commitment. Useful for committing to structured data (e.g., a record
* with multiple fields) without revealing any field.
+ * `MIMC` is the BN254/off-chain path. `POSEIDON` uses explicit BLS12-381
+ * params and is the Cardano-oriented path.
+ */
public enum HashType { MIMC, POSEIDON }
private final int depth;
diff --git a/zeroj-examples/src/main/java/com/bloxbean/cardano/zeroj/examples/dsl/voting/AnonymousVotingCircuit.java b/zeroj-examples/src/main/java/com/bloxbean/cardano/zeroj/examples/dsl/voting/AnonymousVotingCircuit.java
index 82f12ea..5828735 100644
--- a/zeroj-examples/src/main/java/com/bloxbean/cardano/zeroj/examples/dsl/voting/AnonymousVotingCircuit.java
+++ b/zeroj-examples/src/main/java/com/bloxbean/cardano/zeroj/examples/dsl/voting/AnonymousVotingCircuit.java
@@ -4,12 +4,14 @@
import com.bloxbean.cardano.zeroj.circuit.CircuitSpec;
import com.bloxbean.cardano.zeroj.circuit.Signal;
import com.bloxbean.cardano.zeroj.circuit.SignalBuilder;
-import com.bloxbean.cardano.zeroj.circuit.lib.SignalMiMC;
+import com.bloxbean.cardano.zeroj.circuit.lib.SignalPoseidon;
+import com.bloxbean.cardano.zeroj.circuit.lib.poseidon.PoseidonParamsBLS12_381T3;
/**
* Anonymous voting circuit — proves a vote is valid without revealing the choice.
*
- * The voter commits to their vote: {@code commitment = MiMC(vote, nullifier)}.
+ * The voter commits to their vote:
+ * {@code commitment = PoseidonBLS12_381(vote, nullifier)}.
* The nullifier prevents double-voting (revealed on-chain), while the vote remains private. Signals:
*
*
*/
public class SealedBidCircuit implements CircuitSpec {
@@ -31,32 +33,30 @@ public void define(SignalBuilder c) {
Signal bidAmount = c.privateInput("bidAmount");
Signal salt = c.privateInput("salt");
- // Public input — the auction's minimum price
- Signal reservePrice = c.publicInput("reservePrice");
-
- // Public outputs — verifiable by anyone
+ // Public values — verifiable by anyone and consumed by the on-chain verifier
Signal bidCommitment = c.publicOutput("bidCommitment");
- Signal isAboveReserve = c.publicOutput("isAboveReserve");
+ Signal reservePrice = c.publicInput("reservePrice");
- // Constraint 1: bidCommitment == MiMC(bidAmount, salt)
- c.assertEqual(SignalMiMC.hash(c, bidAmount, salt), bidCommitment);
+ // Constraint 1: bidCommitment == PoseidonBLS12_381(bidAmount, salt)
+ c.assertEqual(
+ SignalPoseidon.hash(c, PoseidonParamsBLS12_381T3.INSTANCE, bidAmount, salt),
+ bidCommitment);
- // Constraint 2: isAboveReserve == (bidAmount >= reservePrice) ? 1 : 0
+ // Constraint 2: bidAmount >= reservePrice must hold inside the proof.
c.assertEqual(
SignalComparators.greaterOrEqual(c, bidAmount, reservePrice, 64),
- isAboveReserve);
+ c.constant(1));
}
/**
* Build a complete circuit with all signals declared.
*
- *
*
@@ -30,6 +30,9 @@ public class SealedBidProofHelper {
private final CurveId curve;
public SealedBidProofHelper(CurveId curve) {
+ if (curve != CurveId.BLS12_381) {
+ throw new IllegalArgumentException("SealedBidCircuit uses explicit BLS12-381 Poseidon params");
+ }
this.curve = curve;
}
@@ -42,33 +45,32 @@ public byte[] generateR1CS() {
}
/**
- * Compute the bid commitment: MiMC(bidAmount, salt).
+ * Compute the bid commitment: PoseidonBLS12_381(bidAmount, salt).
*/
public BigInteger computeCommitment(BigInteger bidAmount, BigInteger salt) {
- return MiMCHash.hash(bidAmount, salt, FieldConfig.forCurve(curve).prime());
+ return PoseidonHash.hash(PoseidonParamsBLS12_381T3.INSTANCE, bidAmount, salt);
}
/**
* Generate .wtns binary for the given bid parameters.
*
- *