Skip to content
Merged
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
11 changes: 11 additions & 0 deletions crypto-benchmarks.rs/.gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
target/
*.cbor
*.txt

# Demo artifacts
demo/**/*.pretty.json
demo/**/*.json
demo/**/*.png
demo/**/*.csv
demo/scripts/.env_cli

# Python cache
__pycache__/
*.pyc
104 changes: 104 additions & 0 deletions crypto-benchmarks.rs/demo/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@


# Demo Scripts for Leios Crypto Benchmarks

This folder contains scripts that orchestrate end-to-end demonstrations of BLS-based vote aggregation and certificate generation/verification for the Leios project.

## Prerequisites

- Ensure the CLI built from the repository root is available; see `crypto-benchmarks.rs/ReadMe.md` for build instructions and usage details.
- Ensure Python 3 is available with `cbor2` installed.
For example:

```bash
python3 -m venv .venv
source .venv/bin/activate
pip install cbor2
```

## Workflow

The scripts are designed to be run from the `demo/` directory.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The scripts were a bit annoying to run for me:

  • I was using PATH to point to the binary at first (as required on line 9)
  • Then I learned that CLI needs to be set, which I did
  • Then I saw that scripts/.env_cli needs to exist
  • Which had me look at 00_set_cli.sh script, but that did not accept the binary in my ase

I would suggest to lower the specific requirements and just expec the leios_crypto_benchmarks on the PATH, or be explicit about needing CLI to be set.

FWIW I was using direnv and a nix-shell to get the binaries and python packages in place, but this is different for each user.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot for the feedback, @ch1bo — and apologies for the confusion with the README setup instructions.
I reviewed the steps and have now created a PR that updates the README with corrected and simplified instructions for running the demo.

Because my laptop currently has limited disk space, I wasn’t able to use Nix for this setup — so I focused on making sure the demo can also be run easily without it.

Here’s the PR with the fixes:
👉 #606


### Run Step by Step (Manual Mode)

You can run each script individually to understand and control each step of the process for a given number of voters (e.g., 100). Use the `-d` option to specify the output directory (e.g., `run100`).

#### 10_init_inputs.sh

Initialize inputs for N voters:

```bash
scripts/10_init_inputs.sh -d run100 --pools 500 --stake 100000 --alpha 9 --beta 1
```

#### 20_make_registry.sh

Build the registry from initialized inputs:

```bash
./scripts/20_make_registry.sh -d run100 -n 100
```

#### 30_cast_votes.sh

Cast votes with a specified fraction of voters voting (e.g., 1.0 means all vote):

```bash
scripts/30_cast_votes.sh -d run100 -f 0.75
```

#### 40_make_certificate.sh

Generate the aggregated certificate:

```bash
scripts/40_make_certificate.sh -d run100
```

#### 50_verify_certificate.sh

Verify the generated certificate:

```bash
scripts/50_verify_certificate.sh -d run100
```

### Run a Single End-to-End Demo

```bash
scripts/70_run_one.sh -d run100 -p 500 -n 100 -f 0.75
```

This will:

1. Initialize inputs (`10_init_inputs.sh`)
2. Build a registry (`20_make_registry.sh`)
3. Cast votes (`30_cast_votes.sh`)
4. Make a certificate (`40_make_certificate.sh`)
5. Verify the certificate (`50_verify_certificate.sh`)
6. Export data for the UI (`60_export_demo_json.sh`)

All files are placed in `demo/run100/`.

### Launch the Demo UI

After generating a demo run (for example via `scripts/70_run_one.sh`), start the UI server from this directory:

```bash
python3 ui/server.py
```

Then open your browser at [http://127.0.0.1:5050/ui](http://127.0.0.1:5050/ui) to explore the results.

## Notes

- All scripts must be run from within the `demo/` directory.
- Directories passed via `-d` will be created automatically under `demo/`.
- Compression ratio is defined as:

```
votes_bytes / certificate_bytes
```

which illustrates the storage/bandwidth savings achieved by BLS aggregation.
33 changes: 33 additions & 0 deletions crypto-benchmarks.rs/demo/scripts/00_set_cli.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#!/usr/bin/env bash
set -euo pipefail
# Usage: demo/scripts/00_set_cli.sh [-p /abs/path/to/leios_crypto_benchmarks]
# Writes demo/scripts/.env_cli with an absolute CLI path so other scripts can source it.

DIR_SCRIPT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ENV_FILE="$DIR_SCRIPT/.env_cli"
CLI_PATH=""

while getopts ":p:" opt; do
case "$opt" in
p) CLI_PATH="$OPTARG" ;;
*) echo "Usage: $0 [-p /abs/path/to/leios_crypto_benchmarks]"; exit 2 ;;
esac
done

if [[ -z "${CLI_PATH}" ]]; then
read -r -p "Absolute path to leios_crypto_benchmarks binary: " CLI_PATH
fi

if [[ ! -x "${CLI_PATH}" ]]; then
echo "Error: '${CLI_PATH}' is not an executable file." >&2
exit 1
fi

mkdir -p "$DIR_SCRIPT"
cat > "$ENV_FILE" <<EOF
# Auto-generated by 00_set_cli.sh
export CLI="${CLI_PATH}"
EOF

echo "Saved CLI path to $ENV_FILE"
echo "Example: source \"$ENV_FILE\" && \$CLI --help"
75 changes: 75 additions & 0 deletions crypto-benchmarks.rs/demo/scripts/10_init_inputs.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#!/usr/bin/env bash
set -euo pipefail
# Usage: demo/scripts/10_init_inputs.sh [-d DEMO_DIR] [--pools 5000] [--stake 100000] [--alpha 5] [--beta 1]
DIR_SCRIPT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$DIR_SCRIPT/.env_cli"

DEMO_DIR="$(cd "$DIR_SCRIPT/.." && pwd)"
POOLS=500
TOTAL_STAKE=1000000
ALPHA=9
BETA=1

while [[ $# -gt 0 ]]; do
case "$1" in
-d) DEMO_DIR="$2"; shift 2;;
--pools) POOLS="$2"; shift 2;;
--stake) TOTAL_STAKE="$2"; shift 2;;
--alpha) ALPHA="$2"; shift 2;;
--beta) BETA="$2"; shift 2;;
*) echo "Unknown arg: $1"; exit 2;;
esac
done

mkdir -p "$DEMO_DIR"

echo "== [10_init_inputs] DIR=${DEMO_DIR} POOLS=${POOLS} TOTAL_STAKE=${TOTAL_STAKE} =="

pushd "$DEMO_DIR" >/dev/null
"$CLI" gen-eid > eid.txt
"$CLI" gen-eb-hash > ebhash.txt

"$CLI" gen-stake \
--pool-count "${POOLS}" \
--total-stake "${TOTAL_STAKE}" \
--shape-alpha "${ALPHA}" \
--shape-beta "${BETA}" \
--stake-file stake.cbor

"$CLI" gen-pools \
--stake-file stake.cbor \
--pools-file pools.cbor

# Pretty-print some of the generated values
echo "EID: $(cat eid.txt)"
echo "EB Hash: $(cat ebhash.txt)"

# Print first 3 pools and their stakes from pools.cbor using cbor2
PYTHON_EXEC="${VIRTUAL_ENV:+$VIRTUAL_ENV/bin/python}"
PYTHON_EXEC="${PYTHON_EXEC:-python3}"
"$PYTHON_EXEC" - <<'PY'
import sys, os
try:
import cbor2
except ImportError:
print('cbor2 not installed! (pip install cbor2)', file=sys.stderr)
sys.exit(1)

if not os.path.exists('pools.cbor'):
print('pools.cbor not found', file=sys.stderr)
sys.exit(1)

with open('pools.cbor', 'rb') as f:
pools = cbor2.load(f)

print('First 3 pools and their stakes:')
for i, entry in enumerate(pools[:3]):
# Expected structure: {"secret": <bytes>, "reg": {"pool": "<hex>", ...}, "stake": <int>}
reg = entry.get('reg', {})
pool_id = reg.get('pool', '<unknown>')
stake = entry.get('stake', '<unknown>')
print(f' {i:>2}: pool={pool_id} stake={stake}')
PY
popd >/dev/null

echo "Initialized inputs in ${DEMO_DIR}"
86 changes: 86 additions & 0 deletions crypto-benchmarks.rs/demo/scripts/20_make_registry.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@


#!/usr/bin/env bash
set -euo pipefail
# Usage: demo/scripts/20_make_registry.sh -d RUN_DIR -n N
# Example (from demo/): scripts/20_make_registry.sh -d run16 -n 16
DIR_SCRIPT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$DIR_SCRIPT/.env_cli"

RUN_DIR=""
N=""

while [[ $# -gt 0 ]]; do
case "$1" in
-d) RUN_DIR="$2"; shift 2;;
-n) N="$2"; shift 2;;
*) echo "Usage: $0 -d RUN_DIR -n N"; exit 2;;
esac
done

if [[ -z "$RUN_DIR" || -z "$N" ]]; then
echo "Error: need -d RUN_DIR and -n N" >&2; exit 2
fi

RUN_DIR="$(cd "$DIR_SCRIPT/.."; cd "$RUN_DIR" && pwd)"
echo "== [20_make_registry] DIR=${RUN_DIR} N=${N} =="

pushd "$RUN_DIR" >/dev/null
"$CLI" make-registry \
--pools-file pools.cbor \
--voter-count "$N" \
--registry-file registry.cbor
popd >/dev/null

# --- Pretty-print a short registry summary for the audience ---
PYTHON_EXEC="${VIRTUAL_ENV:+$VIRTUAL_ENV/bin/python}"
PYTHON_EXEC="${PYTHON_EXEC:-python3}"
pushd "$RUN_DIR" >/dev/null
"$PYTHON_EXEC" - <<'PY'
import sys, os
try:
import cbor2
except ImportError:
print("CBOR summary skipped (cbor2 not installed). Run: pip install cbor2", file=sys.stderr)
raise SystemExit(0)

path = "registry.cbor"
if not os.path.exists(path):
print("CBOR summary skipped (registry.cbor missing).", file=sys.stderr)
raise SystemExit(0)

c = cbor2.load(open(path, "rb"))

voters = c.get("voters")
total_stake = c.get("total_stake")
persistent_pool = c.get("persistent_pool") or {}
info = c.get("info") or {}

print("Registry summary:")
print(f" Seats requested (N): {voters}")
print(f" Persistent seats: {len(persistent_pool)}")
print(f" Total stake: {total_stake}")

# Top 3 stakepools by stake (from .info)
tops = []
for pool_id, rec in info.items():
stake = rec.get("stake")
if isinstance(stake, int):
tops.append((stake, pool_id))
tops.sort(reverse=True)
tops = tops[:3]

if tops:
print(" Top 3 stakepools by stake:")
for i, (stake, pool) in enumerate(tops, 1):
print(f" {i}. pool={pool} stake={stake}")

# Show up to first 3 persistent IDs → pools
if isinstance(persistent_pool, dict) and persistent_pool:
items = sorted(persistent_pool.items(), key=lambda kv: kv[0])[:3]
print(" Persistent mapping (first 3):")
for pid, pool in items:
print(f" id={pid} -> pool={pool}")
PY
popd >/dev/null
# --- End summary ---
Loading