Skip to content

Commit 5a0c5bf

Browse files
authored
async verify ring signatures (#9)
* additional batch signature verification function * batch verification returns dict of errors * refine batch verification tests * consolidate verify & verify_batch into a single interface * verify invalid ietf signature * improved ring verify fn docstring * create mock signature data file for use in tests * use mock signature json file in python tests * support python formatting in dev deps & makefile * formatted python test files * doc updates * refine mock data structure * refine python tests, group by function under test * update rust tests to source from mocks.json * minor code cleanup in ring mod * use wrong data instead of different signature * makefile format should format both python & rust * improved docs for ring verification function * remove unnecessary batch size check from ring verification function * minor cleanups to ring mods * minor dry refactors * very minor nit
1 parent 7d440ed commit 5a0c5bf

File tree

13 files changed

+822
-170
lines changed

13 files changed

+822
-170
lines changed

Cargo.lock

Lines changed: 489 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@ ark-serialize = "0.4"
1313
pyo3 = { version = "0.23.3", features = ["auto-initialize"] }
1414
hex = "0.4"
1515
ark-vrf = {version = "0.1.0", features = ["bandersnatch", "ring"] }
16+
rayon = "1.10.0"
17+
18+
[dev-dependencies]
19+
serde ={ version = "1.0.217", features = ["derive"] }
20+
serde_json = "1.0.138"
21+
serde_with = { version = "3.12.0", features = ["hex"] }
1622

1723
[features]
1824
extension-module = ["pyo3/extension-module"]

Makefile

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,8 @@ test:
1313
pytest -n auto
1414

1515
docs:
16-
pdoc jam_vrf -o docs
16+
pdoc jam_vrf -o docs
17+
18+
format:
19+
cargo fmt
20+
uv run ruff format python/

docs/jam_vrf.html

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -118,26 +118,25 @@ <h1 class="modulename">
118118
<div class="attr function">
119119

120120
<span class="def">def</span>
121-
<span class="name">verify</span><span class="signature pdoc-code condensed">(<span class="param"><span class="bp">self</span>, </span><span class="param"><span class="o">/</span>, </span><span class="param"><span class="n">data</span>, </span><span class="param"><span class="n">ad</span>, </span><span class="param"><span class="n">signature</span></span><span class="return-annotation">):</span></span>
121+
<span class="name">verify</span><span class="signature pdoc-code condensed">(<span class="param"><span class="bp">self</span>, </span><span class="param"><span class="o">/</span>, </span><span class="param"><span class="n">batch</span></span><span class="return-annotation">):</span></span>
122122

123123

124124
</div>
125125
<a class="headerlink" href="#RingVerifier.verify"></a>
126126

127-
<div class="docstring"><p>Verify a ring signature against some data &amp; additional data</p>
127+
<div class="docstring"><p>Verify a batch of ring signatures</p>
128128

129-
<p><strong>Args:</strong></p>
129+
<p><strong>Args:</strong>
130+
-</p>
130131

131132
<ul>
132-
<li>data: <code>bytes</code></li>
133-
<li>ad: <code>bytes</code> - additional data</li>
134-
<li>signature: <code>bytes</code> - ring signature</li>
133+
<li>batch: [(data, additional data, signature)] - collection of data &amp; signatures to be verified. All of the tuple fields are python bytes type.</li>
135134
</ul>
136135

137136
<p><strong>Raises:</strong></p>
138137

139138
<ul>
140-
<li><code>ValueError</code> - invalid signature</li>
139+
<li><code>ValueError(Dict{index: PyErr})</code> - a dictionary mapping invalid indexes to validation errors</li>
141140
<li><code>Exception</code> - internal error</li>
142141
</ul>
143142

@@ -146,9 +145,9 @@ <h1 class="modulename">
146145
<pre><code>verifier: RingVerifier
147146

148147
try:
149-
verifier.verify(data, ad, signature)
148+
verifier.verify([data, ad, signature], [data, ad, signature])
150149
except ValueError:
151-
print("invalid signature!")
150+
print("batch contains an invalid signature!")
152151
</code></pre>
153152
</div>
154153

docs/search.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

mocks.json

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
{
2+
"ietf": {
3+
"source": "https://github.com/davxy/bandersnatch-vrf-spec/blob/6b1ceba5b3cbc834201732bcdad1377e19e9283e/assets/vectors/bandersnatch_sha-512_ell2_ietf.json#L81",
4+
"public_key": "b0e1f208f9d6e5b310b92014ea7ef3011e649dab038804759f3766e01029d623",
5+
"data": "42616e646572736e6174636820766563746f72",
6+
"additional_data": "1f42",
7+
"signature": "6d1dd583bea262323c7dc9e94e57a472e09874e435719010eeafae503c433f166dbeeab9648505fa6a95de52d611acfbb2febacc58cdc7d0ca45abd8c952ef12ce7f4a2354a6c3f97aee6cc60c6aa4c4430b12ed0f0ef304b326c776618d7609"
8+
},
9+
"ring": {
10+
"commitment": {
11+
"source": "https://github.com/davxy/bandersnatch-vrf-spec/blob/6b1ceba5b3cbc834201732bcdad1377e19e9283e/assets/vectors/bandersnatch_sha-512_ell2_ring.json#L123",
12+
"keys": [
13+
"7b32d917d5aa771d493c47b0e096886827cd056c82dbdba19e60baa8b2c60313",
14+
"d3b1bdb321123449c6e89d310bc6b7f654315eb471c84778353ce08b951ad471",
15+
"561fdb0dcfb8bd443718b942f82fe717238cbcf8d12b8d22861c8a09a984a3c5",
16+
"b0e1f208f9d6e5b310b92014ea7ef3011e649dab038804759f3766e01029d623",
17+
"4fd11f89c2a1aaefe856bb1c5d4a1fad73f4de5e41804ca2c17ba26d6e10050c",
18+
"86d06ee2c70da6cf2da2a828d8a9d8ef755ad6e580e838359a10accb086ae437",
19+
"ad6fdeda0dde0a57c51d3226b87e3795e6474393772da46101fd597fbd456c1b",
20+
"3f9dc0c4f67f207974123830c2d66988fb3fb44becbbba5a64143f376edc51d9"
21+
],
22+
"expected_commitment": "a359e70e307799b111ad89b162b4260fb4a96ebf4232e8b02d396033498d4216305ed9cff3584a4c68f03ab3df87243a80bfc965633efc23c82ca064afe105baacccbf23e47b543d16c3c4466a83242a77acc16f79b8710051b5e97c85319cf392e630ae2b14e758ab0960e372172203f4c9a41777dadd529971d7ab9d23ab29fe0e9c85ec450505dde7f5ac038274cf"
23+
},
24+
"safrole_ticket": {
25+
"source": "https://github.com/davxy/jam-test-vectors/blob/polkajam-vectors/safrole/tiny/publish-tickets-no-mark-6.json",
26+
"attempt": 1,
27+
"root": "85f9095f4abd040839d793d89ab5ff25c61e50c844ab6765e2c0b22373b5a8f6fbe5fc0cd61fdde580b3d44fe1be127197e33b91960b10d2c6fc75aec03f36e16c2a8204961097dbc2c5ba7655543385399cc9ef08bf2e520ccf3b0a7569d88492e630ae2b14e758ab0960e372172203f4c9a41777dadd529971d7ab9d23ab29fe0e9c85ec450505dde7f5ac038274cf",
28+
"entropy": "bb30a42c1e62f0afda5f0a4e8a562f7a13a24cea00ee81917b86b89e801314aa",
29+
"ring_size": 6,
30+
"signature": "1dfb7b61deee0c4a6899c1123e9e362f2b965079be576aebda0b7ac5e111186ec11372ea37a823a74a10a7d0c3b9b850d07ea9367f7560d0271a34125983fb0a4acb929b0817c4e3710915ea07e64d72198cbb2399e318940569d4c80ead4b5b39fa798e7a8327dcba940ffa77659b1850f877be7a439fc3a66191299d5ae92492d1a27a97455ca697913b3d7c7a9f95bfe58bda53a2641e4a0752f4efbb1a0417d77dedf11d514684f94b0729672a5808088b5445ceb540db00aa8934faa314a445e67a96d618c4fc1c100a69fa449cca1db6a7ac609d7bd04107f685411aa1bebecdb3897ed0d6c00b46a56381e5968b7520b215677afa1394464057709837dfb22b04b53c69011da7926c341cf6e77a2ed27912c40267c826cca53f876dad8a11740bbf7fec24eacf37246038a6da9d4fa923e40efb6d0a136ff2349fc1c6a1f0d199e87022d71cb503b9ea45a774988b0a3abe6f2a8bbeade7e72f14a27fd1fd2c34bf751a4397df18d16cea6ae40282ce51c36d85f5a90896070bcca248ecce27455c091c0f2e455ea83aaeac9b3c2df6cac95f34f7bd086746a414a3414f48f24f725ea802bc92a56a089f5af93122f85f7474380f3a3534553663ff34ea66f50ce876aa4bcec33ca5e7d0b16677c190d5c8365b3d55c3873b634ca53e988ca8860b97577f3b0265584b0544dde70556b35b86118c7b7c94232fb8fc30b6f407647ce39e40d0769e8a5d906f17a2ead9ab49ba3b3e669b3d48017ebf340e00a03ad82ad420ac3bc63b5f06cb15a0a938848a382ddaebabfe7b3ec13270f6c3e4c14aca85963f879bfc5937244bad613b0ed92f86205874a639fe758f3ab5c69222ea2460792c9c42732c74716886b2e8f9a155e5d439246bff0b21baf74f8e7b672c61f1328939f03be4e5d4dffa6f2d8231734a0ed8e82fef9dd00cb1ab1dfe37f0ddb12e1861570b6e4cab1ab80e774048227493bb8bad60df218b2a08e6d2230f1d040ce47e2d473d0e925b2a91abcb7f867ee2f41ad64409aa81a0937f130ebdf53e6ee61480c73708af790d1134b7a0b472573e1008b9c9d0ee95d40a3909d94e6cf0044d916ff9461844"
31+
}
32+
}
33+
}

pyproject.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ dev = [
1717
"pytest>=8.3.4",
1818
"pdoc>=15.0.0",
1919
"pytest-xdist>=3.6.1",
20+
"ruff>=0.8.0",
2021
]
2122

2223
[build-system]
@@ -25,3 +26,7 @@ build-backend = "maturin"
2526

2627
[tool.maturin]
2728
python-source = "python"
29+
30+
[tool.ruff]
31+
line-length = 120
32+
lint.select = ["E", "W", "I", "N", "RUF", "F"]

python/jam_vrf/jam_vrf.pyi

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
from __future__ import annotations
22

3-
from typing import List
3+
from typing import List, Tuple
44

55
__all__ = ["RingVerifier", "VRFOutput", "get_ring_commitment", "ietf_verify"]
66

77
class RingVerifier:
88
def __init__(self, commitment: bytes, ring_size: int) -> None: ...
9-
def verify(self, data: bytes, ad: bytes, signature: bytes) -> None: ...
9+
def verify(self, batch: List[Tuple[data:bytes, ad:bytes, signature:bytes]]) -> None: ...
1010

1111
class VRFOutput:
1212
def __init__(self, output: bytes) -> None: ...

python/tests/test_ietf.py

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,24 @@
11
from jam_vrf import ietf_verify
22
import pytest
3+
import json
34

4-
def test_valid_ietf_sig():
5-
# vector 7 from https://github.com/davxy/bandersnatch-vrf-spec/blob/6b1ceba5b3cbc834201732bcdad1377e19e9283e/assets/vectors/bandersnatch_sha-512_ell2_ietf.json#L81
6-
public_key = bytes.fromhex("b0e1f208f9d6e5b310b92014ea7ef3011e649dab038804759f3766e01029d623")
7-
data = bytes.fromhex("42616e646572736e6174636820766563746f72")
8-
ad = bytes.fromhex("1f42")
9-
signature = bytes.fromhex("6d1dd583bea262323c7dc9e94e57a472e09874e435719010eeafae503c433f166dbeeab9648505fa6a95de52d611acfbb2febacc58cdc7d0ca45abd8c952ef12ce7f4a2354a6c3f97aee6cc60c6aa4c4430b12ed0f0ef304b326c776618d7609")
5+
6+
def test_signature_verification():
7+
# load mock data
8+
with open("mocks.json", "r") as f:
9+
mock = json.load(f)["ietf"]
10+
public_key = bytes.fromhex(mock["public_key"])
11+
data = bytes.fromhex(mock["data"])
12+
ad = bytes.fromhex(mock["additional_data"])
13+
signature = bytes.fromhex(mock["signature"])
14+
15+
# verify valid signature
1016
ietf_verify(public_key, data, ad, signature)
1117

12-
def test_invalid_ietf_sig():
13-
# vector 7 from https://github.com/davxy/bandersnatch-vrf-spec/blob/6b1ceba5b3cbc834201732bcdad1377e19e9283e/assets/vectors/bandersnatch_sha-512_ell2_ietf.json#L81
14-
# invalid signature sourced from vector 6: https://github.com/davxy/bandersnatch-vrf-spec/blob/6b1ceba5b3cbc834201732bcdad1377e19e9283e/assets/vectors/bandersnatch_sha-512_ell2_ietf.json#L75-L78C17
15-
public_key = bytes.fromhex("b0e1f208f9d6e5b310b92014ea7ef3011e649dab038804759f3766e01029d623")
16-
data = bytes.fromhex("42616e646572736e6174636820766563746f72")
17-
ad = bytes.fromhex("1f42")
18-
signature = bytes.fromhex("9508104b820469687488d83f729288d9f70fc0523318beff44a47da10d490b3c4fa53519bd9d17acae4d1021416557d11b84dd4670b563770c14eb98161eaa080f7f9bee9077427f547e69b919cf8d63823c14b20085fd9516768e0f5e3d3f0e")
18+
# verify invalid signature (wrong data)
19+
with pytest.raises(ValueError, match="VRF verification failed"):
20+
ietf_verify(public_key, b"wrong_data", ad, signature)
21+
22+
# verify invalid signature (wrong ad)
1923
with pytest.raises(ValueError, match="VRF verification failed"):
20-
ietf_verify(public_key, data, ad, signature)
24+
ietf_verify(public_key, data, b"wrong_ad", signature)

python/tests/test_ring.py

Lines changed: 41 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,73 +1,52 @@
11
from jam_vrf import RingVerifier, get_ring_commitment
22
import pytest
3+
import json
34

4-
def test_ring_commitment():
5-
# test vector sourced from: https://github.com/davxy/bandersnatch-vrf-spec/blob/6b1ceba5b3cbc834201732bcdad1377e19e9283e/assets/vectors/bandersnatch_sha-512_ell2_ring.json#L123
6-
# public keys
7-
public_keys = [
8-
bytes.fromhex("7b32d917d5aa771d493c47b0e096886827cd056c82dbdba19e60baa8b2c60313"),
9-
bytes.fromhex("d3b1bdb321123449c6e89d310bc6b7f654315eb471c84778353ce08b951ad471"),
10-
bytes.fromhex("561fdb0dcfb8bd443718b942f82fe717238cbcf8d12b8d22861c8a09a984a3c5"),
11-
bytes.fromhex("b0e1f208f9d6e5b310b92014ea7ef3011e649dab038804759f3766e01029d623"),
12-
bytes.fromhex("4fd11f89c2a1aaefe856bb1c5d4a1fad73f4de5e41804ca2c17ba26d6e10050c"),
13-
bytes.fromhex("86d06ee2c70da6cf2da2a828d8a9d8ef755ad6e580e838359a10accb086ae437"),
14-
bytes.fromhex("ad6fdeda0dde0a57c51d3226b87e3795e6474393772da46101fd597fbd456c1b"),
15-
bytes.fromhex("3f9dc0c4f67f207974123830c2d66988fb3fb44becbbba5a64143f376edc51d9")
16-
]
175

18-
commitment = get_ring_commitment(public_keys)
19-
20-
# verify commitment
21-
expected_commitment = bytes.fromhex("a359e70e307799b111ad89b162b4260fb4a96ebf4232e8b02d396033498d4216305ed9cff3584a4c68f03ab3df87243a80bfc965633efc23c82ca064afe105baacccbf23e47b543d16c3c4466a83242a77acc16f79b8710051b5e97c85319cf392e630ae2b14e758ab0960e372172203f4c9a41777dadd529971d7ab9d23ab29fe0e9c85ec450505dde7f5ac038274cf")
22-
assert commitment == expected_commitment
23-
24-
25-
def test_valid_ring_sig():
26-
"""
27-
Verify ring VRF signature of a valid jam ticket.
28-
29-
testvector sourced from: https://github.com/davxy/jam-test-vectors/blob/polkajam-vectors/safrole/tiny/publish-tickets-no-mark-6.json
30-
"""
6+
def test_commitment_generation():
7+
# load mock data
8+
with open("mocks.json", "r") as f:
9+
mock = json.load(f)["ring"]["commitment"]
3110

32-
# safrole ticket
33-
attempt = 1
34-
signature = bytes.fromhex("1dfb7b61deee0c4a6899c1123e9e362f2b965079be576aebda0b7ac5e111186ec11372ea37a823a74a10a7d0c3b9b850d07ea9367f7560d0271a34125983fb0a4acb929b0817c4e3710915ea07e64d72198cbb2399e318940569d4c80ead4b5b39fa798e7a8327dcba940ffa77659b1850f877be7a439fc3a66191299d5ae92492d1a27a97455ca697913b3d7c7a9f95bfe58bda53a2641e4a0752f4efbb1a0417d77dedf11d514684f94b0729672a5808088b5445ceb540db00aa8934faa314a445e67a96d618c4fc1c100a69fa449cca1db6a7ac609d7bd04107f685411aa1bebecdb3897ed0d6c00b46a56381e5968b7520b215677afa1394464057709837dfb22b04b53c69011da7926c341cf6e77a2ed27912c40267c826cca53f876dad8a11740bbf7fec24eacf37246038a6da9d4fa923e40efb6d0a136ff2349fc1c6a1f0d199e87022d71cb503b9ea45a774988b0a3abe6f2a8bbeade7e72f14a27fd1fd2c34bf751a4397df18d16cea6ae40282ce51c36d85f5a90896070bcca248ecce27455c091c0f2e455ea83aaeac9b3c2df6cac95f34f7bd086746a414a3414f48f24f725ea802bc92a56a089f5af93122f85f7474380f3a3534553663ff34ea66f50ce876aa4bcec33ca5e7d0b16677c190d5c8365b3d55c3873b634ca53e988ca8860b97577f3b0265584b0544dde70556b35b86118c7b7c94232fb8fc30b6f407647ce39e40d0769e8a5d906f17a2ead9ab49ba3b3e669b3d48017ebf340e00a03ad82ad420ac3bc63b5f06cb15a0a938848a382ddaebabfe7b3ec13270f6c3e4c14aca85963f879bfc5937244bad613b0ed92f86205874a639fe758f3ab5c69222ea2460792c9c42732c74716886b2e8f9a155e5d439246bff0b21baf74f8e7b672c61f1328939f03be4e5d4dffa6f2d8231734a0ed8e82fef9dd00cb1ab1dfe37f0ddb12e1861570b6e4cab1ab80e774048227493bb8bad60df218b2a08e6d2230f1d040ce47e2d473d0e925b2a91abcb7f867ee2f41ad64409aa81a0937f130ebdf53e6ee61480c73708af790d1134b7a0b472573e1008b9c9d0ee95d40a3909d94e6cf0044d916ff9461844")
35-
ring_root = bytes.fromhex("85f9095f4abd040839d793d89ab5ff25c61e50c844ab6765e2c0b22373b5a8f6fbe5fc0cd61fdde580b3d44fe1be127197e33b91960b10d2c6fc75aec03f36e16c2a8204961097dbc2c5ba7655543385399cc9ef08bf2e520ccf3b0a7569d88492e630ae2b14e758ab0960e372172203f4c9a41777dadd529971d7ab9d23ab29fe0e9c85ec450505dde7f5ac038274cf")
36-
entropy = bytes.fromhex("bb30a42c1e62f0afda5f0a4e8a562f7a13a24cea00ee81917b86b89e801314aa")
37-
ring_size = 6
11+
# compose list of public key bytes
12+
public_keys = []
13+
for key in mock["keys"]:
14+
public_keys.append(bytes.fromhex(key))
3815

39-
# construct ring verifier
40-
verifier = RingVerifier(ring_root, ring_size)
16+
# generate commitment
17+
commitment = get_ring_commitment(public_keys)
4118

42-
# verify signature
43-
verifier.verify(
44-
b"jam_ticket_seal" + entropy + bytes([attempt]),
45-
b"",
46-
signature
47-
)
19+
# verify commitment
20+
assert commitment.hex() == mock["expected_commitment"]
4821

49-
def test_invalid_ring_sig():
50-
"""
51-
Verify ring VRF signature of an invalid jam ticket.
52-
53-
testvector sourced from: https://github.com/davxy/jam-test-vectors/blob/polkajam-vectors/safrole/tiny/publish-tickets-no-mark-6.json
54-
invalid signature sourced from: https://github.com/davxy/jam-test-vectors/blob/25aaedc8abc8c617287d9df56c916794db82eb92/safrole/tiny/publish-tickets-no-mark-3.json#L8
55-
"""
5622

57-
# safrole ticket
58-
attempt = 1
59-
signature = bytes.fromhex("1dfb7b61deee0c4a6899c1123e9e362f2b965079be576aebda0b7ac5e111186e45649b3aa58e18cb4faa3cc74688a322fcd5ab4d591dc2e183f4e31f3f5b926fefcb067f0b43fc9bda32af4bdcbf8767945d01e9816327857a3537929a304eea39fa798e7a8327dcba940ffa77659b1850f877be7a439fc3a66191299d5ae9240e005d84cfbd9fe9a1b250873d484fdf90a03e6b3238a3143f3692ef3128cf1961c8246ca93c957ea7907f7d1dd80e745ecada3f48dbdcbf14dca402df264303a445e67a96d618c4fc1c100a69fa449cca1db6a7ac609d7bd04107f685411aa1bebecdb3897ed0d6c00b46a56381e5968b7520b215677afa1394464057709837dfb22b04b53c69011da7926c341cf6e77a2ed27912c40267c826cca53f876dad8952d2acaa7ebb6da732dd2e34cc2211a953d575e70137e69ce03526f0677ffc2c77f3488b19a3383188e0beaa03fd32b97e7a991fadd8d9d2c71a2d37c836adba04e6f9b5a9f58ecdfb3aaaada4161e283ecb8c295efdf53635ba73ca20f47181e9d7529da701fb654d55d99ff7a9af4c5b678f7ba7d764c48ea2b15569ee1d20a10029a50d5b1100356b64916c6c38526d1dac1f169e5f4250f27dd9cb7454af6591aac3e7353b3a083f310d735eb7a7530fcddc3d06fad7efbca9bf7e3e22306fa2dfd6a184cf5d0acc29ef7cc35c07a7c1e2fc75bb42c80834f000c5d85b293f40ed6b605ec94df44d87712eec2ad1d1386564e5fd2491ec42317aea9058a44e850b08e2a2c4d261c7c59a96be65d89555285c24326c052b5d102cb8a8341b97fcdb28bf8ad1a5591613dc119f7bc44abba455075baf954149a05ae35f13a1e585445577cd9f13c20a04194307716df5f290403147dc728cff8324ee06b0724bbd11fb59a4f3d717a15726c41113e1fd7adcacb5e303a974dd1f6b74028bd1c61f204a43a8ec0bdcf161ff8f2310ac411ceb866d641d29ca3e68fa259f6ee960d3d5835f930f788a3021c5467b619dbc9e5b8b80a6bdac820d1f56fa282fac56c299a7b2cd1d7b2d9b81e6c28bf2a7d6da6b40a02f4ba2aee0f37311c16b941aeaa11e6e40b16f91cad2089ccfc3")
60-
ring_root = bytes.fromhex("85f9095f4abd040839d793d89ab5ff25c61e50c844ab6765e2c0b22373b5a8f6fbe5fc0cd61fdde580b3d44fe1be127197e33b91960b10d2c6fc75aec03f36e16c2a8204961097dbc2c5ba7655543385399cc9ef08bf2e520ccf3b0a7569d88492e630ae2b14e758ab0960e372172203f4c9a41777dadd529971d7ab9d23ab29fe0e9c85ec450505dde7f5ac038274cf")
61-
entropy = bytes.fromhex("bb30a42c1e62f0afda5f0a4e8a562f7a13a24cea00ee81917b86b89e801314aa")
62-
ring_size = 6
23+
def test_signature_verification():
24+
# load mock data
25+
with open("mocks.json", "r") as f:
26+
mock = json.load(f)["ring"]["safrole_ticket"]
27+
data = b"jam_ticket_seal" + bytes.fromhex(mock["entropy"]) + bytes([mock["attempt"]])
28+
ad = b""
29+
signature = bytes.fromhex(mock["signature"])
6330

6431
# construct ring verifier
65-
verifier = RingVerifier(ring_root, ring_size)
66-
67-
# verify signature
68-
with pytest.raises(ValueError, match="VRF verification failed"):
69-
verifier.verify(
70-
b"jam_ticket_seal" + entropy + bytes([attempt]),
71-
b"",
72-
signature
73-
)
32+
verifier = RingVerifier(bytes.fromhex(mock["root"]), mock["ring_size"])
33+
34+
# generate batch of valid signatures
35+
signatures = []
36+
for _ in range(2):
37+
signatures.append((data, ad, signature))
38+
39+
# verify valid signatures
40+
verifier.verify(signatures)
41+
42+
# verify batch that contains invalid signatures
43+
signatures.append((b"wrong_data", ad, signature))
44+
signatures.append((data, b"wrong_ad", signature))
45+
46+
# signature verification should raise a ValueError
47+
with pytest.raises(ValueError) as e:
48+
verifier.verify(signatures)
49+
# verify the ValueError contains a dict identifying each of the invalid signatures
50+
assert len(e.value.args[0]) == 2
51+
assert str(e.value.args[0][2]) == str(ValueError("VRF verification failed"))
52+
assert str(e.value.args[0][3]) == str(ValueError("VRF verification failed"))

0 commit comments

Comments
 (0)