mirror of
https://github.com/bitcoin/bips.git
synced 2026-11-09 19:47:16 +00:00
BIP459: Add DahLIAS fully aggregated signatures for secp256k1
This commit is contained in:
11 files changed
+1632
No files matched your search
@@ -0,0 +1,605 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Generate test vectors for BIP 459 DahLIAS fully aggregated signatures
|
||||
for secp256k1.
|
||||
|
||||
Usage:
|
||||
python gen_test_vectors.py
|
||||
|
||||
Outputs:
|
||||
- vectors/test_vectors_nonce_gen.csv (NonceGen with a fixed rand')
|
||||
- vectors/test_vectors_nonce_agg.csv (NonceAgg: success and failure cases)
|
||||
- vectors/test_vectors_sign.csv (end-to-end signing with fixed nonces)
|
||||
- vectors/test_vectors_sign_error.csv (sessions in which Sign must fail)
|
||||
- vectors/test_vectors_verify.csv (Verify: success and failure cases)
|
||||
- vectors/test_vectors_partial_sig_verify.csv (PartialSigVerify cases)
|
||||
- vectors/test_vectors_tweak.csv (plain and X-only key tweaking)
|
||||
"""
|
||||
|
||||
import csv
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import List
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).parent / "secp256k1lab/src"))
|
||||
from secp256k1lab.secp256k1 import FE, G, GE, Scalar
|
||||
from secp256k1lab.util import bytes_from_int, int_from_bytes, tagged_hash
|
||||
|
||||
from reference import (
|
||||
NonceGenInternal,
|
||||
NonceAgg,
|
||||
Sign,
|
||||
SigAgg,
|
||||
Verify,
|
||||
PartialSigVerify,
|
||||
TweakSK,
|
||||
TweakPK,
|
||||
has_even_y,
|
||||
n,
|
||||
FULLAGG_TAG_SIG,
|
||||
)
|
||||
|
||||
|
||||
VECTORS_DIR = Path(__file__).resolve().parent / "vectors"
|
||||
NONCE_GEN_VECTORS = VECTORS_DIR / "test_vectors_nonce_gen.csv"
|
||||
NONCE_AGG_VECTORS = VECTORS_DIR / "test_vectors_nonce_agg.csv"
|
||||
SIGN_VECTORS = VECTORS_DIR / "test_vectors_sign.csv"
|
||||
SIGN_ERROR_VECTORS = VECTORS_DIR / "test_vectors_sign_error.csv"
|
||||
VERIFY_VECTORS = VECTORS_DIR / "test_vectors_verify.csv"
|
||||
PARTIAL_SIG_VERIFY_VECTORS = VECTORS_DIR / "test_vectors_partial_sig_verify.csv"
|
||||
TWEAK_VECTORS = VECTORS_DIR / "test_vectors_tweak.csv"
|
||||
|
||||
|
||||
def scalar_from_byte(b: int) -> Scalar:
|
||||
"""Scalar whose 32-byte big-endian encoding is bytes([b]*32). Safe for 0x01..0xee."""
|
||||
assert 1 <= b <= 0xee
|
||||
return Scalar.from_bytes_checked(bytes([b] * 32))
|
||||
|
||||
|
||||
def make_signer(i: int):
|
||||
"""Deterministic (sk, pk, msg, secnonce, pubnonce). sk is normalized so pk has even y."""
|
||||
sk = scalar_from_byte(i * 3 + 1)
|
||||
pk = sk * G
|
||||
if not has_even_y(pk):
|
||||
sk = -sk
|
||||
pk = sk * G
|
||||
r1 = scalar_from_byte(i * 3 + 2)
|
||||
r2 = scalar_from_byte(i * 3 + 3)
|
||||
R1, R2 = r1 * G, r2 * G
|
||||
msg = bytes([0x80 + i] * 32)
|
||||
return sk, pk, msg, (r1, r2), (R1, R2)
|
||||
|
||||
|
||||
def make_same_pk_signers():
|
||||
"""Two signers sharing one key, signing different messages."""
|
||||
sk = scalar_from_byte(1)
|
||||
pk = sk * G
|
||||
if not has_even_y(pk):
|
||||
sk = -sk
|
||||
pk = sk * G
|
||||
msg_a = bytes([0xA0] * 32)
|
||||
msg_b = bytes([0xA1] * 32)
|
||||
r1_a, r2_a = scalar_from_byte(11), scalar_from_byte(12)
|
||||
r1_b, r2_b = scalar_from_byte(13), scalar_from_byte(14)
|
||||
return [
|
||||
(sk, pk, msg_a, (r1_a, r2_a), (r1_a * G, r2_a * G)),
|
||||
(sk, pk, msg_b, (r1_b, r2_b), (r1_b * G, r2_b * G)),
|
||||
]
|
||||
|
||||
|
||||
def make_tweaked_signer(i: int, tweak_byte: int, is_xonly: bool):
|
||||
"""Signer with a tweaked key pair, using an odd-y base for X-only tweaks to exercise normalization."""
|
||||
sk, pk, msg, secnonce, pubnonce = make_signer(i)
|
||||
if is_xonly:
|
||||
sk, pk = -sk, -pk
|
||||
t = scalar_from_byte(tweak_byte)
|
||||
return TweakSK(sk, t, is_xonly), TweakPK(pk, t, is_xonly), msg, secnonce, pubnonce
|
||||
|
||||
|
||||
def make_duplicate_pm_signers():
|
||||
"""Two signers with identical (pk, m) but distinct nonces."""
|
||||
sk = scalar_from_byte(1)
|
||||
pk = sk * G
|
||||
if not has_even_y(pk):
|
||||
sk = -sk
|
||||
pk = sk * G
|
||||
msg = bytes([0xC0] * 32)
|
||||
r1_a, r2_a = scalar_from_byte(20), scalar_from_byte(21)
|
||||
r1_b, r2_b = scalar_from_byte(22), scalar_from_byte(23)
|
||||
return [
|
||||
(sk, pk, msg, (r1_a, r2_a), (r1_a * G, r2_a * G)),
|
||||
(sk, pk, msg, (r1_b, r2_b), (r1_b * G, r2_b * G)),
|
||||
]
|
||||
|
||||
|
||||
def serialize_pubnonce(pubnonce) -> bytes:
|
||||
R1, R2 = pubnonce
|
||||
return R1.to_bytes_compressed() + R2.to_bytes_compressed()
|
||||
|
||||
|
||||
def serialize_secnonce(secnonce) -> bytes:
|
||||
r1, r2 = secnonce
|
||||
return r1.to_bytes() + r2.to_bytes()
|
||||
|
||||
|
||||
def serialize_sig(sig) -> bytes:
|
||||
R, s = sig
|
||||
return R.to_bytes_xonly() + s.to_bytes()
|
||||
|
||||
|
||||
def serialize_pk(pk: GE) -> bytes:
|
||||
return pk.to_bytes_xonly()
|
||||
|
||||
|
||||
def format_list(items: List[bytes], sep: str = ";") -> str:
|
||||
if not items:
|
||||
return ""
|
||||
return sep.join(item.hex().upper() for item in items)
|
||||
|
||||
|
||||
def sign_session(signers):
|
||||
"""Run NonceAgg -> Sign (per signer) -> SigAgg with deterministic inputs."""
|
||||
sks = [s[0] for s in signers]
|
||||
pks = [GE.from_bytes_xonly(s[1].to_bytes_xonly()) for s in signers]
|
||||
msgs = [s[2] for s in signers]
|
||||
secnonces = [s[3] for s in signers]
|
||||
pubnonces = [s[4] for s in signers]
|
||||
aggnonce = NonceAgg(pubnonces)
|
||||
psigs = [
|
||||
Sign(secnonces[i], sks[i], msgs[i], aggnonce, pks, msgs, pubnonces)
|
||||
for i in range(len(sks))
|
||||
]
|
||||
sig = SigAgg(aggnonce, pks, msgs, pubnonces, psigs)
|
||||
return aggnonce, psigs, sig
|
||||
|
||||
|
||||
def sign_unchecked(signers, msgs, r: Scalar):
|
||||
"""Aggregate signature from a party holding all secret keys, skipping the message length check."""
|
||||
R = r * G
|
||||
if not has_even_y(R):
|
||||
r = -r
|
||||
R = r * G
|
||||
L = b"".join(serialize_pk(s[1]) + m for s, m in zip(signers, msgs))
|
||||
s = r
|
||||
for (sk, pk, *_), m in zip(signers, msgs):
|
||||
d = sk if has_even_y(pk) else -sk
|
||||
c = Scalar.from_bytes_wrapping(tagged_hash(FULLAGG_TAG_SIG, L + R.to_bytes_xonly() + serialize_pk(pk) + m))
|
||||
s = s + c * d
|
||||
return R, s
|
||||
|
||||
|
||||
def gen_nonce_gen_vectors(f):
|
||||
writer = csv.writer(f)
|
||||
writer.writerow((
|
||||
"index", "rand_", "secret_key", "extra_in",
|
||||
"expected_secnonce", "expected_pubnonce", "comment",
|
||||
))
|
||||
|
||||
rand_prime = bytes([0x0F] * 32)
|
||||
|
||||
def row(idx, sk, extra_in, comment):
|
||||
secnonce, pubnonce = NonceGenInternal(rand_prime, sk, extra_in)
|
||||
writer.writerow((
|
||||
idx, rand_prime.hex().upper(),
|
||||
sk.to_bytes().hex().upper() if sk is not None else "",
|
||||
extra_in.hex().upper(),
|
||||
serialize_secnonce(secnonce).hex().upper(),
|
||||
serialize_pubnonce(pubnonce).hex().upper(),
|
||||
comment,
|
||||
))
|
||||
|
||||
sk = scalar_from_byte(0x02)
|
||||
extra_in = bytes([0x08] * 32)
|
||||
row(0, sk, extra_in, "Secret key and extra_in")
|
||||
row(1, sk, b"", "Secret key and no extra_in")
|
||||
row(2, None, extra_in, "No secret key and extra_in")
|
||||
row(3, None, b"", "No secret key and no extra_in")
|
||||
|
||||
|
||||
def gen_nonce_agg_vectors(f):
|
||||
writer = csv.writer(f)
|
||||
writer.writerow((
|
||||
"index", "pubnonces", "expected_result", "expected_aggnonce", "comment",
|
||||
))
|
||||
|
||||
def nonce_agg_bytes(pubnonces):
|
||||
return NonceAgg([(GE.from_bytes_compressed(p[:33]), GE.from_bytes_compressed(p[33:]))
|
||||
for p in pubnonces])
|
||||
|
||||
def row(idx, pubnonces, comment):
|
||||
aggnonce = serialize_pubnonce(nonce_agg_bytes(pubnonces))
|
||||
writer.writerow((idx, format_list(pubnonces), "TRUE", aggnonce.hex().upper(), comment))
|
||||
|
||||
def error_row(idx, pubnonces, comment):
|
||||
try:
|
||||
nonce_agg_bytes(pubnonces)
|
||||
except ValueError:
|
||||
pass
|
||||
else:
|
||||
raise RuntimeError(f"NonceAgg unexpectedly succeeded: {comment}")
|
||||
writer.writerow((idx, format_list(pubnonces), "FALSE", "", comment))
|
||||
|
||||
signers = [make_signer(i) for i in range(3)]
|
||||
pubnonces = [serialize_pubnonce(s[4]) for s in signers]
|
||||
(R1_0, R2_0), (R1_1, R2_1) = signers[0][4], signers[1][4]
|
||||
row(0, pubnonces[:2], "Two signers")
|
||||
row(1, pubnonces, "Three signers")
|
||||
error_row(2, [pubnonces[0], b"\x04" + pubnonces[1][1:]],
|
||||
"Signer 1's pubnonce first half has prefix 0x04")
|
||||
error_row(3, [pubnonces[0][:33] + b"\x02" + bytes(32), pubnonces[1]],
|
||||
"Signer 0's pubnonce second half is not on the curve")
|
||||
error_row(4, [pubnonces[0][:33] + b"\x02" + bytes_from_int(FE.SIZE + 1), pubnonces[1]],
|
||||
"Signer 0's pubnonce second half exceeds field size")
|
||||
error_row(5, [pubnonces[0], serialize_pubnonce((-R1_0, R2_1))],
|
||||
"Aggregate nonce R1 is infinity")
|
||||
error_row(6, [pubnonces[0], serialize_pubnonce((R1_1, -R2_0))],
|
||||
"Aggregate nonce R2 is infinity")
|
||||
|
||||
|
||||
def gen_sign_vectors(f):
|
||||
writer = csv.writer(f)
|
||||
writer.writerow((
|
||||
"index",
|
||||
"secret_keys",
|
||||
"messages",
|
||||
"secnonces",
|
||||
"expected_aggnonce",
|
||||
"expected_partial_sigs",
|
||||
"expected_sig",
|
||||
"comment",
|
||||
))
|
||||
|
||||
def write_row(idx, signers, comment):
|
||||
aggnonce, psigs, sig = sign_session(signers)
|
||||
writer.writerow((
|
||||
idx,
|
||||
format_list([s[0].to_bytes() for s in signers]),
|
||||
format_list([s[2] for s in signers]),
|
||||
format_list([serialize_secnonce(s[3]) for s in signers]),
|
||||
serialize_pubnonce(aggnonce).hex().upper(),
|
||||
format_list([p.to_bytes() for p in psigs]),
|
||||
serialize_sig(sig).hex().upper(),
|
||||
comment,
|
||||
))
|
||||
pks = [s[1] for s in signers]
|
||||
msgs = [s[2] for s in signers]
|
||||
pubnonces = [s[4] for s in signers]
|
||||
for i in range(len(signers)):
|
||||
assert PartialSigVerify(psigs[i], pks, msgs, pubnonces, i), \
|
||||
f"generated psig failed self-verification: {comment}"
|
||||
assert Verify(pks, msgs, sig), \
|
||||
f"generated sig failed self-verification: {comment}"
|
||||
|
||||
write_row(0, [make_signer(0)], "Single signer")
|
||||
write_row(1, [make_signer(i) for i in range(2)], "Two signers")
|
||||
write_row(2, [make_signer(i) for i in range(3)], "Three signers")
|
||||
write_row(3, [make_signer(i) for i in range(5)], "Five signers")
|
||||
write_row(4, make_same_pk_signers(), "Same pubkey signs two different messages")
|
||||
write_row(5, [make_tweaked_signer(0, 0x21, False), make_tweaked_signer(1, 0x22, True)],
|
||||
"Signers with tweaked keys")
|
||||
write_row(6, make_duplicate_pm_signers(), "Exact duplicate (pk, m) entries")
|
||||
|
||||
|
||||
def gen_sign_error_vectors(f):
|
||||
writer = csv.writer(f)
|
||||
writer.writerow((
|
||||
"index", "secret_key", "message", "secnonce", "aggnonce",
|
||||
"pubkeys", "messages", "pubnonces",
|
||||
"comment",
|
||||
))
|
||||
|
||||
def write_row(idx, signer, pks, msgs, pubnonces, comment, aggnonce=None):
|
||||
sk, _, msg, secnonce, _ = signer
|
||||
if aggnonce is None:
|
||||
aggnonce = serialize_pubnonce(NonceAgg(pubnonces))
|
||||
try:
|
||||
R1, R2 = GE.from_bytes_compressed(aggnonce[:33]), GE.from_bytes_compressed(aggnonce[33:])
|
||||
Sign(secnonce, sk, msg, (R1, R2), pks, msgs, pubnonces)
|
||||
except ValueError:
|
||||
pass
|
||||
else:
|
||||
raise RuntimeError(f"Sign unexpectedly succeeded: {comment}")
|
||||
writer.writerow((
|
||||
idx,
|
||||
sk.to_bytes().hex().upper(),
|
||||
msg.hex().upper(),
|
||||
serialize_secnonce(secnonce).hex().upper(),
|
||||
aggnonce.hex().upper(),
|
||||
format_list([serialize_pk(p) for p in pks]),
|
||||
format_list(msgs),
|
||||
format_list([serialize_pubnonce(p) for p in pubnonces]),
|
||||
comment,
|
||||
))
|
||||
|
||||
signers = [make_signer(i) for i in range(3)]
|
||||
pks = [GE.from_bytes_xonly(s[1].to_bytes_xonly()) for s in signers]
|
||||
msgs = [s[2] for s in signers]
|
||||
pubnonces = [s[4] for s in signers]
|
||||
|
||||
dup_pubnonces = list(pubnonces)
|
||||
dup_pubnonces[2] = (pubnonces[2][0], pubnonces[0][1])
|
||||
write_row(0, signers[0], pks, msgs, dup_pubnonces,
|
||||
"Signer's R2 appears at two indices")
|
||||
|
||||
missing_pubnonces = list(pubnonces)
|
||||
missing_pubnonces[0] = (pubnonces[0][0], scalar_from_byte(0x63) * G)
|
||||
write_row(1, signers[0], pks, msgs, missing_pubnonces,
|
||||
"Signer's R2 appears at no index")
|
||||
|
||||
wrong_msgs = list(msgs)
|
||||
wrong_msgs[0] = bytes([0xEE] * 32)
|
||||
write_row(2, signers[0], pks, wrong_msgs, pubnonces,
|
||||
"Message at signer's index was substituted")
|
||||
|
||||
wrong_pks = list(pks)
|
||||
wrong_pks[0] = GE.from_bytes_xonly((scalar_from_byte(0x55) * G).to_bytes_xonly())
|
||||
write_row(3, signers[0], wrong_pks, msgs, pubnonces,
|
||||
"Public key at signer's index was substituted")
|
||||
|
||||
sk, pk, msg, secnonce, pubnonce = signers[0]
|
||||
write_row(4, (sk, pk, msg, (Scalar(0), Scalar(0)), pubnonce), pks, msgs, pubnonces,
|
||||
"Secnonce is all zeros")
|
||||
write_row(5, (Scalar(0), pk, msg, secnonce, pubnonce), pks, msgs, pubnonces,
|
||||
"Secret key is zero")
|
||||
|
||||
aggnonce = serialize_pubnonce(NonceAgg(pubnonces))
|
||||
write_row(6, signers[0], pks, msgs, pubnonces,
|
||||
"Aggregate nonce first half is all zeros", bytes(33) + aggnonce[33:])
|
||||
write_row(7, signers[0], pks, msgs, pubnonces,
|
||||
"Aggregate nonce second half is not on the curve", aggnonce[:33] + b"\x02" + bytes(32))
|
||||
write_row(8, signers[0], pks, msgs, pubnonces,
|
||||
"Aggregate nonce second half exceeds field size",
|
||||
aggnonce[:33] + b"\x02" + bytes_from_int(FE.SIZE + 1))
|
||||
|
||||
|
||||
def gen_verify_vectors(f):
|
||||
writer = csv.writer(f)
|
||||
writer.writerow((
|
||||
"index", "pubkeys", "messages", "sig", "expected_result", "comment",
|
||||
))
|
||||
|
||||
idx = 0
|
||||
|
||||
signers = [make_signer(i) for i in range(2)]
|
||||
_, _, sig = sign_session(signers)
|
||||
pks = [serialize_pk(s[1]) for s in signers]
|
||||
msgs = [s[2] for s in signers]
|
||||
sig_bytes = serialize_sig(sig)
|
||||
|
||||
writer.writerow((idx, format_list(pks), format_list(msgs),
|
||||
sig_bytes.hex().upper(), "TRUE",
|
||||
"Two-signer valid aggregate"))
|
||||
idx += 1
|
||||
|
||||
signers3 = [make_signer(i) for i in range(3)]
|
||||
_, _, sig3 = sign_session(signers3)
|
||||
pks3 = [serialize_pk(s[1]) for s in signers3]
|
||||
msgs3 = [s[2] for s in signers3]
|
||||
sig3_bytes = serialize_sig(sig3)
|
||||
writer.writerow((idx, format_list(pks3), format_list(msgs3),
|
||||
sig3_bytes.hex().upper(), "TRUE",
|
||||
"Three-signer valid aggregate"))
|
||||
idx += 1
|
||||
|
||||
wrong_msgs = [msgs[0], bytes([0xff] * 32)]
|
||||
writer.writerow((idx, format_list(pks), format_list(wrong_msgs),
|
||||
sig_bytes.hex().upper(), "FALSE",
|
||||
"Wrong message for second signer"))
|
||||
idx += 1
|
||||
|
||||
writer.writerow((idx, format_list([pks[1], pks[0]]), format_list(msgs),
|
||||
sig_bytes.hex().upper(), "FALSE",
|
||||
"Pubkey order swapped"))
|
||||
idx += 1
|
||||
|
||||
writer.writerow((idx, format_list([pks[0]]), format_list([msgs[0]]),
|
||||
sig_bytes.hex().upper(), "FALSE",
|
||||
"Dropped second signer"))
|
||||
idx += 1
|
||||
|
||||
s_int = int_from_bytes(sig_bytes[32:64])
|
||||
tampered = sig_bytes[:32] + bytes_from_int(s_int ^ 1)
|
||||
writer.writerow((idx, format_list(pks), format_list(msgs),
|
||||
tampered.hex().upper(), "FALSE",
|
||||
"Tampered s (bit flip)"))
|
||||
idx += 1
|
||||
|
||||
s_zero = sig_bytes[:32] + bytes(32)
|
||||
writer.writerow((idx, format_list(pks), format_list(msgs),
|
||||
s_zero.hex().upper(), "FALSE",
|
||||
"s = 0 (in range, wrong)"))
|
||||
idx += 1
|
||||
|
||||
s_eq_n = sig_bytes[:32] + bytes_from_int(n)
|
||||
writer.writerow((idx, format_list(pks), format_list(msgs),
|
||||
s_eq_n.hex().upper(), "FALSE",
|
||||
"s = n (out of range)"))
|
||||
idx += 1
|
||||
|
||||
s_max = sig_bytes[:32] + bytes([0xff] * 32)
|
||||
writer.writerow((idx, format_list(pks), format_list(msgs),
|
||||
s_max.hex().upper(), "FALSE",
|
||||
"s = 2^256 - 1"))
|
||||
idx += 1
|
||||
|
||||
def find_off_curve_x() -> bytes:
|
||||
for i in range(1, 256):
|
||||
cand = bytes([i] * 32)
|
||||
try:
|
||||
GE.from_bytes_xonly(cand)
|
||||
except Exception:
|
||||
return cand
|
||||
raise RuntimeError("could not find an off-curve x")
|
||||
|
||||
off_curve = find_off_curve_x()
|
||||
|
||||
bad_R_sig = off_curve + sig_bytes[32:64]
|
||||
writer.writerow((idx, format_list(pks), format_list(msgs),
|
||||
bad_R_sig.hex().upper(), "FALSE",
|
||||
"R x-coord not on curve"))
|
||||
idx += 1
|
||||
|
||||
writer.writerow((idx, format_list([off_curve, pks[1]]), format_list(msgs),
|
||||
sig_bytes.hex().upper(), "FALSE",
|
||||
"Public key not on curve"))
|
||||
idx += 1
|
||||
|
||||
writer.writerow((idx, format_list(pks), format_list(msgs),
|
||||
sig_bytes[:-1].hex().upper(), "FALSE",
|
||||
"Signature too short"))
|
||||
idx += 1
|
||||
|
||||
writer.writerow((idx, format_list(pks), format_list(msgs),
|
||||
(sig_bytes + b"\x00").hex().upper(), "FALSE",
|
||||
"Signature too long"))
|
||||
idx += 1
|
||||
|
||||
writer.writerow((idx, format_list(pks), format_list([msgs[0]]),
|
||||
sig_bytes.hex().upper(), "FALSE",
|
||||
"Pubkey/message count mismatch"))
|
||||
idx += 1
|
||||
|
||||
writer.writerow((idx, "", "",
|
||||
sig_bytes.hex().upper(), "FALSE",
|
||||
"Empty signer list"))
|
||||
idx += 1
|
||||
|
||||
for bad_m0, comment in ((msgs[0][:31], "Message too short"), (msgs[0] + b"\x00", "Message too long")):
|
||||
bad_msgs = [bad_m0, msgs[1]]
|
||||
bad_sig = serialize_sig(sign_unchecked(signers, bad_msgs, scalar_from_byte(0x70)))
|
||||
writer.writerow((idx, format_list(pks), format_list(bad_msgs),
|
||||
bad_sig.hex().upper(), "FALSE", comment))
|
||||
idx += 1
|
||||
|
||||
|
||||
def gen_partial_sig_verify_vectors(f):
|
||||
writer = csv.writer(f)
|
||||
writer.writerow((
|
||||
"index", "signer_index", "psig",
|
||||
"pubkeys", "messages", "pubnonces",
|
||||
"expected_result", "comment",
|
||||
))
|
||||
|
||||
signers = [make_signer(i) for i in range(2)]
|
||||
aggnonce, psigs, _ = sign_session(signers)
|
||||
pks_hex = format_list([serialize_pk(s[1]) for s in signers])
|
||||
msgs_hex = format_list([s[2] for s in signers])
|
||||
pubnonces_hex = format_list([serialize_pubnonce(s[4]) for s in signers])
|
||||
|
||||
def write_row(idx, signer_index, psig_bytes, expected, comment):
|
||||
writer.writerow((
|
||||
idx, signer_index, psig_bytes.hex().upper(),
|
||||
pks_hex, msgs_hex, pubnonces_hex,
|
||||
expected, comment,
|
||||
))
|
||||
|
||||
idx = 0
|
||||
write_row(idx, 0, psigs[0].to_bytes(), "TRUE", "Honest partial sig (signer 0)")
|
||||
idx += 1
|
||||
write_row(idx, 1, psigs[1].to_bytes(), "TRUE", "Honest partial sig (signer 1)")
|
||||
idx += 1
|
||||
write_row(idx, 1, psigs[0].to_bytes(), "FALSE",
|
||||
"Honest psig verified at the wrong signer_index")
|
||||
idx += 1
|
||||
write_row(idx, 0, bytes_from_int(int(psigs[0]) ^ 1), "FALSE",
|
||||
"Tampered partial sig (bit flip)")
|
||||
idx += 1
|
||||
write_row(idx, 0, bytes(32), "FALSE", "psig = 0 (in range, wrong)")
|
||||
idx += 1
|
||||
write_row(idx, 0, bytes_from_int(n), "FALSE", "psig = n (out of range)")
|
||||
idx += 1
|
||||
write_row(idx, 2, psigs[0].to_bytes(), "FALSE", "signer_index out of range")
|
||||
idx += 1
|
||||
fake_aggnonce = (aggnonce[0] + G, aggnonce[1])
|
||||
psig_wrong = Sign(signers[0][3], signers[0][0], signers[0][2], fake_aggnonce,
|
||||
[s[1] for s in signers], [s[2] for s in signers],
|
||||
[s[4] for s in signers])
|
||||
write_row(idx, 0, psig_wrong.to_bytes(), "FALSE", "psig for a different aggregate nonce")
|
||||
idx += 1
|
||||
R1_0, R2_0 = signers[0][4]
|
||||
_, R2_1 = signers[1][4]
|
||||
inf_pubnonces = format_list([serialize_pubnonce((R1_0, R2_0)),
|
||||
serialize_pubnonce((-R1_0, R2_1))])
|
||||
writer.writerow((idx, 0, psigs[0].to_bytes().hex().upper(),
|
||||
pks_hex, msgs_hex, inf_pubnonces,
|
||||
"FALSE", "Aggregate nonce R1 is infinity"))
|
||||
|
||||
|
||||
def gen_tweak_vectors(f):
|
||||
writer = csv.writer(f)
|
||||
writer.writerow((
|
||||
"index", "internal_secret_key", "tweak", "is_xonly", "expected_result",
|
||||
"expected_secret_key", "expected_pubkey", "comment",
|
||||
))
|
||||
|
||||
def row(idx, sk, t, is_xonly, comment):
|
||||
sk_out = TweakSK(sk, t, is_xonly)
|
||||
pk_out = TweakPK(sk * G, t, is_xonly)
|
||||
assert sk_out * G == pk_out
|
||||
writer.writerow((
|
||||
idx, sk.to_bytes().hex().upper(), t.to_bytes().hex().upper(),
|
||||
"TRUE" if is_xonly else "FALSE", "TRUE",
|
||||
sk_out.to_bytes().hex().upper(), pk_out.to_bytes_compressed().hex().upper(),
|
||||
comment,
|
||||
))
|
||||
|
||||
def error_row(idx, sk, t, is_xonly, comment):
|
||||
for tweak_fn, key in ((TweakSK, sk), (TweakPK, sk * G)):
|
||||
try:
|
||||
tweak_fn(key, t, is_xonly)
|
||||
except ValueError:
|
||||
continue
|
||||
raise RuntimeError(f"{tweak_fn.__name__} unexpectedly succeeded: {comment}")
|
||||
writer.writerow((
|
||||
idx, sk.to_bytes().hex().upper(), t.to_bytes().hex().upper(),
|
||||
"TRUE" if is_xonly else "FALSE", "FALSE", "", "",
|
||||
comment,
|
||||
))
|
||||
|
||||
sk1 = scalar_from_byte(1)
|
||||
even = sk1 if has_even_y(sk1 * G) else -sk1
|
||||
odd = -even
|
||||
t = scalar_from_byte(0x02)
|
||||
row(0, even, t, False, "Plain tweak of an even-y key")
|
||||
row(1, odd, t, False, "Plain tweak of an odd-y key")
|
||||
row(2, even, t, True, "X-only tweak of an even-y key")
|
||||
row(3, odd, t, True, "X-only tweak of an odd-y key")
|
||||
error_row(4, odd, -odd, False, "Plain tweak resulting in the point at infinity")
|
||||
error_row(5, odd, odd, True, "X-only tweak resulting in the point at infinity")
|
||||
writer.writerow((6, even.to_bytes().hex().upper(), bytes_from_int(n).hex().upper(),
|
||||
"FALSE", "FALSE", "", "", "Tweak = n (out of range)"))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
os.makedirs(VECTORS_DIR, exist_ok=True)
|
||||
|
||||
print(f"Generating {NONCE_GEN_VECTORS}")
|
||||
with open(NONCE_GEN_VECTORS, "w", newline="", encoding="utf-8") as f:
|
||||
gen_nonce_gen_vectors(f)
|
||||
|
||||
print(f"Generating {NONCE_AGG_VECTORS}")
|
||||
with open(NONCE_AGG_VECTORS, "w", newline="", encoding="utf-8") as f:
|
||||
gen_nonce_agg_vectors(f)
|
||||
|
||||
print(f"Generating {SIGN_VECTORS}")
|
||||
with open(SIGN_VECTORS, "w", newline="", encoding="utf-8") as f:
|
||||
gen_sign_vectors(f)
|
||||
|
||||
print(f"Generating {SIGN_ERROR_VECTORS}")
|
||||
with open(SIGN_ERROR_VECTORS, "w", newline="", encoding="utf-8") as f:
|
||||
gen_sign_error_vectors(f)
|
||||
|
||||
print(f"Generating {VERIFY_VECTORS}")
|
||||
with open(VERIFY_VECTORS, "w", newline="", encoding="utf-8") as f:
|
||||
gen_verify_vectors(f)
|
||||
|
||||
print(f"Generating {PARTIAL_SIG_VERIFY_VECTORS}")
|
||||
with open(PARTIAL_SIG_VERIFY_VECTORS, "w", newline="", encoding="utf-8") as f:
|
||||
gen_partial_sig_verify_vectors(f)
|
||||
|
||||
print(f"Generating {TWEAK_VECTORS}")
|
||||
with open(TWEAK_VECTORS, "w", newline="", encoding="utf-8") as f:
|
||||
gen_tweak_vectors(f)
|
||||
|
||||
print("Done.")
|
||||
@@ -0,0 +1,211 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Reference implementation of BIP 459 DahLIAS fully aggregated signatures
|
||||
for secp256k1.
|
||||
|
||||
WARNING: This implementation is for demonstration purposes only and is not
|
||||
optimized for production use.
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
from typing import List, Tuple, Optional
|
||||
import secrets
|
||||
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, xor_bytes
|
||||
|
||||
n = GE.ORDER
|
||||
|
||||
FULLAGG_TAG_AUX = "BIP0459/aux"
|
||||
FULLAGG_TAG_NONCE = "BIP0459/nonce"
|
||||
FULLAGG_TAG_NONCECOEF = "BIP0459/noncecoef"
|
||||
FULLAGG_TAG_SIG = "BIP0459/sig"
|
||||
|
||||
|
||||
#
|
||||
# Helpers
|
||||
#
|
||||
|
||||
def has_even_y(P: GE) -> bool:
|
||||
return P.has_even_y()
|
||||
|
||||
|
||||
def cbytes(P: GE) -> bytes:
|
||||
return P.to_bytes_compressed()
|
||||
|
||||
|
||||
def xbytes(P: GE) -> bytes:
|
||||
return P.to_bytes_xonly()
|
||||
|
||||
|
||||
#
|
||||
# Key Tweaking
|
||||
#
|
||||
|
||||
def TweakSK(sk: Scalar, t: Scalar, is_xonly: bool) -> Scalar:
|
||||
d = sk if (not is_xonly or has_even_y(sk * G)) else -sk
|
||||
sk_out = d + t
|
||||
if sk_out == 0:
|
||||
raise ValueError("tweaked secret key is zero")
|
||||
return sk_out
|
||||
|
||||
|
||||
def TweakPK(pk: GE, t: Scalar, is_xonly: bool) -> GE:
|
||||
P = pk if (not is_xonly or has_even_y(pk)) else -pk
|
||||
Q = P + t * G
|
||||
if Q.infinity:
|
||||
raise ValueError("tweaked public key is the point at infinity")
|
||||
return Q
|
||||
|
||||
|
||||
#
|
||||
# Nonce Generation and Aggregation
|
||||
#
|
||||
|
||||
def NonceGenInternal(rand_prime: bytes, sk: Optional[Scalar] = None,
|
||||
extra_in: bytes = b'') -> Tuple[Tuple[Scalar, Scalar], Tuple[GE, GE]]:
|
||||
if sk is not None:
|
||||
rand = xor_bytes(sk.to_bytes(), tagged_hash(FULLAGG_TAG_AUX, rand_prime))
|
||||
else:
|
||||
rand = rand_prime
|
||||
r1 = Scalar.from_bytes_wrapping(tagged_hash(FULLAGG_TAG_NONCE, rand + extra_in + b'\x00'))
|
||||
r2 = Scalar.from_bytes_wrapping(tagged_hash(FULLAGG_TAG_NONCE, rand + extra_in + b'\x01'))
|
||||
assert r1 != 0 and r2 != 0
|
||||
R1, R2 = r1 * G, r2 * G
|
||||
return (r1, r2), (R1, R2)
|
||||
|
||||
|
||||
def NonceGen(sk: Optional[Scalar] = None,
|
||||
extra_in: bytes = b'') -> Tuple[Tuple[Scalar, Scalar], Tuple[GE, GE]]:
|
||||
rand_prime = secrets.token_bytes(32)
|
||||
return NonceGenInternal(rand_prime, sk, extra_in)
|
||||
|
||||
|
||||
def NonceAgg(pubnonces: List[Tuple[GE, GE]]) -> Tuple[GE, GE]:
|
||||
u = len(pubnonces)
|
||||
R1, R2 = pubnonces[0]
|
||||
for i in range(1, u):
|
||||
R1 = R1 + pubnonces[i][0]
|
||||
R2 = R2 + pubnonces[i][1]
|
||||
if R1.infinity or R2.infinity:
|
||||
raise ValueError("aggregate nonce is the point at infinity")
|
||||
return R1, R2
|
||||
|
||||
|
||||
#
|
||||
# Session Values
|
||||
#
|
||||
|
||||
def GetSessionValues(aggnonce: Tuple[GE, GE], pks: List[GE], msgs: List[bytes],
|
||||
pubnonces: List[Tuple[GE, GE]]) -> Tuple[GE, Scalar]:
|
||||
R1, R2 = aggnonce
|
||||
u = len(pks)
|
||||
nonce_data = cbytes(R1) + cbytes(R2)
|
||||
for i in range(u):
|
||||
nonce_data += xbytes(pks[i]) + msgs[i] + cbytes(pubnonces[i][1])
|
||||
b = Scalar.from_bytes_wrapping(tagged_hash(FULLAGG_TAG_NONCECOEF, nonce_data))
|
||||
R = R1 + b * R2
|
||||
assert not R.infinity
|
||||
return R, b
|
||||
|
||||
|
||||
#
|
||||
# Signing
|
||||
#
|
||||
|
||||
def Sign(secnonce: Tuple[Scalar, Scalar], sk: Scalar, m: bytes,
|
||||
aggnonce: Tuple[GE, GE], pks: List[GE], msgs: List[bytes],
|
||||
pubnonces: List[Tuple[GE, GE]]) -> Scalar:
|
||||
if not (len(pks) == len(msgs) == len(pubnonces) >= 1):
|
||||
raise ValueError("list lengths must match and be nonzero")
|
||||
if len(m) != 32 or any(len(mi) != 32 for mi in msgs):
|
||||
raise ValueError("messages must be 32 bytes")
|
||||
r1, r2 = secnonce
|
||||
if r1 == 0 or r2 == 0:
|
||||
raise ValueError("secnonce value is zero")
|
||||
if sk == 0:
|
||||
raise ValueError("secret key is zero")
|
||||
P = sk * G
|
||||
R2_local = r2 * G
|
||||
|
||||
# Index lookup and uniqueness check
|
||||
matches = [j for j in range(len(pubnonces)) if pubnonces[j][1] == R2_local]
|
||||
if len(matches) != 1:
|
||||
raise ValueError("signer's R2 must appear exactly once")
|
||||
j = matches[0]
|
||||
if xbytes(pks[j]) != xbytes(P) or msgs[j] != m:
|
||||
raise ValueError("public key or message at signer's index does not match")
|
||||
|
||||
R, b = GetSessionValues(aggnonce, pks, msgs, pubnonces)
|
||||
e = Scalar(1) if has_even_y(R) else -Scalar(1)
|
||||
d_prime = sk if has_even_y(P) else -sk
|
||||
|
||||
L = b''
|
||||
for i in range(len(pks)):
|
||||
L += xbytes(pks[i]) + msgs[i]
|
||||
c_j = Scalar.from_bytes_wrapping(tagged_hash(FULLAGG_TAG_SIG, L + xbytes(R) + xbytes(pks[j]) + msgs[j]))
|
||||
s_j = e * (r1 + b * r2) + c_j * d_prime
|
||||
return s_j
|
||||
|
||||
|
||||
#
|
||||
# Aggregation
|
||||
#
|
||||
|
||||
def SigAgg(aggnonce: Tuple[GE, GE], pks: List[GE], msgs: List[bytes],
|
||||
pubnonces: List[Tuple[GE, GE]], psigs: List[Scalar]) -> Tuple[GE, Scalar]:
|
||||
if not (len(pks) == len(msgs) == len(pubnonces) == len(psigs) >= 1):
|
||||
raise ValueError("list lengths must match and be nonzero")
|
||||
if any(len(mi) != 32 for mi in msgs):
|
||||
raise ValueError("messages must be 32 bytes")
|
||||
R, _ = GetSessionValues(aggnonce, pks, msgs, pubnonces)
|
||||
s = Scalar.sum(*psigs)
|
||||
return R, s
|
||||
|
||||
|
||||
#
|
||||
# Partial Signature Verification
|
||||
#
|
||||
|
||||
def PartialSigVerify(psig: Scalar, pks: List[GE], msgs: List[bytes],
|
||||
pubnonces: List[Tuple[GE, GE]], signer_index: int) -> bool:
|
||||
if not (len(pks) == len(msgs) == len(pubnonces) >= 1) or any(len(mi) != 32 for mi in msgs):
|
||||
return False
|
||||
if not (0 <= signer_index < len(pks)):
|
||||
return False
|
||||
i = signer_index
|
||||
R1_i, R2_i = pubnonces[i]
|
||||
P_i = GE.from_bytes_xonly(xbytes(pks[i]))
|
||||
R, b = GetSessionValues(NonceAgg(pubnonces), pks, msgs, pubnonces)
|
||||
e = Scalar(1) if has_even_y(R) else -Scalar(1)
|
||||
|
||||
L = b''
|
||||
for k in range(len(pks)):
|
||||
L += xbytes(pks[k]) + msgs[k]
|
||||
c_i = Scalar.from_bytes_wrapping(tagged_hash(FULLAGG_TAG_SIG, L + xbytes(R) + xbytes(pks[i]) + msgs[i]))
|
||||
R_eff_i = R1_i + b * R2_i
|
||||
return psig * G == e * R_eff_i + c_i * P_i
|
||||
|
||||
|
||||
#
|
||||
# Aggregate Signature Verification
|
||||
#
|
||||
|
||||
def Verify(pks: List[GE], msgs: List[bytes], sig: Tuple[GE, Scalar]) -> bool:
|
||||
R_point, s = sig
|
||||
if not (len(pks) == len(msgs) >= 1) or any(len(mi) != 32 for mi in msgs):
|
||||
return False
|
||||
u = len(pks)
|
||||
R = GE.from_bytes_xonly(xbytes(R_point))
|
||||
Ps = [GE.from_bytes_xonly(xbytes(pks[i])) for i in range(u)]
|
||||
|
||||
L = b''
|
||||
for i in range(u):
|
||||
L += xbytes(pks[i]) + msgs[i]
|
||||
rhs = R
|
||||
for i in range(u):
|
||||
c_i = Scalar.from_bytes_wrapping(tagged_hash(FULLAGG_TAG_SIG, L + xbytes(R) + xbytes(pks[i]) + msgs[i]))
|
||||
rhs = rhs + c_i * Ps[i]
|
||||
return s * G == rhs
|
||||
@@ -0,0 +1,314 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Run test vectors for BIP 459 DahLIAS fully aggregated signatures
|
||||
for secp256k1.
|
||||
|
||||
Usage:
|
||||
python run_test_vectors.py
|
||||
|
||||
Expects CSV files generated by gen_test_vectors.py in vectors/ directory.
|
||||
"""
|
||||
|
||||
import csv
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import List, Tuple
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).parent / "secp256k1lab/src"))
|
||||
from secp256k1lab.secp256k1 import G, GE, Scalar
|
||||
|
||||
from reference import NonceGenInternal, NonceAgg, Sign, SigAgg, Verify, PartialSigVerify, TweakSK, TweakPK
|
||||
|
||||
|
||||
VECTORS_DIR = Path(__file__).resolve().parent / "vectors"
|
||||
NONCE_GEN_VECTORS = VECTORS_DIR / "test_vectors_nonce_gen.csv"
|
||||
NONCE_AGG_VECTORS = VECTORS_DIR / "test_vectors_nonce_agg.csv"
|
||||
SIGN_VECTORS = VECTORS_DIR / "test_vectors_sign.csv"
|
||||
SIGN_ERROR_VECTORS = VECTORS_DIR / "test_vectors_sign_error.csv"
|
||||
VERIFY_VECTORS = VECTORS_DIR / "test_vectors_verify.csv"
|
||||
PARTIAL_SIG_VERIFY_VECTORS = VECTORS_DIR / "test_vectors_partial_sig_verify.csv"
|
||||
TWEAK_VECTORS = VECTORS_DIR / "test_vectors_tweak.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_pubnonce(b: bytes) -> Tuple[GE, GE]:
|
||||
if len(b) != 66:
|
||||
raise ValueError("pubnonce must be 66 bytes")
|
||||
return GE.from_bytes_compressed(b[:33]), GE.from_bytes_compressed(b[33:])
|
||||
|
||||
|
||||
def parse_secnonce(b: bytes) -> Tuple[Scalar, Scalar]:
|
||||
if len(b) != 64:
|
||||
raise ValueError("secnonce must be 64 bytes")
|
||||
return Scalar.from_bytes_checked(b[:32]), Scalar.from_bytes_checked(b[32:])
|
||||
|
||||
|
||||
def parse_sig(b: bytes) -> Tuple[GE, Scalar]:
|
||||
"""Parse R (32-byte x-only) || s (32-byte big-endian).
|
||||
|
||||
Lifts R to even y and raises ValueError on length mismatch, off-curve R, or
|
||||
s >= n.
|
||||
"""
|
||||
if len(b) != 64:
|
||||
raise ValueError("signature must be 64 bytes")
|
||||
R = GE.from_bytes_xonly(b[:32])
|
||||
s = Scalar.from_bytes_checked(b[32:])
|
||||
return R, s
|
||||
|
||||
|
||||
def run_nonce_gen_tests() -> List[str]:
|
||||
failures = []
|
||||
|
||||
with open(NONCE_GEN_VECTORS, newline="", encoding="utf-8") as f:
|
||||
reader = csv.reader(f)
|
||||
next(reader)
|
||||
|
||||
for row in reader:
|
||||
(index, rand_str, sk_str, extra_in_str,
|
||||
expected_secnonce_str, expected_pubnonce_str, comment) = row
|
||||
sk = Scalar.from_bytes_checked(bytes.fromhex(sk_str)) if sk_str else None
|
||||
(r1, r2), (R1, R2) = NonceGenInternal(bytes.fromhex(rand_str), sk, bytes.fromhex(extra_in_str))
|
||||
secnonce = r1.to_bytes() + r2.to_bytes()
|
||||
pubnonce = R1.to_bytes_compressed() + R2.to_bytes_compressed()
|
||||
if (secnonce.hex().upper() != expected_secnonce_str
|
||||
or pubnonce.hex().upper() != expected_pubnonce_str):
|
||||
failures.append(f"NonceGen #{index}: {comment}")
|
||||
|
||||
return failures
|
||||
|
||||
|
||||
def run_nonce_agg_tests() -> List[str]:
|
||||
failures = []
|
||||
|
||||
with open(NONCE_AGG_VECTORS, newline="", encoding="utf-8") as f:
|
||||
reader = csv.reader(f)
|
||||
next(reader)
|
||||
|
||||
for row in reader:
|
||||
index, pubnonces_str, expected_result, expected_aggnonce_str, comment = row
|
||||
expected = (expected_result == "TRUE")
|
||||
|
||||
try:
|
||||
pubnonces = [parse_pubnonce(b) for b in parse_hex_list(pubnonces_str)]
|
||||
R1, R2 = NonceAgg(pubnonces)
|
||||
aggnonce = R1.to_bytes_compressed() + R2.to_bytes_compressed()
|
||||
except ValueError:
|
||||
aggnonce = None
|
||||
|
||||
if expected:
|
||||
ok = aggnonce is not None and aggnonce.hex().upper() == expected_aggnonce_str
|
||||
else:
|
||||
ok = aggnonce is None
|
||||
if not ok:
|
||||
failures.append(f"NonceAgg #{index}: {comment}")
|
||||
|
||||
return failures
|
||||
|
||||
|
||||
def run_sign_tests() -> List[str]:
|
||||
failures = []
|
||||
|
||||
with open(SIGN_VECTORS, newline="", encoding="utf-8") as f:
|
||||
reader = csv.reader(f)
|
||||
next(reader)
|
||||
|
||||
for row in reader:
|
||||
(index, sks_str, msgs_str, secnonces_str,
|
||||
expected_aggnonce_str, expected_psigs_str,
|
||||
expected_sig_str, comment) = row
|
||||
|
||||
try:
|
||||
sks = [Scalar.from_bytes_checked(b) for b in parse_hex_list(sks_str)]
|
||||
msgs = parse_hex_list(msgs_str)
|
||||
secnonces = [parse_secnonce(b) for b in parse_hex_list(secnonces_str)]
|
||||
expected_aggnonce = bytes.fromhex(expected_aggnonce_str)
|
||||
expected_psigs = parse_hex_list(expected_psigs_str)
|
||||
expected_sig = bytes.fromhex(expected_sig_str)
|
||||
|
||||
pks = [GE.from_bytes_xonly((sk * G).to_bytes_xonly()) for sk in sks]
|
||||
pubnonces = [(r1 * G, r2 * G) for (r1, r2) in secnonces]
|
||||
|
||||
aggnonce = NonceAgg(pubnonces)
|
||||
aggnonce_bytes = (aggnonce[0].to_bytes_compressed()
|
||||
+ aggnonce[1].to_bytes_compressed())
|
||||
if aggnonce_bytes != expected_aggnonce:
|
||||
failures.append(f"Sign #{index}: {comment} (aggnonce mismatch)")
|
||||
continue
|
||||
|
||||
psigs = [
|
||||
Sign(secnonces[i], sks[i], msgs[i], aggnonce, pks, msgs, pubnonces)
|
||||
for i in range(len(sks))
|
||||
]
|
||||
derived_psigs = [p.to_bytes() for p in psigs]
|
||||
if derived_psigs != expected_psigs:
|
||||
failures.append(f"Sign #{index}: {comment} (partial sig mismatch)")
|
||||
continue
|
||||
|
||||
for i in range(len(sks)):
|
||||
if not PartialSigVerify(psigs[i], pks, msgs, pubnonces, i):
|
||||
failures.append(f"Sign #{index}: {comment} (PartialSigVerify failed for signer {i})")
|
||||
break
|
||||
else:
|
||||
R, s = SigAgg(aggnonce, pks, msgs, pubnonces, psigs)
|
||||
actual_sig = R.to_bytes_xonly() + s.to_bytes()
|
||||
if actual_sig != expected_sig:
|
||||
failures.append(f"Sign #{index}: {comment} (aggsig mismatch)")
|
||||
elif not Verify(pks, msgs, (R, s)):
|
||||
failures.append(f"Sign #{index}: {comment} (Verify failed)")
|
||||
except ValueError as e:
|
||||
failures.append(f"Sign #{index}: {comment} (raised {e!r})")
|
||||
|
||||
return failures
|
||||
|
||||
|
||||
def run_sign_error_tests() -> List[str]:
|
||||
failures = []
|
||||
|
||||
with open(SIGN_ERROR_VECTORS, newline="", encoding="utf-8") as f:
|
||||
reader = csv.reader(f)
|
||||
next(reader)
|
||||
|
||||
for row in reader:
|
||||
(index, sk_str, msg_str, secnonce_str, aggnonce_str,
|
||||
pks_str, msgs_str, pubnonces_str, comment) = row
|
||||
|
||||
sk = Scalar.from_bytes_checked(bytes.fromhex(sk_str))
|
||||
m = bytes.fromhex(msg_str)
|
||||
secnonce = parse_secnonce(bytes.fromhex(secnonce_str))
|
||||
pks = [GE.from_bytes_xonly(b) for b in parse_hex_list(pks_str)]
|
||||
msgs = parse_hex_list(msgs_str)
|
||||
pubnonces = [parse_pubnonce(b) for b in parse_hex_list(pubnonces_str)]
|
||||
|
||||
try:
|
||||
aggnonce = parse_pubnonce(bytes.fromhex(aggnonce_str))
|
||||
Sign(secnonce, sk, m, aggnonce, pks, msgs, pubnonces)
|
||||
except ValueError:
|
||||
continue
|
||||
failures.append(f"SignError #{index}: {comment} (Sign did not fail)")
|
||||
|
||||
return failures
|
||||
|
||||
|
||||
def run_partial_sig_verify_tests() -> List[str]:
|
||||
failures = []
|
||||
|
||||
with open(PARTIAL_SIG_VERIFY_VECTORS, newline="", encoding="utf-8") as f:
|
||||
reader = csv.reader(f)
|
||||
next(reader)
|
||||
|
||||
for row in reader:
|
||||
(index, signer_index_str, psig_str,
|
||||
pks_str, msgs_str, pubnonces_str,
|
||||
expected_result, comment) = row
|
||||
expected = (expected_result == "TRUE")
|
||||
|
||||
try:
|
||||
signer_index = int(signer_index_str)
|
||||
psig = Scalar.from_bytes_checked(bytes.fromhex(psig_str))
|
||||
pks = [GE.from_bytes_xonly(b) for b in parse_hex_list(pks_str)]
|
||||
msgs = parse_hex_list(msgs_str)
|
||||
pubnonces = [parse_pubnonce(b) for b in parse_hex_list(pubnonces_str)]
|
||||
result = PartialSigVerify(psig, pks, msgs, pubnonces, signer_index)
|
||||
except ValueError:
|
||||
result = False
|
||||
|
||||
if result != expected:
|
||||
failures.append(f"PartialSigVerify #{index}: {comment}")
|
||||
|
||||
return failures
|
||||
|
||||
|
||||
def run_verify_tests() -> List[str]:
|
||||
failures = []
|
||||
|
||||
with open(VERIFY_VECTORS, newline="", encoding="utf-8") as f:
|
||||
reader = csv.reader(f)
|
||||
next(reader)
|
||||
|
||||
for row in reader:
|
||||
index, pks_str, msgs_str, sig_str, expected_result, comment = row
|
||||
expected = (expected_result == "TRUE")
|
||||
|
||||
try:
|
||||
pks = [GE.from_bytes_xonly(b) for b in parse_hex_list(pks_str)]
|
||||
msgs = parse_hex_list(msgs_str)
|
||||
R, s = parse_sig(bytes.fromhex(sig_str))
|
||||
result = Verify(pks, msgs, (R, s))
|
||||
except ValueError:
|
||||
result = False
|
||||
|
||||
if result != expected:
|
||||
failures.append(f"Verify #{index}: {comment}")
|
||||
|
||||
return failures
|
||||
|
||||
|
||||
def run_tweak_tests() -> List[str]:
|
||||
failures = []
|
||||
|
||||
with open(TWEAK_VECTORS, newline="", encoding="utf-8") as f:
|
||||
reader = csv.reader(f)
|
||||
next(reader)
|
||||
|
||||
for row in reader:
|
||||
(index, sk_str, t_str, is_xonly_str, expected_result,
|
||||
exp_sk_str, exp_pk_str, comment) = row
|
||||
sk = Scalar.from_bytes_checked(bytes.fromhex(sk_str))
|
||||
is_xonly = (is_xonly_str == "TRUE")
|
||||
expected = (expected_result == "TRUE")
|
||||
|
||||
results = []
|
||||
for tweak_fn, key in ((TweakSK, sk), (TweakPK, sk * G)):
|
||||
try:
|
||||
t = Scalar.from_bytes_checked(bytes.fromhex(t_str))
|
||||
results.append(tweak_fn(key, t, is_xonly))
|
||||
except ValueError:
|
||||
results.append(None)
|
||||
sk_out, pk_out = results
|
||||
|
||||
if expected:
|
||||
ok = (sk_out is not None and pk_out is not None
|
||||
and sk_out.to_bytes().hex().upper() == exp_sk_str
|
||||
and pk_out.to_bytes_compressed().hex().upper() == exp_pk_str)
|
||||
else:
|
||||
ok = sk_out is None and pk_out is None
|
||||
if not ok:
|
||||
failures.append(f"Tweak #{index}: {comment}")
|
||||
|
||||
return failures
|
||||
|
||||
|
||||
def main():
|
||||
for filename in [NONCE_GEN_VECTORS, NONCE_AGG_VECTORS, SIGN_VECTORS, SIGN_ERROR_VECTORS,
|
||||
VERIFY_VECTORS, PARTIAL_SIG_VERIFY_VECTORS, TWEAK_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_nonce_gen_tests())
|
||||
failures.extend(run_nonce_agg_tests())
|
||||
failures.extend(run_sign_tests())
|
||||
failures.extend(run_sign_error_tests())
|
||||
failures.extend(run_partial_sig_verify_tests())
|
||||
failures.extend(run_verify_tests())
|
||||
failures.extend(run_tweak_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,8 @@
|
||||
index,pubnonces,expected_result,expected_aggnonce,comment
|
||||
0,024D4B6CD1361032CA9BD2AEB9D900AA4D45D9EAD80AC9423374C451A7254D076602531FE6068134503D2723133227C867AC8FA6C83C537E9A44C3C5BDBDCB1FE337;0362C0A046DACCE86DDD0343C6D3C7C79C2208BA0D9C9CF24A6D046D21D21F90F703F006A18D5653C4EDF5391FF23A61F03FF83D237E880EE61187FA9F379A028E0A,TRUE,02989C0B76CB563971FDC9BEF31EC06C3560F3249D6EE9E5D83C57625596E05F6F0256B328B30C8BF5839E24058747879408BDB36241DC9C2E7C619FAA12B2920967,Two signers
|
||||
1,024D4B6CD1361032CA9BD2AEB9D900AA4D45D9EAD80AC9423374C451A7254D076602531FE6068134503D2723133227C867AC8FA6C83C537E9A44C3C5BDBDCB1FE337;0362C0A046DACCE86DDD0343C6D3C7C79C2208BA0D9C9CF24A6D046D21D21F90F703F006A18D5653C4EDF5391FF23A61F03FF83D237E880EE61187FA9F379A028E0A;03F991F944D1E1954A7FC8B9BF62E0D78F015F4C07762D505E20E6C45260A3661B0256B328B30C8BF5839E24058747879408BDB36241DC9C2E7C619FAA12B2920967,TRUE,021A7A569E91DBF60581509C7FC946D1003B60C7DEE85299538DB6353538D59574036360E856310CE5D294E8BE33FC807077DC56AC80D95D9CD4DDBD21325EFF73F7,Three signers
|
||||
2,024D4B6CD1361032CA9BD2AEB9D900AA4D45D9EAD80AC9423374C451A7254D076602531FE6068134503D2723133227C867AC8FA6C83C537E9A44C3C5BDBDCB1FE337;0462C0A046DACCE86DDD0343C6D3C7C79C2208BA0D9C9CF24A6D046D21D21F90F703F006A18D5653C4EDF5391FF23A61F03FF83D237E880EE61187FA9F379A028E0A,FALSE,,Signer 1's pubnonce first half has prefix 0x04
|
||||
3,024D4B6CD1361032CA9BD2AEB9D900AA4D45D9EAD80AC9423374C451A7254D0766020000000000000000000000000000000000000000000000000000000000000000;0362C0A046DACCE86DDD0343C6D3C7C79C2208BA0D9C9CF24A6D046D21D21F90F703F006A18D5653C4EDF5391FF23A61F03FF83D237E880EE61187FA9F379A028E0A,FALSE,,Signer 0's pubnonce second half is not on the curve
|
||||
4,024D4B6CD1361032CA9BD2AEB9D900AA4D45D9EAD80AC9423374C451A7254D076602FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC30;0362C0A046DACCE86DDD0343C6D3C7C79C2208BA0D9C9CF24A6D046D21D21F90F703F006A18D5653C4EDF5391FF23A61F03FF83D237E880EE61187FA9F379A028E0A,FALSE,,Signer 0's pubnonce second half exceeds field size
|
||||
5,024D4B6CD1361032CA9BD2AEB9D900AA4D45D9EAD80AC9423374C451A7254D076602531FE6068134503D2723133227C867AC8FA6C83C537E9A44C3C5BDBDCB1FE337;034D4B6CD1361032CA9BD2AEB9D900AA4D45D9EAD80AC9423374C451A7254D076603F006A18D5653C4EDF5391FF23A61F03FF83D237E880EE61187FA9F379A028E0A,FALSE,,Aggregate nonce R1 is infinity
|
||||
6,024D4B6CD1361032CA9BD2AEB9D900AA4D45D9EAD80AC9423374C451A7254D076602531FE6068134503D2723133227C867AC8FA6C83C537E9A44C3C5BDBDCB1FE337;0362C0A046DACCE86DDD0343C6D3C7C79C2208BA0D9C9CF24A6D046D21D21F90F703531FE6068134503D2723133227C867AC8FA6C83C537E9A44C3C5BDBDCB1FE337,FALSE,,Aggregate nonce R2 is infinity
|
||||
|
@@ -0,0 +1,5 @@
|
||||
index,rand_,secret_key,extra_in,expected_secnonce,expected_pubnonce,comment
|
||||
0,0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F,0202020202020202020202020202020202020202020202020202020202020202,0808080808080808080808080808080808080808080808080808080808080808,496C8F2EBAEAB2FD7189A9F217BE77ABA036B87CD947EDEFA001CF8D0BF452D55CB6CF68A9A528BBCB71DB15B150806ABB7E92E724FCEE78AEB5B9024EB34CE4,031E006EEDAE3D3820BE8C8EFCD4CE67715EE9B2AB2218CD6330AA1F025AB79FA803538EF9EDCC35E77A69C7C4720D3E6BE495CBA5E3D8ADAFAE7E0F5FFCABC6AC8A,Secret key and extra_in
|
||||
1,0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F,0202020202020202020202020202020202020202020202020202020202020202,,94EB69603F7D12C1C511F187C8AC92B4DC61ED8E76CF42ACEFD9904C1720F46F7249D0E01A33C71BA9E14AE1CBC749C103A16D3E5DD7B172B4397E5E16180866,02E1DB4796E1D36F6CDD734CCAECB9D35530BAA46CBB0C33EBB689E6B5E6550B9F033FEC0D4E18F85C00F484DE0CFD867ED0F4258227F8739DC0F6033C920E8EDC48,Secret key and no extra_in
|
||||
2,0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F,,0808080808080808080808080808080808080808080808080808080808080808,78BA95FD557F793BD321CC690E0C695E72B330201BFACC489CF0D42485C850AE2A5C817B42B11ADF4B96B2C94BCEBD9072426A2AC632C9B7BDF810CE5283A556,03C1829FEABAADD69DC5EEAE3778AF61AF82B56AE8D7F1CA980D95DAA6677FD75F038E523C53F4FDBF0F4AB9D0FBD615DE191D7ABD764B03355DCE7331D1F39A9E94,No secret key and extra_in
|
||||
3,0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F,,,01E41FFC41183A6C0CC981D66F98CB0E460AC059F4F2B9AFA5EA9FA34636098B090315C8AFB605FFB1791365F90B8602E79D4E0D32FD6916F61A7F82ECA20132,027E7AAC81E61DF4F2BAEA16F5544592D2E556B7BFB034B7811064E3DAC46883F70382EDACAD18AF9ADF8395B4F3D1198F3FD5A7E9365177000D4769B92F6ECFFBEA,No secret key and no extra_in
|
||||
|
@@ -0,0 +1,10 @@
|
||||
index,signer_index,psig,pubkeys,messages,pubnonces,expected_result,comment
|
||||
0,0,AC7EA4711D03C9C5F0D0CDD761B81FC27D18187655A75D37E4EE8879545756AA,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F;462779AD4AAD39514614751A71085F2F10E1C7A593E4E030EFB5B8721CE55B0B,8080808080808080808080808080808080808080808080808080808080808080;8181818181818181818181818181818181818181818181818181818181818181,024D4B6CD1361032CA9BD2AEB9D900AA4D45D9EAD80AC9423374C451A7254D076602531FE6068134503D2723133227C867AC8FA6C83C537E9A44C3C5BDBDCB1FE337;0362C0A046DACCE86DDD0343C6D3C7C79C2208BA0D9C9CF24A6D046D21D21F90F703F006A18D5653C4EDF5391FF23A61F03FF83D237E880EE61187FA9F379A028E0A,TRUE,Honest partial sig (signer 0)
|
||||
1,1,B83BBCAA5F0D6E0DEBEE0000E41B21D2E9304D0387660F96D3664735B0B954A3,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F;462779AD4AAD39514614751A71085F2F10E1C7A593E4E030EFB5B8721CE55B0B,8080808080808080808080808080808080808080808080808080808080808080;8181818181818181818181818181818181818181818181818181818181818181,024D4B6CD1361032CA9BD2AEB9D900AA4D45D9EAD80AC9423374C451A7254D076602531FE6068134503D2723133227C867AC8FA6C83C537E9A44C3C5BDBDCB1FE337;0362C0A046DACCE86DDD0343C6D3C7C79C2208BA0D9C9CF24A6D046D21D21F90F703F006A18D5653C4EDF5391FF23A61F03FF83D237E880EE61187FA9F379A028E0A,TRUE,Honest partial sig (signer 1)
|
||||
2,1,AC7EA4711D03C9C5F0D0CDD761B81FC27D18187655A75D37E4EE8879545756AA,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F;462779AD4AAD39514614751A71085F2F10E1C7A593E4E030EFB5B8721CE55B0B,8080808080808080808080808080808080808080808080808080808080808080;8181818181818181818181818181818181818181818181818181818181818181,024D4B6CD1361032CA9BD2AEB9D900AA4D45D9EAD80AC9423374C451A7254D076602531FE6068134503D2723133227C867AC8FA6C83C537E9A44C3C5BDBDCB1FE337;0362C0A046DACCE86DDD0343C6D3C7C79C2208BA0D9C9CF24A6D046D21D21F90F703F006A18D5653C4EDF5391FF23A61F03FF83D237E880EE61187FA9F379A028E0A,FALSE,Honest psig verified at the wrong signer_index
|
||||
3,0,AC7EA4711D03C9C5F0D0CDD761B81FC27D18187655A75D37E4EE8879545756AB,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F;462779AD4AAD39514614751A71085F2F10E1C7A593E4E030EFB5B8721CE55B0B,8080808080808080808080808080808080808080808080808080808080808080;8181818181818181818181818181818181818181818181818181818181818181,024D4B6CD1361032CA9BD2AEB9D900AA4D45D9EAD80AC9423374C451A7254D076602531FE6068134503D2723133227C867AC8FA6C83C537E9A44C3C5BDBDCB1FE337;0362C0A046DACCE86DDD0343C6D3C7C79C2208BA0D9C9CF24A6D046D21D21F90F703F006A18D5653C4EDF5391FF23A61F03FF83D237E880EE61187FA9F379A028E0A,FALSE,Tampered partial sig (bit flip)
|
||||
4,0,0000000000000000000000000000000000000000000000000000000000000000,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F;462779AD4AAD39514614751A71085F2F10E1C7A593E4E030EFB5B8721CE55B0B,8080808080808080808080808080808080808080808080808080808080808080;8181818181818181818181818181818181818181818181818181818181818181,024D4B6CD1361032CA9BD2AEB9D900AA4D45D9EAD80AC9423374C451A7254D076602531FE6068134503D2723133227C867AC8FA6C83C537E9A44C3C5BDBDCB1FE337;0362C0A046DACCE86DDD0343C6D3C7C79C2208BA0D9C9CF24A6D046D21D21F90F703F006A18D5653C4EDF5391FF23A61F03FF83D237E880EE61187FA9F379A028E0A,FALSE,"psig = 0 (in range, wrong)"
|
||||
5,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F;462779AD4AAD39514614751A71085F2F10E1C7A593E4E030EFB5B8721CE55B0B,8080808080808080808080808080808080808080808080808080808080808080;8181818181818181818181818181818181818181818181818181818181818181,024D4B6CD1361032CA9BD2AEB9D900AA4D45D9EAD80AC9423374C451A7254D076602531FE6068134503D2723133227C867AC8FA6C83C537E9A44C3C5BDBDCB1FE337;0362C0A046DACCE86DDD0343C6D3C7C79C2208BA0D9C9CF24A6D046D21D21F90F703F006A18D5653C4EDF5391FF23A61F03FF83D237E880EE61187FA9F379A028E0A,FALSE,psig = n (out of range)
|
||||
6,2,AC7EA4711D03C9C5F0D0CDD761B81FC27D18187655A75D37E4EE8879545756AA,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F;462779AD4AAD39514614751A71085F2F10E1C7A593E4E030EFB5B8721CE55B0B,8080808080808080808080808080808080808080808080808080808080808080;8181818181818181818181818181818181818181818181818181818181818181,024D4B6CD1361032CA9BD2AEB9D900AA4D45D9EAD80AC9423374C451A7254D076602531FE6068134503D2723133227C867AC8FA6C83C537E9A44C3C5BDBDCB1FE337;0362C0A046DACCE86DDD0343C6D3C7C79C2208BA0D9C9CF24A6D046D21D21F90F703F006A18D5653C4EDF5391FF23A61F03FF83D237E880EE61187FA9F379A028E0A,FALSE,signer_index out of range
|
||||
7,0,2873FA643DD95EDDDCE81DE64A0C7A8C8166E11E5C687261AAC94F9044EBC9E6,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F;462779AD4AAD39514614751A71085F2F10E1C7A593E4E030EFB5B8721CE55B0B,8080808080808080808080808080808080808080808080808080808080808080;8181818181818181818181818181818181818181818181818181818181818181,024D4B6CD1361032CA9BD2AEB9D900AA4D45D9EAD80AC9423374C451A7254D076602531FE6068134503D2723133227C867AC8FA6C83C537E9A44C3C5BDBDCB1FE337;0362C0A046DACCE86DDD0343C6D3C7C79C2208BA0D9C9CF24A6D046D21D21F90F703F006A18D5653C4EDF5391FF23A61F03FF83D237E880EE61187FA9F379A028E0A,FALSE,psig for a different aggregate nonce
|
||||
8,0,AC7EA4711D03C9C5F0D0CDD761B81FC27D18187655A75D37E4EE8879545756AA,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F;462779AD4AAD39514614751A71085F2F10E1C7A593E4E030EFB5B8721CE55B0B,8080808080808080808080808080808080808080808080808080808080808080;8181818181818181818181818181818181818181818181818181818181818181,024D4B6CD1361032CA9BD2AEB9D900AA4D45D9EAD80AC9423374C451A7254D076602531FE6068134503D2723133227C867AC8FA6C83C537E9A44C3C5BDBDCB1FE337;034D4B6CD1361032CA9BD2AEB9D900AA4D45D9EAD80AC9423374C451A7254D076603F006A18D5653C4EDF5391FF23A61F03FF83D237E880EE61187FA9F379A028E0A,FALSE,Aggregate nonce R1 is infinity
|
||||
|
@@ -0,0 +1,8 @@
|
||||
index,secret_keys,messages,secnonces,expected_aggnonce,expected_partial_sigs,expected_sig,comment
|
||||
0,FEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFDB9ADDBE5AE479F3ABED15D8BCF354040,8080808080808080808080808080808080808080808080808080808080808080,02020202020202020202020202020202020202020202020202020202020202020303030303030303030303030303030303030303030303030303030303030303,024D4B6CD1361032CA9BD2AEB9D900AA4D45D9EAD80AC9423374C451A7254D076602531FE6068134503D2723133227C867AC8FA6C83C537E9A44C3C5BDBDCB1FE337,52127919CC414D892F6FD0FE262E3811F188A02C14867A7A1D4B69BCC771FC61,C8F3414CAF7ED655F450E7AA8B0164FFA38882DAD001CED9E82AFA11806DFD3B52127919CC414D892F6FD0FE262E3811F188A02C14867A7A1D4B69BCC771FC61,Single signer
|
||||
1,FEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFDB9ADDBE5AE479F3ABED15D8BCF354040;FBFBFBFBFBFBFBFBFBFBFBFBFBFBFBFAB6AAD8E2AB449C37BBCE5A88CC323D3D,8080808080808080808080808080808080808080808080808080808080808080;8181818181818181818181818181818181818181818181818181818181818181,02020202020202020202020202020202020202020202020202020202020202020303030303030303030303030303030303030303030303030303030303030303;05050505050505050505050505050505050505050505050505050505050505050606060606060606060606060606060606060606060606060606060606060606,02989C0B76CB563971FDC9BEF31EC06C3560F3249D6EE9E5D83C57625596E05F6F0256B328B30C8BF5839E24058747879408BDB36241DC9C2E7C619FAA12B2920967,AC7EA4711D03C9C5F0D0CDD761B81FC27D18187655A75D37E4EE8879545756AA;B83BBCAA5F0D6E0DEBEE0000E41B21D2E9304D0387660F96D3664735B0B954A3,5485290A0E23A1912901F3CD0F2F8884CF8528B089F86ACFE5184670ECB8F06D64BA611B7C1137D3DCBECDD845D34196AB9988932DC4CC92F882712234DA6A0C,Two signers
|
||||
2,FEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFDB9ADDBE5AE479F3ABED15D8BCF354040;FBFBFBFBFBFBFBFBFBFBFBFBFBFBFBFAB6AAD8E2AB449C37BBCE5A88CC323D3D;0707070707070707070707070707070707070707070707070707070707070707,8080808080808080808080808080808080808080808080808080808080808080;8181818181818181818181818181818181818181818181818181818181818181;8282828282828282828282828282828282828282828282828282828282828282,02020202020202020202020202020202020202020202020202020202020202020303030303030303030303030303030303030303030303030303030303030303;05050505050505050505050505050505050505050505050505050505050505050606060606060606060606060606060606060606060606060606060606060606;08080808080808080808080808080808080808080808080808080808080808080909090909090909090909090909090909090909090909090909090909090909,021A7A569E91DBF60581509C7FC946D1003B60C7DEE85299538DB6353538D59574036360E856310CE5D294E8BE33FC807077DC56AC80D95D9CD4DDBD21325EFF73F7,9567B1D92D32A863462A5373E775095C64F36F6546CDE60A972550EC9D27E963;3780F8549BB5C8704A3A75F3B6A9E93EF3D844B80C3F8BC730F0658B4F729B08;E42ABB02908EEB24A91CB5530551A45D9501026E16EEDBC1B15FB38088030F54,2F02469D98943B63C85904CA5F34AD0525B650A79B55D4C5730FBE1AAC7C004FB113653059775BF839817EBAA37096FA331DD9A4BAB3AD57B9A30B6BA467527E,Three signers
|
||||
3,FEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFDB9ADDBE5AE479F3ABED15D8BCF354040;FBFBFBFBFBFBFBFBFBFBFBFBFBFBFBFAB6AAD8E2AB449C37BBCE5A88CC323D3D;0707070707070707070707070707070707070707070707070707070707070707;F5F5F5F5F5F5F5F5F5F5F5F5F5F5F5F4B0A4D2DCA53E9631B5C85482C62C3737;0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D,8080808080808080808080808080808080808080808080808080808080808080;8181818181818181818181818181818181818181818181818181818181818181;8282828282828282828282828282828282828282828282828282828282828282;8383838383838383838383838383838383838383838383838383838383838383;8484848484848484848484848484848484848484848484848484848484848484,02020202020202020202020202020202020202020202020202020202020202020303030303030303030303030303030303030303030303030303030303030303;05050505050505050505050505050505050505050505050505050505050505050606060606060606060606060606060606060606060606060606060606060606;08080808080808080808080808080808080808080808080808080808080808080909090909090909090909090909090909090909090909090909090909090909;0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C;0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F,02BA72A6E8BA53E8B971AD0C9823968AEF4D78CE8AF255AB43DFF83003C902FB8D03948B53DA97FDF674C0877315ACBCC8761AA3B9A582B439982FBAFAC99F97210F,40BD244B3077B384CC4FB475EA4B75F00534F8C8AC9495DF5D501AB8EBEFE95C;7413D7A5D78AF26516FE5CD9D7D769DA04B4934162CF212761F8C6BF145F33A6;EC4BA1816B30306CE38A02FFE0D742DB131069DFF013C1CCC95DEC12816E0FAE;1A3D61F95D6C6FC23871AA5795E0F7DC8B2C4AB7A70D7AFAA7D3C51FB0F646E2;CBEF31FEF7E60491D7E986CF11E8F6739FD215A8098BAD81E03F29ADDAFA9DAD,8E1F9F4D2716EBA94D4DCA8A484F08B121EC7CB56331C056E7CA68955AB55D018749316AC8854AAAD73345764AC410F7D29A9C7C517F60D89114FF3E6D418EBD,Five signers
|
||||
4,FEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFDB9ADDBE5AE479F3ABED15D8BCF354040;FEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFDB9ADDBE5AE479F3ABED15D8BCF354040,A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0;A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1,0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C;0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E,0329CE758BB2D21DEF214CEA069ADDBD16896EC77924BF0EC9219E00DCF077605E02DCEC806DEB8DA0774EC5A5D0F5097FFDE1F70A9F40D44363BD3DC2DC2590CA5D,F9E5D159B41C9BAC7B61B034E88DE52F6E5035700312ACCCAC9518B123F172E8;F1EC4EB02363C0A81FF82BD9500A990BFA59E3AE38102D59FF41B1C451B67D4E,6EF86E78B8043F5F2683D1A4018F57527D1992B2A8090770ECD375B45310FEE4EBD22009D7805C549B59DC0E38987E3CADFB3C378BDA39EAEC046BE8A571AEF5,Same pubkey signs two different messages
|
||||
5,2020202020202020202020202020202020202020202020202020202020202020;1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E,8080808080808080808080808080808080808080808080808080808080808080;8181818181818181818181818181818181818181818181818181818181818181,02020202020202020202020202020202020202020202020202020202020202020303030303030303030303030303030303030303030303030303030303030303;05050505050505050505050505050505050505050505050505050505050505050606060606060606060606060606060606060606060606060606060606060606,02989C0B76CB563971FDC9BEF31EC06C3560F3249D6EE9E5D83C57625596E05F6F0256B328B30C8BF5839E24058747879408BDB36241DC9C2E7C619FAA12B2920967,20DCE3CE1C51AE4F82A282B06989EC59206BC6E5EE42507FC7E4A49118182977;1D1F36CADF491EA12E121FA6520BCE32B2BAFE31AEFD0E840B1725A10F9FE76B,C01306054091CC81F54D5A49DD591706CB36BF621C984E9F7FEBA26E0C544E553DFC1A98FB9ACCF0B0B4A256BB95BA8BD326C5179D3F5F03D2FBCA3227B810E2,Signers with tweaked keys
|
||||
6,FEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFDB9ADDBE5AE479F3ABED15D8BCF354040;FEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFDB9ADDBE5AE479F3ABED15D8BCF354040,C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0;C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0,14141414141414141414141414141414141414141414141414141414141414141515151515151515151515151515151515151515151515151515151515151515;16161616161616161616161616161616161616161616161616161616161616161717171717171717171717171717171717171717171717171717171717171717,035BE5E9478209674A96E60F1F037F6176540FD001FA1D64694770C56A7709C42C028F5304E2373E56EE7D774CB89E9F1AFECF0EE7E3E3757F189908F069DAA36C60,1AF1A3721CA970F3A158EB32176A71B69C8886AF98C7EF9F50E14D8E11B1A2A9;C0B6BBB2725E30F338DB5C032959AE8D766B0E8389077A4F217DF88FB190260C,9669004E9B03D7C34670914CD09024A65DAA635497C42BE33F21C56CD740BBDEDBA85F248F07A1E6DA34473540C4204412F3953321CF69EE725F461DC341C8B5,"Exact duplicate (pk, m) entries"
|
||||
|
@@ -0,0 +1,10 @@
|
||||
index,secret_key,message,secnonce,aggnonce,pubkeys,messages,pubnonces,comment
|
||||
0,FEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFDB9ADDBE5AE479F3ABED15D8BCF354040,8080808080808080808080808080808080808080808080808080808080808080,02020202020202020202020202020202020202020202020202020202020202020303030303030303030303030303030303030303030303030303030303030303,021A7A569E91DBF60581509C7FC946D1003B60C7DEE85299538DB6353538D59574030F0FB9A244AD31A369EE02B7ABFBBB0BFA3812B9A39ED93346D03D67D412D177,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F;462779AD4AAD39514614751A71085F2F10E1C7A593E4E030EFB5B8721CE55B0B;989C0B76CB563971FDC9BEF31EC06C3560F3249D6EE9E5D83C57625596E05F6F,8080808080808080808080808080808080808080808080808080808080808080;8181818181818181818181818181818181818181818181818181818181818181;8282828282828282828282828282828282828282828282828282828282828282,024D4B6CD1361032CA9BD2AEB9D900AA4D45D9EAD80AC9423374C451A7254D076602531FE6068134503D2723133227C867AC8FA6C83C537E9A44C3C5BDBDCB1FE337;0362C0A046DACCE86DDD0343C6D3C7C79C2208BA0D9C9CF24A6D046D21D21F90F703F006A18D5653C4EDF5391FF23A61F03FF83D237E880EE61187FA9F379A028E0A;03F991F944D1E1954A7FC8B9BF62E0D78F015F4C07762D505E20E6C45260A3661B02531FE6068134503D2723133227C867AC8FA6C83C537E9A44C3C5BDBDCB1FE337,Signer's R2 appears at two indices
|
||||
1,FEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFDB9ADDBE5AE479F3ABED15D8BCF354040,8080808080808080808080808080808080808080808080808080808080808080,02020202020202020202020202020202020202020202020202020202020202020303030303030303030303030303030303030303030303030303030303030303,021A7A569E91DBF60581509C7FC946D1003B60C7DEE85299538DB6353538D5957403B83130DE0D1386592FE7B9F407F5F1AE8F1DB91D772E484B3D81DF0FA2E88F24,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F;462779AD4AAD39514614751A71085F2F10E1C7A593E4E030EFB5B8721CE55B0B;989C0B76CB563971FDC9BEF31EC06C3560F3249D6EE9E5D83C57625596E05F6F,8080808080808080808080808080808080808080808080808080808080808080;8181818181818181818181818181818181818181818181818181818181818181;8282828282828282828282828282828282828282828282828282828282828282,024D4B6CD1361032CA9BD2AEB9D900AA4D45D9EAD80AC9423374C451A7254D0766031195A8046DCBB8E17034BCA630065E7A0982E4E36F6F7E5A8D4554E4846FCD99;0362C0A046DACCE86DDD0343C6D3C7C79C2208BA0D9C9CF24A6D046D21D21F90F703F006A18D5653C4EDF5391FF23A61F03FF83D237E880EE61187FA9F379A028E0A;03F991F944D1E1954A7FC8B9BF62E0D78F015F4C07762D505E20E6C45260A3661B0256B328B30C8BF5839E24058747879408BDB36241DC9C2E7C619FAA12B2920967,Signer's R2 appears at no index
|
||||
2,FEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFDB9ADDBE5AE479F3ABED15D8BCF354040,8080808080808080808080808080808080808080808080808080808080808080,02020202020202020202020202020202020202020202020202020202020202020303030303030303030303030303030303030303030303030303030303030303,021A7A569E91DBF60581509C7FC946D1003B60C7DEE85299538DB6353538D59574036360E856310CE5D294E8BE33FC807077DC56AC80D95D9CD4DDBD21325EFF73F7,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F;462779AD4AAD39514614751A71085F2F10E1C7A593E4E030EFB5B8721CE55B0B;989C0B76CB563971FDC9BEF31EC06C3560F3249D6EE9E5D83C57625596E05F6F,EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE;8181818181818181818181818181818181818181818181818181818181818181;8282828282828282828282828282828282828282828282828282828282828282,024D4B6CD1361032CA9BD2AEB9D900AA4D45D9EAD80AC9423374C451A7254D076602531FE6068134503D2723133227C867AC8FA6C83C537E9A44C3C5BDBDCB1FE337;0362C0A046DACCE86DDD0343C6D3C7C79C2208BA0D9C9CF24A6D046D21D21F90F703F006A18D5653C4EDF5391FF23A61F03FF83D237E880EE61187FA9F379A028E0A;03F991F944D1E1954A7FC8B9BF62E0D78F015F4C07762D505E20E6C45260A3661B0256B328B30C8BF5839E24058747879408BDB36241DC9C2E7C619FAA12B2920967,Message at signer's index was substituted
|
||||
3,FEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFDB9ADDBE5AE479F3ABED15D8BCF354040,8080808080808080808080808080808080808080808080808080808080808080,02020202020202020202020202020202020202020202020202020202020202020303030303030303030303030303030303030303030303030303030303030303,021A7A569E91DBF60581509C7FC946D1003B60C7DEE85299538DB6353538D59574036360E856310CE5D294E8BE33FC807077DC56AC80D95D9CD4DDBD21325EFF73F7,9AC20335EB38768D2052BE1DBBC3C8F6178407458E51E6B4AD22F1D91758895B;462779AD4AAD39514614751A71085F2F10E1C7A593E4E030EFB5B8721CE55B0B;989C0B76CB563971FDC9BEF31EC06C3560F3249D6EE9E5D83C57625596E05F6F,8080808080808080808080808080808080808080808080808080808080808080;8181818181818181818181818181818181818181818181818181818181818181;8282828282828282828282828282828282828282828282828282828282828282,024D4B6CD1361032CA9BD2AEB9D900AA4D45D9EAD80AC9423374C451A7254D076602531FE6068134503D2723133227C867AC8FA6C83C537E9A44C3C5BDBDCB1FE337;0362C0A046DACCE86DDD0343C6D3C7C79C2208BA0D9C9CF24A6D046D21D21F90F703F006A18D5653C4EDF5391FF23A61F03FF83D237E880EE61187FA9F379A028E0A;03F991F944D1E1954A7FC8B9BF62E0D78F015F4C07762D505E20E6C45260A3661B0256B328B30C8BF5839E24058747879408BDB36241DC9C2E7C619FAA12B2920967,Public key at signer's index was substituted
|
||||
4,FEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFDB9ADDBE5AE479F3ABED15D8BCF354040,8080808080808080808080808080808080808080808080808080808080808080,00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,021A7A569E91DBF60581509C7FC946D1003B60C7DEE85299538DB6353538D59574036360E856310CE5D294E8BE33FC807077DC56AC80D95D9CD4DDBD21325EFF73F7,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F;462779AD4AAD39514614751A71085F2F10E1C7A593E4E030EFB5B8721CE55B0B;989C0B76CB563971FDC9BEF31EC06C3560F3249D6EE9E5D83C57625596E05F6F,8080808080808080808080808080808080808080808080808080808080808080;8181818181818181818181818181818181818181818181818181818181818181;8282828282828282828282828282828282828282828282828282828282828282,024D4B6CD1361032CA9BD2AEB9D900AA4D45D9EAD80AC9423374C451A7254D076602531FE6068134503D2723133227C867AC8FA6C83C537E9A44C3C5BDBDCB1FE337;0362C0A046DACCE86DDD0343C6D3C7C79C2208BA0D9C9CF24A6D046D21D21F90F703F006A18D5653C4EDF5391FF23A61F03FF83D237E880EE61187FA9F379A028E0A;03F991F944D1E1954A7FC8B9BF62E0D78F015F4C07762D505E20E6C45260A3661B0256B328B30C8BF5839E24058747879408BDB36241DC9C2E7C619FAA12B2920967,Secnonce is all zeros
|
||||
5,0000000000000000000000000000000000000000000000000000000000000000,8080808080808080808080808080808080808080808080808080808080808080,02020202020202020202020202020202020202020202020202020202020202020303030303030303030303030303030303030303030303030303030303030303,021A7A569E91DBF60581509C7FC946D1003B60C7DEE85299538DB6353538D59574036360E856310CE5D294E8BE33FC807077DC56AC80D95D9CD4DDBD21325EFF73F7,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F;462779AD4AAD39514614751A71085F2F10E1C7A593E4E030EFB5B8721CE55B0B;989C0B76CB563971FDC9BEF31EC06C3560F3249D6EE9E5D83C57625596E05F6F,8080808080808080808080808080808080808080808080808080808080808080;8181818181818181818181818181818181818181818181818181818181818181;8282828282828282828282828282828282828282828282828282828282828282,024D4B6CD1361032CA9BD2AEB9D900AA4D45D9EAD80AC9423374C451A7254D076602531FE6068134503D2723133227C867AC8FA6C83C537E9A44C3C5BDBDCB1FE337;0362C0A046DACCE86DDD0343C6D3C7C79C2208BA0D9C9CF24A6D046D21D21F90F703F006A18D5653C4EDF5391FF23A61F03FF83D237E880EE61187FA9F379A028E0A;03F991F944D1E1954A7FC8B9BF62E0D78F015F4C07762D505E20E6C45260A3661B0256B328B30C8BF5839E24058747879408BDB36241DC9C2E7C619FAA12B2920967,Secret key is zero
|
||||
6,FEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFDB9ADDBE5AE479F3ABED15D8BCF354040,8080808080808080808080808080808080808080808080808080808080808080,02020202020202020202020202020202020202020202020202020202020202020303030303030303030303030303030303030303030303030303030303030303,000000000000000000000000000000000000000000000000000000000000000000036360E856310CE5D294E8BE33FC807077DC56AC80D95D9CD4DDBD21325EFF73F7,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F;462779AD4AAD39514614751A71085F2F10E1C7A593E4E030EFB5B8721CE55B0B;989C0B76CB563971FDC9BEF31EC06C3560F3249D6EE9E5D83C57625596E05F6F,8080808080808080808080808080808080808080808080808080808080808080;8181818181818181818181818181818181818181818181818181818181818181;8282828282828282828282828282828282828282828282828282828282828282,024D4B6CD1361032CA9BD2AEB9D900AA4D45D9EAD80AC9423374C451A7254D076602531FE6068134503D2723133227C867AC8FA6C83C537E9A44C3C5BDBDCB1FE337;0362C0A046DACCE86DDD0343C6D3C7C79C2208BA0D9C9CF24A6D046D21D21F90F703F006A18D5653C4EDF5391FF23A61F03FF83D237E880EE61187FA9F379A028E0A;03F991F944D1E1954A7FC8B9BF62E0D78F015F4C07762D505E20E6C45260A3661B0256B328B30C8BF5839E24058747879408BDB36241DC9C2E7C619FAA12B2920967,Aggregate nonce first half is all zeros
|
||||
7,FEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFDB9ADDBE5AE479F3ABED15D8BCF354040,8080808080808080808080808080808080808080808080808080808080808080,02020202020202020202020202020202020202020202020202020202020202020303030303030303030303030303030303030303030303030303030303030303,021A7A569E91DBF60581509C7FC946D1003B60C7DEE85299538DB6353538D59574020000000000000000000000000000000000000000000000000000000000000000,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F;462779AD4AAD39514614751A71085F2F10E1C7A593E4E030EFB5B8721CE55B0B;989C0B76CB563971FDC9BEF31EC06C3560F3249D6EE9E5D83C57625596E05F6F,8080808080808080808080808080808080808080808080808080808080808080;8181818181818181818181818181818181818181818181818181818181818181;8282828282828282828282828282828282828282828282828282828282828282,024D4B6CD1361032CA9BD2AEB9D900AA4D45D9EAD80AC9423374C451A7254D076602531FE6068134503D2723133227C867AC8FA6C83C537E9A44C3C5BDBDCB1FE337;0362C0A046DACCE86DDD0343C6D3C7C79C2208BA0D9C9CF24A6D046D21D21F90F703F006A18D5653C4EDF5391FF23A61F03FF83D237E880EE61187FA9F379A028E0A;03F991F944D1E1954A7FC8B9BF62E0D78F015F4C07762D505E20E6C45260A3661B0256B328B30C8BF5839E24058747879408BDB36241DC9C2E7C619FAA12B2920967,Aggregate nonce second half is not on the curve
|
||||
8,FEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFDB9ADDBE5AE479F3ABED15D8BCF354040,8080808080808080808080808080808080808080808080808080808080808080,02020202020202020202020202020202020202020202020202020202020202020303030303030303030303030303030303030303030303030303030303030303,021A7A569E91DBF60581509C7FC946D1003B60C7DEE85299538DB6353538D5957402FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC30,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F;462779AD4AAD39514614751A71085F2F10E1C7A593E4E030EFB5B8721CE55B0B;989C0B76CB563971FDC9BEF31EC06C3560F3249D6EE9E5D83C57625596E05F6F,8080808080808080808080808080808080808080808080808080808080808080;8181818181818181818181818181818181818181818181818181818181818181;8282828282828282828282828282828282828282828282828282828282828282,024D4B6CD1361032CA9BD2AEB9D900AA4D45D9EAD80AC9423374C451A7254D076602531FE6068134503D2723133227C867AC8FA6C83C537E9A44C3C5BDBDCB1FE337;0362C0A046DACCE86DDD0343C6D3C7C79C2208BA0D9C9CF24A6D046D21D21F90F703F006A18D5653C4EDF5391FF23A61F03FF83D237E880EE61187FA9F379A028E0A;03F991F944D1E1954A7FC8B9BF62E0D78F015F4C07762D505E20E6C45260A3661B0256B328B30C8BF5839E24058747879408BDB36241DC9C2E7C619FAA12B2920967,Aggregate nonce second half exceeds field size
|
||||
|
@@ -0,0 +1,8 @@
|
||||
index,internal_secret_key,tweak,is_xonly,expected_result,expected_secret_key,expected_pubkey,comment
|
||||
0,FEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFDB9ADDBE5AE479F3ABED15D8BCF354040,0202020202020202020202020202020202020202020202020202020202020202,FALSE,TRUE,0101010101010101010101010101010101010101010101010101010101010101,031B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F,Plain tweak of an even-y key
|
||||
1,0101010101010101010101010101010101010101010101010101010101010101,0202020202020202020202020202020202020202020202020202020202020202,FALSE,TRUE,0303030303030303030303030303030303030303030303030303030303030303,02531FE6068134503D2723133227C867AC8FA6C83C537E9A44C3C5BDBDCB1FE337,Plain tweak of an odd-y key
|
||||
2,FEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFDB9ADDBE5AE479F3ABED15D8BCF354040,0202020202020202020202020202020202020202020202020202020202020202,TRUE,TRUE,0101010101010101010101010101010101010101010101010101010101010101,031B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F,X-only tweak of an even-y key
|
||||
3,0101010101010101010101010101010101010101010101010101010101010101,0202020202020202020202020202020202020202020202020202020202020202,TRUE,TRUE,0101010101010101010101010101010101010101010101010101010101010101,031B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F,X-only tweak of an odd-y key
|
||||
4,0101010101010101010101010101010101010101010101010101010101010101,FEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFDB9ADDBE5AE479F3ABED15D8BCF354040,FALSE,FALSE,,,Plain tweak resulting in the point at infinity
|
||||
5,0101010101010101010101010101010101010101010101010101010101010101,0101010101010101010101010101010101010101010101010101010101010101,TRUE,FALSE,,,X-only tweak resulting in the point at infinity
|
||||
6,FEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFDB9ADDBE5AE479F3ABED15D8BCF354040,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141,FALSE,FALSE,,,Tweak = n (out of range)
|
||||
|
@@ -0,0 +1,18 @@
|
||||
index,pubkeys,messages,sig,expected_result,comment
|
||||
0,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F;462779AD4AAD39514614751A71085F2F10E1C7A593E4E030EFB5B8721CE55B0B,8080808080808080808080808080808080808080808080808080808080808080;8181818181818181818181818181818181818181818181818181818181818181,5485290A0E23A1912901F3CD0F2F8884CF8528B089F86ACFE5184670ECB8F06D64BA611B7C1137D3DCBECDD845D34196AB9988932DC4CC92F882712234DA6A0C,TRUE,Two-signer valid aggregate
|
||||
1,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F;462779AD4AAD39514614751A71085F2F10E1C7A593E4E030EFB5B8721CE55B0B;989C0B76CB563971FDC9BEF31EC06C3560F3249D6EE9E5D83C57625596E05F6F,8080808080808080808080808080808080808080808080808080808080808080;8181818181818181818181818181818181818181818181818181818181818181;8282828282828282828282828282828282828282828282828282828282828282,2F02469D98943B63C85904CA5F34AD0525B650A79B55D4C5730FBE1AAC7C004FB113653059775BF839817EBAA37096FA331DD9A4BAB3AD57B9A30B6BA467527E,TRUE,Three-signer valid aggregate
|
||||
2,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F;462779AD4AAD39514614751A71085F2F10E1C7A593E4E030EFB5B8721CE55B0B,8080808080808080808080808080808080808080808080808080808080808080;FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF,5485290A0E23A1912901F3CD0F2F8884CF8528B089F86ACFE5184670ECB8F06D64BA611B7C1137D3DCBECDD845D34196AB9988932DC4CC92F882712234DA6A0C,FALSE,Wrong message for second signer
|
||||
3,462779AD4AAD39514614751A71085F2F10E1C7A593E4E030EFB5B8721CE55B0B;1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F,8080808080808080808080808080808080808080808080808080808080808080;8181818181818181818181818181818181818181818181818181818181818181,5485290A0E23A1912901F3CD0F2F8884CF8528B089F86ACFE5184670ECB8F06D64BA611B7C1137D3DCBECDD845D34196AB9988932DC4CC92F882712234DA6A0C,FALSE,Pubkey order swapped
|
||||
4,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F,8080808080808080808080808080808080808080808080808080808080808080,5485290A0E23A1912901F3CD0F2F8884CF8528B089F86ACFE5184670ECB8F06D64BA611B7C1137D3DCBECDD845D34196AB9988932DC4CC92F882712234DA6A0C,FALSE,Dropped second signer
|
||||
5,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F;462779AD4AAD39514614751A71085F2F10E1C7A593E4E030EFB5B8721CE55B0B,8080808080808080808080808080808080808080808080808080808080808080;8181818181818181818181818181818181818181818181818181818181818181,5485290A0E23A1912901F3CD0F2F8884CF8528B089F86ACFE5184670ECB8F06D64BA611B7C1137D3DCBECDD845D34196AB9988932DC4CC92F882712234DA6A0D,FALSE,Tampered s (bit flip)
|
||||
6,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F;462779AD4AAD39514614751A71085F2F10E1C7A593E4E030EFB5B8721CE55B0B,8080808080808080808080808080808080808080808080808080808080808080;8181818181818181818181818181818181818181818181818181818181818181,5485290A0E23A1912901F3CD0F2F8884CF8528B089F86ACFE5184670ECB8F06D0000000000000000000000000000000000000000000000000000000000000000,FALSE,"s = 0 (in range, wrong)"
|
||||
7,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F;462779AD4AAD39514614751A71085F2F10E1C7A593E4E030EFB5B8721CE55B0B,8080808080808080808080808080808080808080808080808080808080808080;8181818181818181818181818181818181818181818181818181818181818181,5485290A0E23A1912901F3CD0F2F8884CF8528B089F86ACFE5184670ECB8F06DFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141,FALSE,s = n (out of range)
|
||||
8,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F;462779AD4AAD39514614751A71085F2F10E1C7A593E4E030EFB5B8721CE55B0B,8080808080808080808080808080808080808080808080808080808080808080;8181818181818181818181818181818181818181818181818181818181818181,5485290A0E23A1912901F3CD0F2F8884CF8528B089F86ACFE5184670ECB8F06DFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF,FALSE,s = 2^256 - 1
|
||||
9,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F;462779AD4AAD39514614751A71085F2F10E1C7A593E4E030EFB5B8721CE55B0B,8080808080808080808080808080808080808080808080808080808080808080;8181818181818181818181818181818181818181818181818181818181818181,030303030303030303030303030303030303030303030303030303030303030364BA611B7C1137D3DCBECDD845D34196AB9988932DC4CC92F882712234DA6A0C,FALSE,R x-coord not on curve
|
||||
10,0303030303030303030303030303030303030303030303030303030303030303;462779AD4AAD39514614751A71085F2F10E1C7A593E4E030EFB5B8721CE55B0B,8080808080808080808080808080808080808080808080808080808080808080;8181818181818181818181818181818181818181818181818181818181818181,5485290A0E23A1912901F3CD0F2F8884CF8528B089F86ACFE5184670ECB8F06D64BA611B7C1137D3DCBECDD845D34196AB9988932DC4CC92F882712234DA6A0C,FALSE,Public key not on curve
|
||||
11,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F;462779AD4AAD39514614751A71085F2F10E1C7A593E4E030EFB5B8721CE55B0B,8080808080808080808080808080808080808080808080808080808080808080;8181818181818181818181818181818181818181818181818181818181818181,5485290A0E23A1912901F3CD0F2F8884CF8528B089F86ACFE5184670ECB8F06D64BA611B7C1137D3DCBECDD845D34196AB9988932DC4CC92F882712234DA6A,FALSE,Signature too short
|
||||
12,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F;462779AD4AAD39514614751A71085F2F10E1C7A593E4E030EFB5B8721CE55B0B,8080808080808080808080808080808080808080808080808080808080808080;8181818181818181818181818181818181818181818181818181818181818181,5485290A0E23A1912901F3CD0F2F8884CF8528B089F86ACFE5184670ECB8F06D64BA611B7C1137D3DCBECDD845D34196AB9988932DC4CC92F882712234DA6A0C00,FALSE,Signature too long
|
||||
13,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F;462779AD4AAD39514614751A71085F2F10E1C7A593E4E030EFB5B8721CE55B0B,8080808080808080808080808080808080808080808080808080808080808080,5485290A0E23A1912901F3CD0F2F8884CF8528B089F86ACFE5184670ECB8F06D64BA611B7C1137D3DCBECDD845D34196AB9988932DC4CC92F882712234DA6A0C,FALSE,Pubkey/message count mismatch
|
||||
14,,,5485290A0E23A1912901F3CD0F2F8884CF8528B089F86ACFE5184670ECB8F06D64BA611B7C1137D3DCBECDD845D34196AB9988932DC4CC92F882712234DA6A0C,FALSE,Empty signer list
|
||||
15,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F;462779AD4AAD39514614751A71085F2F10E1C7A593E4E030EFB5B8721CE55B0B,80808080808080808080808080808080808080808080808080808080808080;8181818181818181818181818181818181818181818181818181818181818181,9FBE8AD98EB962605C09D4541BF3EA4F95323236E3D729824E946376160F703175198F905A3DA7CDF8B558F83DBE9D0BB43BA9BD4072DDEB4204ED49C48DBA2E,FALSE,Message too short
|
||||
16,1B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F;462779AD4AAD39514614751A71085F2F10E1C7A593E4E030EFB5B8721CE55B0B,808080808080808080808080808080808080808080808080808080808080808000;8181818181818181818181818181818181818181818181818181818181818181,9FBE8AD98EB962605C09D4541BF3EA4F95323236E3D729824E946376160F70315EFE5CFEF5DE1A0B3B0A26CD6C5C4BC088A703C78AD72ADFB9E8F619122CAA77,FALSE,Message too long
|
||||
|
Reference in new issue
Block a user