Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Test generators for kzg-4844 libraries #3274

Merged
merged 49 commits into from
Mar 2, 2023
Merged
Show file tree
Hide file tree
Changes from 39 commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
b2b7a98
bls.py : Abstract away usage of py_ecc methods
kevaundray Feb 24, 2023
773addb
polynomial-commitments: Remove usage of concrete py_ecc types
kevaundray Feb 24, 2023
b2d413e
fix lint
kevaundray Feb 24, 2023
636c572
Arkworks integration
dankrad Feb 24, 2023
4a61089
add py_arkworks to setup.py
kevaundray Feb 24, 2023
f59dd7c
add setuptools-rust to see if it adds the rust compiler
kevaundray Feb 24, 2023
d8e0cf1
remove setuptools: seems easier to install rust via the CI
kevaundray Feb 24, 2023
1a34476
Fix bug when using milagro bls
dankrad Feb 25, 2023
dbfb1ac
Add new 'fastest' BLS option that combines arkworks and milagro
dankrad Feb 25, 2023
df9167f
Test generators for compute_kzg_proof
dankrad Feb 25, 2023
55e00f3
update to use 0.3.2
kevaundray Feb 26, 2023
882fc72
fix linter
kevaundray Feb 26, 2023
927f673
Bump py_arkworks_bls12381 to v0.3.2
hwwhww Feb 26, 2023
ca27126
upgrade to 0.3.3
kevaundray Feb 26, 2023
e4c938d
More test generators for 4844
dankrad Feb 26, 2023
e47f0a8
Merge branch 'kw/py-ecc-agnostic-4844' into kzg-4844-generators
dankrad Feb 26, 2023
5d8d9c8
Lint
dankrad Feb 26, 2023
70de749
Whitespace
dankrad Feb 26, 2023
8cb5976
Add tests for verify_blob_kzg_proof
dankrad Feb 27, 2023
ecd7654
Add tests for compute_blob_kzg_proof
dankrad Feb 27, 2023
484fbe1
Tests for verify_blob_kzg_proof_batch
dankrad Feb 27, 2023
f771ed1
Lint
dankrad Feb 27, 2023
5d49e20
Refactor and more systematic invalid blob/z tests
dankrad Feb 27, 2023
8043669
Line too long
dankrad Feb 27, 2023
95f7a56
update py-arkworks to 0.3.4
kevaundray Feb 28, 2023
34dc5e5
Update tests/core/pyspec/eth2spec/utils/bls.py
kevaundray Feb 28, 2023
39e6c45
Update bls.py
kevaundray Feb 28, 2023
169bde6
fix lint
kevaundray Feb 28, 2023
e614ae4
Update tests/generators/kzg_4844/main.py
dankrad Feb 28, 2023
078096f
Update tests/generators/kzg_4844/main.py
dankrad Feb 28, 2023
d6c0a50
Update tests/generators/kzg_4844/main.py
dankrad Feb 28, 2023
7425b43
Add another root of unity
dankrad Feb 28, 2023
ce6a3fd
Update tests/generators/kzg_4844/main.py
dankrad Feb 28, 2023
fd4c189
Long line
dankrad Feb 28, 2023
7c71baf
minor nits from code review
djrtwo Feb 28, 2023
66c1e14
Plurals
dankrad Feb 28, 2023
e5dcb36
Merge branch 'dev' into kzg-4844-generators
dankrad Feb 28, 2023
cad12c1
Merge branch 'kw/py-ecc-agnostic-4844' into kzg-4844-generators
dankrad Feb 28, 2023
f41cf35
Add test format docs
dankrad Feb 28, 2023
0768d52
Update tests/formats/kzg/blob_to_kzg_commitment.md
dankrad Mar 1, 2023
def5c48
Update tests/formats/kzg/compute_blob_kzg_proof.md
dankrad Mar 1, 2023
aaf00c7
Update tests/formats/kzg/verify_blob_kzg_proof.md
dankrad Mar 1, 2023
69e7d18
Update tests/formats/kzg/compute_kzg_proof.md
dankrad Mar 1, 2023
c23fe5f
Update tests/formats/kzg/verify_blob_kzg_proof_batch.md
dankrad Mar 1, 2023
695b49a
Update tests/formats/kzg/verify_kzg_proof.md
dankrad Mar 1, 2023
f1c3c7d
INVALID_BLOB -> blob
dankrad Mar 2, 2023
d52da28
another INVALID_BLOB -> blob
dankrad Mar 2, 2023
01873c0
Simplify incorrect proof in batch test
dankrad Mar 2, 2023
c497ef9
Lint
dankrad Mar 2, 2023
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
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -117,10 +117,10 @@ citest: pyspec
mkdir -p $(TEST_REPORT_DIR);
ifdef fork
. venv/bin/activate; cd $(PY_SPEC_DIR); \
python3 -m pytest -n 16 --bls-type=milagro --preset=$(TEST_PRESET_TYPE) --fork=$(fork) --junitxml=test-reports/test_results.xml eth2spec
python3 -m pytest -n 16 --bls-type=fastest --preset=$(TEST_PRESET_TYPE) --fork=$(fork) --junitxml=test-reports/test_results.xml eth2spec
else
. venv/bin/activate; cd $(PY_SPEC_DIR); \
python3 -m pytest -n 16 --bls-type=milagro --preset=$(TEST_PRESET_TYPE) --junitxml=test-reports/test_results.xml eth2spec
python3 -m pytest -n 16 --bls-type=fastest --preset=$(TEST_PRESET_TYPE) --junitxml=test-reports/test_results.xml eth2spec
endif


Expand Down
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -1174,5 +1174,6 @@ def run(self):
RUAMEL_YAML_VERSION,
"lru-dict==1.1.8",
MARKO_VERSION,
"py_arkworks_bls12381==0.3.4",
]
)
15 changes: 8 additions & 7 deletions specs/deneb/polynomial-commitments.md
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ def g1_lincomb(points: Sequence[KZGCommitment], scalars: Sequence[BLSFieldElemen
BLS multiscalar multiplication. This function can be optimized using Pippenger's algorithm and variants.
"""
assert len(points) == len(scalars)
result = bls.Z1
result = bls.Z1()
for x, a in zip(points, scalars):
result = bls.add(result, bls.multiply(bls.bytes48_to_G1(x), a))
return KZGCommitment(bls.G1_to_bytes48(result))
Expand Down Expand Up @@ -323,7 +323,7 @@ def evaluate_polynomial_in_evaluation_form(polynomial: Polynomial,
a = BLSFieldElement(int(polynomial[i]) * int(roots_of_unity_brp[i]) % BLS_MODULUS)
b = BLSFieldElement((int(BLS_MODULUS) + int(z) - int(roots_of_unity_brp[i])) % BLS_MODULUS)
result += int(div(a, b) % BLS_MODULUS)
result = result * int(pow(z, width, BLS_MODULUS) - 1) * int(inverse_width)
result = result * int(BLS_MODULUS + pow(z, width, BLS_MODULUS) - 1) * int(inverse_width)
return BLSFieldElement(result % BLS_MODULUS)
```

Expand Down Expand Up @@ -371,10 +371,10 @@ def verify_kzg_proof_impl(commitment: KZGCommitment,
Verify KZG proof that ``p(z) == y`` where ``p(z)`` is the polynomial represented by ``polynomial_kzg``.
"""
# Verify: P - y = Q * (X - z)
X_minus_z = bls.add(bls.bytes96_to_G2(KZG_SETUP_G2[1]), bls.multiply(bls.G2, BLS_MODULUS - z))
P_minus_y = bls.add(bls.bytes48_to_G1(commitment), bls.multiply(bls.G1, BLS_MODULUS - y))
X_minus_z = bls.add(bls.bytes96_to_G2(KZG_SETUP_G2[1]), bls.multiply(bls.G2(), (BLS_MODULUS - z) % BLS_MODULUS))
P_minus_y = bls.add(bls.bytes48_to_G1(commitment), bls.multiply(bls.G1(), (BLS_MODULUS - y) % BLS_MODULUS))
return bls.pairing_check([
[P_minus_y, bls.neg(bls.G2)],
[P_minus_y, bls.neg(bls.G2())],
[bls.bytes48_to_G1(proof), X_minus_z]
])
```
Expand Down Expand Up @@ -415,14 +415,14 @@ def verify_kzg_proof_batch(commitments: Sequence[KZGCommitment],
proofs,
[BLSFieldElement((int(z) * int(r_power)) % BLS_MODULUS) for z, r_power in zip(zs, r_powers)],
)
C_minus_ys = [bls.add(bls.bytes48_to_G1(commitment), bls.multiply(bls.G1, BLS_MODULUS - y))
C_minus_ys = [bls.add(bls.bytes48_to_G1(commitment), bls.multiply(bls.G1(), (BLS_MODULUS - y) % BLS_MODULUS))
for commitment, y in zip(commitments, ys)]
C_minus_y_as_KZGCommitments = [KZGCommitment(bls.G1_to_bytes48(x)) for x in C_minus_ys]
C_minus_y_lincomb = g1_lincomb(C_minus_y_as_KZGCommitments, r_powers)

return bls.pairing_check([
[bls.bytes48_to_G1(proof_lincomb), bls.neg(bls.bytes96_to_G2(KZG_SETUP_G2[1]))],
[bls.add(bls.bytes48_to_G1(C_minus_y_lincomb), bls.bytes48_to_G1(proof_z_lincomb)), bls.G2]
[bls.add(bls.bytes48_to_G1(C_minus_y_lincomb), bls.bytes48_to_G1(proof_z_lincomb)), bls.G2()]
])
```

Expand Down Expand Up @@ -561,3 +561,4 @@ def verify_blob_kzg_proof_batch(blobs: Sequence[Blob],

return verify_kzg_proof_batch(commitments, evaluation_challenges, ys, proofs)
```

11 changes: 9 additions & 2 deletions tests/core/pyspec/eth2spec/test/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,11 @@ def pytest_addoption(parser):
help="bls-default: make tests that are not dependent on BLS run without BLS"
)
parser.addoption(
"--bls-type", action="store", type=str, default="py_ecc", choices=["py_ecc", "milagro"],
help="bls-type: use 'pyecc' or 'milagro' implementation for BLS"
"--bls-type", action="store", type=str, default="py_ecc", choices=["py_ecc", "milagro", "arkworks", "fastest"],
help=(
"bls-type: use specified BLS implementation;"
"fastest: use milagro for signatures and arkworks for everything else (e.g. KZG)"
)
)


Expand Down Expand Up @@ -88,5 +91,9 @@ def bls_type(request):
bls_utils.use_py_ecc()
elif bls_type == "milagro":
bls_utils.use_milagro()
elif bls_type == "arkworks":
bls_utils.use_arkworks()
elif bls_type == "fastest":
bls_utils.use_fastest()
else:
raise Exception(f"unrecognized bls type: {bls_type}")
223 changes: 196 additions & 27 deletions tests/core/pyspec/eth2spec/utils/bls.py
Original file line number Diff line number Diff line change
@@ -1,28 +1,49 @@
from py_ecc.bls import G2ProofOfPossession as py_ecc_bls
from py_ecc.bls.g2_primatives import signature_to_G2 as _signature_to_G2
from py_ecc.optimized_bls12_381 import ( # noqa: F401
G1,
G2,
Z1,
Z2,
FQ,
add,
multiply,
neg,
pairing,
final_exponentiate,
FQ12
G1 as py_ecc_G1,
G2 as py_ecc_G2,
Z1 as py_ecc_Z1,
add as py_ecc_add,
multiply as py_ecc_mul,
neg as py_ecc_neg,
pairing as py_ecc_pairing,
final_exponentiate as py_ecc_final_exponentiate,
FQ12 as py_ecc_GT,
)
from py_ecc.bls.g2_primitives import ( # noqa: F401
G1_to_pubkey as G1_to_bytes48,
pubkey_to_G1 as bytes48_to_G1,
G2_to_signature as G2_to_bytes96,
signature_to_G2 as bytes96_to_G2,
G1_to_pubkey as py_ecc_G1_to_bytes48,
pubkey_to_G1 as py_ecc_bytes48_to_G1,
G2_to_signature as py_ecc_G2_to_bytes96,
signature_to_G2 as py_ecc_bytes96_to_G2,
)
from py_arkworks_bls12381 import (
G1Point as arkworks_G1,
G2Point as arkworks_G2,
Scalar as arkworks_Scalar,
GT as arkworks_GT,
)


import milagro_bls_binding as milagro_bls # noqa: F401 for BLS switching option

import py_arkworks_bls12381 as arkworks_bls # noqa: F401 for BLS switching option


class fastest_bls:
G1 = arkworks_G1
G2 = arkworks_G2
Scalar = arkworks_Scalar
GT = arkworks_GT
_AggregatePKs = milagro_bls._AggregatePKs
Sign = milagro_bls.Sign
Verify = milagro_bls.Verify
Aggregate = milagro_bls.Aggregate
AggregateVerify = milagro_bls.AggregateVerify
FastAggregateVerify = milagro_bls.FastAggregateVerify
SkToPk = milagro_bls.SkToPk


# Flag to make BLS active or not. Used for testing, do not ignore BLS in production unless you know what you are doing.
bls_active = True

Expand All @@ -43,6 +64,14 @@ def use_milagro():
bls = milagro_bls


def use_arkworks():
"""
Shortcut to use Arkworks as BLS library
"""
global bls
bls = arkworks_bls


def use_py_ecc():
"""
Shortcut to use Py-ecc as BLS library
Expand All @@ -51,6 +80,14 @@ def use_py_ecc():
bls = py_ecc_bls


def use_fastest():
"""
Shortcut to use Milagro for signatures and Arkworks for other BLS operations
"""
global bls
bls = fastest_bls


def only_with_bls(alt_return=None):
"""
Decorator factory to make a function only run when BLS is active. Otherwise return the default.
Expand All @@ -68,7 +105,10 @@ def entry(*args, **kw):
@only_with_bls(alt_return=True)
def Verify(PK, message, signature):
try:
result = bls.Verify(PK, message, signature)
if bls == arkworks_bls: # no signature API in arkworks
djrtwo marked this conversation as resolved.
Show resolved Hide resolved
result = py_ecc_bls.Verify(PK, message, signature)
else:
result = bls.Verify(PK, message, signature)
except Exception:
result = False
finally:
Expand All @@ -78,7 +118,10 @@ def Verify(PK, message, signature):
@only_with_bls(alt_return=True)
def AggregateVerify(pubkeys, messages, signature):
try:
result = bls.AggregateVerify(list(pubkeys), list(messages), signature)
if bls == arkworks_bls: # no signature API in arkworks
result = py_ecc_bls.AggregateVerify(list(pubkeys), list(messages), signature)
else:
result = bls.AggregateVerify(list(pubkeys), list(messages), signature)
except Exception:
result = False
finally:
Expand All @@ -88,7 +131,10 @@ def AggregateVerify(pubkeys, messages, signature):
@only_with_bls(alt_return=True)
def FastAggregateVerify(pubkeys, message, signature):
try:
result = bls.FastAggregateVerify(list(pubkeys), message, signature)
if bls == arkworks_bls: # no signature API in arkworks
result = py_ecc_bls.FastAggregateVerify(list(pubkeys), message, signature)
else:
result = bls.FastAggregateVerify(list(pubkeys), message, signature)
except Exception:
result = False
finally:
Expand All @@ -97,12 +143,16 @@ def FastAggregateVerify(pubkeys, message, signature):

@only_with_bls(alt_return=STUB_SIGNATURE)
def Aggregate(signatures):
if bls == arkworks_bls: # no signature API in arkworks
return py_ecc_bls.Aggregate(signatures)
return bls.Aggregate(signatures)


@only_with_bls(alt_return=STUB_SIGNATURE)
def Sign(SK, message):
if bls == py_ecc_bls:
if bls == arkworks_bls: # no signature API in arkworks
return py_ecc_bls.Sign(SK, message)
elif bls == py_ecc_bls:
return bls.Sign(SK, message)
else:
return bls.Sign(SK.to_bytes(32, 'big'), message)
Expand All @@ -121,24 +171,143 @@ def AggregatePKs(pubkeys):
# milagro_bls._AggregatePKs checks KeyValidate internally
pass

if bls == arkworks_bls: # no signature API in arkworks
return py_ecc_bls._AggregatePKs(list(pubkeys))

return bls._AggregatePKs(list(pubkeys))


@only_with_bls(alt_return=STUB_SIGNATURE)
def SkToPk(SK):
if bls == py_ecc_bls:
return bls.SkToPk(SK)
if bls == py_ecc_bls or bls == arkworks_bls: # no signature API in arkworks
return py_ecc_bls.SkToPk(SK)
else:
return bls.SkToPk(SK.to_bytes(32, 'big'))


def pairing_check(values):
p_q_1, p_q_2 = values
final_exponentiation = final_exponentiate(
pairing(p_q_1[1], p_q_1[0], final_exponentiate=False)
* pairing(p_q_2[1], p_q_2[0], final_exponentiate=False)
)
return final_exponentiation == FQ12.one()
if bls == arkworks_bls or bls == fastest_bls:
p_q_1, p_q_2 = values
g1s = [p_q_1[0], p_q_2[0]]
g2s = [p_q_1[1], p_q_2[1]]
return arkworks_GT.multi_pairing(g1s, g2s) == arkworks_GT.one()
else:
p_q_1, p_q_2 = values
final_exponentiation = py_ecc_final_exponentiate(
py_ecc_pairing(p_q_1[1], p_q_1[0], final_exponentiate=False)
djrtwo marked this conversation as resolved.
Show resolved Hide resolved
* py_ecc_pairing(p_q_2[1], p_q_2[0], final_exponentiate=False)
)
return final_exponentiation == py_ecc_GT.one()


def add(lhs, rhs):
"""
Performs point addition of `lhs` and `rhs`.
The points can either be in G1 or G2.
"""
if bls == arkworks_bls or bls == fastest_bls:
return lhs + rhs
return py_ecc_add(lhs, rhs)


def multiply(point, scalar):
"""
Performs Scalar multiplication between
`point` and `scalar`.
`point` can either be in G1 or G2
"""
if bls == arkworks_bls or bls == fastest_bls:
int_as_bytes = scalar.to_bytes(32, 'little')
scalar = arkworks_Scalar.from_le_bytes(int_as_bytes)
return point * scalar
return py_ecc_mul(point, scalar)


def neg(point):
"""
Returns the point negation of `point`
`point` can either be in G1 or G2
"""
if bls == arkworks_bls or bls == fastest_bls:
return -point
return py_ecc_neg(point)


def Z1():
"""
Returns the identity point in G1
"""
if bls == arkworks_bls or bls == fastest_bls:
return arkworks_G1.identity()
return py_ecc_Z1


def G1():
"""
Returns the chosen generator point in G1
"""
if bls == arkworks_bls or bls == fastest_bls:
return arkworks_G1()
return py_ecc_G1


def G2():
"""
Returns the chosen generator point in G2
"""
if bls == arkworks_bls or bls == fastest_bls:
return arkworks_G2()
return py_ecc_G2


def G1_to_bytes48(point):
"""
Serializes a point in G1.
Returns a bytearray of size 48 as
we use the compressed format
"""
if bls == arkworks_bls or bls == fastest_bls:
return bytes(point.to_compressed_bytes())
return py_ecc_G1_to_bytes48(point)


def G2_to_bytes96(point):
"""
Serializes a point in G2.
Returns a bytearray of size 96 as
we use the compressed format
"""
if bls == arkworks_bls or bls == fastest_bls:
return bytes(point.to_compressed_bytes())
return py_ecc_G2_to_bytes96(point)


def bytes48_to_G1(bytes48):
"""
Deserializes a purported compressed serialized
point in G1.
- No subgroup checks are performed
- If the bytearray is not a valid serialization
of a point in G1, then this method will raise
an exception
"""
if bls == arkworks_bls or bls == fastest_bls:
return arkworks_G1.from_compressed_bytes_unchecked(bytes48)
return py_ecc_bytes48_to_G1(bytes48)


def bytes96_to_G2(bytes96):
"""
Deserializes a purported compressed serialized
point in G2.
- No subgroup checks are performed
- If the bytearray is not a valid serialization
of a point in G2, then this method will raise
an exception
"""
if bls == arkworks_bls or bls == fastest_bls:
return arkworks_G2.from_compressed_bytes_unchecked(bytes96)
return py_ecc_bytes96_to_G2(bytes96)


@only_with_bls(alt_return=True)
Expand Down
Loading