You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
54 lines
2.1 KiB
54 lines
2.1 KiB
# Implementation of proposal as per |
|
# https://gist.github.com/AdamISZ/2c13fb5819bd469ca318156e2cf25d79 |
|
# (BIP SNICKER) |
|
# TODO: BIP69 is removed in this implementation, will update BIP draft. |
|
|
|
from jmbitcoin.secp256k1_ecies import * |
|
from jmbitcoin.secp256k1_main import * |
|
from jmbitcoin.secp256k1_transaction import * |
|
|
|
SNICKER_MAGIC_BYTES = b'SNICKER' |
|
|
|
# Flags may be added in future versions |
|
SNICKER_FLAG_NONE = b"\x00" |
|
|
|
def snicker_pubkey_tweak(pub, tweak): |
|
""" use secp256k1 library to perform tweak. |
|
Both `pub` and `tweak` are expected as byte strings |
|
(33 and 32 bytes respectively). |
|
Return value is also a 33 byte string serialization |
|
of the resulting pubkey (compressed). |
|
""" |
|
base_pub = secp256k1.PublicKey(pub) |
|
return base_pub.add(tweak).format() |
|
|
|
def snicker_privkey_tweak(priv, tweak): |
|
""" use secp256k1 library to perform tweak. |
|
Both `priv` and `tweak` are expected as byte strings |
|
(32 or 33 and 32 bytes respectively). |
|
Return value isa 33 byte string serialization |
|
of the resulting private key/secret (with compression flag). |
|
""" |
|
if len(priv) == 33 and priv[-1] == 1: |
|
priv = priv[:-1] |
|
base_priv = secp256k1.PrivateKey(priv) |
|
return base_priv.add(tweak).secret + b'\x01' |
|
|
|
def verify_snicker_output(tx, pub, tweak, spk_type='p2sh-p2wpkh'): |
|
""" A convenience function to check that one output address in a transaction |
|
is a SNICKER-type tweak of an existing key. Returns the index of the output |
|
for which this is True (and there must be only 1), and the derived spk, |
|
or -1 and None if it is not found exactly once. |
|
TODO Add support for other scriptPubKey types. |
|
""" |
|
assert isinstance(tx, btc.CTransaction) |
|
expected_destination_pub = snicker_pubkey_tweak(pub, tweak) |
|
expected_destination_spk = pubkey_to_p2sh_p2wpkh_script(expected_destination_pub) |
|
found = 0 |
|
for i, o in enumerate(tx.vout): |
|
if o.scriptPubKey == expected_destination_spk: |
|
found += 1 |
|
found_index = i |
|
if found != 1: |
|
return -1, None |
|
return found_index, expected_destination_spk
|
|
|