diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4e5652a..775a23e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -70,20 +70,20 @@ jobs: uses: dtolnay/rust-toolchain@stable - name: Build halo2 shared library - working-directory: zeroj-verifier-halo2/halo2-rust + working-directory: incubator/zeroj-verifier-halo2/halo2-rust run: cargo build --release - name: Copy library to resource path run: | - mkdir -p zeroj-verifier-halo2/src/main/resources/native/${{ matrix.os }} - cp zeroj-verifier-halo2/halo2-rust/target/release/${{ matrix.lib }} \ - zeroj-verifier-halo2/src/main/resources/native/${{ matrix.os }}/ + mkdir -p incubator/zeroj-verifier-halo2/src/main/resources/native/${{ matrix.os }} + cp incubator/zeroj-verifier-halo2/halo2-rust/target/release/${{ matrix.lib }} \ + incubator/zeroj-verifier-halo2/src/main/resources/native/${{ matrix.os }}/ - name: Upload native library uses: actions/upload-artifact@v4 with: name: halo2-native-${{ matrix.os }} - path: zeroj-verifier-halo2/src/main/resources/native/${{ matrix.os }}/${{ matrix.lib }} + path: incubator/zeroj-verifier-halo2/src/main/resources/native/${{ matrix.os }}/${{ matrix.lib }} retention-days: 1 # ================================================================ @@ -127,26 +127,26 @@ jobs: uses: actions/download-artifact@v4 with: name: halo2-native-linux-x86_64 - path: zeroj-verifier-halo2/src/main/resources/native/linux-x86_64/ + path: incubator/zeroj-verifier-halo2/src/main/resources/native/linux-x86_64/ - name: Download halo2 native (linux-arm64) uses: actions/download-artifact@v4 with: name: halo2-native-linux-arm64 - path: zeroj-verifier-halo2/src/main/resources/native/linux-arm64/ + path: incubator/zeroj-verifier-halo2/src/main/resources/native/linux-arm64/ - name: Download halo2 native (macos-arm64) uses: actions/download-artifact@v4 with: name: halo2-native-macos-arm64 - path: zeroj-verifier-halo2/src/main/resources/native/macos-arm64/ + path: incubator/zeroj-verifier-halo2/src/main/resources/native/macos-arm64/ - name: Verify native libraries are in place run: | echo "=== gnark native libraries ===" find zeroj-prover-gnark/src/main/resources/native -type f echo "=== halo2 native libraries ===" - find zeroj-verifier-halo2/src/main/resources/native -type f + find incubator/zeroj-verifier-halo2/src/main/resources/native -type f - name: Setup Gradle uses: gradle/actions/setup-gradle@v4 @@ -199,7 +199,7 @@ jobs: uses: actions/download-artifact@v4 with: name: halo2-native-${{ matrix.os }} - path: zeroj-verifier-halo2/src/main/resources/native/${{ matrix.os }}/ + path: incubator/zeroj-verifier-halo2/src/main/resources/native/${{ matrix.os }}/ - name: Setup Gradle uses: gradle/actions/setup-gradle@v4 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9334e83..4641444 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -69,20 +69,20 @@ jobs: uses: dtolnay/rust-toolchain@stable - name: Build halo2 shared library - working-directory: zeroj-verifier-halo2/halo2-rust + working-directory: incubator/zeroj-verifier-halo2/halo2-rust run: cargo build --release - name: Copy library to resource path run: | - mkdir -p zeroj-verifier-halo2/src/main/resources/native/${{ matrix.os }} - cp zeroj-verifier-halo2/halo2-rust/target/release/${{ matrix.lib }} \ - zeroj-verifier-halo2/src/main/resources/native/${{ matrix.os }}/ + mkdir -p incubator/zeroj-verifier-halo2/src/main/resources/native/${{ matrix.os }} + cp incubator/zeroj-verifier-halo2/halo2-rust/target/release/${{ matrix.lib }} \ + incubator/zeroj-verifier-halo2/src/main/resources/native/${{ matrix.os }}/ - name: Upload native library uses: actions/upload-artifact@v4 with: name: halo2-native-${{ matrix.os }} - path: zeroj-verifier-halo2/src/main/resources/native/${{ matrix.os }}/${{ matrix.lib }} + path: incubator/zeroj-verifier-halo2/src/main/resources/native/${{ matrix.os }}/${{ matrix.lib }} retention-days: 1 # ================================================================ @@ -125,14 +125,14 @@ jobs: cp gnark-native-$platform/* zeroj-prover-gnark/src/main/resources/native/$platform/ || true # halo2 - mkdir -p zeroj-verifier-halo2/src/main/resources/native/$platform - cp halo2-native-$platform/* zeroj-verifier-halo2/src/main/resources/native/$platform/ || true + mkdir -p incubator/zeroj-verifier-halo2/src/main/resources/native/$platform + cp halo2-native-$platform/* incubator/zeroj-verifier-halo2/src/main/resources/native/$platform/ || true done echo "=== gnark native libraries ===" find zeroj-prover-gnark/src/main/resources/native -type f echo "=== halo2 native libraries ===" - find zeroj-verifier-halo2/src/main/resources/native -type f + find incubator/zeroj-verifier-halo2/src/main/resources/native -type f - name: Setup Gradle uses: gradle/actions/setup-gradle@v4 diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml index b06d977..bff9fa4 100644 --- a/.github/workflows/snapshot.yml +++ b/.github/workflows/snapshot.yml @@ -67,20 +67,20 @@ jobs: uses: dtolnay/rust-toolchain@stable - name: Build halo2 shared library - working-directory: zeroj-verifier-halo2/halo2-rust + working-directory: incubator/zeroj-verifier-halo2/halo2-rust run: cargo build --release - name: Copy library to resource path run: | - mkdir -p zeroj-verifier-halo2/src/main/resources/native/${{ matrix.os }} - cp zeroj-verifier-halo2/halo2-rust/target/release/${{ matrix.lib }} \ - zeroj-verifier-halo2/src/main/resources/native/${{ matrix.os }}/ + mkdir -p incubator/zeroj-verifier-halo2/src/main/resources/native/${{ matrix.os }} + cp incubator/zeroj-verifier-halo2/halo2-rust/target/release/${{ matrix.lib }} \ + incubator/zeroj-verifier-halo2/src/main/resources/native/${{ matrix.os }}/ - name: Upload native library uses: actions/upload-artifact@v4 with: name: halo2-native-${{ matrix.os }} - path: zeroj-verifier-halo2/src/main/resources/native/${{ matrix.os }}/${{ matrix.lib }} + path: incubator/zeroj-verifier-halo2/src/main/resources/native/${{ matrix.os }}/${{ matrix.lib }} retention-days: 1 # ================================================================ @@ -126,26 +126,26 @@ jobs: uses: actions/download-artifact@v4 with: name: halo2-native-linux-x86_64 - path: zeroj-verifier-halo2/src/main/resources/native/linux-x86_64/ + path: incubator/zeroj-verifier-halo2/src/main/resources/native/linux-x86_64/ - name: Download halo2 native (linux-arm64) uses: actions/download-artifact@v4 with: name: halo2-native-linux-arm64 - path: zeroj-verifier-halo2/src/main/resources/native/linux-arm64/ + path: incubator/zeroj-verifier-halo2/src/main/resources/native/linux-arm64/ - name: Download halo2 native (macos-arm64) uses: actions/download-artifact@v4 with: name: halo2-native-macos-arm64 - path: zeroj-verifier-halo2/src/main/resources/native/macos-arm64/ + path: incubator/zeroj-verifier-halo2/src/main/resources/native/macos-arm64/ - name: Verify native libraries are in place run: | echo "=== gnark native libraries ===" find zeroj-prover-gnark/src/main/resources/native -type f echo "=== halo2 native libraries ===" - find zeroj-verifier-halo2/src/main/resources/native -type f + find incubator/zeroj-verifier-halo2/src/main/resources/native -type f - name: Setup Gradle uses: gradle/actions/setup-gradle@v4 diff --git a/.gitignore b/.gitignore index 4672b56..532d021 100644 --- a/.gitignore +++ b/.gitignore @@ -62,6 +62,7 @@ zeroj-test-vectors/scripts/build-plonk/ *.r1cs *.sym *.ptau +!zeroj-crypto/src/test/resources/test-circuits/plonk-multiplier/pot8_final.ptau ### Node.js (circom tooling) ### node_modules/ diff --git a/zeroj-api/src/main/java/com/bloxbean/cardano/zeroj/api/R1CSConstraint.java b/zeroj-api/src/main/java/com/bloxbean/cardano/zeroj/api/R1CSConstraint.java new file mode 100644 index 0000000..17ded01 --- /dev/null +++ b/zeroj-api/src/main/java/com/bloxbean/cardano/zeroj/api/R1CSConstraint.java @@ -0,0 +1,16 @@ +package com.bloxbean.cardano.zeroj.api; + +import java.math.BigInteger; +import java.util.Map; + +/** + * A single R1CS (Rank-1 Constraint System) constraint of the form + * {@code (A · w) × (B · w) = (C · w)}, where {@code A}, {@code B}, and + * {@code C} are sparse vectors mapping wire indices to field coefficients + * and {@code w} is the witness vector. + */ +public record R1CSConstraint( + Map a, + Map b, + Map c +) {} diff --git a/zeroj-circuit-dsl/src/main/java/com/bloxbean/cardano/zeroj/circuit/r1cs/R1CSCompiler.java b/zeroj-circuit-dsl/src/main/java/com/bloxbean/cardano/zeroj/circuit/r1cs/R1CSCompiler.java index c0a4f88..5438e12 100644 --- a/zeroj-circuit-dsl/src/main/java/com/bloxbean/cardano/zeroj/circuit/r1cs/R1CSCompiler.java +++ b/zeroj-circuit-dsl/src/main/java/com/bloxbean/cardano/zeroj/circuit/r1cs/R1CSCompiler.java @@ -1,5 +1,6 @@ package com.bloxbean.cardano.zeroj.circuit.r1cs; +import com.bloxbean.cardano.zeroj.api.R1CSConstraint; import com.bloxbean.cardano.zeroj.circuit.*; import java.math.BigInteger; @@ -38,7 +39,7 @@ public static R1CSConstraintSystem compile(ConstraintGraph graph, FieldConfig co exprMap.put(v.id(), Map.of(v.id(), BigInteger.ONE)); } - List constraints = new ArrayList<>(); + List constraints = new ArrayList<>(); for (var gate : graph.gates()) { switch (gate) { @@ -73,7 +74,7 @@ public static R1CSConstraintSystem compile(ConstraintGraph graph, FieldConfig co var a = getExpr(exprMap, left.id()); var b = getExpr(exprMap, right.id()); var c = Map.of(out.id(), BigInteger.ONE); - constraints.add(new R1CSConstraintSystem.R1CSConstraint(a, b, c)); + constraints.add(new R1CSConstraint(a, b, c)); // Multiplication output is a new base variable exprMap.put(out.id(), Map.of(out.id(), BigInteger.ONE)); } @@ -84,7 +85,7 @@ public static R1CSConstraintSystem compile(ConstraintGraph graph, FieldConfig co var rightExpr = getExpr(exprMap, right.id()); var diff = subExprs(leftExpr, rightExpr, p); if (!diff.isEmpty()) { - constraints.add(new R1CSConstraintSystem.R1CSConstraint( + constraints.add(new R1CSConstraint( diff, Map.of(graph.oneWire().id(), BigInteger.ONE), Map.of() // = 0 diff --git a/zeroj-circuit-dsl/src/main/java/com/bloxbean/cardano/zeroj/circuit/r1cs/R1CSConstraintSystem.java b/zeroj-circuit-dsl/src/main/java/com/bloxbean/cardano/zeroj/circuit/r1cs/R1CSConstraintSystem.java index 92b1356..fe5ac97 100644 --- a/zeroj-circuit-dsl/src/main/java/com/bloxbean/cardano/zeroj/circuit/r1cs/R1CSConstraintSystem.java +++ b/zeroj-circuit-dsl/src/main/java/com/bloxbean/cardano/zeroj/circuit/r1cs/R1CSConstraintSystem.java @@ -1,10 +1,10 @@ package com.bloxbean.cardano.zeroj.circuit.r1cs; +import com.bloxbean.cardano.zeroj.api.R1CSConstraint; import com.bloxbean.cardano.zeroj.circuit.FieldConfig; import java.math.BigInteger; import java.util.List; -import java.util.Map; /** * A compiled R1CS (Rank-1 Constraint System) for Groth16 proving. @@ -19,19 +19,6 @@ public record R1CSConstraintSystem( int numPrivateInputs, List constraints ) { - /** - * A single R1CS constraint: (A · w) × (B · w) = (C · w). - * - * @param a sparse vector: wire index → coefficient - * @param b sparse vector - * @param c sparse vector - */ - public record R1CSConstraint( - Map a, - Map b, - Map c - ) {} - public BigInteger prime() { return fieldConfig.prime(); } public int numConstraints() { return constraints.size(); } } diff --git a/zeroj-crypto/src/main/java/com/bloxbean/cardano/zeroj/crypto/groth16/Groth16Prover.java b/zeroj-crypto/src/main/java/com/bloxbean/cardano/zeroj/crypto/groth16/Groth16Prover.java index 1a58663..d8dbdf4 100644 --- a/zeroj-crypto/src/main/java/com/bloxbean/cardano/zeroj/crypto/groth16/Groth16Prover.java +++ b/zeroj-crypto/src/main/java/com/bloxbean/cardano/zeroj/crypto/groth16/Groth16Prover.java @@ -1,5 +1,6 @@ package com.bloxbean.cardano.zeroj.crypto.groth16; +import com.bloxbean.cardano.zeroj.api.R1CSConstraint; import com.bloxbean.cardano.zeroj.crypto.ec.JacobianG1BN254; import com.bloxbean.cardano.zeroj.crypto.ec.JacobianG1BN254.AffineG1; import com.bloxbean.cardano.zeroj.crypto.ec.JacobianG2BN254; @@ -10,6 +11,7 @@ import java.math.BigInteger; import java.security.SecureRandom; +import java.util.List; import java.util.Map; /** @@ -47,7 +49,7 @@ private Groth16Prover() {} public static Groth16Proof prove( Groth16ProvingKey pk, BigInteger[] witness, - R1CSConstraint[] constraints, + List constraints, int numWires) { // Domain size = length of H points array in proving key int domainSize = pk.pointsH().length; @@ -57,7 +59,7 @@ public static Groth16Proof prove( public static Groth16Proof prove( Groth16ProvingKey pk, BigInteger[] witness, - R1CSConstraint[] constraints, + List constraints, int numWires, int domainSize) { @@ -82,7 +84,7 @@ public static Groth16Proof prove( if (!pk.deltaG2().isOnCurve()) throw new IllegalArgumentException("Proving key deltaG2 is not on curve"); - int numConstraints = constraints.length; + int numConstraints = constraints.size(); // Note: witness validation is available via validateWitness() for R1CS-standard constraints. // Not called here because .zkey Section 4 constraints use a different encoding @@ -102,8 +104,8 @@ public static Groth16Proof prove( /** Prove without blinding (r=0, s=0) — for debugging only. */ static Groth16Proof proveUnblinded( Groth16ProvingKey pk, BigInteger[] witness, - R1CSConstraint[] constraints, int numWires, int domainSize) { - BigInteger[] hCoeffs = computeH(constraints, witness, constraints.length, domainSize); + List constraints, int numWires, int domainSize) { + BigInteger[] hCoeffs = computeH(constraints, witness, constraints.size(), domainSize); BigInteger r = BigInteger.ZERO; BigInteger s = BigInteger.ZERO; return proveInternal(pk, witness, hCoeffs, r, s); @@ -146,7 +148,7 @@ private static Groth16Proof proveInternal( *

The coset generator is omega_{2n} = the primitive (2*domainSize)-th root of unity, * which equals the square root of the domain's omega_n.

*/ - static BigInteger[] computeH(R1CSConstraint[] constraints, BigInteger[] witness, + static BigInteger[] computeH(List constraints, BigInteger[] witness, int numConstraints, int domainSize) { BigInteger mod = MontFr254.modulus(); if (domainSize < 2) domainSize = 2; @@ -156,10 +158,12 @@ static BigInteger[] computeH(R1CSConstraint[] constraints, BigInteger[] witness, MontFr254[] aEval = new MontFr254[domainSize]; MontFr254[] bEval = new MontFr254[domainSize]; + int constraintCount = constraints.size(); for (int i = 0; i < domainSize; i++) { - if (i < numConstraints && i < constraints.length) { - aEval[i] = evalLinComb(constraints[i].a(), witness, mod); - bEval[i] = evalLinComb(constraints[i].b(), witness, mod); + if (i < numConstraints && i < constraintCount) { + R1CSConstraint constraint = constraints.get(i); + aEval[i] = evalLinComb(constraint.a(), witness, mod); + bEval[i] = evalLinComb(constraint.b(), witness, mod); } else { aEval[i] = MontFr254.ZERO; bEval[i] = MontFr254.ZERO; @@ -389,10 +393,10 @@ private static BigInteger randomScalar(SecureRandom rng) { *

Use this with standard R1CS constraints (from .r1cs files), NOT with .zkey * Section 4 constraints which use a different encoding where C is implicit.

*/ - public static void validateWitness(R1CSConstraint[] constraints, BigInteger[] witness, int numConstraints) { + public static void validateWitness(List constraints, BigInteger[] witness, int numConstraints) { BigInteger mod = MontFr254.modulus(); for (int i = 0; i < numConstraints; i++) { - var c = constraints[i]; + var c = constraints.get(i); // Empty constraints (0*0=0) are trivially satisfied — skip if (c.a().isEmpty() && c.b().isEmpty() && c.c().isEmpty()) continue; @@ -423,10 +427,4 @@ private static BigInteger evalLCBigInt(Map lc, BigInteger[] return sum.mod(mod); } - /** R1CS constraint: A · w × B · w = C · w */ - public record R1CSConstraint( - Map a, - Map b, - Map c - ) {} } diff --git a/zeroj-crypto/src/main/java/com/bloxbean/cardano/zeroj/crypto/groth16/Groth16ProverBLS381.java b/zeroj-crypto/src/main/java/com/bloxbean/cardano/zeroj/crypto/groth16/Groth16ProverBLS381.java index 6f6ddfc..0719b84 100644 --- a/zeroj-crypto/src/main/java/com/bloxbean/cardano/zeroj/crypto/groth16/Groth16ProverBLS381.java +++ b/zeroj-crypto/src/main/java/com/bloxbean/cardano/zeroj/crypto/groth16/Groth16ProverBLS381.java @@ -1,5 +1,6 @@ package com.bloxbean.cardano.zeroj.crypto.groth16; +import com.bloxbean.cardano.zeroj.api.R1CSConstraint; import com.bloxbean.cardano.zeroj.crypto.ec.JacobianG1BLS381; import com.bloxbean.cardano.zeroj.crypto.ec.JacobianG1BLS381.AffineG1; import com.bloxbean.cardano.zeroj.crypto.ec.JacobianG2BLS381; @@ -10,6 +11,7 @@ import java.math.BigInteger; import java.security.SecureRandom; +import java.util.List; import java.util.Map; /** @@ -24,7 +26,7 @@ private Groth16ProverBLS381() {} public static Groth16ProofBLS381 prove( Groth16ProvingKeyBLS381 pk, BigInteger[] witness, - Groth16Prover.R1CSConstraint[] constraints, + List constraints, int numWires) { int domainSize = pk.pointsH().length; return prove(pk, witness, constraints, numWires, domainSize); @@ -33,7 +35,7 @@ public static Groth16ProofBLS381 prove( public static Groth16ProofBLS381 prove( Groth16ProvingKeyBLS381 pk, BigInteger[] witness, - Groth16Prover.R1CSConstraint[] constraints, + List constraints, int numWires, int domainSize) { @@ -56,7 +58,7 @@ public static Groth16ProofBLS381 prove( if (!pk.deltaG2().isOnCurve()) throw new IllegalArgumentException("Proving key deltaG2 is not on curve"); - int numConstraints = constraints.length; + int numConstraints = constraints.size(); BigInteger[] hCoeffs = computeH(constraints, witness, numConstraints, domainSize); var rng = new SecureRandom(); @@ -68,8 +70,8 @@ public static Groth16ProofBLS381 prove( static Groth16ProofBLS381 proveUnblinded( Groth16ProvingKeyBLS381 pk, BigInteger[] witness, - Groth16Prover.R1CSConstraint[] constraints, int numWires, int domainSize) { - BigInteger[] hCoeffs = computeH(constraints, witness, constraints.length, domainSize); + List constraints, int numWires, int domainSize) { + BigInteger[] hCoeffs = computeH(constraints, witness, constraints.size(), domainSize); return proveInternal(pk, witness, hCoeffs, BigInteger.ZERO, BigInteger.ZERO); } @@ -85,7 +87,7 @@ private static Groth16ProofBLS381 proveInternal( return new Groth16ProofBLS381(piA.toAffine(), piB.toAffine(), piC.toAffine()); } - static BigInteger[] computeH(Groth16Prover.R1CSConstraint[] constraints, BigInteger[] witness, + static BigInteger[] computeH(List constraints, BigInteger[] witness, int numConstraints, int domainSize) { BigInteger mod = MontFr381.modulus(); if (domainSize < 2) domainSize = 2; @@ -94,10 +96,12 @@ static BigInteger[] computeH(Groth16Prover.R1CSConstraint[] constraints, BigInte MontFr381[] aEval = new MontFr381[domainSize]; MontFr381[] bEval = new MontFr381[domainSize]; + int constraintCount = constraints.size(); for (int i = 0; i < domainSize; i++) { - if (i < numConstraints && i < constraints.length) { - aEval[i] = evalLinComb(constraints[i].a(), witness, mod); - bEval[i] = evalLinComb(constraints[i].b(), witness, mod); + if (i < numConstraints && i < constraintCount) { + R1CSConstraint constraint = constraints.get(i); + aEval[i] = evalLinComb(constraint.a(), witness, mod); + bEval[i] = evalLinComb(constraint.b(), witness, mod); } else { aEval[i] = MontFr381.ZERO; bEval[i] = MontFr381.ZERO; diff --git a/zeroj-crypto/src/main/java/com/bloxbean/cardano/zeroj/crypto/groth16/R1CSImporter.java b/zeroj-crypto/src/main/java/com/bloxbean/cardano/zeroj/crypto/groth16/R1CSImporter.java index 98920b1..b59fa1b 100644 --- a/zeroj-crypto/src/main/java/com/bloxbean/cardano/zeroj/crypto/groth16/R1CSImporter.java +++ b/zeroj-crypto/src/main/java/com/bloxbean/cardano/zeroj/crypto/groth16/R1CSImporter.java @@ -1,5 +1,7 @@ package com.bloxbean.cardano.zeroj.crypto.groth16; +import com.bloxbean.cardano.zeroj.api.R1CSConstraint; + import java.io.IOException; import java.io.InputStream; import java.math.BigInteger; @@ -66,12 +68,12 @@ public static R1CSData importR1CS(InputStream input) throws IOException { // Section 2: Constraints buf.position((int) sections.get(2)[0]); - var constraints = new Groth16Prover.R1CSConstraint[nConstraints]; + List constraints = new ArrayList<>(nConstraints); for (int i = 0; i < nConstraints; i++) { var a = readLC(buf, n8); var b = readLC(buf, n8); var c = readLC(buf, n8); - constraints[i] = new Groth16Prover.R1CSConstraint(a, b, c); + constraints.add(new R1CSConstraint(a, b, c)); } return new R1CSData(prime, nWires, nPubOut + nPubIn, nConstraints, constraints); @@ -102,6 +104,6 @@ public record R1CSData( int numWires, int numPublic, int numConstraints, - Groth16Prover.R1CSConstraint[] constraints + List constraints ) {} } diff --git a/zeroj-crypto/src/main/java/com/bloxbean/cardano/zeroj/crypto/groth16/ZkeyData.java b/zeroj-crypto/src/main/java/com/bloxbean/cardano/zeroj/crypto/groth16/ZkeyData.java index 46c4a58..662739b 100644 --- a/zeroj-crypto/src/main/java/com/bloxbean/cardano/zeroj/crypto/groth16/ZkeyData.java +++ b/zeroj-crypto/src/main/java/com/bloxbean/cardano/zeroj/crypto/groth16/ZkeyData.java @@ -1,5 +1,9 @@ package com.bloxbean.cardano.zeroj.crypto.groth16; +import com.bloxbean.cardano.zeroj.api.R1CSConstraint; + +import java.util.List; + /** * Complete data from a parsed .zkey file: proving key + R1CS constraints. * @@ -8,7 +12,7 @@ */ public record ZkeyData( Groth16ProvingKey provingKey, - Groth16Prover.R1CSConstraint[] constraints, + List constraints, int numConstraints, int numWires, int domainSize diff --git a/zeroj-crypto/src/main/java/com/bloxbean/cardano/zeroj/crypto/groth16/ZkeyDataBLS381.java b/zeroj-crypto/src/main/java/com/bloxbean/cardano/zeroj/crypto/groth16/ZkeyDataBLS381.java index f7861a1..b384a15 100644 --- a/zeroj-crypto/src/main/java/com/bloxbean/cardano/zeroj/crypto/groth16/ZkeyDataBLS381.java +++ b/zeroj-crypto/src/main/java/com/bloxbean/cardano/zeroj/crypto/groth16/ZkeyDataBLS381.java @@ -1,11 +1,15 @@ package com.bloxbean.cardano.zeroj.crypto.groth16; +import com.bloxbean.cardano.zeroj.api.R1CSConstraint; + +import java.util.List; + /** * Complete data from a parsed BLS12-381 .zkey file: proving key + R1CS constraints. */ public record ZkeyDataBLS381( Groth16ProvingKeyBLS381 provingKey, - Groth16Prover.R1CSConstraint[] constraints, + List constraints, int numConstraints, int numWires, int domainSize diff --git a/zeroj-crypto/src/main/java/com/bloxbean/cardano/zeroj/crypto/groth16/ZkeyImporter.java b/zeroj-crypto/src/main/java/com/bloxbean/cardano/zeroj/crypto/groth16/ZkeyImporter.java index 811f747..165d7cc 100644 --- a/zeroj-crypto/src/main/java/com/bloxbean/cardano/zeroj/crypto/groth16/ZkeyImporter.java +++ b/zeroj-crypto/src/main/java/com/bloxbean/cardano/zeroj/crypto/groth16/ZkeyImporter.java @@ -1,5 +1,6 @@ package com.bloxbean.cardano.zeroj.crypto.groth16; +import com.bloxbean.cardano.zeroj.api.R1CSConstraint; import com.bloxbean.cardano.zeroj.crypto.ec.JacobianG1BN254.AffineG1; import com.bloxbean.cardano.zeroj.crypto.ec.JacobianG2BN254.AffineG2; import com.bloxbean.cardano.zeroj.crypto.field.MontFp254; @@ -170,9 +171,9 @@ public static ZkeyData importZkeyFull(byte[] data) throws IOException { actualConstraints = i + 1; } } - var constraints = new Groth16Prover.R1CSConstraint[numConstraints]; + List constraints = new ArrayList<>(numConstraints); for (int i = 0; i < numConstraints; i++) { - constraints[i] = new Groth16Prover.R1CSConstraint(aMap[i], bMap[i], cMap[i]); + constraints.add(new R1CSConstraint(aMap[i], bMap[i], cMap[i])); } // Section 5: A points in G1 diff --git a/zeroj-crypto/src/main/java/com/bloxbean/cardano/zeroj/crypto/groth16/ZkeyImporterBLS381.java b/zeroj-crypto/src/main/java/com/bloxbean/cardano/zeroj/crypto/groth16/ZkeyImporterBLS381.java index d4ca713..4702f50 100644 --- a/zeroj-crypto/src/main/java/com/bloxbean/cardano/zeroj/crypto/groth16/ZkeyImporterBLS381.java +++ b/zeroj-crypto/src/main/java/com/bloxbean/cardano/zeroj/crypto/groth16/ZkeyImporterBLS381.java @@ -1,5 +1,6 @@ package com.bloxbean.cardano.zeroj.crypto.groth16; +import com.bloxbean.cardano.zeroj.api.R1CSConstraint; import com.bloxbean.cardano.zeroj.crypto.ec.JacobianG1BLS381.AffineG1; import com.bloxbean.cardano.zeroj.crypto.ec.JacobianG2BLS381.AffineG2; import com.bloxbean.cardano.zeroj.crypto.field.MontFp381; @@ -146,9 +147,9 @@ public static ZkeyDataBLS381 importZkeyFull(byte[] data) throws IOException { actualConstraints = i + 1; } } - var constraints = new Groth16Prover.R1CSConstraint[numConstraints]; + List constraints = new ArrayList<>(numConstraints); for (int i = 0; i < numConstraints; i++) { - constraints[i] = new Groth16Prover.R1CSConstraint(aMap[i], bMap[i], cMap[i]); + constraints.add(new R1CSConstraint(aMap[i], bMap[i], cMap[i])); } // Section 5: A points in G1 diff --git a/zeroj-crypto/src/main/java/com/bloxbean/cardano/zeroj/crypto/setup/Groth16Setup.java b/zeroj-crypto/src/main/java/com/bloxbean/cardano/zeroj/crypto/setup/Groth16Setup.java index dc1ffcb..5e8db55 100644 --- a/zeroj-crypto/src/main/java/com/bloxbean/cardano/zeroj/crypto/setup/Groth16Setup.java +++ b/zeroj-crypto/src/main/java/com/bloxbean/cardano/zeroj/crypto/setup/Groth16Setup.java @@ -1,17 +1,18 @@ package com.bloxbean.cardano.zeroj.crypto.setup; +import com.bloxbean.cardano.zeroj.api.R1CSConstraint; import com.bloxbean.cardano.zeroj.crypto.ec.JacobianG1BN254; import com.bloxbean.cardano.zeroj.crypto.ec.JacobianG1BN254.AffineG1; import com.bloxbean.cardano.zeroj.crypto.ec.JacobianG2BN254; import com.bloxbean.cardano.zeroj.crypto.ec.JacobianG2BN254.AffineG2; import com.bloxbean.cardano.zeroj.crypto.field.MontFr254; import com.bloxbean.cardano.zeroj.crypto.groth16.Groth16ProvingKey; -import com.bloxbean.cardano.zeroj.crypto.groth16.Groth16Prover.R1CSConstraint; import com.bloxbean.cardano.zeroj.crypto.poly.FieldFFT; import java.math.BigInteger; import java.security.SecureRandom; import java.util.Arrays; +import java.util.List; import java.util.Map; /** @@ -47,14 +48,14 @@ private Groth16Setup() {} * @param tau the toxic waste from PowersOfTau (KNOWN — dev/test only) * @return Groth16 proving key ready for Groth16Prover.prove() */ - public static Groth16ProvingKey setup(R1CSConstraint[] constraints, int numWires, + public static Groth16ProvingKey setup(List constraints, int numWires, int numPublic, BigInteger tau) { System.err.println("WARNING: Single-party Groth16 Phase 2 setup — " + "for DEVELOPMENT and TESTING only. " + "Use snarkjs multi-party ceremony for production."); var rng = new SecureRandom(); - int nConstraints = constraints.length; + int nConstraints = constraints.size(); // Domain size: next power of 2 >= nConstraints int domainSize = Integer.highestOneBit(nConstraints); @@ -104,7 +105,7 @@ public static Groth16ProvingKey setup(R1CSConstraint[] constraints, int numWires Arrays.fill(ws, BigInteger.ZERO); for (int c = 0; c < nConstraints && c < domainSize; c++) { - var constraint = constraints[c]; + var constraint = constraints.get(c); BigInteger lc = lagrange[c]; accumulate(us, constraint.a(), lc); accumulate(vs, constraint.b(), lc); diff --git a/zeroj-crypto/src/main/java/com/bloxbean/cardano/zeroj/crypto/setup/Groth16SetupBLS381.java b/zeroj-crypto/src/main/java/com/bloxbean/cardano/zeroj/crypto/setup/Groth16SetupBLS381.java index 3374ad8..c75a306 100644 --- a/zeroj-crypto/src/main/java/com/bloxbean/cardano/zeroj/crypto/setup/Groth16SetupBLS381.java +++ b/zeroj-crypto/src/main/java/com/bloxbean/cardano/zeroj/crypto/setup/Groth16SetupBLS381.java @@ -1,17 +1,18 @@ package com.bloxbean.cardano.zeroj.crypto.setup; +import com.bloxbean.cardano.zeroj.api.R1CSConstraint; import com.bloxbean.cardano.zeroj.crypto.ec.JacobianG1BLS381; import com.bloxbean.cardano.zeroj.crypto.ec.JacobianG1BLS381.AffineG1; import com.bloxbean.cardano.zeroj.crypto.ec.JacobianG2BLS381; import com.bloxbean.cardano.zeroj.crypto.ec.JacobianG2BLS381.AffineG2; import com.bloxbean.cardano.zeroj.crypto.field.MontFr381; import com.bloxbean.cardano.zeroj.crypto.groth16.Groth16ProvingKeyBLS381; -import com.bloxbean.cardano.zeroj.crypto.groth16.Groth16Prover.R1CSConstraint; import com.bloxbean.cardano.zeroj.crypto.poly.FieldFFTBLS381; import java.math.BigInteger; import java.security.SecureRandom; import java.util.Arrays; +import java.util.List; import java.util.Map; /** @@ -47,14 +48,14 @@ private Groth16SetupBLS381() {} * @param tau the toxic waste from PowersOfTauBLS381 (KNOWN — dev/test only) * @return Groth16 proving key ready for Groth16ProverBLS381.prove() */ - public static SetupResult setup(R1CSConstraint[] constraints, int numWires, + public static SetupResult setup(List constraints, int numWires, int numPublic, BigInteger tau) { System.err.println("WARNING: Single-party Groth16 Phase 2 setup (BLS12-381) — " + "for DEVELOPMENT and TESTING only. " + "Use snarkjs multi-party ceremony for production."); var rng = new SecureRandom(); - int nConstraints = constraints.length; + int nConstraints = constraints.size(); // Domain size: next power of 2 >= nConstraints int domainSize = Integer.highestOneBit(nConstraints); @@ -104,7 +105,7 @@ public static SetupResult setup(R1CSConstraint[] constraints, int numWires, Arrays.fill(ws, BigInteger.ZERO); for (int c = 0; c < nConstraints && c < domainSize; c++) { - var constraint = constraints[c]; + var constraint = constraints.get(c); BigInteger lc = lagrange[c]; accumulate(us, constraint.a(), lc); accumulate(vs, constraint.b(), lc); diff --git a/zeroj-crypto/src/test/java/com/bloxbean/cardano/zeroj/crypto/groth16/Groth16BLS381EndToEndTest.java b/zeroj-crypto/src/test/java/com/bloxbean/cardano/zeroj/crypto/groth16/Groth16BLS381EndToEndTest.java index ad595b4..cf288a0 100644 --- a/zeroj-crypto/src/test/java/com/bloxbean/cardano/zeroj/crypto/groth16/Groth16BLS381EndToEndTest.java +++ b/zeroj-crypto/src/test/java/com/bloxbean/cardano/zeroj/crypto/groth16/Groth16BLS381EndToEndTest.java @@ -1,5 +1,6 @@ package com.bloxbean.cardano.zeroj.crypto.groth16; +import com.bloxbean.cardano.zeroj.api.R1CSConstraint; import com.bloxbean.cardano.zeroj.crypto.ec.JacobianG1BLS381; import com.bloxbean.cardano.zeroj.crypto.ec.JacobianG2BLS381; import com.bloxbean.cardano.zeroj.crypto.setup.Groth16SetupBLS381; @@ -8,6 +9,7 @@ import org.junit.jupiter.api.Test; import java.math.BigInteger; +import java.util.List; import java.util.Map; import static org.junit.jupiter.api.Assertions.*; @@ -24,12 +26,12 @@ class Groth16BLS381EndToEndTest { void fullPipeline_multiplier_proveAndPairingVerify() { // Circuit: c = a * b (multiplier) // R1CS: 1 constraint, 4 wires [1, c, a, b] - var constraints = new Groth16Prover.R1CSConstraint[]{ - new Groth16Prover.R1CSConstraint( + var constraints = List.of( + new R1CSConstraint( Map.of(2, BigInteger.ONE), // A: wire 2 (a) Map.of(3, BigInteger.ONE), // B: wire 3 (b) Map.of(1, BigInteger.ONE)) // C: wire 1 (c) - }; + ); int numWires = 4; int numPublic = 1; // wire 1 = c (public output) diff --git a/zeroj-crypto/src/test/java/com/bloxbean/cardano/zeroj/crypto/groth16/Groth16ProverTest.java b/zeroj-crypto/src/test/java/com/bloxbean/cardano/zeroj/crypto/groth16/Groth16ProverTest.java index fb421ab..ddcefd7 100644 --- a/zeroj-crypto/src/test/java/com/bloxbean/cardano/zeroj/crypto/groth16/Groth16ProverTest.java +++ b/zeroj-crypto/src/test/java/com/bloxbean/cardano/zeroj/crypto/groth16/Groth16ProverTest.java @@ -1,10 +1,11 @@ package com.bloxbean.cardano.zeroj.crypto.groth16; +import com.bloxbean.cardano.zeroj.api.R1CSConstraint; import com.bloxbean.cardano.zeroj.crypto.field.MontFr254; -import com.bloxbean.cardano.zeroj.crypto.groth16.Groth16Prover.R1CSConstraint; import org.junit.jupiter.api.Test; import java.math.BigInteger; +import java.util.List; import java.util.Map; import static org.junit.jupiter.api.Assertions.*; @@ -29,7 +30,7 @@ void computeH_multiplierCircuit() { // Constraint: (a) * (b) = (product) → A={2:1}, B={3:1}, C={4:1} // assertEqual: (product - c) * 1 = 0 → A={4:1, 1:-1}, B={0:1}, C={} - var constraints = new R1CSConstraint[]{ + var constraints = List.of( // a * b = product new R1CSConstraint( Map.of(2, BigInteger.ONE), // A: wire 2 (a) @@ -40,7 +41,7 @@ void computeH_multiplierCircuit() { Map.of(4, BigInteger.ONE, 1, R.subtract(BigInteger.ONE)), // A: product - c Map.of(0, BigInteger.ONE), // B: 1 Map.of()) // C: 0 - }; + ); // Witness: [1, 33, 3, 11, 33] BigInteger[] witness = { @@ -68,12 +69,12 @@ void computeH_multiplierCircuit() { @Test void computeH_trivialConstraint() { // Single constraint: 1 * 1 = 1 - var constraints = new R1CSConstraint[]{ + var constraints = List.of( new R1CSConstraint( Map.of(0, BigInteger.ONE), Map.of(0, BigInteger.ONE), Map.of(0, BigInteger.ONE)) - }; + ); BigInteger[] witness = {BigInteger.ONE}; // h(x) should be computable (may be zero polynomial for trivial cases) @@ -88,19 +89,19 @@ void computeH_adderCircuit() { // But we can express it as: (a + b) * 1 = sum // Wire 0=1, 1=sum(public), 2=a, 3=b - var constraints = new R1CSConstraint[]{ + var constraints = List.of( new R1CSConstraint( Map.of(2, BigInteger.ONE, 3, BigInteger.ONE), // A: a + b Map.of(0, BigInteger.ONE), // B: 1 Map.of(1, BigInteger.ONE)) // C: sum - }; + ); BigInteger[] witness = {BigInteger.ONE, BigInteger.valueOf(15), BigInteger.valueOf(7), BigInteger.valueOf(8)}; // Verify constraint: (7 + 8) * 1 = 15 ✓ - BigInteger aVal = evalLC(constraints[0].a(), witness); - BigInteger bVal = evalLC(constraints[0].b(), witness); - BigInteger cVal = evalLC(constraints[0].c(), witness); + BigInteger aVal = evalLC(constraints.get(0).a(), witness); + BigInteger bVal = evalLC(constraints.get(0).b(), witness); + BigInteger cVal = evalLC(constraints.get(0).c(), witness); assertEquals(aVal.multiply(bVal).mod(R), cVal); BigInteger[] h = Groth16Prover.computeH(constraints, witness, 1, 2); @@ -114,12 +115,12 @@ void computeH_invalidWitness_hNonZeroAtRoots() { // that doesn't divide evenly (remainder != 0). // We verify this doesn't crash, at minimum. - var constraints = new R1CSConstraint[]{ + var constraints = List.of( new R1CSConstraint( Map.of(1, BigInteger.ONE), Map.of(2, BigInteger.ONE), Map.of(3, BigInteger.ONE)) - }; + ); // Wrong witness: 3 * 11 != 99 BigInteger[] witness = {BigInteger.ONE, BigInteger.valueOf(3), BigInteger.valueOf(11), BigInteger.valueOf(99)}; diff --git a/zeroj-crypto/src/test/java/com/bloxbean/cardano/zeroj/crypto/setup/Groth16SetupTest.java b/zeroj-crypto/src/test/java/com/bloxbean/cardano/zeroj/crypto/setup/Groth16SetupTest.java index fbb86df..8267a64 100644 --- a/zeroj-crypto/src/test/java/com/bloxbean/cardano/zeroj/crypto/setup/Groth16SetupTest.java +++ b/zeroj-crypto/src/test/java/com/bloxbean/cardano/zeroj/crypto/setup/Groth16SetupTest.java @@ -3,7 +3,6 @@ import com.bloxbean.cardano.zeroj.api.CurveId; import com.bloxbean.cardano.zeroj.circuit.CircuitBuilder; import com.bloxbean.cardano.zeroj.crypto.groth16.Groth16Prover; -import com.bloxbean.cardano.zeroj.crypto.groth16.Groth16Prover.R1CSConstraint; import com.bloxbean.cardano.zeroj.verifier.groth16.bn254.*; import org.junit.jupiter.api.Test; @@ -34,9 +33,7 @@ void fullPipeline_multiplier_proveAndVerify() { var r1cs = circuit.compileR1CS(CurveId.BN254); // === Step 4: Convert R1CS constraints to prover format === - var constraints = r1cs.constraints().stream() - .map(c -> new R1CSConstraint(c.a(), c.b(), c.c())) - .toArray(R1CSConstraint[]::new); + var constraints = r1cs.constraints(); // === Step 5: Groth16 Phase 2 setup (pure Java!) === var pk = Groth16Setup.setup(constraints, r1cs.numWires(), @@ -97,9 +94,7 @@ void setup_provingKeyDimensions() { .define(api -> api.assertEqual(api.add(api.var("a"), api.var("b")), api.var("sum"))); var r1cs = circuit.compileR1CS(CurveId.BN254); - var constraints = r1cs.constraints().stream() - .map(c -> new R1CSConstraint(c.a(), c.b(), c.c())) - .toArray(R1CSConstraint[]::new); + var constraints = r1cs.constraints(); var pk = Groth16Setup.setup(constraints, r1cs.numWires(), r1cs.numPublicInputs(), srs.tauScalar()); diff --git a/zeroj-crypto/src/test/resources/test-circuits/plonk-multiplier/pot8_final.ptau b/zeroj-crypto/src/test/resources/test-circuits/plonk-multiplier/pot8_final.ptau new file mode 100644 index 0000000..8922d19 Binary files /dev/null and b/zeroj-crypto/src/test/resources/test-circuits/plonk-multiplier/pot8_final.ptau differ diff --git a/zeroj-examples/build.gradle b/zeroj-examples/build.gradle index 6cfa7c6..578f31e 100644 --- a/zeroj-examples/build.gradle +++ b/zeroj-examples/build.gradle @@ -6,7 +6,7 @@ plugins { description = 'ZeroJ end-to-end examples and demos' ext { - julcVersion = '0.1.0-pre10-7c66301-SNAPSHOT' + julcVersion = '0.1.0-pre11' cclVersion = '0.8.0-pre2' } 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 91995bf..4980562 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 @@ -13,10 +13,9 @@ import com.bloxbean.cardano.zeroj.api.CurveId; import com.bloxbean.cardano.zeroj.crypto.groth16.Groth16ProverBLS381; import com.bloxbean.cardano.zeroj.examples.dsl.multiplier.PrivateMultiplierCircuit; -import com.bloxbean.cardano.zeroj.crypto.groth16.Groth16Prover.R1CSConstraint; import com.bloxbean.cardano.zeroj.crypto.setup.Groth16SetupBLS381; import com.bloxbean.cardano.zeroj.crypto.setup.PowersOfTauBLS381; -import com.bloxbean.cardano.zeroj.examples.dsl.common.ProverToCardano; +import com.bloxbean.cardano.zeroj.onchain.julc.ProverToCardano; import com.bloxbean.cardano.zeroj.examples.dsl.common.YaciHelper; import com.bloxbean.cardano.zeroj.onchain.julc.Groth16BLS12381Verifier; import org.junit.jupiter.api.BeforeAll; @@ -99,9 +98,7 @@ void pureJavaProve_groth16_onChainVerify() throws Exception { var r1cs = circuit.compileR1CS(CurveId.BLS12_381); assertEquals(2, r1cs.numPublicInputs(), "Need exactly 2 public inputs for generic verifier"); - var constraints = r1cs.constraints().stream() - .map(c -> new R1CSConstraint(c.a(), c.b(), c.c())) - .toArray(R1CSConstraint[]::new); + var constraints = r1cs.constraints(); // 2. Witness: a=3, b=11, c=33 BigInteger[] witness = circuit.calculateWitness(Map.of( diff --git a/zeroj-examples/src/test/java/com/bloxbean/cardano/zeroj/examples/dsl/auction/SealedBidPureJavaE2ETest.java b/zeroj-examples/src/test/java/com/bloxbean/cardano/zeroj/examples/dsl/auction/SealedBidPureJavaE2ETest.java index f9aa698..1317fb0 100644 --- a/zeroj-examples/src/test/java/com/bloxbean/cardano/zeroj/examples/dsl/auction/SealedBidPureJavaE2ETest.java +++ b/zeroj-examples/src/test/java/com/bloxbean/cardano/zeroj/examples/dsl/auction/SealedBidPureJavaE2ETest.java @@ -2,7 +2,6 @@ import com.bloxbean.cardano.zeroj.api.CurveId; import com.bloxbean.cardano.zeroj.crypto.groth16.Groth16ProverBLS381; -import com.bloxbean.cardano.zeroj.crypto.groth16.Groth16Prover.R1CSConstraint; import com.bloxbean.cardano.zeroj.crypto.setup.Groth16SetupBLS381; import com.bloxbean.cardano.zeroj.crypto.setup.PowersOfTauBLS381; import com.bloxbean.cardano.zeroj.examples.dsl.common.MiMCHash; @@ -43,9 +42,7 @@ void devTau_sealedBid_fullStack() { // === Step 1: Circuit definition via Java DSL === var circuit = SealedBidCircuit.build(); var r1cs = circuit.compileR1CS(CurveId.BLS12_381); - var constraints = r1cs.constraints().stream() - .map(c -> new R1CSConstraint(c.a(), c.b(), c.c())) - .toArray(R1CSConstraint[]::new); + var constraints = r1cs.constraints(); System.out.println("SealedBid: " + r1cs.numConstraints() + " constraints, " + r1cs.numWires() + " wires"); diff --git a/zeroj-examples/src/test/java/com/bloxbean/cardano/zeroj/examples/dsl/balance/BalanceThresholdPureJavaE2ETest.java b/zeroj-examples/src/test/java/com/bloxbean/cardano/zeroj/examples/dsl/balance/BalanceThresholdPureJavaE2ETest.java index e563ca9..9a85a92 100644 --- a/zeroj-examples/src/test/java/com/bloxbean/cardano/zeroj/examples/dsl/balance/BalanceThresholdPureJavaE2ETest.java +++ b/zeroj-examples/src/test/java/com/bloxbean/cardano/zeroj/examples/dsl/balance/BalanceThresholdPureJavaE2ETest.java @@ -2,7 +2,6 @@ import com.bloxbean.cardano.zeroj.api.CurveId; import com.bloxbean.cardano.zeroj.crypto.groth16.Groth16ProverBLS381; -import com.bloxbean.cardano.zeroj.crypto.groth16.Groth16Prover.R1CSConstraint; import com.bloxbean.cardano.zeroj.crypto.setup.Groth16SetupBLS381; import com.bloxbean.cardano.zeroj.crypto.setup.PowersOfTauBLS381; import com.bloxbean.cardano.zeroj.verifier.groth16.bls12381.field.*; @@ -33,9 +32,7 @@ void devTau_balanceThreshold_fullStack() { // === Step 1: Circuit === var circuit = BalanceThresholdCircuit.build(); var r1cs = circuit.compileR1CS(CurveId.BLS12_381); - var constraints = r1cs.constraints().stream() - .map(c -> new R1CSConstraint(c.a(), c.b(), c.c())) - .toArray(R1CSConstraint[]::new); + var constraints = r1cs.constraints(); System.out.println("BalanceThreshold: " + r1cs.numConstraints() + " constraints, " + r1cs.numPublicInputs() + " public inputs"); diff --git a/zeroj-examples/src/test/java/com/bloxbean/cardano/zeroj/examples/dsl/templates/ParameterizedCircuitE2ETest.java b/zeroj-examples/src/test/java/com/bloxbean/cardano/zeroj/examples/dsl/templates/ParameterizedCircuitE2ETest.java index 4fa28d6..18ab938 100644 --- a/zeroj-examples/src/test/java/com/bloxbean/cardano/zeroj/examples/dsl/templates/ParameterizedCircuitE2ETest.java +++ b/zeroj-examples/src/test/java/com/bloxbean/cardano/zeroj/examples/dsl/templates/ParameterizedCircuitE2ETest.java @@ -4,7 +4,6 @@ import com.bloxbean.cardano.zeroj.circuit.CircuitBuilder; import com.bloxbean.cardano.zeroj.circuit.FieldConfig; import com.bloxbean.cardano.zeroj.crypto.groth16.Groth16ProverBLS381; -import com.bloxbean.cardano.zeroj.crypto.groth16.Groth16Prover.R1CSConstraint; import com.bloxbean.cardano.zeroj.crypto.setup.Groth16SetupBLS381; import com.bloxbean.cardano.zeroj.crypto.setup.PowersOfTauBLS381; import com.bloxbean.cardano.zeroj.examples.dsl.common.MiMCHash; @@ -232,9 +231,7 @@ private ProveResult proveMerkle(int depth, NWayMerkleCircuit.HashType hashType) private boolean proveAndVerify(CircuitBuilder circuit, com.bloxbean.cardano.zeroj.circuit.r1cs.R1CSConstraintSystem r1cs, BigInteger[] witness) { - var constraints = r1cs.constraints().stream() - .map(c -> new R1CSConstraint(c.a(), c.b(), c.c())) - .toArray(R1CSConstraint[]::new); + var constraints = r1cs.constraints(); int power = nextPowerOf2Log(r1cs.numConstraints()); var srs = PowersOfTauBLS381.generate(power); diff --git a/zeroj-examples/src/test/java/com/bloxbean/cardano/zeroj/examples/dsl/voting/AnonymousVotingPureJavaE2ETest.java b/zeroj-examples/src/test/java/com/bloxbean/cardano/zeroj/examples/dsl/voting/AnonymousVotingPureJavaE2ETest.java index 6cfb35f..3d8df97 100644 --- a/zeroj-examples/src/test/java/com/bloxbean/cardano/zeroj/examples/dsl/voting/AnonymousVotingPureJavaE2ETest.java +++ b/zeroj-examples/src/test/java/com/bloxbean/cardano/zeroj/examples/dsl/voting/AnonymousVotingPureJavaE2ETest.java @@ -2,7 +2,6 @@ import com.bloxbean.cardano.zeroj.api.CurveId; import com.bloxbean.cardano.zeroj.crypto.groth16.Groth16ProverBLS381; -import com.bloxbean.cardano.zeroj.crypto.groth16.Groth16Prover.R1CSConstraint; import com.bloxbean.cardano.zeroj.crypto.setup.Groth16SetupBLS381; import com.bloxbean.cardano.zeroj.crypto.setup.PowersOfTauBLS381; import com.bloxbean.cardano.zeroj.examples.dsl.common.MiMCHash; @@ -30,9 +29,7 @@ class AnonymousVotingPureJavaE2ETest { void devTau_voteYes_proveAndVerify() { var circuit = AnonymousVotingCircuit.build(); var r1cs = circuit.compileR1CS(CurveId.BLS12_381); - var constraints = r1cs.constraints().stream() - .map(c -> new R1CSConstraint(c.a(), c.b(), c.c())) - .toArray(R1CSConstraint[]::new); + var constraints = r1cs.constraints(); System.out.println("AnonymousVoting: " + r1cs.numConstraints() + " constraints"); @@ -70,9 +67,7 @@ void devTau_voteYes_proveAndVerify() { void devTau_voteNo_proveAndVerify() { var circuit = AnonymousVotingCircuit.build(); var r1cs = circuit.compileR1CS(CurveId.BLS12_381); - var constraints = r1cs.constraints().stream() - .map(c -> new R1CSConstraint(c.a(), c.b(), c.c())) - .toArray(R1CSConstraint[]::new); + var constraints = r1cs.constraints(); BigInteger vote = BigInteger.ZERO; // NO BigInteger nullifier = BigInteger.valueOf(67890); diff --git a/zeroj-onchain-julc/build.gradle b/zeroj-onchain-julc/build.gradle index 3bc719f..b9fe4f1 100644 --- a/zeroj-onchain-julc/build.gradle +++ b/zeroj-onchain-julc/build.gradle @@ -22,10 +22,13 @@ dependencies { api "com.bloxbean.cardano:julc-stdlib:${julcVersion}" annotationProcessor "com.bloxbean.cardano:julc-annotation-processor:${julcVersion}" - // ZeroJ — blst for point compression in SnarkjsToCardano + // ZeroJ — blst for point compression in SnarkjsToCardano / ProverToCardano api project(':zeroj-api') implementation project(':zeroj-blst') + // Pure Java prover types — used by ProverToCardano to compress prover output + implementation project(':zeroj-crypto') + // JSON parsing for SnarkjsToCardano implementation 'com.fasterxml.jackson.core:jackson-databind:2.18.2' @@ -34,8 +37,7 @@ dependencies { testImplementation "com.bloxbean.cardano:julc-compiler:${julcVersion}" testRuntimeOnly "com.bloxbean.cardano:julc-vm-java:${julcVersion}" - // Test — pure Java prover for on-chain verification tests - testImplementation project(':zeroj-crypto') + // Test — circuit DSL for on-chain verification tests testImplementation project(':zeroj-circuit-dsl') } diff --git a/zeroj-examples/src/main/java/com/bloxbean/cardano/zeroj/examples/dsl/common/ProverToCardano.java b/zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/ProverToCardano.java similarity index 92% rename from zeroj-examples/src/main/java/com/bloxbean/cardano/zeroj/examples/dsl/common/ProverToCardano.java rename to zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/ProverToCardano.java index daae63c..ed14159 100644 --- a/zeroj-examples/src/main/java/com/bloxbean/cardano/zeroj/examples/dsl/common/ProverToCardano.java +++ b/zeroj-onchain-julc/src/main/java/com/bloxbean/cardano/zeroj/onchain/julc/ProverToCardano.java @@ -1,10 +1,9 @@ -package com.bloxbean.cardano.zeroj.examples.dsl.common; +package com.bloxbean.cardano.zeroj.onchain.julc; import com.bloxbean.cardano.zeroj.crypto.ec.JacobianG1BLS381; import com.bloxbean.cardano.zeroj.crypto.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.SnarkjsToCardano; import supranational.blst.P1_Affine; import supranational.blst.P2_Affine; @@ -16,11 +15,13 @@ * Converts pure Java BLS12-381 prover output to compressed BLS point bytes * suitable for Cardano on-chain use (UPLC BLS12-381 builtins). * - *

Bridges zeroj-crypto prover types → zeroj-onchain-julc compressed format.

+ *

Bridges {@code zeroj-crypto} prover types to the on-chain Plutus V3 + * verifier in this module. Sibling of {@link SnarkjsToCardano}, which performs + * the same conversion from snarkjs JSON output.

* *

For production: Use this to convert proofs generated by the pure Java * prover ({@code Groth16ProverBLS381}) into the byte format expected by the - * on-chain Plutus V3 verifier ({@code Groth16BLS12381Verifier}).

+ * on-chain verifier ({@link Groth16BLS12381Verifier}).

*/ public final class ProverToCardano { 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/Groth16BLS12381PureJavaProverTest.java index b9379ab..383bcfd 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/Groth16BLS12381PureJavaProverTest.java @@ -6,7 +6,6 @@ import com.bloxbean.cardano.zeroj.crypto.ec.JacobianG2BLS381; import com.bloxbean.cardano.zeroj.crypto.groth16.Groth16ProverBLS381; import com.bloxbean.cardano.zeroj.crypto.groth16.Groth16ProofBLS381; -import com.bloxbean.cardano.zeroj.crypto.groth16.Groth16Prover.R1CSConstraint; import com.bloxbean.cardano.zeroj.crypto.setup.Groth16SetupBLS381; import com.bloxbean.cardano.zeroj.crypto.setup.PowersOfTauBLS381; import com.bloxbean.cardano.julc.core.PlutusData; @@ -50,9 +49,7 @@ void twoPublicInputs_pureJavaProve_onChainVerify() { var r1cs = circuit.compileR1CS(CurveId.BLS12_381); assertEquals(2, r1cs.numPublicInputs(), "Must have exactly 2 public inputs for generic verifier"); - var constraints = r1cs.constraints().stream() - .map(c -> new R1CSConstraint(c.a(), c.b(), c.c())) - .toArray(R1CSConstraint[]::new); + var constraints = r1cs.constraints(); // Witness: a=3, b=11, c=33 BigInteger[] witness = circuit.calculateWitness(Map.of(