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
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,20 @@ The zkInterval protocol proves the statement $a \geq d \geq b$ where $a$ and $b$

Python code for generating the proofs and Aiken code for on-chain validation of the proofs. The on-chain Cardano form of the proof is about 2.2 Kb.

```bash
# Prove: 100 >= 42 >= 0
python3 zk_interval.py --value 42 --lower 0 --upper 100 --file_path datum.json
```

Current memory and steps estimate with Aiken:

```
```bash
[mem: 100336, cpu: 2226339408]

0.0577 * 100336 + 0.0000721 * 2226339408 = 166308
```

Estimate cost is about 167,000 Lovelace to compute on-chain.
Estimate cost is about 166,308 Lovelace to compute on-chain.

## The Paper

Expand Down
10 changes: 5 additions & 5 deletions py/README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
# zkInterval Proof Generation

# Setup
## Setup

```bash
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
```

# Test
## Test

Use `pytest` for testing.

Expand All @@ -17,11 +17,11 @@ pytest
```


# Use
## Generation

Use `zk_interval.py` to generate proofs.
Use `zk_interval.py` to generate proofs for Cardano.

```bash
# Example: Prove 100 >= 42 >= 0
# Prove: 100 >= 42 >= 0
python3 zk_interval.py --value 42 --lower 0 --upper 100 --file_path datum.json
```
2 changes: 1 addition & 1 deletion py/src/blake2b_224.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from hashlib import blake2b


def hash_function():
def hash_function() -> type[blake2b]:
"""
Assigns sha3_256 as a hash function for the hash to g2 function inside the bls12-381 module.

Expand Down
2 changes: 1 addition & 1 deletion py/src/bls12_381.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ def pair(g2_element: str, g1_element: str, final_exponentiate: bool = True) -> F
return pairing(uncompress(g2_element), uncompress(g1_element), final_exponentiate)


def hash_to_g2(message: str):
def hash_to_g2(message: str) -> str:
"""
Generate a G2 point from a hex message string.

Expand Down
14 changes: 7 additions & 7 deletions py/src/commitment.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from dataclasses import dataclass, field

from typing import Self
from src.blake2b_224 import generate
from src.bls12_381 import field_order, g1_point, rng
from src.element import Element
Expand Down Expand Up @@ -28,7 +28,7 @@ class Commitment:

c: Element = field(init=False)

def __post_init__(self):
def __post_init__(self) -> None:
# this are fixed inside of a commitment
g = Element(g1_point(1))
h = Element(g1_point(2))
Expand All @@ -40,10 +40,10 @@ def __post_init__(self):
def hash(self) -> str:
return generate(self.c.value)

def __str__(self):
def __str__(self) -> str:
return f"Commitment(c={self.c}, r={self.r}, v={self.v})"

def __add__(self, other):
def __add__(self, other) -> Self:
if not isinstance(other, Commitment):
return NotImplemented
# Add the r values
Expand All @@ -53,7 +53,7 @@ def __add__(self, other):
# Create a new Commitment instance with combined values
return Commitment(combined_v, combined_r)

def __sub__(self, other):
def __sub__(self, other) -> Self:
if not isinstance(other, Commitment):
return NotImplemented
# Add the r values
Expand All @@ -63,12 +63,12 @@ def __sub__(self, other):
# Create a new Commitment instance with combined values
return Commitment(combined_v, combined_r)

def __eq__(self, other):
def __eq__(self, other) -> bool:
if not isinstance(other, Commitment):
return NotImplemented
return self.c == other.c and self.r == other.r and self.v == other.v

def prove_knowledge_of_r(self, value: int):
def prove_knowledge_of_r(self, value: int) -> bool:
v_commitment = Commitment(value, 0)
r_commitment = self - v_commitment
alpha = rng()
Expand Down
15 changes: 7 additions & 8 deletions py/src/element.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# src/Registry/element.py
from dataclasses import dataclass

from typing import Self
from src.blake2b_224 import generate
from src.bls12_381 import combine, compress, invert, scale, uncompress

Expand All @@ -18,26 +17,26 @@ def uncompressed(self) -> tuple:
def hash(self) -> str:
return generate(self.value)

def __str__(self):
def __str__(self) -> str:
return self.value

def __add__(self, other):
def __add__(self, other) -> Self:
if not isinstance(other, Element):
return NotImplemented
return Element(combine(self.value, other.value))

def __mul__(self, other):
def __mul__(self, other) -> Self:
if not isinstance(other, int):
return NotImplemented
return Element(scale(self.value, other))

def __rmul__(self, other):
def __rmul__(self, other) -> Self:
return self.__mul__(other)

def __invert__(self):
def __invert__(self) -> Self:
return Element(invert(self.value))

def __eq__(self, other):
def __eq__(self, other) -> bool:
if not isinstance(other, Element):
return NotImplemented
return self.value == other.value
10 changes: 5 additions & 5 deletions py/src/range.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class Range:
Q: Element = field(init=False)
QI: Element = field(init=False)

def __post_init__(self):
def __post_init__(self) -> None:
# if upper bound is not set then it becomes field prime minus one
if self.upper_bound is None:
self.upper_bound = field_order - 1
Expand Down Expand Up @@ -80,10 +80,10 @@ def __post_init__(self):
self.right = Commitment(0, self.A_commit.r + self.B_commit.r + self.W_commit.r)
self.left = Commitment(0, self.Y_commit.r + self.D_commit.r + self.D_commit.r)

def __str__(self):
def __str__(self) -> str:
return f"Range(\nY={self.Y_commit.c},\n{(self.D_commit + self.D_commit).c},\nR={self.right.c},\nW={self.W_commit.c},\nL={self.left.c}\n)"

def schnorr(self, z_a, a_c, flag):
def schnorr(self, z_a, a_c, flag) -> bool:
if flag is True:
r_commitment = self.A_commit - Commitment(self.upper_bound, 0)
else:
Expand All @@ -104,7 +104,7 @@ def prove(self, z_a, a_c, z_b, b_c) -> bool:
# Verifying that the commitments are consistent with the expected range proof
return check_p and check_a and check_b

def generate_proof(self):
def generate_proof(self) -> dict:
# do the schnorr proofs
r_upper_commitment = self.A_commit - Commitment(self.upper_bound, 0)
r_lower_commitment = self.B_commit - Commitment(self.lower_bound, 0)
Expand Down Expand Up @@ -141,7 +141,7 @@ def generate_proof(self):
return data

@staticmethod
def verify_proof(proof, lower_bound, upper_bound):
def verify_proof(proof, lower_bound, upper_bound) -> bool:
#
# Verify A
#
Expand Down
2 changes: 1 addition & 1 deletion py/tests/test_range.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ def test_lower_range_value():

def test_null_range_value():
lower = 0
upper = 0 # oldest ever is 122
upper = 0
age = 0
r = Range(secret_value=age, lower_bound=lower, upper_bound=upper)

Expand Down
4 changes: 2 additions & 2 deletions py/zk_interval.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ def zk_data(proof: dict, lower: int, upper: int, file_path: str) -> None:
save_proof_to_json(data, file_path)


def main():
def main() -> None:
parser = argparse.ArgumentParser(
description=(
"Generate a range proof based on a value, lower bound, and upper bound.\n\n"
Expand Down Expand Up @@ -75,7 +75,7 @@ def main():
args = parser.parse_args()

# Create Range object and generate proof
print(f"Prove {args.upper} >= {args.value} >= {args.lower}")
print(f"Prove: {args.upper} >= {args.value} >= {args.lower}")
r = Range(secret_value=args.value, lower_bound=args.lower, upper_bound=args.upper)
proof = r.generate_proof()
print(f"Is the Proof Valid? {r.verify_proof(proof, args.lower, args.upper)}")
Expand Down