python – non-mandatory-script-verify-flag (Invalid Schnorr signature) when I attempt to ship a P2TR tx on testnet

on

|

views

and

comments


I am studying to create tx from scratch with a purpose to perceive higher how bitcoin tx works and the way they’re structured. I learnt to create tx with legacy handle, segwit v0 and I’m now studying taproot tx.

I learn BIP340, BIP341, BIP342, BIP86 and BIP350.

And so I did the next:

  1. Create a random privkey1 (to obtain from a faucet some tBTC).
  2. Derive the bech32m addr1 from privkey1 and ship some tBTC.
  3. Create one other random privkey2.
  4. Derive the bech32m addr2 from privkey2.

Now I wish to create a tx spending tBTC from addr1 to addr2 (P2TR).

And so I did:

  1. Create the unsigned tx
  2. Create the sighash msg (with SIGHASH_ALL 0x00)
  3. Signal it with schnorr signature
  4. Assemble witness area
  5. Assemble full signed tx

So now I’ve the complete tx. However when I attempt to ship it to the community, it says “non-mandatory-script-verify-flag (Invalid Schnorr signature)“.

I initially thought it was an incorrect signature, however after I confirm it, it says it is a right one.

So my guess is possibly I am doing one thing improper on the sighash building.

Right here is the code I exploit:

import BIP350
import Schnorr
import ToolsUnit

# privkey1 and pubkey1 - from handle
privkey1 = 115062707324911670947436473822948305952960242165803084361225582276718195358086
pubkey1_point = Schnorr.multiply(privkey1)
pubkey1 = Schnorr.ser256_schnorr(pubkey1_point)  # bytes

# addr_from = BIP350.encode_addr_bech32m(pubkey1)
addr_from = BIP350.encode_addr_bech32m(pubkey1, "False")
# tb1pr8ja6wp3wzwzpt9ervw6jsd9nchlpsfa7k7qyrygj3g3srlpxxyqjwv8av

# privkey2 and pubkey2 - to handle
privkey2 = 75282383716026770851796771414193474962426130999119568701422782830663027711075
pubkey2_point = Schnorr.multiply(privkey2)
pubkey2 = Schnorr.ser256_schnorr(pubkey2_point)  # bytes

# addr_to= BIP350.encode_addr_bech32m(pubkey1)
addr_to = BIP350.encode_addr_bech32m(pubkey2, "False")
# tb1pkqy6q5qlhejfdcgvv47dqnt468nqzl82am5kqz374e6ddpxllxfqm6hpzj


# ----------
# I will create a tx spending from 1 inputs (P2TR) derived from addr_from and sending to addr_to
# ----------

# information for the tx that despatched me 0.00991456 BTC (taproot)
txid = "23168058d8701d5c2c738500fc7261e313511f333db1fc93f74bb935b9fd7458"
txid_reverse = ToolsUnit.reverse_byte_order(txid)
vout = "00000000"  # 0
amount_received = ToolsUnit.reverse_byte_order(hex(991456)[2:].rjust(16, "0"))  # 991456 sats = 0.00991456 BTC
locking_script_input = BIP350.create_witness_locking_script(addr_from, "False")  # 512019e5dd3831709c20acb91b1da941a59e2ff0c13df5bc020c889451180fe13188
len_locking_script_input = ToolsUnit.calculate_varint(locking_script_input)


# information for the tx I wish to create
marker = "00"
flag = "01"
input_count = "01"
model = "01000000"
amount_to_send = ToolsUnit.reverse_byte_order(hex(990000)[2:].rjust(16, "0"))  # 990000 sats = 0.0099 BTC
sequence = "ffffffff"
output_count = "01"
locking_script_dest = BIP350.create_witness_locking_script(addr_to, "False")  # 5120b009a0501fbe6496e10c657cd04d75d1e6017ceaeee9600a3eae74d684dff992
len_locking_script_dest = ToolsUnit.calculate_varint(locking_script_dest)
locktime = "00000000"
sig_hash_type = "00000000"  # SIGHASH_ALL_TAPROOT 00
sig_hash_type_1bytes = "00"  # SIGHASH_ALL_TAPROOT 00


# ----------
# CONSTRUCTING SIGHASH x INPUT (taproot)
# ----------

hash_type = bytes.fromhex(sig_hash_type_1bytes)
nversion = bytes.fromhex(model)
nlocktime = bytes.fromhex(locktime)

# sha_prevouts (32) = SHA256(serialization of all enter outpoints)
sha_prevouts = Schnorr.hash_sha256(bytes.fromhex(txid_reverse + vout))

# sha_amounts (32): the SHA256 of the serialization of all spent output quantities
sha_amounts = Schnorr.hash_sha256(bytes.fromhex(amount_received))

# sha_scriptpubkeys (32): the SHA256 of all spent outputs' scriptPubKeys, serialized as script inside CTxOut
sha_scriptpubkeys = Schnorr.hash_sha256(bytes.fromhex(locking_script_input))

# sha_sequences (32): the SHA256 of the serialization of all enter nSequence.
sha_sequences = Schnorr.hash_sha256(bytes.fromhex(sequence))

# sha_outputs (32): the SHA256 of the serialization of all outputs in CTxOut format.
sha_outputs = Schnorr.hash_sha256(bytes.fromhex(amount_to_send + len_locking_script_dest + locking_script_dest))

# spend_type (1): equal to (ext_flag * 2) + annex_present, the place annex_present is 0 if no annex is current,
# or 1 in any other case (the unique witness stack has two or extra witness parts,
# and the primary byte of the final factor is 0x50)
spend_type = bytes.fromhex("00")

# input_index (4): index of this enter within the transaction enter vector. Index of the primary enter is 0
input_index = bytes.fromhex(vout)

sig_to_hash = hash_type + nversion + nlocktime + sha_prevouts + sha_amounts + sha_scriptpubkeys + sha_sequences
    + sha_outputs + spend_type + input_index

sighash = Schnorr.tagged_hash("TapSighash", sig_to_hash)


# ----------
# SIGNING
# ----------

sig = Schnorr.sign_schnorr(private_key_int=privkey1, msg_hash_bytes=sighash)


# ----------
# CONSTRUCTING WITNESS
# ----------
witness_count = "01"  # sig
r, s = sig
sig_hex = r.hex() + s.hex()
witness_sig_size = ToolsUnit.calculate_varint(sig_hex)

witness = witness_count + witness_sig_size + sig_hex

# ----------
# TX READY
# ----------

tx = model + marker + flag + input_count + txid_reverse + vout + "00" + sequence
    + output_count + amount_to_send + len_locking_script_dest + locking_script_dest
    + witness + locktime

print(tx)


For the signature a part of the code, right here is the code:

def sign_schnorr(private_key_int, msg_hash_bytes, ok=None):
    P = multiply(private_key_int)
    if not P[1] % 2 == 0:
        private_key_int = n - private_key_int

    if ok is None:
        ok = secrets and techniques.randbelow(n)

    R = multiply(ok)
    if not R[1] % 2 == 0:
        ok = n - ok

    e = int_from_bytes(tagged_hash("BIP0340/problem", ser256_schnorr(R) + ser256_schnorr(P) + msg_hash_bytes))

    sig = ser256_schnorr(R), bytes_from_int((ok + e * private_key_int) % n)
    return sig

Share this
Tags

Must-read

Waymo raises $16bn to gas international robotaxi enlargement | Know-how

Self-driving automobile firm Waymo on Monday stated it raised $16bn in a funding spherical that valued the Alphabet subsidiary at $126bn.Waymo co-chief executives...

Self-driving taxis are coming to London – ought to we be anxious? | Jack Stilgoe

At the top of the nineteenth century, the world’s main cities had an issue. The streets had been flooded with manure, the unintended...

US regulators open inquiry into Waymo self-driving automobile that struck youngster in California | Expertise

The US’s federal transportation regulator stated Thursday it had opened an investigation after a Waymo self-driving car struck a toddler close to an...

Recent articles

More like this

LEAVE A REPLY

Please enter your comment!
Please enter your name here