Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
156 changes: 84 additions & 72 deletions README.md

Large diffs are not rendered by default.

7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@
"scripts": {
"build:pubkeygen": "cd ./scripts/pubkeygen && ./build_pubkeygen.sh",
"build:groupsig": "cd ./scripts/groupsig && ./build_groupsig.sh",
"build-windows:groupsig": "cd ./scripts/groupsig && ./windows_build_groupsig.sh",
"build:verify": "cd ./scripts/verify && ./build_verify.sh",
"build:eth_addr": "cd ./scripts/eth_addr && ./build_eth_addr.sh",
"test": "NODE_OPTIONS=--max_old_space_size=56000 mocha -r ts-node/register 'test/**/*.ts'",
"groupsig-demo": "npx ts-node scripts/groupsign_cli.ts"
"groupsig-demo": "npx ts-node scripts/groupsign_cli.ts",
"prototype-demo": "npx ts-node scripts/variable_groupsign_cli.ts"
},
"repository": "git@github.com:0xPARC/circom-ecdsa.git",
"author": "0xPARC <hello@0xparc.org>",
Expand All @@ -29,5 +31,6 @@
"mocha": "^9.1.3",
"ts-node": "^10.4.0",
"typescript": "^4.5.4"
}
},
"packageManager": "yarn@1.22.22+sha1.ac34549e6aa8e7ead463a7407e1c7390f61a6610"
}
55 changes: 55 additions & 0 deletions scripts/groupsig/build_circuits.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#!/bin/bash
set -e # Exit on error

export MSYS_NO_PATHCONV=1
PHASE1=../../circuits/pot20_final.ptau
CIRCUIT_NAME=secure_variable_groupsig
BUILD_BASE=../../build/groupsig

# Check for Phase 1
if [ ! -f "$PHASE1" ]; then
echo "Error: Phase 1 ptau file not found at $PHASE1"
exit 1
fi

# Sizes we want to support
SIZES=(2 3 4)

for m in "${SIZES[@]}"
do
echo "-------------------------------------------"
echo "🔨 BUILDING FOR GROUP SIZE: m = $m"
echo "-------------------------------------------"

# Create a specific directory for this size
TARGET_DIR="$BUILD_BASE/m_$m"
mkdir -p "$TARGET_DIR"

# 1. Modify the circom file temporarily to set the group size
# This replaces the 'Main(64, 4, X)' line with the current size 'm'
sed -i "s/component main {public \[addrs, msg, nonce\]} = Main(64, 4, [0-9]*);/component main {public [addrs, msg, nonce]} = Main(64, 4, $m);/" "$CIRCUIT_NAME".circom

echo "**** COMPILING ****"
circom "$CIRCUIT_NAME".circom --r1cs --wasm --output "$TARGET_DIR"

echo "**** GENERATING ZKEY ****"
# Groth16 Setup
snarkjs groth16 setup "$TARGET_DIR/$CIRCUIT_NAME.r1cs" "$PHASE1" "$TARGET_DIR/temp_0.zkey"

# Quick Contribution (using 'test' as entropy)
echo "test" | snarkjs zkey contribute "$TARGET_DIR/temp_0.zkey" "$TARGET_DIR/temp_1.zkey" --name="Builder" -v -e="entropy"

# Final Beacon and ZKey
snarkjs zkey beacon "$TARGET_DIR/temp_1.zkey" "$TARGET_DIR/$CIRCUIT_NAME.zkey" 0102030405060708090a0b0c0d0e0f101112231415161718221a1b1c1d1e1f 10

echo "**** EXPORTING VKEY ****"
snarkjs zkey export verificationkey "$TARGET_DIR/$CIRCUIT_NAME.zkey" "$TARGET_DIR/vkey.json"

# Cleanup intermediate files to save space
rm "$TARGET_DIR/temp_0.zkey" "$TARGET_DIR/temp_1.zkey" "$TARGET_DIR/$CIRCUIT_NAME.r1cs"

echo "✅ Done for m=$m"
done

echo "-------------------------------------------"
echo "All builds complete in $BUILD_BASE"
143 changes: 143 additions & 0 deletions scripts/groupsig/build_private_groupsig_circuits.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
#!/bin/bash
set -e

export MSYS_NO_PATHCONV=1

# --------------------------------
# Config
# --------------------------------
PHASE1=../../circuits/pot20_final.ptau
CIRCUIT_NAME=private_secure_variable_groupsig
BUILD_BASE=../../build/groupsig
VERIFIER_DIR="$BUILD_BASE/verifiers"

# --------------------------------
# Check Phase1
# --------------------------------
if [ ! -f "$PHASE1" ]; then
echo "❌ Phase1 ptau not found: $PHASE1"
exit 1
fi

# --------------------------------
# User Input
# --------------------------------
read -p "Enter maximum group size (>=2): " MAX_M

if ! [[ "$MAX_M" =~ ^[0-9]+$ ]] || [ "$MAX_M" -lt 2 ]; then
echo "❌ Invalid group size"
exit 1
fi

read -p "Create Solidity verifiers? (y/n): " MAKE_VERIFIERS

if [[ "$MAKE_VERIFIERS" == "y" || "$MAKE_VERIFIERS" == "Y" ]]; then
MAKE_VERIFIERS=true
mkdir -p "$VERIFIER_DIR"
else
MAKE_VERIFIERS=false
fi

echo
echo "==================================="
echo " Max group size: $MAX_M"
echo " Generate verifiers: $MAKE_VERIFIERS"
echo "==================================="
echo

# --------------------------------
# Build Loop
# --------------------------------
for (( m=2; m<=MAX_M; m++ ))
do
echo "-------------------------------------------"
echo "🔨 BUILDING FOR GROUP SIZE: m = $m"
echo "-------------------------------------------"

TARGET_DIR="$BUILD_BASE/p_m_$m"
mkdir -p "$TARGET_DIR"

# --------------------------------
# Patch circuit
# --------------------------------
# Robust sed: matches Main(64, 4, ANY_NUMBER) regardless of spacing inside brackets
# The [[:space:]]* handles potential variations in whitespace
echo "⚙️ Patching circuit for m=$m..."

sed -i "s/Main[[:space:]]*([[:space:]]*64[[:space:]]*,[[:space:]]*4[[:space:]]*,[[:space:]]*[0-9]*[[:space:]]*)/Main(64, 4, $m)/g" "$CIRCUIT_NAME.circom"

# Verify the patch worked by checking the file
if ! grep -q "Main(64, 4, $m)" "$CIRCUIT_NAME.circom"; then
echo "❌ Error: Failed to patch $CIRCUIT_NAME.circom for m=$m"
exit 1
fi

# --------------------------------
# Compile
# --------------------------------
echo "⚙️ Compiling R1CS and WASM..."
circom "$CIRCUIT_NAME.circom" \
--r1cs \
--wasm \
--sym \
--output "$TARGET_DIR"

# --------------------------------
# Groth16 Setup
# --------------------------------
echo "⚙️ Groth16 setup (zkey generation)..."
snarkjs groth16 setup \
"$TARGET_DIR/$CIRCUIT_NAME.r1cs" \
"$PHASE1" \
"$TARGET_DIR/temp_0.zkey"

echo "contribution" | snarkjs zkey contribute \
"$TARGET_DIR/temp_0.zkey" \
"$TARGET_DIR/temp_1.zkey" \
--name="Builder" \
-v \
-e="entropy_$(date +%s)"

snarkjs zkey beacon \
"$TARGET_DIR/temp_1.zkey" \
"$TARGET_DIR/$CIRCUIT_NAME.zkey" \
0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f \
10

# --------------------------------
# Export vkey (Check nPublic here!)
# --------------------------------
echo "⚙️ Exporting verification key..."
snarkjs zkey export verificationkey \
"$TARGET_DIR/$CIRCUIT_NAME.zkey" \
"$TARGET_DIR/vkey.json"

# --------------------------------
# Export Solidity Verifier
# --------------------------------
if [ "$MAKE_VERIFIERS" = true ]; then
echo "⚙️ Exporting Solidity verifier..."
snarkjs zkey export solidityverifier \
"$TARGET_DIR/$CIRCUIT_NAME.zkey" \
"$VERIFIER_DIR/VerifierM$m.sol"

# Rename contract to match the filename
sed -i "s/contract Groth16Verifier/contract VerifierM$m/g" "$VERIFIER_DIR/VerifierM$m.sol"
echo " → $VERIFIER_DIR/VerifierM$m.sol"
fi

# --------------------------------
# Cleanup
# --------------------------------
rm "$TARGET_DIR/temp_0.zkey"
rm "$TARGET_DIR/temp_1.zkey"
rm "$TARGET_DIR/$CIRCUIT_NAME.r1cs"

echo "✅ Done for m=$m"
echo
done

echo "==================================="
echo " All builds complete"
echo " Output: $BUILD_BASE"
echo "==================================="
22 changes: 17 additions & 5 deletions scripts/groupsig/groupsig.circom
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ include "../../circuits/eth_addr.circom";
- addr2 (pub)
- addr3 (pub)
- msg (pub)
- nonce (pub)
- privkey

Intermediate values:
Expand All @@ -24,15 +25,25 @@ include "../../circuits/eth_addr.circom";
- msgAttestation == mimc(msg, privkey)
*/

// TODO:
// 1. add nonce for safegarding against replac attacks
// 2. make scalable so that instead of addr1, addr2, and addr3 an array is used called: addrs
// 3. fix: No domain separation issue casued by cross-context replay
// 4. check validity of public key

template Main(n, k) {
assert(n * k >= 256);
assert(n * (k-1) < 256);

// private inputs
signal input privkey[k];

// public inputs
signal input addr1;
signal input addr2;
signal input addr3;
signal input msg;
signal input nonce; // to protect against replay attacks

signal myAddr;

Expand All @@ -50,21 +61,22 @@ template Main(n, k) {
for (var i = 0; i < k; i++) {
privToAddr.privkey[i] <== privkey[i];
}
myAddr <== privToAddr.addr;
myAddr <== privToAddr.addr; // enforces: "I know a private key whose Ethereum address is myAddr"

// verify address is one of the provided
signal temp;
temp <== (myAddr - addr1) * (myAddr - addr2);
0 === temp * (myAddr - addr3);
0 === temp * (myAddr - addr3); // enforces: "I know myAddr is part of group (= addr1-3)"

// produce signature
component mimcAttestation = MiMCSponge(k+1, 220, 1);
component mimcAttestation = MiMCSponge(k+2, 220, 1); //+2 bcause of msg and nonce
mimcAttestation.ins[0] <== msg;
mimcAttestation.ins[1] <== nonce; // bind the proof to this specific nonce
for (var i = 0; i < k; i++) {
mimcAttestation.ins[i+1] <== privkey[i];
mimcAttestation.ins[i+2] <== privkey[i]; // enforces: "I know that the private key of myAddr signed msg"
}
mimcAttestation.k <== 0;
msgAttestation <== mimcAttestation.outs[0];
}

component main {public [addr1, addr2, addr3, msg]} = Main(64, 4);
component main {public [addr1, addr2, addr3, msg, nonce]} = Main(64, 4);
2 changes: 1 addition & 1 deletion scripts/groupsig/input_groupsig.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"privkey": ["7", "0", "0", "0"], "addr1": "50", "addr2": "1210930943336347771396396330116102456817544228795", "addr3": "51", "msg": "42"}
{"privkey": ["7", "0", "0", "0"], "addr1": "50", "addr2": "1210930943336347771396396330116102456817544228795", "addr3": "51", "msg": "42", "nonce":"12345"}
Loading