Skip to content
Merged
6 changes: 6 additions & 0 deletions crates/batcher/go_verifiers_lib/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@ module verifier

go 1.22.3

replace github.com/iden3/go-rapidsnark => github.com/yetanotherco/go-rapidsnark v0.0.0-20250828172020-87df0a23ada4
Comment thread
MarcosNicolau marked this conversation as resolved.
Outdated

replace github.com/iden3/go-rapidsnark/types => github.com/yetanotherco/go-rapidsnark/types v0.0.0-20250828172020-87df0a23ada4
Comment thread
MarcosNicolau marked this conversation as resolved.
Outdated

replace github.com/iden3/go-rapidsnark/verifier => github.com/yetanotherco/go-rapidsnark/verifier v0.0.0-20250828172020-87df0a23ada4
Comment thread
MarcosNicolau marked this conversation as resolved.
Outdated

require (
github.com/consensys/gnark v0.12.0
github.com/consensys/gnark-crypto v0.17.0
Expand Down
8 changes: 4 additions & 4 deletions crates/batcher/go_verifiers_lib/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,6 @@ github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73
github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
github.com/iden3/go-iden3-crypto v0.0.17 h1:NdkceRLJo/pI4UpcjVah4lN/a3yzxRUGXqxbWcYh9mY=
github.com/iden3/go-iden3-crypto v0.0.17/go.mod h1:dLpM4vEPJ3nDHzhWFXDjzkn1qHoBeOT/3UEhXsEsP3E=
github.com/iden3/go-rapidsnark/types v0.0.3 h1:f0s1Qdut1qHe1O67+m+xUVRBPwSXnq5j0xSrBi0jqM4=
github.com/iden3/go-rapidsnark/types v0.0.3/go.mod h1:ApgcaUxKIgSRA6fAeFxK7p+lgXXfG4oA2HN5DhFlfF4=
github.com/iden3/go-rapidsnark/verifier v0.0.5 h1:J7y0ovrEjDQoWtZmlrp4tgGng1A9faMeYsQH4igAEqA=
github.com/iden3/go-rapidsnark/verifier v0.0.5/go.mod h1:KgL3Yr9NehlFDI4EIWVLE3UDUi8ulyjbp7HcXSBfiGI=
github.com/ingonyama-zk/icicle/v3 v3.1.1-0.20241118092657-fccdb2f0921b h1:AvQTK7l0PTHODD06PVQX1Tn2o29sRIaKIDOvTJmKurY=
github.com/ingonyama-zk/icicle/v3 v3.1.1-0.20241118092657-fccdb2f0921b/go.mod h1:e0JHb27/P6WorCJS3YolbY5XffS4PGBuoW38OthLkDs=
github.com/leanovate/gopter v0.2.11 h1:vRjThO1EKPb/1NsDXuDrzldR28RLkBflWYcU9CvzWu4=
Expand All @@ -50,6 +46,10 @@ github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOf
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/yetanotherco/go-rapidsnark/types v0.0.0-20250828172020-87df0a23ada4 h1:AAUBT4TrU8p66nW8aHVCFme87NfkUi03xTeuNA5HQws=
github.com/yetanotherco/go-rapidsnark/types v0.0.0-20250828172020-87df0a23ada4/go.mod h1:ApgcaUxKIgSRA6fAeFxK7p+lgXXfG4oA2HN5DhFlfF4=
github.com/yetanotherco/go-rapidsnark/verifier v0.0.0-20250828172020-87df0a23ada4 h1:9NfnU0RAhwC4hPXSG7tHvkHPsAVO2sJBliXguLn5ZgQ=
github.com/yetanotherco/go-rapidsnark/verifier v0.0.0-20250828172020-87df0a23ada4/go.mod h1:KgL3Yr9NehlFDI4EIWVLE3UDUi8ulyjbp7HcXSBfiGI=
golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
Expand Down
45 changes: 35 additions & 10 deletions crates/batcher/go_verifiers_lib/verifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ import "C"
import (
"bytes"
"encoding/json"
"github.com/iden3/go-rapidsnark/types"
"github.com/iden3/go-rapidsnark/verifier"
"math/big"

"log"
"unsafe"
Expand All @@ -24,6 +23,8 @@ import (
"github.com/consensys/gnark/backend/groth16"
"github.com/consensys/gnark/backend/plonk"
"github.com/consensys/gnark/backend/witness"
"github.com/iden3/go-rapidsnark/types"
"github.com/iden3/go-rapidsnark/verifier"
)

func listRefToBytes(listRef C.ListRef) []byte {
Expand Down Expand Up @@ -122,6 +123,20 @@ func verifyGnarkGroth16Proof(proofBytesRef C.ListRef, pubInputBytesRef C.ListRef
return err == nil
}

func bytesToBigInts32(b []byte) []*big.Int {
if len(b)%32 != 0 {
panic("pubInputBytes length is not a multiple of 32")
}

inputs := make([]*big.Int, 0, len(b)/32)
for i := 0; i < len(b); i += 32 {
chunk := b[i : i+32]
bi := new(big.Int).SetBytes(chunk)
inputs = append(inputs, bi)
}
return inputs
}

//export VerifyCircomGroth16ProofBN256
func VerifyCircomGroth16ProofBN256(proofBytesRef C.ListRef, pubInputBytesRef C.ListRef, verificationKeyBytesRef C.ListRef) bool {
proofBytes := listRefToBytes(proofBytesRef)
Expand All @@ -131,26 +146,36 @@ func VerifyCircomGroth16ProofBN256(proofBytesRef C.ListRef, pubInputBytesRef C.L
proofData := &types.ProofData{}
err := json.Unmarshal(proofBytes, proofData)
if err != nil {
log.Printf("Could not marshal proof: %v", err)
log.Printf("Could not unmarshal proof: %v", err)
return false
}

var pubSignals []string
err = json.Unmarshal(pubInputBytes, &pubSignals)
parsedProofData, err := verifier.ParseProofData(*proofData)
if err != nil {
log.Printf("Error unmarshaling JSON: %v", err)
log.Printf("Could not parse proof: %v", err)
return false
}

zkProof := types.ZKProof{
Proof: proofData,
PubSignals: pubSignals,
var vkStr verifier.VkJSON
err = json.Unmarshal(verificationKeyBytes, &vkStr)
if err != nil {
log.Printf("Could not unmarshal vk: %v", err)
return false
}

vk, err := verifier.ParseVK(vkStr)
if err != nil {
log.Printf("Could not parse vk: %v", err)
return false
}

err = verifier.VerifyGroth16(zkProof, verificationKeyBytes)
inputs := bytesToBigInts32(pubInputBytes)

err = verifier.VerifyRaw(vk, parsedProofData, inputs)
if err != nil {
log.Printf("Could not verify Groth16 proof: %v", err)
return false
}

return true
}
15 changes: 11 additions & 4 deletions crates/cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -926,10 +926,17 @@ fn verification_data_from_args(args: &SubmitArgs) -> Result<VerificationData, Su
"--vk",
args.verification_key_file_name.clone(),
)?);
pub_input = Some(read_file_option(
"--public_input",
args.pub_input_file_name.clone(),
)?);
let pub_input_file =
read_file_option("--public_input", args.pub_input_file_name.clone())?;
let pub_inputs: Vec<String> = serde_json::from_slice(&pub_input_file)
.map_err(|e| SubmitError::MissingRequiredParameter(e.to_string()))?;

let decode_inputs = aligned_sdk::common::utils::encode_circom_pub_inputs(&pub_inputs)
.map_err(|_| {
SubmitError::MissingRequiredParameter("Invalid public inputs".into())
})?;

pub_input = Some(decode_inputs);
}
}

Expand Down
1 change: 1 addition & 0 deletions crates/sdk/src/common/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod constants;
pub mod errors;
pub mod types;
pub mod utils;
32 changes: 32 additions & 0 deletions crates/sdk/src/common/utils.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
use ethers::{abi::ethereum_types::FromDecStrErr, types::U256};

/// Encodes Circom public inputs into a single byte vector.
///
/// Circom normally outputs public inputs as a JSON array of strings, where each
/// entry is actually a big integer represented in decimal. For example:
///
/// ```json
/// { "pubInputs": ["123", "456", "789"] }
/// ```
///
/// For on-chain usage (e.g. in Solidity), working with JSON is inefficient.
/// Instead, we prefer the **raw form**: each input is converted to a 32-byte
/// big-endian encoding of the integer, concatenated together. This makes it
/// simple to compute commitments and verify proofs on-chain, since the contract
/// receives a compact `bytes` array rather than parsing JSON.
///
/// Each input must fit in 32 bytes (i.e. < 2^256).
pub fn encode_circom_pub_inputs(input: &[String]) -> Result<Vec<u8>, FromDecStrErr> {
let mut out = Vec::with_capacity(input.len() * 32);

for s in input {
// parse as decimal (base 10). Use from_str_radix(s, 16) if they're hex.
let n = U256::from_dec_str(s)?;
let mut bytes = [0u8; 32];
n.to_big_endian(&mut bytes);

out.extend_from_slice(&bytes);
}

Ok(out)
}
6 changes: 6 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ go 1.22.3

toolchain go1.23.4

replace github.com/iden3/go-rapidsnark => github.com/yetanotherco/go-rapidsnark v0.0.0-20250828172020-87df0a23ada4

replace github.com/iden3/go-rapidsnark/types => github.com/yetanotherco/go-rapidsnark/types v0.0.0-20250828172020-87df0a23ada4

replace github.com/iden3/go-rapidsnark/verifier => github.com/yetanotherco/go-rapidsnark/verifier v0.0.0-20250828172020-87df0a23ada4

require (
github.com/Layr-Labs/eigensdk-go v0.2.0-beta.1
github.com/ethereum/go-ethereum v1.14.0
Expand Down
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -192,10 +192,6 @@ github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFck
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/iden3/go-iden3-crypto v0.0.17 h1:NdkceRLJo/pI4UpcjVah4lN/a3yzxRUGXqxbWcYh9mY=
github.com/iden3/go-iden3-crypto v0.0.17/go.mod h1:dLpM4vEPJ3nDHzhWFXDjzkn1qHoBeOT/3UEhXsEsP3E=
github.com/iden3/go-rapidsnark/types v0.0.3 h1:f0s1Qdut1qHe1O67+m+xUVRBPwSXnq5j0xSrBi0jqM4=
github.com/iden3/go-rapidsnark/types v0.0.3/go.mod h1:ApgcaUxKIgSRA6fAeFxK7p+lgXXfG4oA2HN5DhFlfF4=
github.com/iden3/go-rapidsnark/verifier v0.0.5 h1:J7y0ovrEjDQoWtZmlrp4tgGng1A9faMeYsQH4igAEqA=
github.com/iden3/go-rapidsnark/verifier v0.0.5/go.mod h1:KgL3Yr9NehlFDI4EIWVLE3UDUi8ulyjbp7HcXSBfiGI=
github.com/ingonyama-zk/icicle/v3 v3.1.1-0.20241118092657-fccdb2f0921b h1:AvQTK7l0PTHODD06PVQX1Tn2o29sRIaKIDOvTJmKurY=
github.com/ingonyama-zk/icicle/v3 v3.1.1-0.20241118092657-fccdb2f0921b/go.mod h1:e0JHb27/P6WorCJS3YolbY5XffS4PGBuoW38OthLkDs=
github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=
Expand Down Expand Up @@ -323,6 +319,10 @@ github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4=
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM=
github.com/yetanotherco/go-rapidsnark/types v0.0.0-20250828172020-87df0a23ada4 h1:AAUBT4TrU8p66nW8aHVCFme87NfkUi03xTeuNA5HQws=
github.com/yetanotherco/go-rapidsnark/types v0.0.0-20250828172020-87df0a23ada4/go.mod h1:ApgcaUxKIgSRA6fAeFxK7p+lgXXfG4oA2HN5DhFlfF4=
github.com/yetanotherco/go-rapidsnark/verifier v0.0.0-20250828172020-87df0a23ada4 h1:9NfnU0RAhwC4hPXSG7tHvkHPsAVO2sJBliXguLn5ZgQ=
github.com/yetanotherco/go-rapidsnark/verifier v0.0.0-20250828172020-87df0a23ada4/go.mod h1:KgL3Yr9NehlFDI4EIWVLE3UDUi8ulyjbp7HcXSBfiGI=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw=
github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
Expand Down
44 changes: 34 additions & 10 deletions operator/pkg/operator.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (
"time"

rapidsnark_types "github.com/iden3/go-rapidsnark/types"
"github.com/iden3/go-rapidsnark/verifier"
rapidsnark_verifier "github.com/iden3/go-rapidsnark/verifier"

"github.com/ethereum/go-ethereum/crypto"
"github.com/urfave/cli/v2"
Expand Down Expand Up @@ -621,30 +621,54 @@ func (o *Operator) verifyGnarkGroth16Proof(proofBytes []byte, pubInputBytes []by

// verifyCircomGroth16Bn256Proof verifies a Circom Groth16 proof using BN256 curve.
func (o *Operator) verifyCircomGroth16Bn256Proof(proofBytes []byte, pubInputBytes []byte, verificationKeyBytes []byte) bool {
bytesToBigInts32 := func(b []byte) []*big.Int {
if len(b)%32 != 0 {
panic("pubInputBytes length is not a multiple of 32")
}

inputs := make([]*big.Int, 0, len(b)/32)
for i := 0; i < len(b); i += 32 {
chunk := b[i : i+32]
bi := new(big.Int).SetBytes(chunk)
inputs = append(inputs, bi)
}
return inputs
}

proofData := &rapidsnark_types.ProofData{}
err := json.Unmarshal(proofBytes, proofData)
if err != nil {
o.Logger.Infof("Could not marshal proof: %v", err)
log.Printf("Could not unmarshal proof: %v", err)
return false
}

var pubSignals []string
err = json.Unmarshal(pubInputBytes, &pubSignals)
parsedProofData, err := rapidsnark_verifier.ParseProofData(*proofData)
if err != nil {
o.Logger.Infof("Could not marshal public signals: %v", err)
log.Printf("Could not parse proof: %v", err)
return false
}

zkProof := rapidsnark_types.ZKProof{
Proof: proofData,
PubSignals: pubSignals,
var vkStr rapidsnark_verifier.VkJSON
err = json.Unmarshal(verificationKeyBytes, &vkStr)
if err != nil {
log.Printf("Could not unmarshal vk: %v", err)
return false
}

err = verifier.VerifyGroth16(zkProof, verificationKeyBytes)
vk, err := rapidsnark_verifier.ParseVK(vkStr)
if err != nil {
o.Logger.Infof("Could not verify Circom Groth16 BN256 proof: %v", err)
log.Printf("Could not parse vk: %v", err)
return false
}

inputs := bytesToBigInts32(pubInputBytes)

err = rapidsnark_verifier.VerifyRaw(vk, parsedProofData, inputs)
if err != nil {
log.Printf("Could not verify Groth16 proof: %v", err)
return false
}

return true
}

Expand Down
Loading