bip-0458: Add half-aggregation of BIP 340 signatures

This commit is contained in:
Fabian Jahr committed 2026-11-01 07:56:15 +01:00
1 parent 1eb496599c
commit 2d439430b1
7 files changed
+1463

No files matched your search

+831
View File
@@ -0,0 +1,831 @@
#!/usr/bin/env python3
"""
Generate test vectors for Schnorr signature half-aggregation.
Usage:
python gen_test_vectors.py
Outputs:
- vectors/test_vectors_aggregate.csv
- vectors/test_vectors_incaggregate.csv
- vectors/test_vectors_verify.csv
"""
import csv
import os
from pathlib import Path
from typing import List, Tuple
from halfagg import Aggregate, IncAggregate, hashHalfAgg_randomizer
from secp256k1lab.secp256k1 import GE, FE, Scalar
from secp256k1lab.util import bytes_from_int
from secp256k1lab.bip340 import pubkey_gen, schnorr_sign, schnorr_verify
ROOT = Path(__file__).resolve().parent
VECTORS_DIR = ROOT / "vectors"
AGGREGATE_VECTORS = VECTORS_DIR / 'test_vectors_aggregate.csv'
INCAGGREGATE_VECTORS = VECTORS_DIR / 'test_vectors_incaggregate.csv'
VERIFY_VECTORS = VECTORS_DIR / 'test_vectors_verify.csv'
n = GE.ORDER
p = FE.SIZE
def create_signature(index: int, msg_len: int = 32) -> Tuple[bytes, bytes, bytes]:
"""Create a deterministic (pubkey, message, signature) triple."""
sk = bytes([index + 1] * 32)
pk = pubkey_gen(sk)
msg = bytes([index + 2] * msg_len)
aux = bytes([index + 3] * 32)
sig = schnorr_sign(msg, sk, aux)
return pk, msg, sig
def format_list(items: List[bytes], sep: str = ";") -> str:
"""Format a list of bytes as semicolon-separated hex strings."""
if not items:
return ""
return sep.join(item.hex().upper() for item in items)
def gen_aggregate_vectors(f):
"""Generate test vectors for Aggregate function."""
writer = csv.writer(f)
writer.writerow((
"index",
"pubkeys",
"messages",
"signatures",
"expected_result",
"expected_aggsig",
"comment"
))
idx = 0
sigs = [create_signature(i) for i in range(5)]
# Success: Empty aggregation
aggsig_empty = Aggregate([])
writer.writerow((
idx, "", "", "",
"TRUE",
aggsig_empty.hex().upper(),
"Empty signature list"
))
idx += 1
# Success: Single signature
pk0, msg0, sig0 = sigs[0]
aggsig_1 = Aggregate([(pk0, msg0, sig0)])
writer.writerow((
idx,
pk0.hex().upper(),
msg0.hex().upper(),
sig0.hex().upper(),
"TRUE",
aggsig_1.hex().upper(),
"Single signature"
))
idx += 1
# Success: Two signatures
pk1, msg1, sig1 = sigs[1]
pms_2 = [(pk0, msg0, sig0), (pk1, msg1, sig1)]
aggsig_2 = Aggregate(pms_2)
writer.writerow((
idx,
format_list([pk0, pk1]),
format_list([msg0, msg1]),
format_list([sig0, sig1]),
"TRUE",
aggsig_2.hex().upper(),
"Two signatures"
))
idx += 1
# Success: Three signatures
pk2, msg2, sig2 = sigs[2]
pms_3 = [(pk0, msg0, sig0), (pk1, msg1, sig1), (pk2, msg2, sig2)]
aggsig_3 = Aggregate(pms_3)
writer.writerow((
idx,
format_list([pk0, pk1, pk2]),
format_list([msg0, msg1, msg2]),
format_list([sig0, sig1, sig2]),
"TRUE",
aggsig_3.hex().upper(),
"Three signatures"
))
idx += 1
# Success: Five signatures
pms_5 = [sigs[i] for i in range(5)]
aggsig_5 = Aggregate(pms_5)
writer.writerow((
idx,
format_list([s[0] for s in pms_5]),
format_list([s[1] for s in pms_5]),
format_list([s[2] for s in pms_5]),
"TRUE",
aggsig_5.hex().upper(),
"Five signatures"
))
idx += 1
# Success: Strange aggregation - individual invalid sigs that are valid
# in aggregate
pk_a, msg_a, sig_a = sigs[0]
pk_b, msg_b, sig_b = sigs[1]
pms_valid = [(pk_a, msg_a, sig_a), (pk_b, msg_b, sig_b)]
aggsig_valid = Aggregate(pms_valid)
pmr = []
z = []
for i in range(2):
pk, msg, sig = pms_valid[i]
pmr.append((pk, msg, sig[:32]))
z.append(hashHalfAgg_randomizer(pmr))
sagg = Scalar.from_bytes_wrapping(aggsig_valid[64:96])
s1_new = Scalar.from_int_wrapping(0x123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0)
s0_new = (sagg - z[1] * s1_new) / z[0]
sig_a_invalid = sig_a[:32] + s0_new.to_bytes()
assert not schnorr_verify(msg_a, pk_a, sig_a_invalid), "sig_a_invalid should not verify"
sig_b_invalid = sig_b[:32] + s1_new.to_bytes()
assert not schnorr_verify(msg_b, pk_b, sig_b_invalid), "sig_b_invalid should not verify"
pms_strange = [(pk_a, msg_a, sig_a_invalid), (pk_b, msg_b, sig_b_invalid)]
aggsig_strange = Aggregate(pms_strange)
writer.writerow((
idx,
format_list([pk_a, pk_b]),
format_list([msg_a, msg_b]),
format_list([sig_a_invalid, sig_b_invalid]),
"TRUE",
aggsig_strange.hex().upper(),
"Strange aggregation - invalid individual sigs, valid aggregate"
))
idx += 1
# Failure: Signature with s = n
invalid_sig_n = sig0[0:32] + bytes_from_int(n)
writer.writerow((
idx,
pk0.hex().upper(),
msg0.hex().upper(),
invalid_sig_n.hex().upper(),
"FALSE",
"",
"Signature s = n (at boundary)"
))
idx += 1
# Failure: Signature with s > n
invalid_sig_gt_n = sig0[0:32] + bytes_from_int(n + 1000)
writer.writerow((
idx,
pk0.hex().upper(),
msg0.hex().upper(),
invalid_sig_gt_n.hex().upper(),
"FALSE",
"",
"Signature s > n"
))
idx += 1
# Failure: Signature with s = 2^256 - 1
invalid_sig_max = sig0[0:32] + bytes([0xff] * 32)
writer.writerow((
idx,
pk0.hex().upper(),
msg0.hex().upper(),
invalid_sig_max.hex().upper(),
"FALSE",
"",
"Signature s = 2^256 - 1"
))
idx += 1
# Failure: Public key too short
writer.writerow((
idx,
pk0[0:31].hex().upper(),
msg0.hex().upper(),
sig0.hex().upper(),
"FALSE",
"",
"Public key too short"
))
idx += 1
# Failure: Message too long
pk_long, msg_long, sig_long = create_signature(0, 33)
writer.writerow((
idx,
pk_long.hex().upper(),
msg_long.hex().upper(),
sig_long.hex().upper(),
"FALSE",
"",
"Message too long"
))
idx += 1
# Failure: Signature too short
writer.writerow((
idx,
pk0.hex().upper(),
msg0.hex().upper(),
sig0[0:63].hex().upper(),
"FALSE",
"",
"Signature too short"
))
idx += 1
# Failure: Signature too long
writer.writerow((
idx,
pk0.hex().upper(),
msg0.hex().upper(),
(sig0 + bytes([0])).hex().upper(),
"FALSE",
"",
"Signature too long"
))
idx += 1
# Failure: Public key too long
writer.writerow((
idx,
(bytes([2]) + pk0).hex().upper(),
msg0.hex().upper(),
sig0.hex().upper(),
"FALSE",
"",
"Public key too long"
))
idx += 1
# Failure: Message too short
pk_short, msg_short, sig_short = create_signature(0, 31)
writer.writerow((
idx,
pk_short.hex().upper(),
msg_short.hex().upper(),
sig_short.hex().upper(),
"FALSE",
"",
"Message too short"
))
idx += 1
def gen_incaggregate_vectors(f):
"""Generate test vectors for IncAggregate function."""
writer = csv.writer(f)
writer.writerow((
"index",
"aggsig",
"pm_aggd_pubkeys",
"pm_aggd_messages",
"pms_pubkeys",
"pms_messages",
"pms_signatures",
"expected_result",
"expected_aggsig",
"comment"
))
idx = 0
sigs = [create_signature(i) for i in range(4)]
pk0, msg0, sig0 = sigs[0]
pk1, msg1, sig1 = sigs[1]
pk2, msg2, sig2 = sigs[2]
# Success: Increment empty aggregate with single signature
empty_aggsig = bytes([0] * 32)
result_0 = IncAggregate(empty_aggsig, [], [(pk0, msg0, sig0)])
writer.writerow((
idx,
empty_aggsig.hex().upper(),
"", "",
pk0.hex().upper(),
msg0.hex().upper(),
sig0.hex().upper(),
"TRUE",
result_0.hex().upper(),
"Add single signature to empty aggregate"
))
idx += 1
# Success: Increment single-sig aggregate with another signature
aggsig_1 = Aggregate([(pk0, msg0, sig0)])
result_1 = IncAggregate(aggsig_1, [(pk0, msg0)], [(pk1, msg1, sig1)])
writer.writerow((
idx,
aggsig_1.hex().upper(),
pk0.hex().upper(),
msg0.hex().upper(),
pk1.hex().upper(),
msg1.hex().upper(),
sig1.hex().upper(),
"TRUE",
result_1.hex().upper(),
"Add second signature to single-sig aggregate"
))
idx += 1
# Success: Add two signatures at once
result_2 = IncAggregate(aggsig_1, [(pk0, msg0)], [(pk1, msg1, sig1), (pk2, msg2, sig2)])
writer.writerow((
idx,
aggsig_1.hex().upper(),
pk0.hex().upper(),
msg0.hex().upper(),
format_list([pk1, pk2]),
format_list([msg1, msg2]),
format_list([sig1, sig2]),
"TRUE",
result_2.hex().upper(),
"Add two signatures at once"
))
idx += 1
# Success: Increment with empty new signatures (no change)
result_3 = IncAggregate(aggsig_1, [(pk0, msg0)], [])
writer.writerow((
idx,
aggsig_1.hex().upper(),
pk0.hex().upper(),
msg0.hex().upper(),
"", "", "",
"TRUE",
result_3.hex().upper(),
"Add no new signatures (unchanged)"
))
idx += 1
# Failure: Wrong aggsig length (too long)
wrong_len_aggsig = bytes([0] * 64)
writer.writerow((
idx,
wrong_len_aggsig.hex().upper(),
"", "",
"", "", "",
"FALSE",
"",
"Aggregate signature wrong length"
))
idx += 1
# Failure: Empty aggsig
writer.writerow((
idx,
"",
"", "",
"", "", "",
"FALSE",
"",
"Aggregate signature empty"
))
idx += 1
# Failure: Existing aggsig with s = n
invalid_aggsig_s = bytes_from_int(n)
writer.writerow((
idx,
invalid_aggsig_s.hex().upper(),
"", "",
"", "", "",
"FALSE",
"",
"Existing aggregate has s = n"
))
idx += 1
# Failure: New signature with s = n
invalid_new_sig = sig0[0:32] + bytes_from_int(n)
writer.writerow((
idx,
empty_aggsig.hex().upper(),
"", "",
pk0.hex().upper(),
msg0.hex().upper(),
invalid_new_sig.hex().upper(),
"FALSE",
"",
"New signature has s = n"
))
idx += 1
# Failure: Existing public key too short
writer.writerow((
idx,
aggsig_1.hex().upper(),
pk0[0:31].hex().upper(),
msg0.hex().upper(),
pk1.hex().upper(),
msg1.hex().upper(),
sig1.hex().upper(),
"FALSE",
"",
"Existing public key too short"
))
idx += 1
# Failure: Existing message too long
pk_long, msg_long, sig_long = create_signature(0, 33)
writer.writerow((
idx,
sig_long.hex().upper(),
pk_long.hex().upper(),
msg_long.hex().upper(),
pk1.hex().upper(),
msg1.hex().upper(),
sig1.hex().upper(),
"FALSE",
"",
"Existing message too long"
))
idx += 1
# Failure: Existing public key too long
writer.writerow((
idx,
aggsig_1.hex().upper(),
(bytes([2]) + pk0).hex().upper(),
msg0.hex().upper(),
pk1.hex().upper(),
msg1.hex().upper(),
sig1.hex().upper(),
"FALSE",
"",
"Existing public key too long"
))
idx += 1
# Failure: Existing message too short
pk_short, msg_short, sig_short = create_signature(0, 31)
writer.writerow((
idx,
sig_short.hex().upper(),
pk_short.hex().upper(),
msg_short.hex().upper(),
pk1.hex().upper(),
msg1.hex().upper(),
sig1.hex().upper(),
"FALSE",
"",
"Existing message too short"
))
idx += 1
def gen_verify_vectors(f):
"""Generate test vectors for VerifyAggregate function."""
writer = csv.writer(f)
writer.writerow((
"index",
"aggsig",
"pubkeys",
"messages",
"expected_result",
"comment"
))
idx = 0
sigs = [create_signature(i) for i in range(5)]
pk0, msg0, sig0 = sigs[0]
pk1, msg1, sig1 = sigs[1]
pk2, msg2, sig2 = sigs[2]
# Success: Empty signature list
writer.writerow((
idx,
"0000000000000000000000000000000000000000000000000000000000000000",
"", "",
"TRUE",
"Empty signature list"
))
idx += 1
# Success: Single signature
writer.writerow((
idx,
"B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA80E066C34819936549FF49B6FD4D41EDFC401A367B87DDD59FEE38177961C225F",
"1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F",
"0202020202020202020202020202020202020202020202020202020202020202",
"TRUE",
"Single signature"
))
idx += 1
# Success: Two signatures
pk3, msg3, sig3 = sigs[3]
aggsig_2 = Aggregate([(pk0, msg0, sig0), (pk3, msg3, sig3)])
writer.writerow((
idx,
aggsig_2.hex().upper(),
format_list([pk0, pk3]),
format_list([msg0, msg3]),
"TRUE",
"Two signatures"
))
idx += 1
# Success: Three signatures
aggsig_3 = Aggregate([(pk0, msg0, sig0), (pk1, msg1, sig1), (pk2, msg2, sig2)])
writer.writerow((
idx,
aggsig_3.hex().upper(),
format_list([pk0, pk1, pk2]),
format_list([msg0, msg1, msg2]),
"TRUE",
"Three signatures"
))
idx += 1
# Success: Five signatures
pms_5 = [sigs[i] for i in range(5)]
aggsig_5 = Aggregate(pms_5)
writer.writerow((
idx,
aggsig_5.hex().upper(),
format_list([s[0] for s in pms_5]),
format_list([s[1] for s in pms_5]),
"TRUE",
"Five signatures"
))
idx += 1
# Failure: Public key not on curve
aggsig_1 = Aggregate([(pk0, msg0, sig0)])
invalid_x = 0x4A298DACAE57395A15D0795DDBFD1DCB564DA82B0F269BC70A74F8220429BA1D # From BIP340
invalid_pk = bytes_from_int(invalid_x)
writer.writerow((
idx,
aggsig_1.hex().upper(),
invalid_pk.hex().upper(),
msg0.hex().upper(),
"FALSE",
"Public key not on curve"
))
idx += 1
# Failure: Public key is zero
zero_pk = bytes([0] * 32)
writer.writerow((
idx,
aggsig_1.hex().upper(),
zero_pk.hex().upper(),
msg0.hex().upper(),
"FALSE",
"Public key is zero"
))
idx += 1
# Failure: Public key >= field size
pk_too_large = bytes_from_int(p)
writer.writerow((
idx,
aggsig_1.hex().upper(),
pk_too_large.hex().upper(),
msg0.hex().upper(),
"FALSE",
"Public key >= field size"
))
idx += 1
# Failure: R value not on curve
invalid_r = bytes_from_int(invalid_x)
invalid_r_aggsig = invalid_r + sig0[32:64]
writer.writerow((
idx,
invalid_r_aggsig.hex().upper(),
pk0.hex().upper(),
msg0.hex().upper(),
"FALSE",
"R value not on curve"
))
idx += 1
# Failure: R value is zero
zero_r_aggsig = bytes([0] * 32) + sig0[32:64]
writer.writerow((
idx,
zero_r_aggsig.hex().upper(),
pk0.hex().upper(),
msg0.hex().upper(),
"FALSE",
"R value is zero"
))
idx += 1
# Failure: R value >= field size
r_too_large_aggsig = bytes_from_int(p + 100) + sig0[32:64]
writer.writerow((
idx,
r_too_large_aggsig.hex().upper(),
pk0.hex().upper(),
msg0.hex().upper(),
"FALSE",
"R value >= field size"
))
idx += 1
# Failure: Aggregate s = n
s_n_aggsig = sig0[0:32] + bytes_from_int(n)
writer.writerow((
idx,
s_n_aggsig.hex().upper(),
pk0.hex().upper(),
msg0.hex().upper(),
"FALSE",
"Aggregate s = n"
))
idx += 1
# Failure: Aggregate s > n
s_gt_n_aggsig = sig0[0:32] + bytes_from_int(n + 1000)
writer.writerow((
idx,
s_gt_n_aggsig.hex().upper(),
pk0.hex().upper(),
msg0.hex().upper(),
"FALSE",
"Aggregate s > n"
))
idx += 1
# Failure: Aggregate s = 2^256 - 1
max_s_aggsig = sig0[0:32] + bytes([0xff] * 32)
writer.writerow((
idx,
max_s_aggsig.hex().upper(),
pk0.hex().upper(),
msg0.hex().upper(),
"FALSE",
"Aggregate s = 2^256 - 1"
))
idx += 1
# Failure: Wrong message
wrong_msg = bytes([0xff] * 32)
writer.writerow((
idx,
aggsig_1.hex().upper(),
pk0.hex().upper(),
wrong_msg.hex().upper(),
"FALSE",
"Wrong message"
))
idx += 1
# Failure: Wrong public key
writer.writerow((
idx,
aggsig_1.hex().upper(),
pk1.hex().upper(),
msg0.hex().upper(),
"FALSE",
"Wrong public key"
))
idx += 1
# Failure: Tampered signature
tampered_aggsig = aggsig_1[:-1] + bytes([(aggsig_1[-1] + 1) % 256])
writer.writerow((
idx,
tampered_aggsig.hex().upper(),
pk0.hex().upper(),
msg0.hex().upper(),
"FALSE",
"Tampered signature (bit flip)"
))
idx += 1
# Failure: Swapped order
aggsig_2 = Aggregate([(pk0, msg0, sig0), (pk1, msg1, sig1)])
writer.writerow((
idx,
aggsig_2.hex().upper(),
format_list([pk1, pk0]),
format_list([msg1, msg0]),
"FALSE",
"Swapped order"
))
idx += 1
# Failure: s = n - 1 (valid range, wrong signature)
s_n_minus_1_aggsig = sig0[0:32] + bytes_from_int(n - 1)
writer.writerow((
idx,
s_n_minus_1_aggsig.hex().upper(),
pk0.hex().upper(),
msg0.hex().upper(),
"FALSE",
"s = n-1 (valid range, wrong sig)"
))
idx += 1
# Failure: s = 0 (valid range, wrong signature)
s_zero_aggsig = sig0[0:32] + bytes([0] * 32)
writer.writerow((
idx,
s_zero_aggsig.hex().upper(),
pk0.hex().upper(),
msg0.hex().upper(),
"FALSE",
"s = 0 (valid range, wrong sig)"
))
idx += 1
# Failure: Aggsig too short
writer.writerow((
idx,
sig0[0:31].hex().upper(),
pk0.hex().upper(),
msg0.hex().upper(),
"FALSE",
"Aggregate signature too short"
))
idx += 1
# Failure: Aggsig too long
writer.writerow((
idx,
(aggsig_1 + bytes([0] * 32)).hex().upper(),
pk0.hex().upper(),
msg0.hex().upper(),
"FALSE",
"Aggregate signature too long"
))
idx += 1
# Failure: Public key too short
writer.writerow((
idx,
aggsig_1.hex().upper(),
pk0[0:31].hex().upper(),
msg0.hex().upper(),
"FALSE",
"Public key too short"
))
idx += 1
# Failure: Message too long
pk_long, msg_long, sig_long = create_signature(0, 33)
writer.writerow((
idx,
sig_long.hex().upper(),
pk_long.hex().upper(),
msg_long.hex().upper(),
"FALSE",
"Message too long"
))
idx += 1
# Failure: Public key too long
writer.writerow((
idx,
aggsig_1.hex().upper(),
(bytes([2]) + pk0).hex().upper(),
msg0.hex().upper(),
"FALSE",
"Public key too long"
))
idx += 1
# Failure: Message too short
pk_short, msg_short, sig_short = create_signature(0, 31)
writer.writerow((
idx,
sig_short.hex().upper(),
pk_short.hex().upper(),
msg_short.hex().upper(),
"FALSE",
"Message too short"
))
idx += 1
if __name__ == "__main__":
os.makedirs(VECTORS_DIR, exist_ok=True)
print(f"Generating {AGGREGATE_VECTORS}")
with open(AGGREGATE_VECTORS, "w", newline='', encoding="utf-8") as f:
gen_aggregate_vectors(f)
print(f"Generating {INCAGGREGATE_VECTORS}")
with open(INCAGGREGATE_VECTORS, "w", newline='', encoding="utf-8") as f:
gen_incaggregate_vectors(f)
print(f"Generating {VERIFY_VECTORS}")
with open(VERIFY_VECTORS, "w", newline='', encoding="utf-8") as f:
gen_verify_vectors(f)
print("Done.")
+197
View File
@@ -0,0 +1,197 @@
#!/usr/bin/env python3
"""
Schnorr signature half-aggregation reference implementation
WARNING: This implementation is for demonstration purposes only and _not_ to
be used in production environments.
"""
from pathlib import Path
import sys
sys.path.insert(0, str(Path(__file__).parent / "secp256k1lab/src"))
from secp256k1lab.secp256k1 import (
G,
GE,
Scalar,
)
from secp256k1lab.util import (
tagged_hash,
)
def Aggregate(pms):
"""
Aggregates an array of triples (public key, message, signature) into a single aggregate signature.
:param pms: An array of triples (public key, message, signature).
:return: The aggregate signature.
"""
# Let aggsig = bytes(0)
aggsig = bytes([0] * 32)
pm_aggd = []
# Return IncAggregate(aggsig, pms0..u-1); fail if that fails.
return IncAggregate(aggsig, pm_aggd, pms)
# IncAggregate(aggsig, pm_aggd0..v-1, pms_to_agg0..u-1)
def IncAggregate(aggsig, pm_aggd, pms_to_agg):
"""
Incrementally aggregates an additional array of triples (public key, message, signature)
into an existing aggregate signature.
:param aggsig: A byte array representing the aggregate signature.
:param pm_aggd: An array of tuples (public key, message).
:param pms_to_agg: An array of triples (public key, message, signature).
:return: The new aggregate signature.
"""
v = len(pm_aggd)
u = len(pms_to_agg)
# Fail if len(aggsig) ≠ 32 * (v + 1)
if len(aggsig) != 32 * (v + 1):
raise ValueError("Length of aggsig must be 32 * (v + 1)")
r_values = []
pmr_to_agg = []
# For i = 0 .. v-1:
for i in range(v):
# Let (pki, mi) = pm_aggdi
(pki, mi) = pm_aggd[i]
if len(pki) != 32 or len(mi) != 32:
raise ValueError("Public key and message must be 32 bytes")
# Let ri = aggsig[i⋅32:(i+1)⋅32]
ri = aggsig[i * 32:(i + 1) * 32]
r_values.append(ri)
pmr_to_agg.append((pki, mi, ri))
z_values = []
s_values = []
# For i = v .. v+u-1:
for i in range(v, v + u):
# Let (pki, mi, sigi) = pms_to_aggi-v
(pki, mi, sigi) = pms_to_agg[i - v]
if len(pki) != 32 or len(mi) != 32 or len(sigi) != 64:
raise ValueError("Public key and message must be 32 bytes and signature 64 bytes")
# Let ri = sigi[0:32]
ri = sigi[0:32]
r_values.append(ri)
# Let si = int(sigi[32:64]); fail if si ≥ n
si = Scalar.from_bytes_checked(sigi[32:64])
s_values.append(si)
# If i = 0:
# Let zi = 1
# Else:
# Let zi = int(hashBIP0458/randomizer(r0 || pk0 || m0 || ... || ri || pki || mi)) mod n
pmr_to_agg.append((pki, mi, ri))
z_values.append(hashHalfAgg_randomizer(pmr_to_agg))
# Let sagg = int(aggsig[v⋅32:(v+1)⋅32]); fail if sagg ≥ n
s = Scalar.from_bytes_checked(aggsig[v * 32:(v + 1) * 32])
# Let s = sagg + zv⋅sv + ... + zv+u-1⋅sv+u-1 mod n
for i in range(u):
s = s + z_values[i] * s_values[i]
# Return r0 || ... || rv+u-1 || bytes(s)
return b''.join(r_values) + s.to_bytes()
# VerifyAggregate(aggsig, pm_aggd0..u-1)
def VerifyAggregate(aggsig, pm_aggd):
"""
Verifies an aggregate signature against an array of public key and message tuples.
:param aggsig: A byte array representing the aggregate signature.
:param pm_aggd: An array of tuples (public key, message).
:return: Boolean indicating whether the verification is successful.
"""
u = len(pm_aggd)
# Fail if len(aggsig) ≠ 32 * (u + 1)
if len(aggsig) != 32 * (u + 1):
raise ValueError("Length of aggsig must be 32 * (u + 1)")
z_values = []
R_values = []
P_values = []
e_values = []
r_values = []
# For i = 0 .. u-1:
for i in range(u):
# Let (pki, mi) = pm_aggdi
(pki, mi) = pm_aggd[i]
if len(pki) != 32 or len(mi) != 32:
raise ValueError("Public key and message must be 32 bytes")
# Let Pi = lift_x(int(pki)); fail if that fails
try:
Pi = GE.from_bytes_xonly(pki)
except ValueError:
return False
P_values.append(Pi)
# Let ri = aggsig[i⋅32:(i+1)⋅32]
ri = aggsig[i * 32:(i + 1) * 32]
# Let Ri = lift_x(int(ri)); fail if that fails
try:
Ri = GE.from_bytes_xonly(ri)
except ValueError:
return False
R_values.append(Ri)
r_values.append(ri)
# Let ei = int(hashBIP0340/challenge(ri || pki || mi)) mod n
ei = Scalar.from_bytes_wrapping(hashBIP0340_challenge(ri, pki, mi))
e_values.append(ei)
# If i = 0:
# Let zi = 1
# Else:
# Let zi = int(hashBIP0458/randomizer(r0 || pk0 || m0 || ... || ri || pki || mi)) mod n
pmr = [(pki, mi, ri) for (pki, mi), ri in zip(pm_aggd, r_values)]
z_values.append(hashHalfAgg_randomizer(pmr))
# Let s = int(aggsig[u⋅32:(u+1)⋅32]); fail if s ≥ n
try:
s = Scalar.from_bytes_checked(aggsig[u * 32:(u + 1) * 32])
except ValueError:
return False
# Fail if s⋅G ≠ z0⋅(R0 + e0⋅P0) + ... + zu-1⋅(Ru-1 + eu-1⋅Pu-1)
lhs = s * G
rhs = GE()
for i in range(u):
rhs += z_values[i] * (R_values[i] + e_values[i] * P_values[i])
return lhs == rhs
def hashBIP0340_challenge(sig, pubkey, msg):
return tagged_hash("BIP0340/challenge", sig + pubkey + msg)
def hashHalfAgg_randomizer(pmr):
if len(pmr) == 1:
return Scalar(1)
random_input = bytes()
for (pki, mi, ri) in pmr:
random_input += ri
random_input += pki
random_input += mi
return Scalar.from_bytes_wrapping(tagged_hash("BIP0458/randomizer", random_input))
+161
View File
@@ -0,0 +1,161 @@
#!/usr/bin/env python3
"""
Run test vectors for Schnorr signature half-aggregation.
Usage:
python run_test_vectors.py
Expects CSV files generated by gen_test_vectors.py in vectors/ directory.
"""
import csv
import os
from pathlib import Path
import sys
from typing import List, Tuple
from halfagg import Aggregate, IncAggregate, VerifyAggregate
ROOT = Path(__file__).resolve().parent
VECTORS_DIR = ROOT / "vectors"
AGGREGATE_VECTORS = VECTORS_DIR / 'test_vectors_aggregate.csv'
INCAGGREGATE_VECTORS = VECTORS_DIR / 'test_vectors_incaggregate.csv'
VERIFY_VECTORS = VECTORS_DIR / 'test_vectors_verify.csv'
def parse_hex_list(hex_str: str) -> List[bytes]:
if not hex_str:
return []
return [bytes.fromhex(h) for h in hex_str.split(';')]
def parse_pms(pks_str: str, msgs_str: str, sigs_str: str) -> List[Tuple[bytes, bytes, bytes]]:
pks = parse_hex_list(pks_str)
msgs = parse_hex_list(msgs_str)
sigs = parse_hex_list(sigs_str)
if not pks:
return []
return list(zip(pks, msgs, sigs))
def parse_pm(pks_str: str, msgs_str: str) -> List[Tuple[bytes, bytes]]:
pks = parse_hex_list(pks_str)
msgs = parse_hex_list(msgs_str)
if not pks:
return []
return list(zip(pks, msgs))
def run_aggregate_tests() -> List[str]:
"""Run Aggregate test vectors. Returns list of failed test descriptions."""
failures = []
with open(AGGREGATE_VECTORS, newline='', encoding='utf-8') as f:
reader = csv.reader(f)
next(reader)
for row in reader:
index, pks_str, msgs_str, sigs_str, expected_result, expected_aggsig, comment = row
pms = parse_pms(pks_str, msgs_str, sigs_str)
if expected_result == "FALSE":
try:
Aggregate(pms)
failures.append(f"Aggregate #{index}: {comment}")
except ValueError:
pass
else:
try:
actual = Aggregate(pms)
if actual != bytes.fromhex(expected_aggsig):
failures.append(f"Aggregate #{index}: {comment}")
except ValueError:
failures.append(f"Aggregate #{index}: {comment}")
return failures
def run_incaggregate_tests() -> List[str]:
"""Run IncAggregate test vectors. Returns list of failed test descriptions."""
failures = []
with open(INCAGGREGATE_VECTORS, newline='', encoding='utf-8') as f:
reader = csv.reader(f)
next(reader)
for row in reader:
(index, aggsig_str, pm_pks_str, pm_msgs_str,
pms_pks_str, pms_msgs_str, pms_sigs_str,
expected_result, expected_aggsig, comment) = row
aggsig = bytes.fromhex(aggsig_str) if aggsig_str else bytes()
pm_aggd = parse_pm(pm_pks_str, pm_msgs_str)
pms_to_agg = parse_pms(pms_pks_str, pms_msgs_str, pms_sigs_str)
if expected_result == "FALSE":
try:
IncAggregate(aggsig, pm_aggd, pms_to_agg)
failures.append(f"IncAggregate #{index}: {comment}")
except ValueError:
pass
else:
try:
actual = IncAggregate(aggsig, pm_aggd, pms_to_agg)
if actual != bytes.fromhex(expected_aggsig):
failures.append(f"IncAggregate #{index}: {comment}")
except ValueError:
failures.append(f"IncAggregate #{index}: {comment}")
return failures
def run_verify_tests() -> List[str]:
"""Run VerifyAggregate test vectors. Returns list of failed test descriptions."""
failures = []
with open(VERIFY_VECTORS, newline='', encoding='utf-8') as f:
reader = csv.reader(f)
next(reader)
for row in reader:
index, aggsig_str, pks_str, msgs_str, expected_result, comment = row
aggsig = bytes.fromhex(aggsig_str)
pm = parse_pm(pks_str, msgs_str)
try:
result = VerifyAggregate(aggsig, pm)
expected = (expected_result == "TRUE")
if result != expected:
failures.append(f"VerifyAggregate #{index}: {comment}")
except ValueError:
if expected_result == "TRUE":
failures.append(f"VerifyAggregate #{index}: {comment}")
return failures
def main():
for filename in [AGGREGATE_VECTORS, INCAGGREGATE_VECTORS, VERIFY_VECTORS]:
if not os.path.exists(filename):
print(f"ERROR: Missing {filename}. Run gen_test_vectors.py first.")
sys.exit(1)
failures = []
failures.extend(run_aggregate_tests())
failures.extend(run_incaggregate_tests())
failures.extend(run_verify_tests())
if failures:
print("FAILED:")
for f in failures:
print(f" {f}")
sys.exit(1)
else:
print("All tests have passed.")
sys.exit(0)
if __name__ == "__main__":
main()
@@ -0,0 +1,16 @@
index,pubkeys,messages,signatures,expected_result,expected_aggsig,comment
0,,,,TRUE,0000000000000000000000000000000000000000000000000000000000000000,Empty signature list
1,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F,0202020202020202020202020202020202020202020202020202020202020202,B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA80E066C34819936549FF49B6FD4D41EDFC401A367B87DDD59FEE38177961C225F,TRUE,B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA80E066C34819936549FF49B6FD4D41EDFC401A367B87DDD59FEE38177961C225F,Single signature
2,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F;4D4B6CD1361032CA9BD2AEB9D900AA4D45D9EAD80AC9423374C451A7254D0766,0202020202020202020202020202020202020202020202020202020202020202;0303030303030303030303030303030303030303030303030303030303030303,B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA80E066C34819936549FF49B6FD4D41EDFC401A367B87DDD59FEE38177961C225F;C9D9B1CCE8C0A99AA79F56185358CD82B7649D6132DAACB31612C7C9B14CE3A9233428AEB77468852520B0256DE84562A29629194DAEAC45444C7711CD379E57,TRUE,B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA8C9D9B1CCE8C0A99AA79F56185358CD82B7649D6132DAACB31612C7C9B14CE3A9F51B04478B464890B540F1BBE15E5E5965A348F2B3D09BD4021D9E1F67D9D774,Two signatures
3,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F;4D4B6CD1361032CA9BD2AEB9D900AA4D45D9EAD80AC9423374C451A7254D0766;531FE6068134503D2723133227C867AC8FA6C83C537E9A44C3C5BDBDCB1FE337,0202020202020202020202020202020202020202020202020202020202020202;0303030303030303030303030303030303030303030303030303030303030303;0404040404040404040404040404040404040404040404040404040404040404,B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA80E066C34819936549FF49B6FD4D41EDFC401A367B87DDD59FEE38177961C225F;C9D9B1CCE8C0A99AA79F56185358CD82B7649D6132DAACB31612C7C9B14CE3A9233428AEB77468852520B0256DE84562A29629194DAEAC45444C7711CD379E57;F62B58B1908197B6D732F0564AD2AD5C6E438D24C65AF758DA9ACCCCCF5B3F923A17EA0CD56ED3A824AA14BC67839CED465BA5269700F600EDFC3DAAC8A6B069,TRUE,B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA8C9D9B1CCE8C0A99AA79F56185358CD82B7649D6132DAACB31612C7C9B14CE3A9F62B58B1908197B6D732F0564AD2AD5C6E438D24C65AF758DA9ACCCCCF5B3F92B7A5E19F2F438EAE2D3D9630B4D69921A7E920CBF6E54585261B21D7E1395493,Three signatures
4,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F;4D4B6CD1361032CA9BD2AEB9D900AA4D45D9EAD80AC9423374C451A7254D0766;531FE6068134503D2723133227C867AC8FA6C83C537E9A44C3C5BDBDCB1FE337;462779AD4AAD39514614751A71085F2F10E1C7A593E4E030EFB5B8721CE55B0B;62C0A046DACCE86DDD0343C6D3C7C79C2208BA0D9C9CF24A6D046D21D21F90F7,0202020202020202020202020202020202020202020202020202020202020202;0303030303030303030303030303030303030303030303030303030303030303;0404040404040404040404040404040404040404040404040404040404040404;0505050505050505050505050505050505050505050505050505050505050505;0606060606060606060606060606060606060606060606060606060606060606,B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA80E066C34819936549FF49B6FD4D41EDFC401A367B87DDD59FEE38177961C225F;C9D9B1CCE8C0A99AA79F56185358CD82B7649D6132DAACB31612C7C9B14CE3A9233428AEB77468852520B0256DE84562A29629194DAEAC45444C7711CD379E57;F62B58B1908197B6D732F0564AD2AD5C6E438D24C65AF758DA9ACCCCCF5B3F923A17EA0CD56ED3A824AA14BC67839CED465BA5269700F600EDFC3DAAC8A6B069;A3AFBDB45A6A34BF7C8C00F1B6D7E7D375B54540F13716C87B62E51E2F4F22FF3E57DF859581383FA53C564BC72EC8A60145C502E91B0B508A6F1BD7961FC45D;C1319F3743A9B8A5A30408FA90E96B3A8BB3FD4FF5B790935C465DDC68859B2935B87C950EB399CCCD956D5BE6327B164D4C4080671A6B2CB39FD6A755C5987E,TRUE,B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA8C9D9B1CCE8C0A99AA79F56185358CD82B7649D6132DAACB31612C7C9B14CE3A9F62B58B1908197B6D732F0564AD2AD5C6E438D24C65AF758DA9ACCCCCF5B3F92A3AFBDB45A6A34BF7C8C00F1B6D7E7D375B54540F13716C87B62E51E2F4F22FFC1319F3743A9B8A5A30408FA90E96B3A8BB3FD4FF5B790935C465DDC68859B2917D482DF65A9338B797D020D0FC24439F80BBBAFAE0C01FE9C60E6BB6C1E9BFE,Five signatures
5,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F;4D4B6CD1361032CA9BD2AEB9D900AA4D45D9EAD80AC9423374C451A7254D0766,0202020202020202020202020202020202020202020202020202020202020202;0303030303030303030303030303030303030303030303030303030303030303,B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA83B5F55690F0A13C12CBC1B569D10E3D919CE0E799D4AD29CEF1AE51DA64F9B57;C9D9B1CCE8C0A99AA79F56185358CD82B7649D6132DAACB31612C7C9B14CE3A9123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0,TRUE,B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA8C9D9B1CCE8C0A99AA79F56185358CD82B7649D6132DAACB31612C7C9B14CE3A9F51B04478B464890B540F1BBE15E5E5965A348F2B3D09BD4021D9E1F67D9D774,"Strange aggregation - invalid individual sigs, valid aggregate"
6,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F,0202020202020202020202020202020202020202020202020202020202020202,B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141,FALSE,,Signature s = n (at boundary)
7,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F,0202020202020202020202020202020202020202020202020202020202020202,B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364529,FALSE,,Signature s > n
8,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F,0202020202020202020202020202020202020202020202020202020202020202,B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF,FALSE,,Signature s = 2^256 - 1
9,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD07,0202020202020202020202020202020202020202020202020202020202020202,B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA80E066C34819936549FF49B6FD4D41EDFC401A367B87DDD59FEE38177961C225F,FALSE,,Public key too short
10,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F,020202020202020202020202020202020202020202020202020202020202020202,80B68E6A009D95B162880A6942C2308A04F6E75037EF10646F826FF4F658A9B139DE000C1E00C3B70E0490D6A034EB25090761400B08DE7A92390D5B3B2220B6,FALSE,,Message too long
11,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F,0202020202020202020202020202020202020202020202020202020202020202,B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA80E066C34819936549FF49B6FD4D41EDFC401A367B87DDD59FEE38177961C22,FALSE,,Signature too short
12,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F,0202020202020202020202020202020202020202020202020202020202020202,B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA80E066C34819936549FF49B6FD4D41EDFC401A367B87DDD59FEE38177961C225F00,FALSE,,Signature too long
13,021B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F,0202020202020202020202020202020202020202020202020202020202020202,B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA80E066C34819936549FF49B6FD4D41EDFC401A367B87DDD59FEE38177961C225F,FALSE,,Public key too long
14,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F,02020202020202020202020202020202020202020202020202020202020202,BBE3DE7700230815FC246C1001266C4730A272B118B5651F2BFB656BA27930332DD2503A5B9CEDA204DF1636E0E578142211FFC98497B49C769A33989889B740,FALSE,,Message too short
1 index pubkeys messages signatures expected_result expected_aggsig comment
2 0 TRUE 0000000000000000000000000000000000000000000000000000000000000000 Empty signature list
3 1 1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F 0202020202020202020202020202020202020202020202020202020202020202 B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA80E066C34819936549FF49B6FD4D41EDFC401A367B87DDD59FEE38177961C225F TRUE B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA80E066C34819936549FF49B6FD4D41EDFC401A367B87DDD59FEE38177961C225F Single signature
4 2 1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F;4D4B6CD1361032CA9BD2AEB9D900AA4D45D9EAD80AC9423374C451A7254D0766 0202020202020202020202020202020202020202020202020202020202020202;0303030303030303030303030303030303030303030303030303030303030303 B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA80E066C34819936549FF49B6FD4D41EDFC401A367B87DDD59FEE38177961C225F;C9D9B1CCE8C0A99AA79F56185358CD82B7649D6132DAACB31612C7C9B14CE3A9233428AEB77468852520B0256DE84562A29629194DAEAC45444C7711CD379E57 TRUE B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA8C9D9B1CCE8C0A99AA79F56185358CD82B7649D6132DAACB31612C7C9B14CE3A9F51B04478B464890B540F1BBE15E5E5965A348F2B3D09BD4021D9E1F67D9D774 Two signatures
5 3 1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F;4D4B6CD1361032CA9BD2AEB9D900AA4D45D9EAD80AC9423374C451A7254D0766;531FE6068134503D2723133227C867AC8FA6C83C537E9A44C3C5BDBDCB1FE337 0202020202020202020202020202020202020202020202020202020202020202;0303030303030303030303030303030303030303030303030303030303030303;0404040404040404040404040404040404040404040404040404040404040404 B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA80E066C34819936549FF49B6FD4D41EDFC401A367B87DDD59FEE38177961C225F;C9D9B1CCE8C0A99AA79F56185358CD82B7649D6132DAACB31612C7C9B14CE3A9233428AEB77468852520B0256DE84562A29629194DAEAC45444C7711CD379E57;F62B58B1908197B6D732F0564AD2AD5C6E438D24C65AF758DA9ACCCCCF5B3F923A17EA0CD56ED3A824AA14BC67839CED465BA5269700F600EDFC3DAAC8A6B069 TRUE B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA8C9D9B1CCE8C0A99AA79F56185358CD82B7649D6132DAACB31612C7C9B14CE3A9F62B58B1908197B6D732F0564AD2AD5C6E438D24C65AF758DA9ACCCCCF5B3F92B7A5E19F2F438EAE2D3D9630B4D69921A7E920CBF6E54585261B21D7E1395493 Three signatures
6 4 1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F;4D4B6CD1361032CA9BD2AEB9D900AA4D45D9EAD80AC9423374C451A7254D0766;531FE6068134503D2723133227C867AC8FA6C83C537E9A44C3C5BDBDCB1FE337;462779AD4AAD39514614751A71085F2F10E1C7A593E4E030EFB5B8721CE55B0B;62C0A046DACCE86DDD0343C6D3C7C79C2208BA0D9C9CF24A6D046D21D21F90F7 0202020202020202020202020202020202020202020202020202020202020202;0303030303030303030303030303030303030303030303030303030303030303;0404040404040404040404040404040404040404040404040404040404040404;0505050505050505050505050505050505050505050505050505050505050505;0606060606060606060606060606060606060606060606060606060606060606 B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA80E066C34819936549FF49B6FD4D41EDFC401A367B87DDD59FEE38177961C225F;C9D9B1CCE8C0A99AA79F56185358CD82B7649D6132DAACB31612C7C9B14CE3A9233428AEB77468852520B0256DE84562A29629194DAEAC45444C7711CD379E57;F62B58B1908197B6D732F0564AD2AD5C6E438D24C65AF758DA9ACCCCCF5B3F923A17EA0CD56ED3A824AA14BC67839CED465BA5269700F600EDFC3DAAC8A6B069;A3AFBDB45A6A34BF7C8C00F1B6D7E7D375B54540F13716C87B62E51E2F4F22FF3E57DF859581383FA53C564BC72EC8A60145C502E91B0B508A6F1BD7961FC45D;C1319F3743A9B8A5A30408FA90E96B3A8BB3FD4FF5B790935C465DDC68859B2935B87C950EB399CCCD956D5BE6327B164D4C4080671A6B2CB39FD6A755C5987E TRUE B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA8C9D9B1CCE8C0A99AA79F56185358CD82B7649D6132DAACB31612C7C9B14CE3A9F62B58B1908197B6D732F0564AD2AD5C6E438D24C65AF758DA9ACCCCCF5B3F92A3AFBDB45A6A34BF7C8C00F1B6D7E7D375B54540F13716C87B62E51E2F4F22FFC1319F3743A9B8A5A30408FA90E96B3A8BB3FD4FF5B790935C465DDC68859B2917D482DF65A9338B797D020D0FC24439F80BBBAFAE0C01FE9C60E6BB6C1E9BFE Five signatures
7 5 1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F;4D4B6CD1361032CA9BD2AEB9D900AA4D45D9EAD80AC9423374C451A7254D0766 0202020202020202020202020202020202020202020202020202020202020202;0303030303030303030303030303030303030303030303030303030303030303 B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA83B5F55690F0A13C12CBC1B569D10E3D919CE0E799D4AD29CEF1AE51DA64F9B57;C9D9B1CCE8C0A99AA79F56185358CD82B7649D6132DAACB31612C7C9B14CE3A9123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0 TRUE B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA8C9D9B1CCE8C0A99AA79F56185358CD82B7649D6132DAACB31612C7C9B14CE3A9F51B04478B464890B540F1BBE15E5E5965A348F2B3D09BD4021D9E1F67D9D774 Strange aggregation - invalid individual sigs, valid aggregate
8 6 1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F 0202020202020202020202020202020202020202020202020202020202020202 B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 FALSE Signature s = n (at boundary)
9 7 1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F 0202020202020202020202020202020202020202020202020202020202020202 B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364529 FALSE Signature s > n
10 8 1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F 0202020202020202020202020202020202020202020202020202020202020202 B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FALSE Signature s = 2^256 - 1
11 9 1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD07 0202020202020202020202020202020202020202020202020202020202020202 B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA80E066C34819936549FF49B6FD4D41EDFC401A367B87DDD59FEE38177961C225F FALSE Public key too short
12 10 1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F 020202020202020202020202020202020202020202020202020202020202020202 80B68E6A009D95B162880A6942C2308A04F6E75037EF10646F826FF4F658A9B139DE000C1E00C3B70E0490D6A034EB25090761400B08DE7A92390D5B3B2220B6 FALSE Message too long
13 11 1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F 0202020202020202020202020202020202020202020202020202020202020202 B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA80E066C34819936549FF49B6FD4D41EDFC401A367B87DDD59FEE38177961C22 FALSE Signature too short
14 12 1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F 0202020202020202020202020202020202020202020202020202020202020202 B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA80E066C34819936549FF49B6FD4D41EDFC401A367B87DDD59FEE38177961C225F00 FALSE Signature too long
15 13 021B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F 0202020202020202020202020202020202020202020202020202020202020202 B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA80E066C34819936549FF49B6FD4D41EDFC401A367B87DDD59FEE38177961C225F FALSE Public key too long
16 14 1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F 02020202020202020202020202020202020202020202020202020202020202 BBE3DE7700230815FC246C1001266C4730A272B118B5651F2BFB656BA27930332DD2503A5B9CEDA204DF1636E0E578142211FFC98497B49C769A33989889B740 FALSE Message too short
@@ -0,0 +1,13 @@
index,aggsig,pm_aggd_pubkeys,pm_aggd_messages,pms_pubkeys,pms_messages,pms_signatures,expected_result,expected_aggsig,comment
0,0000000000000000000000000000000000000000000000000000000000000000,,,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F,0202020202020202020202020202020202020202020202020202020202020202,B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA80E066C34819936549FF49B6FD4D41EDFC401A367B87DDD59FEE38177961C225F,TRUE,B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA80E066C34819936549FF49B6FD4D41EDFC401A367B87DDD59FEE38177961C225F,Add single signature to empty aggregate
1,B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA80E066C34819936549FF49B6FD4D41EDFC401A367B87DDD59FEE38177961C225F,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F,0202020202020202020202020202020202020202020202020202020202020202,4D4B6CD1361032CA9BD2AEB9D900AA4D45D9EAD80AC9423374C451A7254D0766,0303030303030303030303030303030303030303030303030303030303030303,C9D9B1CCE8C0A99AA79F56185358CD82B7649D6132DAACB31612C7C9B14CE3A9233428AEB77468852520B0256DE84562A29629194DAEAC45444C7711CD379E57,TRUE,B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA8C9D9B1CCE8C0A99AA79F56185358CD82B7649D6132DAACB31612C7C9B14CE3A9F51B04478B464890B540F1BBE15E5E5965A348F2B3D09BD4021D9E1F67D9D774,Add second signature to single-sig aggregate
2,B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA80E066C34819936549FF49B6FD4D41EDFC401A367B87DDD59FEE38177961C225F,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F,0202020202020202020202020202020202020202020202020202020202020202,4D4B6CD1361032CA9BD2AEB9D900AA4D45D9EAD80AC9423374C451A7254D0766;531FE6068134503D2723133227C867AC8FA6C83C537E9A44C3C5BDBDCB1FE337,0303030303030303030303030303030303030303030303030303030303030303;0404040404040404040404040404040404040404040404040404040404040404,C9D9B1CCE8C0A99AA79F56185358CD82B7649D6132DAACB31612C7C9B14CE3A9233428AEB77468852520B0256DE84562A29629194DAEAC45444C7711CD379E57;F62B58B1908197B6D732F0564AD2AD5C6E438D24C65AF758DA9ACCCCCF5B3F923A17EA0CD56ED3A824AA14BC67839CED465BA5269700F600EDFC3DAAC8A6B069,TRUE,B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA8C9D9B1CCE8C0A99AA79F56185358CD82B7649D6132DAACB31612C7C9B14CE3A9F62B58B1908197B6D732F0564AD2AD5C6E438D24C65AF758DA9ACCCCCF5B3F92B7A5E19F2F438EAE2D3D9630B4D69921A7E920CBF6E54585261B21D7E1395493,Add two signatures at once
3,B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA80E066C34819936549FF49B6FD4D41EDFC401A367B87DDD59FEE38177961C225F,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F,0202020202020202020202020202020202020202020202020202020202020202,,,,TRUE,B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA80E066C34819936549FF49B6FD4D41EDFC401A367B87DDD59FEE38177961C225F,Add no new signatures (unchanged)
4,00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,,,,,,FALSE,,Aggregate signature wrong length
5,,,,,,,FALSE,,Aggregate signature empty
6,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141,,,,,,FALSE,,Existing aggregate has s = n
7,0000000000000000000000000000000000000000000000000000000000000000,,,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F,0202020202020202020202020202020202020202020202020202020202020202,B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141,FALSE,,New signature has s = n
8,B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA80E066C34819936549FF49B6FD4D41EDFC401A367B87DDD59FEE38177961C225F,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD07,0202020202020202020202020202020202020202020202020202020202020202,4D4B6CD1361032CA9BD2AEB9D900AA4D45D9EAD80AC9423374C451A7254D0766,0303030303030303030303030303030303030303030303030303030303030303,C9D9B1CCE8C0A99AA79F56185358CD82B7649D6132DAACB31612C7C9B14CE3A9233428AEB77468852520B0256DE84562A29629194DAEAC45444C7711CD379E57,FALSE,,Existing public key too short
9,80B68E6A009D95B162880A6942C2308A04F6E75037EF10646F826FF4F658A9B139DE000C1E00C3B70E0490D6A034EB25090761400B08DE7A92390D5B3B2220B6,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F,020202020202020202020202020202020202020202020202020202020202020202,4D4B6CD1361032CA9BD2AEB9D900AA4D45D9EAD80AC9423374C451A7254D0766,0303030303030303030303030303030303030303030303030303030303030303,C9D9B1CCE8C0A99AA79F56185358CD82B7649D6132DAACB31612C7C9B14CE3A9233428AEB77468852520B0256DE84562A29629194DAEAC45444C7711CD379E57,FALSE,,Existing message too long
10,B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA80E066C34819936549FF49B6FD4D41EDFC401A367B87DDD59FEE38177961C225F,021B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F,0202020202020202020202020202020202020202020202020202020202020202,4D4B6CD1361032CA9BD2AEB9D900AA4D45D9EAD80AC9423374C451A7254D0766,0303030303030303030303030303030303030303030303030303030303030303,C9D9B1CCE8C0A99AA79F56185358CD82B7649D6132DAACB31612C7C9B14CE3A9233428AEB77468852520B0256DE84562A29629194DAEAC45444C7711CD379E57,FALSE,,Existing public key too long
11,BBE3DE7700230815FC246C1001266C4730A272B118B5651F2BFB656BA27930332DD2503A5B9CEDA204DF1636E0E578142211FFC98497B49C769A33989889B740,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F,02020202020202020202020202020202020202020202020202020202020202,4D4B6CD1361032CA9BD2AEB9D900AA4D45D9EAD80AC9423374C451A7254D0766,0303030303030303030303030303030303030303030303030303030303030303,C9D9B1CCE8C0A99AA79F56185358CD82B7649D6132DAACB31612C7C9B14CE3A9233428AEB77468852520B0256DE84562A29629194DAEAC45444C7711CD379E57,FALSE,,Existing message too short
1 index aggsig pm_aggd_pubkeys pm_aggd_messages pms_pubkeys pms_messages pms_signatures expected_result expected_aggsig comment
2 0 0000000000000000000000000000000000000000000000000000000000000000 1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F 0202020202020202020202020202020202020202020202020202020202020202 B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA80E066C34819936549FF49B6FD4D41EDFC401A367B87DDD59FEE38177961C225F TRUE B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA80E066C34819936549FF49B6FD4D41EDFC401A367B87DDD59FEE38177961C225F Add single signature to empty aggregate
3 1 B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA80E066C34819936549FF49B6FD4D41EDFC401A367B87DDD59FEE38177961C225F 1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F 0202020202020202020202020202020202020202020202020202020202020202 4D4B6CD1361032CA9BD2AEB9D900AA4D45D9EAD80AC9423374C451A7254D0766 0303030303030303030303030303030303030303030303030303030303030303 C9D9B1CCE8C0A99AA79F56185358CD82B7649D6132DAACB31612C7C9B14CE3A9233428AEB77468852520B0256DE84562A29629194DAEAC45444C7711CD379E57 TRUE B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA8C9D9B1CCE8C0A99AA79F56185358CD82B7649D6132DAACB31612C7C9B14CE3A9F51B04478B464890B540F1BBE15E5E5965A348F2B3D09BD4021D9E1F67D9D774 Add second signature to single-sig aggregate
4 2 B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA80E066C34819936549FF49B6FD4D41EDFC401A367B87DDD59FEE38177961C225F 1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F 0202020202020202020202020202020202020202020202020202020202020202 4D4B6CD1361032CA9BD2AEB9D900AA4D45D9EAD80AC9423374C451A7254D0766;531FE6068134503D2723133227C867AC8FA6C83C537E9A44C3C5BDBDCB1FE337 0303030303030303030303030303030303030303030303030303030303030303;0404040404040404040404040404040404040404040404040404040404040404 C9D9B1CCE8C0A99AA79F56185358CD82B7649D6132DAACB31612C7C9B14CE3A9233428AEB77468852520B0256DE84562A29629194DAEAC45444C7711CD379E57;F62B58B1908197B6D732F0564AD2AD5C6E438D24C65AF758DA9ACCCCCF5B3F923A17EA0CD56ED3A824AA14BC67839CED465BA5269700F600EDFC3DAAC8A6B069 TRUE B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA8C9D9B1CCE8C0A99AA79F56185358CD82B7649D6132DAACB31612C7C9B14CE3A9F62B58B1908197B6D732F0564AD2AD5C6E438D24C65AF758DA9ACCCCCF5B3F92B7A5E19F2F438EAE2D3D9630B4D69921A7E920CBF6E54585261B21D7E1395493 Add two signatures at once
5 3 B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA80E066C34819936549FF49B6FD4D41EDFC401A367B87DDD59FEE38177961C225F 1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F 0202020202020202020202020202020202020202020202020202020202020202 TRUE B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA80E066C34819936549FF49B6FD4D41EDFC401A367B87DDD59FEE38177961C225F Add no new signatures (unchanged)
6 4 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 FALSE Aggregate signature wrong length
7 5 FALSE Aggregate signature empty
8 6 FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 FALSE Existing aggregate has s = n
9 7 0000000000000000000000000000000000000000000000000000000000000000 1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F 0202020202020202020202020202020202020202020202020202020202020202 B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 FALSE New signature has s = n
10 8 B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA80E066C34819936549FF49B6FD4D41EDFC401A367B87DDD59FEE38177961C225F 1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD07 0202020202020202020202020202020202020202020202020202020202020202 4D4B6CD1361032CA9BD2AEB9D900AA4D45D9EAD80AC9423374C451A7254D0766 0303030303030303030303030303030303030303030303030303030303030303 C9D9B1CCE8C0A99AA79F56185358CD82B7649D6132DAACB31612C7C9B14CE3A9233428AEB77468852520B0256DE84562A29629194DAEAC45444C7711CD379E57 FALSE Existing public key too short
11 9 80B68E6A009D95B162880A6942C2308A04F6E75037EF10646F826FF4F658A9B139DE000C1E00C3B70E0490D6A034EB25090761400B08DE7A92390D5B3B2220B6 1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F 020202020202020202020202020202020202020202020202020202020202020202 4D4B6CD1361032CA9BD2AEB9D900AA4D45D9EAD80AC9423374C451A7254D0766 0303030303030303030303030303030303030303030303030303030303030303 C9D9B1CCE8C0A99AA79F56185358CD82B7649D6132DAACB31612C7C9B14CE3A9233428AEB77468852520B0256DE84562A29629194DAEAC45444C7711CD379E57 FALSE Existing message too long
12 10 B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA80E066C34819936549FF49B6FD4D41EDFC401A367B87DDD59FEE38177961C225F 021B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F 0202020202020202020202020202020202020202020202020202020202020202 4D4B6CD1361032CA9BD2AEB9D900AA4D45D9EAD80AC9423374C451A7254D0766 0303030303030303030303030303030303030303030303030303030303030303 C9D9B1CCE8C0A99AA79F56185358CD82B7649D6132DAACB31612C7C9B14CE3A9233428AEB77468852520B0256DE84562A29629194DAEAC45444C7711CD379E57 FALSE Existing public key too long
13 11 BBE3DE7700230815FC246C1001266C4730A272B118B5651F2BFB656BA27930332DD2503A5B9CEDA204DF1636E0E578142211FFC98497B49C769A33989889B740 1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F 02020202020202020202020202020202020202020202020202020202020202 4D4B6CD1361032CA9BD2AEB9D900AA4D45D9EAD80AC9423374C451A7254D0766 0303030303030303030303030303030303030303030303030303030303030303 C9D9B1CCE8C0A99AA79F56185358CD82B7649D6132DAACB31612C7C9B14CE3A9233428AEB77468852520B0256DE84562A29629194DAEAC45444C7711CD379E57 FALSE Existing message too short
+27
View File
@@ -0,0 +1,27 @@
index,aggsig,pubkeys,messages,expected_result,comment
0,0000000000000000000000000000000000000000000000000000000000000000,,,TRUE,Empty signature list
1,B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA80E066C34819936549FF49B6FD4D41EDFC401A367B87DDD59FEE38177961C225F,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F,0202020202020202020202020202020202020202020202020202020202020202,TRUE,Single signature
2,B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA8A3AFBDB45A6A34BF7C8C00F1B6D7E7D375B54540F13716C87B62E51E2F4F22FFAC87D631EE4A69E8D25F1977AFB86DD3A8FD3BEA9116F25A0CB523C25BCB5A41,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F;462779AD4AAD39514614751A71085F2F10E1C7A593E4E030EFB5B8721CE55B0B,0202020202020202020202020202020202020202020202020202020202020202;0505050505050505050505050505050505050505050505050505050505050505,TRUE,Two signatures
3,B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA8C9D9B1CCE8C0A99AA79F56185358CD82B7649D6132DAACB31612C7C9B14CE3A9F62B58B1908197B6D732F0564AD2AD5C6E438D24C65AF758DA9ACCCCCF5B3F92B7A5E19F2F438EAE2D3D9630B4D69921A7E920CBF6E54585261B21D7E1395493,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F;4D4B6CD1361032CA9BD2AEB9D900AA4D45D9EAD80AC9423374C451A7254D0766;531FE6068134503D2723133227C867AC8FA6C83C537E9A44C3C5BDBDCB1FE337,0202020202020202020202020202020202020202020202020202020202020202;0303030303030303030303030303030303030303030303030303030303030303;0404040404040404040404040404040404040404040404040404040404040404,TRUE,Three signatures
4,B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA8C9D9B1CCE8C0A99AA79F56185358CD82B7649D6132DAACB31612C7C9B14CE3A9F62B58B1908197B6D732F0564AD2AD5C6E438D24C65AF758DA9ACCCCCF5B3F92A3AFBDB45A6A34BF7C8C00F1B6D7E7D375B54540F13716C87B62E51E2F4F22FFC1319F3743A9B8A5A30408FA90E96B3A8BB3FD4FF5B790935C465DDC68859B2917D482DF65A9338B797D020D0FC24439F80BBBAFAE0C01FE9C60E6BB6C1E9BFE,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F;4D4B6CD1361032CA9BD2AEB9D900AA4D45D9EAD80AC9423374C451A7254D0766;531FE6068134503D2723133227C867AC8FA6C83C537E9A44C3C5BDBDCB1FE337;462779AD4AAD39514614751A71085F2F10E1C7A593E4E030EFB5B8721CE55B0B;62C0A046DACCE86DDD0343C6D3C7C79C2208BA0D9C9CF24A6D046D21D21F90F7,0202020202020202020202020202020202020202020202020202020202020202;0303030303030303030303030303030303030303030303030303030303030303;0404040404040404040404040404040404040404040404040404040404040404;0505050505050505050505050505050505050505050505050505050505050505;0606060606060606060606060606060606060606060606060606060606060606,TRUE,Five signatures
5,B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA80E066C34819936549FF49B6FD4D41EDFC401A367B87DDD59FEE38177961C225F,4A298DACAE57395A15D0795DDBFD1DCB564DA82B0F269BC70A74F8220429BA1D,0202020202020202020202020202020202020202020202020202020202020202,FALSE,Public key not on curve
6,B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA80E066C34819936549FF49B6FD4D41EDFC401A367B87DDD59FEE38177961C225F,0000000000000000000000000000000000000000000000000000000000000000,0202020202020202020202020202020202020202020202020202020202020202,FALSE,Public key is zero
7,B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA80E066C34819936549FF49B6FD4D41EDFC401A367B87DDD59FEE38177961C225F,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F,0202020202020202020202020202020202020202020202020202020202020202,FALSE,Public key >= field size
8,4A298DACAE57395A15D0795DDBFD1DCB564DA82B0F269BC70A74F8220429BA1D0E066C34819936549FF49B6FD4D41EDFC401A367B87DDD59FEE38177961C225F,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F,0202020202020202020202020202020202020202020202020202020202020202,FALSE,R value not on curve
9,00000000000000000000000000000000000000000000000000000000000000000E066C34819936549FF49B6FD4D41EDFC401A367B87DDD59FEE38177961C225F,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F,0202020202020202020202020202020202020202020202020202020202020202,FALSE,R value is zero
10,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC930E066C34819936549FF49B6FD4D41EDFC401A367B87DDD59FEE38177961C225F,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F,0202020202020202020202020202020202020202020202020202020202020202,FALSE,R value >= field size
11,B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F,0202020202020202020202020202020202020202020202020202020202020202,FALSE,Aggregate s = n
12,B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364529,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F,0202020202020202020202020202020202020202020202020202020202020202,FALSE,Aggregate s > n
13,B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F,0202020202020202020202020202020202020202020202020202020202020202,FALSE,Aggregate s = 2^256 - 1
14,B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA80E066C34819936549FF49B6FD4D41EDFC401A367B87DDD59FEE38177961C225F,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF,FALSE,Wrong message
15,B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA80E066C34819936549FF49B6FD4D41EDFC401A367B87DDD59FEE38177961C225F,4D4B6CD1361032CA9BD2AEB9D900AA4D45D9EAD80AC9423374C451A7254D0766,0202020202020202020202020202020202020202020202020202020202020202,FALSE,Wrong public key
16,B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA80E066C34819936549FF49B6FD4D41EDFC401A367B87DDD59FEE38177961C2260,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F,0202020202020202020202020202020202020202020202020202020202020202,FALSE,Tampered signature (bit flip)
17,B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA8C9D9B1CCE8C0A99AA79F56185358CD82B7649D6132DAACB31612C7C9B14CE3A9F51B04478B464890B540F1BBE15E5E5965A348F2B3D09BD4021D9E1F67D9D774,4D4B6CD1361032CA9BD2AEB9D900AA4D45D9EAD80AC9423374C451A7254D0766;1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F,0303030303030303030303030303030303030303030303030303030303030303;0202020202020202020202020202020202020202020202020202020202020202,FALSE,Swapped order
18,B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364140,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F,0202020202020202020202020202020202020202020202020202020202020202,FALSE,"s = n-1 (valid range, wrong sig)"
19,B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA80000000000000000000000000000000000000000000000000000000000000000,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F,0202020202020202020202020202020202020202020202020202020202020202,FALSE,"s = 0 (valid range, wrong sig)"
20,B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4A,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F,0202020202020202020202020202020202020202020202020202020202020202,FALSE,Aggregate signature too short
21,B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA80E066C34819936549FF49B6FD4D41EDFC401A367B87DDD59FEE38177961C225F0000000000000000000000000000000000000000000000000000000000000000,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F,0202020202020202020202020202020202020202020202020202020202020202,FALSE,Aggregate signature too long
22,B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA80E066C34819936549FF49B6FD4D41EDFC401A367B87DDD59FEE38177961C225F,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD07,0202020202020202020202020202020202020202020202020202020202020202,FALSE,Public key too short
23,80B68E6A009D95B162880A6942C2308A04F6E75037EF10646F826FF4F658A9B139DE000C1E00C3B70E0490D6A034EB25090761400B08DE7A92390D5B3B2220B6,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F,020202020202020202020202020202020202020202020202020202020202020202,FALSE,Message too long
24,B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA80E066C34819936549FF49B6FD4D41EDFC401A367B87DDD59FEE38177961C225F,021B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F,0202020202020202020202020202020202020202020202020202020202020202,FALSE,Public key too long
25,BBE3DE7700230815FC246C1001266C4730A272B118B5651F2BFB656BA27930332DD2503A5B9CEDA204DF1636E0E578142211FFC98497B49C769A33989889B740,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F,02020202020202020202020202020202020202020202020202020202020202,FALSE,Message too short
1 index aggsig pubkeys messages expected_result comment
2 0 0000000000000000000000000000000000000000000000000000000000000000 TRUE Empty signature list
3 1 B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA80E066C34819936549FF49B6FD4D41EDFC401A367B87DDD59FEE38177961C225F 1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F 0202020202020202020202020202020202020202020202020202020202020202 TRUE Single signature
4 2 B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA8A3AFBDB45A6A34BF7C8C00F1B6D7E7D375B54540F13716C87B62E51E2F4F22FFAC87D631EE4A69E8D25F1977AFB86DD3A8FD3BEA9116F25A0CB523C25BCB5A41 1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F;462779AD4AAD39514614751A71085F2F10E1C7A593E4E030EFB5B8721CE55B0B 0202020202020202020202020202020202020202020202020202020202020202;0505050505050505050505050505050505050505050505050505050505050505 TRUE Two signatures
5 3 B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA8C9D9B1CCE8C0A99AA79F56185358CD82B7649D6132DAACB31612C7C9B14CE3A9F62B58B1908197B6D732F0564AD2AD5C6E438D24C65AF758DA9ACCCCCF5B3F92B7A5E19F2F438EAE2D3D9630B4D69921A7E920CBF6E54585261B21D7E1395493 1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F;4D4B6CD1361032CA9BD2AEB9D900AA4D45D9EAD80AC9423374C451A7254D0766;531FE6068134503D2723133227C867AC8FA6C83C537E9A44C3C5BDBDCB1FE337 0202020202020202020202020202020202020202020202020202020202020202;0303030303030303030303030303030303030303030303030303030303030303;0404040404040404040404040404040404040404040404040404040404040404 TRUE Three signatures
6 4 B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA8C9D9B1CCE8C0A99AA79F56185358CD82B7649D6132DAACB31612C7C9B14CE3A9F62B58B1908197B6D732F0564AD2AD5C6E438D24C65AF758DA9ACCCCCF5B3F92A3AFBDB45A6A34BF7C8C00F1B6D7E7D375B54540F13716C87B62E51E2F4F22FFC1319F3743A9B8A5A30408FA90E96B3A8BB3FD4FF5B790935C465DDC68859B2917D482DF65A9338B797D020D0FC24439F80BBBAFAE0C01FE9C60E6BB6C1E9BFE 1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F;4D4B6CD1361032CA9BD2AEB9D900AA4D45D9EAD80AC9423374C451A7254D0766;531FE6068134503D2723133227C867AC8FA6C83C537E9A44C3C5BDBDCB1FE337;462779AD4AAD39514614751A71085F2F10E1C7A593E4E030EFB5B8721CE55B0B;62C0A046DACCE86DDD0343C6D3C7C79C2208BA0D9C9CF24A6D046D21D21F90F7 0202020202020202020202020202020202020202020202020202020202020202;0303030303030303030303030303030303030303030303030303030303030303;0404040404040404040404040404040404040404040404040404040404040404;0505050505050505050505050505050505050505050505050505050505050505;0606060606060606060606060606060606060606060606060606060606060606 TRUE Five signatures
7 5 B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA80E066C34819936549FF49B6FD4D41EDFC401A367B87DDD59FEE38177961C225F 4A298DACAE57395A15D0795DDBFD1DCB564DA82B0F269BC70A74F8220429BA1D 0202020202020202020202020202020202020202020202020202020202020202 FALSE Public key not on curve
8 6 B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA80E066C34819936549FF49B6FD4D41EDFC401A367B87DDD59FEE38177961C225F 0000000000000000000000000000000000000000000000000000000000000000 0202020202020202020202020202020202020202020202020202020202020202 FALSE Public key is zero
9 7 B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA80E066C34819936549FF49B6FD4D41EDFC401A367B87DDD59FEE38177961C225F FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F 0202020202020202020202020202020202020202020202020202020202020202 FALSE Public key >= field size
10 8 4A298DACAE57395A15D0795DDBFD1DCB564DA82B0F269BC70A74F8220429BA1D0E066C34819936549FF49B6FD4D41EDFC401A367B87DDD59FEE38177961C225F 1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F 0202020202020202020202020202020202020202020202020202020202020202 FALSE R value not on curve
11 9 00000000000000000000000000000000000000000000000000000000000000000E066C34819936549FF49B6FD4D41EDFC401A367B87DDD59FEE38177961C225F 1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F 0202020202020202020202020202020202020202020202020202020202020202 FALSE R value is zero
12 10 FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC930E066C34819936549FF49B6FD4D41EDFC401A367B87DDD59FEE38177961C225F 1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F 0202020202020202020202020202020202020202020202020202020202020202 FALSE R value >= field size
13 11 B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F 0202020202020202020202020202020202020202020202020202020202020202 FALSE Aggregate s = n
14 12 B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364529 1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F 0202020202020202020202020202020202020202020202020202020202020202 FALSE Aggregate s > n
15 13 B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF 1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F 0202020202020202020202020202020202020202020202020202020202020202 FALSE Aggregate s = 2^256 - 1
16 14 B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA80E066C34819936549FF49B6FD4D41EDFC401A367B87DDD59FEE38177961C225F 1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FALSE Wrong message
17 15 B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA80E066C34819936549FF49B6FD4D41EDFC401A367B87DDD59FEE38177961C225F 4D4B6CD1361032CA9BD2AEB9D900AA4D45D9EAD80AC9423374C451A7254D0766 0202020202020202020202020202020202020202020202020202020202020202 FALSE Wrong public key
18 16 B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA80E066C34819936549FF49B6FD4D41EDFC401A367B87DDD59FEE38177961C2260 1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F 0202020202020202020202020202020202020202020202020202020202020202 FALSE Tampered signature (bit flip)
19 17 B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA8C9D9B1CCE8C0A99AA79F56185358CD82B7649D6132DAACB31612C7C9B14CE3A9F51B04478B464890B540F1BBE15E5E5965A348F2B3D09BD4021D9E1F67D9D774 4D4B6CD1361032CA9BD2AEB9D900AA4D45D9EAD80AC9423374C451A7254D0766;1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F 0303030303030303030303030303030303030303030303030303030303030303;0202020202020202020202020202020202020202020202020202020202020202 FALSE Swapped order
20 18 B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364140 1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F 0202020202020202020202020202020202020202020202020202020202020202 FALSE s = n-1 (valid range, wrong sig)
21 19 B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA80000000000000000000000000000000000000000000000000000000000000000 1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F 0202020202020202020202020202020202020202020202020202020202020202 FALSE s = 0 (valid range, wrong sig)
22 20 B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4A 1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F 0202020202020202020202020202020202020202020202020202020202020202 FALSE Aggregate signature too short
23 21 B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA80E066C34819936549FF49B6FD4D41EDFC401A367B87DDD59FEE38177961C225F0000000000000000000000000000000000000000000000000000000000000000 1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F 0202020202020202020202020202020202020202020202020202020202020202 FALSE Aggregate signature too long
24 22 B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA80E066C34819936549FF49B6FD4D41EDFC401A367B87DDD59FEE38177961C225F 1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD07 0202020202020202020202020202020202020202020202020202020202020202 FALSE Public key too short
25 23 80B68E6A009D95B162880A6942C2308A04F6E75037EF10646F826FF4F658A9B139DE000C1E00C3B70E0490D6A034EB25090761400B08DE7A92390D5B3B2220B6 1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F 020202020202020202020202020202020202020202020202020202020202020202 FALSE Message too long
26 24 B070AAFCEA439A4F6F1BBFC2EB66D29D24B0CAB74D6B745C3CFB009CC8FE4AA80E066C34819936549FF49B6FD4D41EDFC401A367B87DDD59FEE38177961C225F 021B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F 0202020202020202020202020202020202020202020202020202020202020202 FALSE Public key too long
27 25 BBE3DE7700230815FC246C1001266C4730A272B118B5651F2BFB656BA27930332DD2503A5B9CEDA204DF1636E0E578142211FFC98497B49C769A33989889B740 1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F 02020202020202020202020202020202020202020202020202020202020202 FALSE Message too short