mirror of
https://github.com/Such-Software/adaptive-multi-protocol-gateway.git
synced 2026-10-17 15:41:41 +02:00
93 lines
2.9 KiB
Python
93 lines
2.9 KiB
Python
from __future__ import annotations
|
|
|
|
import hashlib
|
|
|
|
|
|
SECP256K1_FIELD_SIZE = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F
|
|
SECP256K1_ORDER = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141
|
|
SECP256K1_GENERATOR = (
|
|
0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798,
|
|
0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8,
|
|
)
|
|
Point = tuple[int, int] | None
|
|
|
|
|
|
def tagged_hash(tag: str, value: bytes) -> bytes:
|
|
tag_hash = hashlib.sha256(tag.encode("utf-8")).digest()
|
|
return hashlib.sha256(tag_hash + tag_hash + value).digest()
|
|
|
|
|
|
def bip340_verify(public_key: bytes, message: bytes, signature: bytes) -> bool:
|
|
"""Verify a BIP-340 signature over the 32-byte AMPG contract digest."""
|
|
|
|
if len(public_key) != 32 or len(message) != 32 or len(signature) != 64:
|
|
return False
|
|
point = _lift_x(int.from_bytes(public_key, "big"))
|
|
if point is None:
|
|
return False
|
|
r = int.from_bytes(signature[:32], "big")
|
|
s = int.from_bytes(signature[32:], "big")
|
|
if r >= SECP256K1_FIELD_SIZE or s >= SECP256K1_ORDER:
|
|
return False
|
|
challenge = int.from_bytes(
|
|
tagged_hash("BIP0340/challenge", signature[:32] + public_key + message), "big"
|
|
) % SECP256K1_ORDER
|
|
result = point_add(
|
|
point_mul(s, SECP256K1_GENERATOR),
|
|
point_mul(SECP256K1_ORDER - challenge, point),
|
|
)
|
|
return result is not None and result[1] % 2 == 0 and result[0] == r
|
|
|
|
|
|
def _lift_x(x: int) -> Point:
|
|
if x >= SECP256K1_FIELD_SIZE:
|
|
return None
|
|
y_sq = (pow(x, 3, SECP256K1_FIELD_SIZE) + 7) % SECP256K1_FIELD_SIZE
|
|
y = pow(y_sq, (SECP256K1_FIELD_SIZE + 1) // 4, SECP256K1_FIELD_SIZE)
|
|
if pow(y, 2, SECP256K1_FIELD_SIZE) != y_sq:
|
|
return None
|
|
return x, y if y % 2 == 0 else SECP256K1_FIELD_SIZE - y
|
|
|
|
|
|
def point_add(left: Point, right: Point) -> Point:
|
|
if left is None:
|
|
return right
|
|
if right is None:
|
|
return left
|
|
x1, y1 = left
|
|
x2, y2 = right
|
|
if x1 == x2 and y1 != y2:
|
|
return None
|
|
if left == right:
|
|
if y1 == 0:
|
|
return None
|
|
slope = (
|
|
(3 * x1 * x1)
|
|
* pow(2 * y1, SECP256K1_FIELD_SIZE - 2, SECP256K1_FIELD_SIZE)
|
|
% SECP256K1_FIELD_SIZE
|
|
)
|
|
else:
|
|
slope = (
|
|
(y2 - y1)
|
|
* pow(
|
|
(x2 - x1) % SECP256K1_FIELD_SIZE,
|
|
SECP256K1_FIELD_SIZE - 2,
|
|
SECP256K1_FIELD_SIZE,
|
|
)
|
|
% SECP256K1_FIELD_SIZE
|
|
)
|
|
x3 = (slope * slope - x1 - x2) % SECP256K1_FIELD_SIZE
|
|
y3 = (slope * (x1 - x3) - y1) % SECP256K1_FIELD_SIZE
|
|
return x3, y3
|
|
|
|
|
|
def point_mul(scalar: int, point: Point) -> Point:
|
|
result: Point = None
|
|
addend = point
|
|
while scalar:
|
|
if scalar & 1:
|
|
result = point_add(result, addend)
|
|
addend = point_add(addend, addend)
|
|
scalar >>= 1
|
|
return result
|