mirror of
https://github.com/aljazceru/nutshell.git
synced 2025-12-20 10:34:20 +01:00
* produce dleq * start working on verification * wip dleq * Use C_ instead of C in verify DLEQ! (#176) * Fix comments (DLEQ sign error) * Fix alice_verify_dleq in d_dhke.py * Fix_generate_promise in ledger.py * Fix verify_proofs_dleq in wallet.py * Fix: invalid public key (#182) * Use C_ instead of C in verify DLEQ! * Fix comments (DLEQ sign error) * Fix alice_verify_dleq in d_dhke.py * Fix_generate_promise in ledger.py * Fix verify_proofs_dleq in wallet.py * Fix: invalid public key * Exception: Mint Error: invalid public key * Update cashu/wallet/wallet.py --------- Co-authored-by: calle <93376500+callebtc@users.noreply.github.com> * Update cashu/core/b_dhke.py * Update tests/test_cli.py * verify all constructed proofs * dleq upon receive * serialize without dleq * all tests passing * make format * remove print * remove debug * option to send with dleq * add tests * fix test * deterministic p in step2_dleq and fix mypy error for hash_to_curve * test crypto/hash_e and crypto/step2_bob_dleq * rename A to K in b_dhke.py and test_alice_verify_dleq * rename tests * make format * store dleq in mint db (and readd balance view) * remove `r` from dleq in tests * add pending output * make format * works with pre-dleq mints * fix comments * make format * fix some tests * fix last test * test serialize dleq fix * flake * flake * keyset.id must be str * fix test decorators * start removing the duplicate fields from the dleq * format * remove print * cleanup * add type anotations to dleq functions * remove unnecessary fields from BlindedSignature * tests not working yet * spelling mistakes * spelling mistakes * fix more spelling mistakes * revert to normal * add comments * bdhke: generalize hash_e * remove P2PKSecret changes * revert tests for P2PKSecret * revert tests * revert test fully * revert p2pksecret changes * refactor proof invalidation * store dleq proofs in wallet db * make mypy happy --------- Co-authored-by: moonsettler <moonsettler@protonmail.com>
169 lines
6.1 KiB
Python
169 lines
6.1 KiB
Python
import base64
|
|
import hashlib
|
|
import random
|
|
|
|
from bitcoin.core import CMutableTxIn, CMutableTxOut, COutPoint, CTransaction, lx
|
|
from bitcoin.core.script import OP_CHECKSIG, SIGHASH_ALL, CScript, SignatureHash
|
|
from bitcoin.core.scripteval import (
|
|
SCRIPT_VERIFY_P2SH,
|
|
EvalScriptError,
|
|
VerifyScript,
|
|
VerifyScriptError,
|
|
)
|
|
from bitcoin.wallet import CBitcoinSecret, P2SHBitcoinAddress
|
|
|
|
COIN = 100_000_000
|
|
TXID = "bff785da9f8169f49be92fa95e31f0890c385bfb1bd24d6b94d7900057c617ae"
|
|
SEED = b"__not__used"
|
|
|
|
|
|
def step0_carol_privkey():
|
|
"""Private key"""
|
|
# h = hashlib.sha256(SEED).digest()
|
|
h = hashlib.sha256(str(random.getrandbits(256)).encode()).digest()
|
|
seckey = CBitcoinSecret.from_secret_bytes(h)
|
|
return seckey
|
|
|
|
|
|
def step0_carol_checksig_redeemscript(carol_pubkey):
|
|
"""Create script"""
|
|
txin_redeemScript = CScript([carol_pubkey, OP_CHECKSIG])
|
|
# txin_redeemScript = CScript([-123, OP_CHECKLOCKTIMEVERIFY])
|
|
# txin_redeemScript = CScript([3, 3, OP_LESSTHAN, OP_VERIFY])
|
|
return txin_redeemScript
|
|
|
|
|
|
def step1_carol_create_p2sh_address(txin_redeemScript):
|
|
"""Create address (serialized scriptPubKey) to share with Alice"""
|
|
txin_p2sh_address = P2SHBitcoinAddress.from_redeemScript(txin_redeemScript)
|
|
return txin_p2sh_address
|
|
|
|
|
|
def step1_bob_carol_create_tx(txin_p2sh_address):
|
|
"""Create transaction"""
|
|
txid = lx(TXID)
|
|
vout = 0
|
|
txin = CMutableTxIn(COutPoint(txid, vout))
|
|
txout = CMutableTxOut(
|
|
int(0.0005 * COIN),
|
|
P2SHBitcoinAddress(str(txin_p2sh_address)).to_scriptPubKey(),
|
|
)
|
|
tx = CTransaction([txin], [txout])
|
|
return tx, txin
|
|
|
|
|
|
def step2_carol_sign_tx(txin_redeemScript, privatekey):
|
|
"""Sign transaction with private key"""
|
|
txin_p2sh_address = step1_carol_create_p2sh_address(txin_redeemScript)
|
|
tx, txin = step1_bob_carol_create_tx(txin_p2sh_address)
|
|
sighash = SignatureHash(txin_redeemScript, tx, 0, SIGHASH_ALL)
|
|
sig = privatekey.sign(sighash) + bytes([SIGHASH_ALL])
|
|
txin.scriptSig = CScript([sig, txin_redeemScript])
|
|
return txin
|
|
|
|
|
|
def step3_bob_verify_script(txin_signature, txin_redeemScript, tx):
|
|
txin_scriptPubKey = txin_redeemScript.to_p2sh_scriptPubKey()
|
|
try:
|
|
VerifyScript(
|
|
txin_signature, txin_scriptPubKey, tx, 0, flags=[SCRIPT_VERIFY_P2SH]
|
|
)
|
|
return True
|
|
except VerifyScriptError as e:
|
|
raise Exception("Script verification failed:", e)
|
|
except EvalScriptError as e:
|
|
print(f"Script: {txin_scriptPubKey.__repr__()}")
|
|
raise Exception("Script evaluation failed:", e)
|
|
except Exception as e:
|
|
raise Exception("Script execution failed:", e)
|
|
|
|
|
|
def verify_bitcoin_script(txin_redeemScript_b64, txin_signature_b64):
|
|
txin_redeemScript = CScript(base64.urlsafe_b64decode(txin_redeemScript_b64))
|
|
# print("Redeem script:", txin_redeemScript.__repr__())
|
|
# txin_redeemScript = CScript([2, 3, OP_LESSTHAN, OP_VERIFY])
|
|
txin_signature = CScript(value=base64.urlsafe_b64decode(txin_signature_b64))
|
|
|
|
txin_p2sh_address = step1_carol_create_p2sh_address(txin_redeemScript)
|
|
# print(f"Bob recreates secret: P2SH:{txin_p2sh_address}")
|
|
# MINT checks that P2SH:txin_p2sh_address has not been spent yet
|
|
# ...
|
|
tx, _ = step1_bob_carol_create_tx(txin_p2sh_address)
|
|
|
|
# print(
|
|
# f"Bob verifies:\nscript: {txin_redeemScript_b64}\nsignature: {txin_signature_b64}\n"
|
|
# )
|
|
script_valid = step3_bob_verify_script(txin_signature, txin_redeemScript, tx)
|
|
# MINT redeems tokens and stores P2SH:txin_p2sh_address
|
|
# ...
|
|
# if script_valid:
|
|
# print("Successfull.")
|
|
# else:
|
|
# print("Error.")
|
|
return txin_p2sh_address, script_valid
|
|
|
|
|
|
# simple test case
|
|
if __name__ == "__main__":
|
|
# https://github.com/romanz/python-bitcointx/blob/master/examples/spend-p2sh-txout.py
|
|
# CAROL shares txin_p2sh_address with ALICE:
|
|
|
|
# ---------
|
|
# CAROL defines scripthash and ALICE mints them
|
|
alice_privkey = step0_carol_privkey()
|
|
txin_redeemScript = step0_carol_checksig_redeemscript(alice_privkey.pub)
|
|
print("Script:", txin_redeemScript.__repr__())
|
|
txin_p2sh_address = step1_carol_create_p2sh_address(txin_redeemScript)
|
|
print(f"Carol sends Alice secret = P2SH:{txin_p2sh_address}")
|
|
print("")
|
|
|
|
# ---------
|
|
|
|
# ALICE: mint tokens with secret P2SH:txin_p2sh_address
|
|
print(f"Alice mints tokens with secret = P2SH:{txin_p2sh_address}")
|
|
print("")
|
|
# ...
|
|
|
|
# ---------
|
|
# CAROL redeems with MINT
|
|
|
|
# CAROL PRODUCES txin_redeemScript and txin_signature to send to MINT
|
|
txin_redeemScript = step0_carol_checksig_redeemscript(alice_privkey.pub)
|
|
txin_signature = step2_carol_sign_tx(txin_redeemScript, alice_privkey).scriptSig
|
|
|
|
txin_redeemScript_b64 = base64.urlsafe_b64encode(txin_redeemScript).decode()
|
|
txin_signature_b64 = base64.urlsafe_b64encode(txin_signature).decode()
|
|
print(
|
|
f"Carol to Bob:\nscript: {txin_redeemScript.__repr__()}\nscript:"
|
|
f" {txin_redeemScript_b64}\nsignature: {txin_signature_b64}\n"
|
|
)
|
|
print("")
|
|
# ---------
|
|
# MINT verifies SCRIPT and SIGNATURE and mints tokens
|
|
|
|
# MINT receives txin_redeemScript_b64 and txin_signature_b64 fom CAROL:
|
|
txin_redeemScript = CScript(base64.urlsafe_b64decode(txin_redeemScript_b64))
|
|
txin_redeemScript_p2sh = txin_p2sh_address.to_redeemScript()
|
|
print("Redeem script:", txin_redeemScript.__repr__())
|
|
print("P2SH:", txin_redeemScript_p2sh.__repr__())
|
|
# txin_redeemScript = CScript([2, 3, OP_LESSTHAN, OP_VERIFY])
|
|
txin_signature = CScript(value=base64.urlsafe_b64decode(txin_signature_b64))
|
|
|
|
txin_p2sh_address = step1_carol_create_p2sh_address(txin_redeemScript)
|
|
print(f"Bob recreates secret: P2SH:{txin_p2sh_address}")
|
|
# MINT checks that P2SH:txin_p2sh_address has not been spent yet
|
|
# ...
|
|
tx, _ = step1_bob_carol_create_tx(txin_p2sh_address)
|
|
|
|
print(
|
|
f"Bob verifies:\nscript: {txin_redeemScript_b64}\nsignature:"
|
|
f" {txin_signature_b64}\n"
|
|
)
|
|
script_valid = step3_bob_verify_script(txin_signature, txin_redeemScript, tx)
|
|
# MINT redeems tokens and stores P2SH:txin_p2sh_address
|
|
# ...
|
|
if script_valid:
|
|
print("Successfull.")
|
|
else:
|
|
print("Error.")
|