Metadata-Version: 2.4
Name: py_ark_vrf
Version: 0.2.1
Summary: Python bindings for ark-vrf
Author-email: Prasad <prasad@chainscore.finance>
Requires-Python: >=3.8
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
Project-URL: Homepage, https://github.com/chainscore/py-ark-vrf
Project-URL: Bug Tracker, https://github.com/chainscore/py-ark-vrf/issues

# `py-ark-vrf`

Python bindings for the [`ark-vrf`](https://github.com/w3f/ark-vrf) Rust crate, offering Verifiable Random Function (VRF) constructions. This library specifically uses the Bandersnatch curve (`suite::BandersnatchSha512Ell2`) and exposes IETF and Ring VRF schemes.

This library requires a pre-generated SRS file `bandersnatch_ring.srs` for Ring VRF operations.

## Installation

This project is built using `setuptools-rust`, so you will need the Rust toolchain installed.

```bash
# Install Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
```

After installing Rust, you can install the library using pip:

```bash
pip install .
```

## Usage

### Key Generation

You can generate a secret/public key pair from a 32-byte seed. The public key can also be derived from the secret scalar.

```python
from py_ark_vrf import secret_from_seed, public_from_le_secret

# Generate keys from a seed
seed = 12345
public_key, secret_scalar = secret_from_seed(seed.to_bytes(32))

print(f"Public Key: {public_key.hex()}")
print(f"Secret Scalar: {secret_scalar.hex()}")

# Derive public key from the secret
derived_public_key = public_from_le_secret(secret_scalar)
assert derived_public_key == public_key
```

### IETF VRF

This scheme is defined in the IETF draft for VRFs. You can create and verify proofs.

```python
from py_ark_vrf import secret_from_seed, prove_ietf, verify_ietf, vrf_output

# 1. Key Generation
seed = 0
pub_key, scalar = secret_from_seed(seed.to_bytes(32))

# 2. Proving
input_data = b"hello"
ad = b"additional data" # associated data
proof = prove_ietf(scalar, input_data, ad)

assert len(proof) == 96

# 3. Verification
is_valid = verify_ietf(pub_key, proof, input_data, ad)
assert is_valid

# An invalid proof should fail verification
assert not verify_ietf(pub_key, bytes(96), input_data, ad)

# 4. Get VRF output hash
output = vrf_output(proof)
assert len(output) == 32
print(f"VRF Output: {output.hex()}")
```

### Ring VRF

Ring VRFs allow proving that a secret key holder is part of a "ring" (a set of public keys) without revealing which one.

**Note:** Ring VRF operations require a Structured Reference String (SRS) file named `bandersnatch_ring.srs` to be present in the working directory.

```python
from py_ark_vrf import secret_from_seed, prove_ring, verify_ring

# 1. Setup a ring of public keys
seeds = [1, 2, 3, 4, 5, 6, 7, 8]
keys = [secret_from_seed(seed.to_bytes(32)) for seed in seeds]
ring = [k[0] for k in keys]

# 2. Select a prover from the ring
prover_index = 4
prover_secret_scalar = keys[prover_index][1]

# 3. Proving
input_data = b"message"
ad = b""
ring_proof = prove_ring(prover_secret_scalar, input_data, ring, ad)

# 4. Verification
# Anyone with the ring can verify the proof
is_valid = verify_ring(input_data, ring_proof, ring, ad)
assert is_valid

# Verification should fail with wrong input
assert not verify_ring(b"wrong message", ring_proof, ring, ad)
```

### API

#### `secret_from_seed(seed: bytes) -> (bytes, bytes)`
Generates a (public_key, secret_scalar) pair from a 32-byte seed.

#### `public_from_le_secret(secret_scalar: bytes) -> bytes`
Derives a public key from a secret scalar.

#### `prove_ietf(secret_scalar: bytes, input_data: bytes, aux_data: bytes) -> bytes`
Creates an IETF VRF proof. Returns a 96-byte proof.

#### `verify_ietf(public_key: bytes, proof: bytes, input_data: bytes, aux_data: bytes) -> bool`
Verifies an IETF VRF proof.

#### `prove_ring(secret_scalar: bytes, input_data: bytes, ring: list[bytes], aux_data: bytes) -> bytes`
Creates a Ring VRF proof. The prover's public key must be in the `ring`.

#### `verify_ring(input_data: bytes, proof: bytes, ring: list[bytes], aux_data: bytes) -> bool`
Verifies a Ring VRF proof.

#### `vrf_output(proof: bytes) -> bytes`
Extracts the 32-byte VRF output hash from a proof (works for both IETF and Ring proofs).

#### `get_ring_root(public_keys: list[bytes]) -> bytes`
Returns a 144-bytes ring root

