<p>It is usualy discouraged to embed data directly on the blockchain because it is not supposed to be used like that and by doing so you can congest the network and make the blockchain grow in size for no real reason, but if you still want to do it you should be using a P2WSH ( Pay-to-Witness-Script-Hash ) you could do it with taproot too but we will be using P2WSH here.
with this transaction you would create a transaction output that can only be spent by providing a valid witness script that satisfies the spending conditions and since the condition can be arbitrary, such as requiring a specific signature it can do what you want and the witness script will also contain the file hash you want to store.</p>
<p>For your script we will modify it by removing the OP_RETURN and using a P2WSH instead:</p>
<p>edit: there was a misunderstanding in your code you try to call <code>get_address()</code> on a Script object, lets use <code>to_p2wsh_script_pub_key</code> directly on <code>witness_script</code> then we convert it to <code>hash160</code></p>
<pre class="lang-python prettyprint-override"><code>from bitcoinutils.utils import to_satoshis
from bitcoinutils.setup import setup
from bitcoinutils.transactions import Transaction, TxInput, TxOutput
from bitcoinutils.script import Script
from bitcoinutils.keys import PrivateKey as utilPrivKey
from bitcoinutils.constants import SIGHASH_ALL

setup('testnet')

# private key for the sender address
sender_priv_key = utilPrivKey.from_wif('PRIVATE KEY FOR THE SENDING ADDRESS')
sender_pub_key = sender_priv_key.get_public_key().to_hex()
addrs_for_script = sender_priv_key.get_public_key().get_address()

# private key for the receiver address
receiver_priv_key = utilPrivKey.from_wif('PRIVATE KEY FOR THE RECEIVING ADDRESS')
receiver_addr = receiver_priv_key.get_public_key().get_segwit_address()

txin1 = TxInput(&quot;a86f0187be2eca4590a456e2423a2f5286b269c3b777846092ceb2fc44270aad&quot;, 1)
txin2 = TxInput(&quot;9019818039f181ed00046d682411719050a4b2dc1d1eb6aaa2d781df863522fc&quot;, 0)

script_code = Script(['OP_DUP', 'OP_HASH160', addrs_for_script.to_hash160(), 'OP_EQUALVERIFY', 'OP_CHECKSIG'])

msg1 = &quot;69eb032167c25784108b9783c9d59ce23608d00238eb9e3c03c73cdd79f74528&quot;
witness_script = Script(['OP_IF', 'OP_SHA256', msg1, 'OP_EQUAL', 'OP_ELSE', 'OP_DUP', 'OP_HASH160', addrs_for_script.to_hash160(), 'OP_EQUALVERIFY', 'OP_CHECKSIG', 'OP_ENDIF'])
p2wsh_script_pub_key = witness_script.to_p2wsh_script_pub_key()
witness_script_hash = p2wsh_script_pub_key.to_hash160()

txoutP2WSH = TxOutput(0, Script(['OP_0', witness_script_hash]))

# 0.00005 left for transaction fee
txout = TxOutput(to_satoshis(0.00036275), receiver_addr.to_script_pub_key())

tx = Transaction([txin1, txin2], [txoutP2WSH, txout], has_segwit=True)
txsign1 = sender_priv_key.sign_segwit_input(tx, 0, script_code, to_satoshis(0.00034416), SIGHASH_ALL)
tx.witnesses = [Script([txsign1, sender_pub_key])]
txsign2 = sender_priv_key.sign_segwit_input(tx, 1, script_code, to_satoshis(0.00006859), SIGHASH_ALL)
tx.witnesses.append(Script([txsign2, sender_pub_key]))

signed_tx = tx.serialize()
print(&quot;Signed raw transaction:&quot;, signed_tx)
</code></pre>

CC BY-SA 4.0
2023-04-21T20:13:57.183Z
I get `AttributeError: 'Script' object has no attribute 'get_address'` on this line: `witness_script_hash = witness_script.to_p2wsh_script_pub_key().get_address().to_hash160()`
ChristianOConnor
CC BY-SA 4.0
2023-04-21T20:34:06.030Z
I modified my answer
Saxtheowl
CC BY-SA 4.0
2023-04-21T21:52:43.967Z
Getting closer... I got `AttributeError: 'Script' object has no attribute 'to_hash160'` on the line: `witness_script_hash = p2wsh_script_pub_key.to_hash160()`
ChristianOConnor
CC BY-SA 4.0
2023-04-22T06:14:38.590Z
I am kinda lost here, not used to this library
Saxtheowl
CC BY-SA 4.0
2023-04-21T00:03:31.890Z
2023-05-15T15:43:36.333Z
2023-05-15T15:43:36.333Z
Saxtheowl
<p>I have this python script that puts file hashes on the bitcoin blockchain:</p>
<pre class="lang-python prettyprint-override"><code>from bitcoinutils.utils import to_satoshis
from bitcoinutils.setup import setup
from bitcoinutils.transactions import Transaction, TxInput, TxOutput
from bitcoinutils.script import Script
from bitcoinutils.keys import PrivateKey as utilPrivKey
from bitcoinutils.constants import SIGHASH_ALL

setup('testnet')

# private key for tb1qpeervdxrt2np74xhm4q4jjp76ey5f9fh9tf58f
sender_priv_key = utilPrivKey.from_wif('PRIVATE KEY FOR THE SENDING ADDRESS')
sender_pub_key = sender_priv_key.get_public_key().to_hex()
addrs_for_script = sender_priv_key.get_public_key().get_address()

# private key for tb1qj57tu40e9da959w4lj9s3njwteq2z89uy7kenh
receiver_priv_key = utilPrivKey.from_wif('PRIVATE KEY FOR THE RECEIVING ADDRESS')
receiver_addr = receiver_priv_key.get_public_key().get_segwit_address()

txin1 = TxInput(&quot;a86f0187be2eca4590a456e2423a2f5286b269c3b777846092ceb2fc44270aad&quot;, 1)
txin2 = TxInput(&quot;9019818039f181ed00046d682411719050a4b2dc1d1eb6aaa2d781df863522fc&quot;, 0)

script_code = Script(['OP_DUP', 'OP_HASH160', addrs_for_script.to_hash160(), 'OP_EQUALVERIFY', 'OP_CHECKSIG'])
msg1 = &quot;69eb032167c25784108b9783c9d59ce23608d00238eb9e3c03c73cdd79f74528&quot;
op_return_script = Script([&quot;OP_RETURN&quot;, msg1])

txoutOpR = TxOutput(0, op_return_script)

# 0.00005 left for transaction fee
txout = TxOutput(to_satoshis(0.00036275), receiver_addr.to_script_pub_key())

tx = Transaction([txin1, txin2], [txoutOpR, txout], has_segwit=True)
txsign1 = sender_priv_key.sign_segwit_input(tx, 0, script_code, to_satoshis(0.00034416), SIGHASH_ALL)
tx.witnesses = [Script([txsign1, sender_pub_key])]
txsign2 = sender_priv_key.sign_segwit_input(tx, 1, script_code, to_satoshis(0.00006859), SIGHASH_ALL)
tx.witnesses.append(Script([txsign2, sender_pub_key]))

signed_tx = tx.serialize()
print(&quot;raw tx below this line&quot;)
print(signed_tx)
print(&quot;raw tx above this line&quot;)  
</code></pre>
<p>The above python script works, but I am trying to move away from OP_RETURN. Some Bitcoin devs have voiced their opinion against OP_RETURN so I'm afraid it will get deprecated.</p>
<p>Is there any way to modify my python script to store the hash in a Schnorr signature instead of an OP_RETURN? Or some other future proof way to store a file hash in a Bitcoin transaction?</p>

<python><schnorr-signatures><op-return>
How can I store a file hash in a Schnorr signature? Or something other than an OP_RETURN?
ChristianOConnor
# How can I store a file hash in a Schnorr signature? Or something other than an OP_RETURN?

(Asked by: username_0 on 2023-04-17)

I have this python script that puts file hashes on the bitcoin blockchain:

```python
from bitcoinutils.utils import to_satoshis
from bitcoinutils.setup import setup
from bitcoinutils.transactions import Transaction, TxInput, TxOutput
from bitcoinutils.script import Script
from bitcoinutils.keys import PrivateKey as utilPrivKey
from bitcoinutils.constants import SIGHASH_ALL

setup('testnet')

# private key for tb1qpeervdxrt2np74xhm4q4jjp76ey5f9fh9tf58f
sender_priv_key = utilPrivKey.from_wif('PRIVATE KEY FOR THE SENDING ADDRESS')
sender_pub_key = sender_priv_key.get_public_key().to_hex()
addrs_for_script = sender_priv_key.get_public_key().get_address()

# private key for tb1qj57tu40e9da959w4lj9s3njwteq2z89uy7kenh
receiver_priv_key = utilPrivKey.from_wif('PRIVATE KEY FOR THE RECEIVING ADDRESS')
receiver_addr = receiver_priv_key.get_public_key().get_segwit_address()

txin1 = TxInput("a86f0187be2eca4590a456e2423a2f5286b269c3b777846092ceb2fc44270aad", 1)
txin2 = TxInput("9019818039f181ed00046d682411719050a4b2dc1d1eb6aaa2d781df863522fc", 0)

script_code = Script(['OP_DUP', 'OP_HASH160', addrs_for_script.to_hash160(), 'OP_EQUALVERIFY', 'OP_CHECKSIG'])
msg1 = "69eb032167c25784108b9783c9d59ce23608d00238eb9e3c03c73cdd79f74528"
op_return_script = Script(["OP_RETURN", msg1])

txoutOpR = TxOutput(0, op_return_script)

# 0.00005 left for transaction fee
txout = TxOutput(to_satoshis(0.00036275), receiver_addr.to_script_pub_key())

tx = Transaction([txin1, txin2], [txoutOpR, txout], has_segwit=True)
txsign1 = sender_priv_key.sign_segwit_input(tx, 0, script_code, to_satoshis(0.00034416), SIGHASH_ALL)
tx.witnesses = [Script([txsign1, sender_pub_key])]
txsign2 = sender_priv_key.sign_segwit_input(tx, 1, script_code, to_satoshis(0.00006859), SIGHASH_ALL)
tx.witnesses.append(Script([txsign2, sender_pub_key]))

signed_tx = tx.serialize()
print("raw tx below this line")
print(signed_tx)
print("raw tx above this line")  

```

The above python script works, but I am trying to move away from OP\_RETURN. Some Bitcoin devs have voiced their opinion against OP\_RETURN so I'm afraid it will get deprecated.

Is there any way to modify my python script to store the hash in a Schnorr signature instead of an OP\_RETURN? Or some other future proof way to store a file hash in a Bitcoin transaction?

**Tags:** python, schnorr-signatures, op-return


---

## 1 answers

### Answer by username_1 on 2023-04-21. Score: 2

It is usualy discouraged to embed data directly on the blockchain because it is not supposed to be used like that and by doing so you can congest the network and make the blockchain grow in size for no real reason, but if you still want to do it you should be using a P2WSH ( Pay-to-Witness-Script-Hash ) you could do it with taproot too but we will be using P2WSH here.
with this transaction you would create a transaction output that can only be spent by providing a valid witness script that satisfies the spending conditions and since the condition can be arbitrary, such as requiring a specific signature it can do what you want and the witness script will also contain the file hash you want to store.

For your script we will modify it by removing the OP\_RETURN and using a P2WSH instead:

edit: there was a misunderstanding in your code you try to call `get_address()` on a Script object, lets use `to_p2wsh_script_pub_key` directly on `witness_script` then we convert it to `hash160`

```python
from bitcoinutils.utils import to_satoshis
from bitcoinutils.setup import setup
from bitcoinutils.transactions import Transaction, TxInput, TxOutput
from bitcoinutils.script import Script
from bitcoinutils.keys import PrivateKey as utilPrivKey
from bitcoinutils.constants import SIGHASH_ALL

setup('testnet')

# private key for the sender address
sender_priv_key = utilPrivKey.from_wif('PRIVATE KEY FOR THE SENDING ADDRESS')
sender_pub_key = sender_priv_key.get_public_key().to_hex()
addrs_for_script = sender_priv_key.get_public_key().get_address()

# private key for the receiver address
receiver_priv_key = utilPrivKey.from_wif('PRIVATE KEY FOR THE RECEIVING ADDRESS')
receiver_addr = receiver_priv_key.get_public_key().get_segwit_address()

txin1 = TxInput("a86f0187be2eca4590a456e2423a2f5286b269c3b777846092ceb2fc44270aad", 1)
txin2 = TxInput("9019818039f181ed00046d682411719050a4b2dc1d1eb6aaa2d781df863522fc", 0)

script_code = Script(['OP_DUP', 'OP_HASH160', addrs_for_script.to_hash160(), 'OP_EQUALVERIFY', 'OP_CHECKSIG'])

msg1 = "69eb032167c25784108b9783c9d59ce23608d00238eb9e3c03c73cdd79f74528"
witness_script = Script(['OP_IF', 'OP_SHA256', msg1, 'OP_EQUAL', 'OP_ELSE', 'OP_DUP', 'OP_HASH160', addrs_for_script.to_hash160(), 'OP_EQUALVERIFY', 'OP_CHECKSIG', 'OP_ENDIF'])
p2wsh_script_pub_key = witness_script.to_p2wsh_script_pub_key()
witness_script_hash = p2wsh_script_pub_key.to_hash160()

txoutP2WSH = TxOutput(0, Script(['OP_0', witness_script_hash]))

# 0.00005 left for transaction fee
txout = TxOutput(to_satoshis(0.00036275), receiver_addr.to_script_pub_key())

tx = Transaction([txin1, txin2], [txoutP2WSH, txout], has_segwit=True)
txsign1 = sender_priv_key.sign_segwit_input(tx, 0, script_code, to_satoshis(0.00034416), SIGHASH_ALL)
tx.witnesses = [Script([txsign1, sender_pub_key])]
txsign2 = sender_priv_key.sign_segwit_input(tx, 1, script_code, to_satoshis(0.00006859), SIGHASH_ALL)
tx.witnesses.append(Script([txsign2, sender_pub_key]))

signed_tx = tx.serialize()
print("Signed raw transaction:", signed_tx)

```

> **Comments:**
> **username_0**: I get `AttributeError: 'Script' object has no attribute 'get_address'` on this line: `witness_script_hash = witness_script.to_p2wsh_script_pub_key().get_address().to_hash160()`  
> **username_1**: I modified my answer  
> **username_0**: Getting closer... I got `AttributeError: 'Script' object has no attribute 'to_hash160'` on the line: `witness_script_hash = p2wsh_script_pub_key.to_hash160()`  
> **username_1**: I am kinda lost here, not used to this library  

---

