From 8c5816d3f8fa6ce095d8eefd49d5b9e956a0ab72 Mon Sep 17 00:00:00 2001 From: JamesC Date: Wed, 4 Sep 2019 22:36:32 +0300 Subject: [PATCH 1/5] Added Jupyter Chapter 2.2 TapTweak --- 2.2-TapTweak.ipynb | 605 +++++++++++++++++++++++ Solutions/2.2-TapTweak-Solutions.ipynb | 646 +++++++++++++++++++++++++ images/taptweak0.jpg | Bin 0 -> 71412 bytes images/taptweak0.svg | 114 +++++ images/taptweak1.jpg | Bin 0 -> 85150 bytes images/taptweak1.svg | 135 ++++++ 6 files changed, 1500 insertions(+) create mode 100644 2.2-TapTweak.ipynb create mode 100644 Solutions/2.2-TapTweak-Solutions.ipynb create mode 100644 images/taptweak0.jpg create mode 100644 images/taptweak0.svg create mode 100644 images/taptweak1.jpg create mode 100644 images/taptweak1.svg diff --git a/2.2-TapTweak.ipynb b/2.2-TapTweak.ipynb new file mode 100644 index 000000000..255990915 --- /dev/null +++ b/2.2-TapTweak.ipynb @@ -0,0 +1,605 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from io import BytesIO\n", + "import hashlib\n", + "import random\n", + "\n", + "import util\n", + "from test_framework.key import ECKey, ECPubKey, SECP256K1_ORDER, generate_schnorr_nonce\n", + "from test_framework.musig import generate_musig_key, aggregate_schnorr_nonces, sign_musig, aggregate_musig_signatures\n", + "from test_framework.script import CScript, OP_1, OP_CHECKSIG, TaprootSignatureHash, TapLeaf, TapTree, Node\n", + "from test_framework.messages import CTransaction, COutPoint, CTxIn, CTxOut, CScriptWitness, CTxInWitness, ser_string\n", + "from test_framework.address import program_to_witness" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 2.2 TapTweak\n", + "\n", + "* Part 1 - Tweaking the Public Key\n", + "* Part 2 - Commitment Schemes with Tweaks\n", + "* Part 3 - TapTweak Script Commitments\n", + "\n", + "\n", + "## Part 1: Tweaking the Public Key\n", + "\n", + "The script commitment scheme of taproot is based on tweaking the public key. \n", + "\n", + "* `[01] [33B Tweaked Public Key]`\n", + "\n", + "Tweaking a public key means to alter it with a value (the tweak) so that it remains spendable with knowledge of the original private key and tweak. \n", + "\n", + "* Output Script: `[01] [P + T]` = `[01] [xG + tG]`\n", + "* Spendable by: `x + t`\n", + "* `P`: Internal Key\n", + "* `t`: TapTweak\n", + "* `T`: TapTweak Point\n", + "\n", + "\n", + "Importantly, an observer cannot distinguish between a tweaked and untweaked public key." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Example 1.1 - Signing with a tweaked keypair\n", + "\n", + "* A) Key pair generation: `xG = P`\n", + "* B) A tweak is positive scalar value where: `t < SECP256K1 Order` \n", + "* C) A tweak has a corresponding point: `T = t*G`\n", + "* D) The private key is tweaked by the tweak scalar: `x' = x + t`\n", + "* E) The public key is tweaked by the tweak point: `P' = P + T`\n", + "* F) Tweaked keypair `(x', P')` will produce a valid signature." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# A) Generate Key Pair.\n", + "privatekey = ECKey()\n", + "privatekey.generate()\n", + "publickey = privatekey.get_pubkey()\n", + "\n", + "# B) Tweak: t < SECP256K1 Order\n", + "tweak = hashlib.sha256(b'tweak').digest()\n", + "assert(int.from_bytes(tweak, 'big') < SECP256K1_ORDER)\n", + "\n", + "# C) Tweak point.\n", + "tweak_private = ECKey()\n", + "tweak_private.set(tweak, True)\n", + "tweak_point = tweak_private.get_pubkey()\n", + "\n", + "# D) Derive tweaked private key.\n", + "privatekey_tweaked = privatekey + tweak_private\n", + "\n", + "# E) Derive public key point.\n", + "publickey_tweaked = publickey + tweak_point\n", + "\n", + "# F) Sign message with tweaked key pair and verify signature.\n", + "msg = hashlib.sha256(b'msg').digest()\n", + "sig = privatekey_tweaked.sign_schnorr(msg)\n", + "print(publickey_tweaked.verify_schnorr(sig, msg))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Programming Exercise 1.2 - Signing with a tweaked 2-of-2 Musig key pairs.\n", + "\n", + "* A. 2-of-2 Musig key generation.\n", + " * Key pair generation for all participants: `xG = P`\n", + " * Aggregate all public keys: `pk_musig`\n", + " * Apply challenge factors to all private keys: `x' = c * x`\n", + "* B. Tweak the `pk_musig`.\n", + "* C. Signing\n", + " * Generate indidividual nonces & aggregate: `R_agg`\n", + " * Sign individually & aggregate: `sig_agg`\n", + " * _Question: Which participant(s) need to tweak keys?_\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# A1) Generate Key Pairs.\n", + "\n", + "\n", + "# A2) Aggregate all public keys: \n", + "\n", + "\n", + "# A3) Apply challenge factors to keys.\n", + "\n", + " \n", + "# B) Tweak musig public key.\n", + "# Given: Tweak.\n", + "tweak = hashlib.sha256(b'tweak').digest()\n", + "\n", + "\n", + "# C1) Nonce generation & aggregation.\n", + "\n", + "\n", + "# C2) Signing and signature aggregation.\n", + "msg = hashlib.sha256(b'msg').digest()\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Part 2: Commitment Schemes with Tweaks\n", + "\n", + "Taproot uses the tweak as a commitment for spending script paths. However, simply applying the committed value as a public key tweak is not sufficient, as this does not represent a cryptographic commitment.\n", + "\n", + "![test](images/taptweak0.jpg)\n", + "\n", + "Instead, the committed value must first be hashed with the untweaked public key point. \n", + "\n", + "**This prevents modification of both untweaked secret and tweak for a given pubkey point Q.**" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Example 2.1- Modifying the tweak for a tweaked public key Q.\n", + "\n", + "* A) Tweaking the public key to obtain: `Point Q`\n", + "* B) Create a new tweak for the same point Q: `t'`\n", + "* C) Solve for `x'` so that `x'G + t'G = Q`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# A) Tweaking the public key.\n", + "x = ECKey()\n", + "x.generate()\n", + "pk = x.get_pubkey()\n", + "t = hashlib.sha256(b'tweak').digest()\n", + "t_int = int.from_bytes(t, \"big\")\n", + "Q = pk.tweak_add(t)\n", + "\n", + "# B) Modifying the tweak.\n", + "t2 = hashlib.sha256(b'tweak2').digest()\n", + "t2_int = int.from_bytes(t2, \"big\")\n", + "\n", + "# C) Solving for: x` = x - (t' - t)\n", + "x_int = int.from_bytes(x.get_bytes(),\"big\")\n", + "s = (t2_int + (SECP256K1_ORDER - t_int)% SECP256K1_ORDER) % SECP256K1_ORDER\n", + "x2_int = (x_int + (SECP256K1_ORDER - s)% SECP256K1_ORDER) % SECP256K1_ORDER\n", + "\n", + "print((x2_int + t2_int)% SECP256K1_ORDER == (x_int + t_int)% SECP256K1_ORDER)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Example 2.2 - Tweaking Pubkey with `H(P|msg)`\n", + "\n", + "* A) Key pair generation: \n", + "* B) The tweak is the hash of both P and message: **`t = H(P|msg)`**\n", + "* C) A tweak has a corresponding point: `T = t*G`\n", + " * A private key is tweaked by the tweak scalar: `x' = x + t`\n", + " * The public key can be tweaked by the tweak point: `P' = P + T`\n", + "* D) We can verify that signature with tweaked key pair is valid." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# A) Key pair generation.\n", + "privkey = ECKey()\n", + "privkey.generate()\n", + "publickey = privkey.get_pubkey()\n", + "\n", + "# B) Compute tweak from H(P|msg)\n", + "# Note: Taproot/Taptweak actualy uses tagged hashes (See Below).\n", + "tag = \"TapTweak\"\n", + "ss = hashlib.sha256(tag.encode('utf-8')).digest()\n", + "ss += ss\n", + "ss += hashlib.sha256(b'commitment').digest()\n", + "t = hashlib.sha256(ss).digest()\n", + "\n", + "# C) Determine Tweak point.\n", + "tweak_private = ECKey()\n", + "tweak_private.set(t, True)\n", + "tweak_point = tweak_private.get_pubkey()\n", + "\n", + "privkey_tweaked = privkey + tweak_private\n", + "publickey_tweaked = publickey + tweak_point\n", + "\n", + "# F) Sign message and verify signature.\n", + "msg = hashlib.sha256(b'msg').digest()\n", + "sig = privkey_tweaked.sign_schnorr(msg)\n", + "print(publickey_tweaked.verify_schnorr(sig, msg))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Taproot: Tagged Hashes.\n", + "\n", + "The Taproot Proposal describes tagged hashes for both the taptree and taptweak. \n", + "\n", + "The TapTweak uses this double nested hashing function because it already used in TapBranches and TapLeafs, where it provides context uniqueness across the Bitcoin protocol. The 64B length of the two sha256 digest concatenation lends itself to optimization in implementations. \n", + "\n", + "**Tagged Hash:**\n", + "* `tagged_hash` = `sha256(sha256(\"Tag\") + sha256(\"Tag\") + data)`\n", + "\n", + "\n", + "**TapTree Node Hashes:**\n", + "* `TapTweak` \n", + " * `= sha256(sha256(\"TapTweak\") + sha256(\"TapTweak\") + node_hash)`\n", + "* `TapBranch` \n", + " * `= sha256(sha256(\"TapBranch\") + sha256(\"TapBranch\") + node_hash_left|node_hash_right)`\n", + "* `TapLeaf` \n", + " * `= sha256(sha256(\"TapLeaf\") + sha256(\"TapLeaf\") + node_hash_left|node_hash_right)`\n", + " \n", + "_Ordering of left and right node hash data is determined lexicographically, see next section._" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Part 3 - TapTweak Script Commitments\n", + "\n", + "The TapTweak commits a Taptree to the segwit version 1 public key. It does so with a commitment structure resembling familiar merkle tree construction.\n", + "\n", + "_Please note that the taptree uses tagged hashes which prevent node height ambiguity currently found in the transaction merkle tree, which allow an attacker to create a node which can be reinterpreted as either a leaf or internal node._\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**The TapTree is different than the header merkle tree in the following ways:**\n", + "\n", + "* Tapleafs can be located at different heights.\n", + "* Ordering of TapLeafs is determined lexicograpically.\n", + "* Location of nodes are tagged (No ambiguity of node type).\n", + " \n", + "![test](images/taptweak1.jpg)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Programming Exercise 3.1 - Constructing a TapTweak from TapScripts.\n", + "\n", + "In the cell below, we will commit three pay-to-pubkey scripts to a taptweak and then derive the segwit address which can be spent by fulfilling these scriptpaths and the internal. We will use the same merkle tree structure as in the previous illustration.\n", + "\n", + "* 1. Compute TapLeafs A, B and C.\n", + "* 2. Compute Internal node TapBranch AB.\n", + "* 3. Compute TapTweak\n", + "* 4. Derive the segwit output address.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "TAPSCRIPT_VER = bytes([0xc0]) # See TapScript chapter for more details.\n", + "internal_pubkey = ECPubKey()\n", + "internal_pubkey.set(bytes.fromhex('03af455f4989d122e9185f8c351dbaecd13adca3eef8a9d38ef8ffed6867e342e3'))\n", + "\n", + "# Derive pay-to-pubkey scripts.\n", + "secA = ECKey()\n", + "secB = ECKey()\n", + "secC = ECKey()\n", + "secA.generate()\n", + "secB.generate()\n", + "secC.generate()\n", + "pkA = secA.get_pubkey()\n", + "pkB = secA.get_pubkey()\n", + "pkC = secA.get_pubkey()\n", + "scriptA = CScript([pkA.get_bytes(), OP_CHECKSIG])\n", + "scriptB = CScript([pkB.get_bytes(), OP_CHECKSIG])\n", + "scriptC = CScript([pkC.get_bytes(), OP_CHECKSIG])\n", + "\n", + "# Method: Returns Tagged Hash.\n", + "def tagged_hash(tag, input_data):\n", + " data = hashlib.sha256(tag.encode('utf-8')).digest()\n", + " data += data\n", + " data += input_data\n", + " return hashlib.sha256(data).digest()\n", + "\n", + "# Method: Returns TapBranch hash.\n", + "def tapbranch(taggedhash_left, taggedhash_right):\n", + " if taggedhash_left > taggedhash_right:\n", + " taggedhash_left, taggedhash_right = taggedhash_right, taggedhash_left\n", + " return tagged_hash(\"TapBranch\", taggedhash_left + taggedhash_right) \n", + "\n", + "# 1) Compute TapLeafs A, B and C.\n", + "# Note: ser_string(data) is a function which adds compactsize to input data.\n", + "\n", + "\n", + "# 2) Compute Internal node TapBranch AB.\n", + "\n", + "\n", + "# 3) Compute TapTweak.\n", + "\n", + "\n", + "# 4) Derive the segwit output address.\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Run the cell below to check if you have correctly computed the TapTweak.**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# This code uses the TapTree and TapLeaf classes to construct the same tweak as above\n", + "\n", + "tapleafA = TapLeaf()\n", + "tapleafB = TapLeaf()\n", + "tapleafC = TapLeaf()\n", + "taptree = TapTree()\n", + "\n", + "tapleafA.from_script(scriptA)\n", + "tapleafB.from_script(scriptB)\n", + "tapleafC.from_script(scriptC)\n", + "\n", + "tapbranchAB = Node()\n", + "tapbranchAB.left = tapleafA\n", + "tapbranchAB.right = tapleafB\n", + "\n", + "tapbranchABC = Node()\n", + "tapbranchABC.left = tapbranchAB\n", + "tapbranchABC.right = tapleafC\n", + "\n", + "taptree.root = tapbranchABC\n", + "taptree.key = internal_pubkey\n", + "\n", + "script_v1, tweak, c_map = taptree.construct()\n", + "print(\"TapTweak:\", tweak.hex())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Programming Exercise 3.2 - Spending a Taproot Output along the Key Path.\n", + "\n", + "Now that we have understood how public keys can be tweaked to commit pay-to-pubkey scripts to a Segwit version 1 output, let us spend this output along the key path. Such as spend does not reveal the script commitments to the observer and is indistinguishable any other key path spend.\n", + "\n", + "* 1. Construct taproot output with tweaked public key.\n", + "* 2. Send funds from the wallet to the taproot output (Segwit Address).\n", + "* 3. Create and sign transaction which sends funds back to wallet with the tweaked private key.\n", + "\n", + "**Note: Most of the cells have been populated already. Simply tweak the pubkey and signing key.**" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Start TestNodes**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Start TestNodes.\n", + "test = util.TestWrapper()\n", + "test.setup()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Generate Wallet Balance**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Generate Coins for Bitcoin Node Wallet.\n", + "test.nodes[0].generate(101)\n", + "balance = test.nodes[0].getbalance()\n", + "print(balance)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**1) Construct taproot output with tweaked public key.**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create Tweaked Pubkey Output.\n", + "sec = ECKey()\n", + "sec.generate()\n", + "internal_pubkey = sec.get_pubkey()\n", + "\n", + "# Taptweak from example 2.3.1\n", + "taptweak = bytes.fromhex('2a2fb476ec9962f262ff358800db0e7364287340db73e5e48db36d1c9f374e30')\n", + "\n", + "# TODO:\n", + "# taproot_pubkey = \n", + "\n", + "\n", + "# TODO: \n", + "# segwit_address =\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**2) Send funds from the wallet to the taproot output (Segwit Address).**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Send funds to taproot output.\n", + "txid = test.nodes[0].sendtoaddress(segwit_address, balance / 100000)\n", + "print(\"Funding tx:\", txid)\n", + "\n", + "# Deserialize wallet transaction.\n", + "tx = CTransaction()\n", + "tx_hex = test.nodes[0].getrawtransaction(txid)\n", + "tx.deserialize(BytesIO(bytes.fromhex(tx_hex)))\n", + "tx.rehash()\n", + "\n", + "# Determine Output Index of Segwit V1 Output.\n", + "# (Wallet places change output at a random txout index.)\n", + "outputs = iter(tx.vout)\n", + "output = next(outputs)\n", + "index = 0\n", + "\n", + "while (output.scriptPubKey != CScript([OP_1, taproot_pubkey_v1])):\n", + " output = next(outputs)\n", + " index += 1\n", + "output_value = output.nValue" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**3) Spend taproot output with key path.**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "tx_schnorr = CTransaction()\n", + "tx_schnorr.nVersion = 1\n", + "tx_schnorr.nLockTime = 0\n", + "outpoint = COutPoint(tx.sha256, index)\n", + "tx_schnorr_in = CTxIn(outpoint = outpoint)\n", + "tx_schnorr.vin = [tx_schnorr_in]\n", + "\n", + "# Generate new Bitcoin Core wallet address to send funds back to.\n", + "dest_addr = test.nodes[0].getnewaddress(address_type=\"bech32\")\n", + "scriptpubkey = bytes.fromhex(test.nodes[0].getaddressinfo(dest_addr)['scriptPubKey'])\n", + "\n", + "# Determine minimum fee required for mempool acceptance.\n", + "min_fee = int(test.nodes[0].getmempoolinfo()['mempoolminfee'] * 100000000)\n", + "\n", + "# Complete output which returns funds to Bitcoin Core wallet.\n", + "dest_output= CTxOut(nValue=output_value-min_fee, scriptPubKey=scriptpubkey)\n", + "tx_schnorr.vout = [dest_output]\n", + "\n", + "# Sign transaction with tweaked private key.\n", + "# TODO: \n", + "# sig =\n", + "\n", + "\n", + "# Construct transaction witness.\n", + "witness = CScriptWitness()\n", + "witness.stack.append(sig)\n", + "witness_in = CTxInWitness()\n", + "witness_in.scriptWitness = witness\n", + "tx_schnorr.wit.vtxinwit.append(witness_in)\n", + "\n", + "# Serialize Schnorr transaction for broadcast.\n", + "tx_schnorr_str = tx_schnorr.serialize().hex()\n", + "\n", + "# Test mempool acceptance.\n", + "print(test.nodes[0].testmempoolaccept([tx_schnorr_str]))\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Shutdown TestNodes**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Shutdown TestNodes.\n", + "test.shutdown()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.5" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/Solutions/2.2-TapTweak-Solutions.ipynb b/Solutions/2.2-TapTweak-Solutions.ipynb new file mode 100644 index 000000000..91c99c66f --- /dev/null +++ b/Solutions/2.2-TapTweak-Solutions.ipynb @@ -0,0 +1,646 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import sys\n", + "from io import BytesIO\n", + "import hashlib\n", + "import random\n", + "\n", + "sys.path.insert(0, \"../\")\n", + "import util\n", + "from test_framework.key import ECKey, ECPubKey, SECP256K1_ORDER, generate_schnorr_nonce\n", + "from test_framework.musig import generate_musig_key, aggregate_schnorr_nonces, sign_musig, aggregate_musig_signatures\n", + "from test_framework.script import CScript, OP_1, OP_CHECKSIG, TaprootSignatureHash, TapLeaf, TapTree, Node\n", + "from test_framework.messages import CTransaction, COutPoint, CTxIn, CTxOut, CScriptWitness, CTxInWitness, ser_string\n", + "from test_framework.address import program_to_witness\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 2.2 TapTweak\n", + "\n", + "* Part 1 - Tweaking the Public Key\n", + "* Part 2 - Commitment Schemes with Tweaks\n", + "* Part 3 - TapTweak Script Commitments\n", + "\n", + "\n", + "## Part 1: Tweaking the Public Key\n", + "\n", + "The script commitment scheme of taproot is based on tweaking the public key. \n", + "\n", + "* `[01] [33B Tweaked Public Key]`\n", + "\n", + "Tweaking a public key means to alter it with a value (the tweak) so that it remains spendable with knowledge of the original private key and tweak. \n", + "\n", + "* Output Script: `[01] [P + T]` = `[01] [xG + tG]`\n", + "* Spendable by: `x + t`\n", + "* `P`: Internal Key\n", + "* `t`: TapTweak\n", + "* `T`: TapTweak Point\n", + "\n", + "\n", + "Importantly, an observer cannot distinguish between a tweaked and untweaked public key." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Example 1.1 - Signing with a tweaked keypair\n", + "\n", + "* A) Key pair generation: `xG = P`\n", + "* B) A tweak is positive scalar value where: `t < SECP256K1 Order` \n", + "* C) A tweak has a corresponding point: `T = t*G`\n", + "* D) The private key is tweaked by the tweak scalar: `x' = x + t`\n", + "* E) The public key is tweaked by the tweak point: `P' = P + T`\n", + "* F) Tweaked keypair `(x', P')` will produce a valid signature." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# A) Generate Key Pair.\n", + "privatekey = ECKey()\n", + "privatekey.generate()\n", + "publickey = privatekey.get_pubkey()\n", + "\n", + "# B) Tweak: t < SECP256K1 Order\n", + "tweak = hashlib.sha256(b'tweak').digest()\n", + "assert(int.from_bytes(tweak, 'big') < SECP256K1_ORDER)\n", + "\n", + "# C) Tweak point.\n", + "tweak_private = ECKey()\n", + "tweak_private.set(tweak, True)\n", + "tweak_point = tweak_private.get_pubkey()\n", + "\n", + "# D) Derive tweaked private key.\n", + "privatekey_tweaked = privatekey + tweak_private\n", + "\n", + "# E) Derive public key point.\n", + "publickey_tweaked = publickey + tweak_point\n", + "\n", + "# F) Sign message with tweaked key pair and verify signature.\n", + "msg = hashlib.sha256(b'msg').digest()\n", + "sig = privatekey_tweaked.sign_schnorr(msg)\n", + "print(publickey_tweaked.verify_schnorr(sig, msg))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Programming Exercise 1.2 - Signing with a tweaked 2-of-2 Musig key pairs.\n", + "\n", + "* A. 2-of-2 Musig key generation.\n", + " * Key pair generation for all participants: `xG = P`\n", + " * Aggregate all public keys: `pk_musig`\n", + " * Apply challenge factors to all private keys: `x' = c * x`\n", + "* B. Tweak the `pk_musig`.\n", + "* C. Signing\n", + " * Generate indidividual nonces & aggregate: `R_agg`\n", + " * Sign individually & aggregate: `sig_agg`\n", + " * _Question: Which participant(s) need to tweak keys?_\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# A1) Generate Key Pairs.\n", + "privkey0 = ECKey()\n", + "privkey1 = ECKey()\n", + "privkey0.generate()\n", + "privkey1.generate()\n", + "pk0 = privkey0.get_pubkey()\n", + "pk1 = privkey1.get_pubkey()\n", + "\n", + "# A2) Aggregate all public keys: \n", + "c_map, pk_musig = generate_musig_key([pk0, pk1])\n", + "\n", + "# A3) Apply challenge factors to keys.\n", + "privkey0_c = privkey0.mul(c_map[pk0])\n", + "privkey1_c = privkey1.mul(c_map[pk1])\n", + "pk0_c = pk0.mul(c_map[pk0])\n", + "pk1_c = pk1.mul(c_map[pk1])\n", + " \n", + "# B) Tweak musig public key.\n", + "# Given: Tweak.\n", + "tweak = hashlib.sha256(b'tweak').digest()\n", + "pk_musig_tweaked = pk_musig.tweak_add(tweak)\n", + "\n", + "# C1) Nonce generation & aggregation.\n", + "k0 = generate_schnorr_nonce()\n", + "k1 = generate_schnorr_nonce()\n", + "R0 = k0.get_pubkey()\n", + "R1 = k1.get_pubkey()\n", + "R_agg, negated = aggregate_schnorr_nonces([R0, R1])\n", + "if negated:\n", + " k0.negate()\n", + " k1.negate()\n", + "\n", + "# C2) Signing and signature aggregation.\n", + "msg = hashlib.sha256(b'msg').digest()\n", + "\n", + "# One person must tweak keys.\n", + "privkey0_c_tweaked = privkey0_c.add(tweak) \n", + "\n", + "sig0 = sign_musig(privkey0_c_tweaked, k0, R_agg, pk_musig_tweaked, msg)\n", + "sig1 = sign_musig(privkey1_c, k1, R_agg, pk_musig_tweaked, msg)\n", + "sig_agg = aggregate_musig_signatures([sig0, sig1])\n", + "pk_musig_tweaked.verify_schnorr(sig_agg, msg)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Part 2: Commitment Schemes with Tweaks\n", + "\n", + "Taproot uses the tweak as a commitment for spending script paths. However, simply applying the committed value as a public key tweak is not sufficient, as this does not represent a cryptographic commitment.\n", + "\n", + "![test](../images/taptweak0.jpg)\n", + "\n", + "Instead, the committed value must first be hashed with the untweaked public key point. \n", + "\n", + "**This prevents modification of both untweaked secret and tweak for a given pubkey point Q.**" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Example 2.1- Modifying the tweak for a tweaked public key Q.\n", + "\n", + "* A) Tweaking the public key to obtain: `Point Q`\n", + "* B) Create a new tweak for the same point Q: `t'`\n", + "* C) Solve for `x'` so that `x'G + t'G = Q`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# A) Tweaking the public key.\n", + "x = ECKey()\n", + "x.generate()\n", + "pk = x.get_pubkey()\n", + "t = hashlib.sha256(b'tweak').digest()\n", + "t_int = int.from_bytes(t, \"big\")\n", + "Q = pk.tweak_add(t)\n", + "\n", + "# B) Modifying the tweak.\n", + "t2 = hashlib.sha256(b'tweak2').digest()\n", + "t2_int = int.from_bytes(t2, \"big\")\n", + "\n", + "# C) Solving for: x` = x - (t' - t)\n", + "x_int = int.from_bytes(x.get_bytes(),\"big\")\n", + "s = (t2_int + (SECP256K1_ORDER - t_int)% SECP256K1_ORDER) % SECP256K1_ORDER\n", + "x2_int = (x_int + (SECP256K1_ORDER - s)% SECP256K1_ORDER) % SECP256K1_ORDER\n", + "\n", + "print((x2_int + t2_int)% SECP256K1_ORDER == (x_int + t_int)% SECP256K1_ORDER)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Example 2.2 - Tweaking Pubkey with `H(P|msg)`\n", + "\n", + "* A) Key pair generation: \n", + "* B) The tweak is the hash of both P and message: **`t = H(P|msg)`**\n", + "* C) A tweak has a corresponding point: `T = t*G`\n", + " * A private key is tweaked by the tweak scalar: `x' = x + t`\n", + " * The public key can be tweaked by the tweak point: `P' = P + T`\n", + "* D) We can verify that signature with tweaked key pair is valid." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from test_framework.key import ECKey, ECPubKey\n", + "import hashlib\n", + "\n", + "# A) Key pair generation.\n", + "privkey = ECKey()\n", + "privkey.generate()\n", + "publickey = privkey.get_pubkey()\n", + "\n", + "# B) Compute tweak from H(P|msg)\n", + "# Note: Taproot/Taptweak actualy uses tagged hashes (See Below).\n", + "tag = \"TapTweak\"\n", + "ss = hashlib.sha256(tag.encode('utf-8')).digest()\n", + "ss += ss\n", + "ss += hashlib.sha256(b'commitment').digest()\n", + "t = hashlib.sha256(ss).digest()\n", + "\n", + "# C) Determine Tweak point.\n", + "tweak_private = ECKey()\n", + "tweak_private.set(t, True)\n", + "tweak_point = tweak_private.get_pubkey()\n", + "\n", + "privkey_tweaked = privkey + tweak_private\n", + "publickey_tweaked = publickey + tweak_point\n", + "\n", + "# F) Sign message and verify signature.\n", + "msg = hashlib.sha256(b'msg').digest()\n", + "sig = privkey_tweaked.sign_schnorr(msg)\n", + "print(publickey_tweaked.verify_schnorr(sig, msg))\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Taproot: Tagged Hashes.\n", + "\n", + "The Taproot Proposal describes tagged hashes for both the taptree and taptweak. \n", + "\n", + "The TapTweak uses this double nested hashing function because it already used in TapBranches and TapLeafs, where it provides context uniqueness across the Bitcoin protocol. The 64B length of the two sha256 digest concatenation lends itself to optimization in implementations. \n", + "\n", + "**Tagged Hash:**\n", + "* `tagged_hash` = `sha256(sha256(\"Tag\") + sha256(\"Tag\") + data)`\n", + "\n", + "\n", + "**TapTree Node Hashes:**\n", + "* `TapTweak` \n", + " * `= sha256(sha256(\"TapTweak\") + sha256(\"TapTweak\") + node_hash)`\n", + "* `TapBranch` \n", + " * `= sha256(sha256(\"TapBranch\") + sha256(\"TapBranch\") + node_hash_left|node_hash_right)`\n", + "* `TapLeaf` \n", + " * `= sha256(sha256(\"TapLeaf\") + sha256(\"TapLeaf\") + node_hash_left|node_hash_right)`\n", + " \n", + "_Ordering of left and right node hash data is determined lexicographically, see next section._" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Part 3 - TapTweak Script Commitments\n", + "\n", + "The TapTweak commits a Taptree to the segwit version 1 public key. It does so with a commitment structure resembling familiar merkle tree construction.\n", + "\n", + "_Please note that the taptree uses tagged hashes which prevent node height ambiguity currently found in the transaction merkle tree, which allow an attacker to create a node which can be reinterpreted as either a leaf or internal node._\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**The TapTree is different than the header merkle tree in the following ways:**\n", + "\n", + "* Tapleafs can be located at different heights.\n", + "* Ordering of TapLeafs is determined lexicograpically.\n", + "* Location of nodes are tagged (No ambiguity of node type).\n", + " \n", + "![test](../images/taptweak1.jpg)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Programming Exercise 3.1 - Constructing a TapTweak from TapScripts.\n", + "\n", + "In the cell below, we will commit three pay-to-pubkey scripts to a taptweak and then derive the segwit address which can be spent by fulfilling these scriptpaths and the internal. We will use the same merkle tree structure as in the previous illustration.\n", + "\n", + "* 1. Compute TapLeafs A, B and C.\n", + "* 2. Compute Internal node TapBranch AB.\n", + "* 3. Compute TapTweak\n", + "* 4. Derive the segwit output address.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "TAPSCRIPT_VER = bytes([0xc0]) # See TapScript chapter for more details.\n", + "internal_pubkey = ECPubKey()\n", + "internal_pubkey.set(bytes.fromhex('03af455f4989d122e9185f8c351dbaecd13adca3eef8a9d38ef8ffed6867e342e3'))\n", + "\n", + "# Derive pay-to-pubkey scripts.\n", + "privkeyA = ECKey()\n", + "privkeyB = ECKey()\n", + "privkeyC = ECKey()\n", + "privkeyA.generate()\n", + "privkeyB.generate()\n", + "privkeyC.generate()\n", + "pkA = privkeyA.get_pubkey()\n", + "pkB = privkeyA.get_pubkey()\n", + "pkC = privkeyA.get_pubkey()\n", + "scriptA = CScript([pkA.get_bytes(), OP_CHECKSIG])\n", + "scriptB = CScript([pkB.get_bytes(), OP_CHECKSIG])\n", + "scriptC = CScript([pkC.get_bytes(), OP_CHECKSIG])\n", + "\n", + "# Method: Returns Tagged Hash.\n", + "def tagged_hash(tag, input_data):\n", + " data = hashlib.sha256(tag.encode('utf-8')).digest()\n", + " data += data\n", + " data += input_data\n", + " return hashlib.sha256(data).digest()\n", + "\n", + "# Method: Returns TapBranch hash.\n", + "def tapbranch(taggedhash_left, taggedhash_right):\n", + " if taggedhash_left > taggedhash_right:\n", + " taggedhash_left, taggedhash_right = taggedhash_right, taggedhash_left\n", + " return tagged_hash(\"TapBranch\", taggedhash_left + taggedhash_right) \n", + "\n", + "# 1) Compute TapLeafs A, B and C.\n", + "# Note: ser_string(data) is a function which adds compactsize to input data.\n", + "hash_inputA = TAPSCRIPT_VER + ser_string(scriptA)\n", + "hash_inputB = TAPSCRIPT_VER + ser_string(scriptB)\n", + "hash_inputC = TAPSCRIPT_VER + ser_string(scriptC)\n", + "taggedhash_leafA = tagged_hash(\"TapLeaf\", hash_inputA)\n", + "taggedhash_leafB = tagged_hash(\"TapLeaf\", hash_inputB)\n", + "taggedhash_leafC = tagged_hash(\"TapLeaf\", hash_inputC)\n", + "\n", + "# 2) Compute Internal node TapBranch AB.\n", + "internal_nodeAB = tapbranch(taggedhash_leafA, taggedhash_leafB)\n", + "\n", + "# 3) Compute TapTweak.\n", + "rootABC = tapbranch(internal_nodeAB, taggedhash_leafC)\n", + "taptweak = tagged_hash(\"TapTweak\", internal_pubkey.get_bytes() + rootABC)\n", + "print(\"TapTweak:\", taptweak.hex())\n", + "\n", + "# 4) Derive the segwit output address.\n", + "taproot_pubkey_b = internal_pubkey.tweak_add(taptweak).get_bytes()\n", + "taproot_pubkey_v1 = bytes([taproot_pubkey_b[0] & 1]) + taproot_pubkey_b[1:]\n", + "segwit_address = program_to_witness(1, taproot_pubkey_v1)\n", + "print('Segwit address:', segwit_address)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Run the cell below to check if you have correctly computed the TapTweak.**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# This code uses the TapTree and TapLeaf classes to construct the same tweak as above\n", + "\n", + "tapleafA = TapLeaf()\n", + "tapleafB = TapLeaf()\n", + "tapleafC = TapLeaf()\n", + "taptree = TapTree()\n", + "\n", + "tapleafA.from_script(scriptA)\n", + "tapleafB.from_script(scriptB)\n", + "tapleafC.from_script(scriptC)\n", + "\n", + "tapbranchAB = Node()\n", + "tapbranchAB.left = tapleafA\n", + "tapbranchAB.right = tapleafB\n", + "\n", + "tapbranchABC = Node()\n", + "tapbranchABC.left = tapbranchAB\n", + "tapbranchABC.right = tapleafC\n", + "\n", + "taptree.root = tapbranchABC\n", + "taptree.key = internal_pubkey\n", + "\n", + "script_v1, tweak, c_map = taptree.construct()\n", + "print(\"TapTweak:\", tweak.hex())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Programming Exercise 3.2 - Spending a Taproot Output along the Key Path.\n", + "\n", + "Now that we have understood how public keys can be tweaked to commit pay-to-pubkey scripts to a Segwit version 1 output, let us spend this output along the key path. Such as spend does not reveal the script commitments to the observer and is indistinguishable any other key path spend.\n", + "\n", + "* 1. Construct taproot output with tweaked public key.\n", + "* 2. Send funds from the wallet to the taproot output (Segwit Address).\n", + "* 3. Create and sign transaction which sends funds back to wallet with the tweaked private key.\n", + "\n", + "**Note: Most of the cells have been populated already. Simply tweak the pubkey and signing key.**" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Start TestNodes**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Start TestNodes.\n", + "test = util.TestWrapper()\n", + "test.setup()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Generate Wallet Balance**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Generate Coins for Bitcoin Node Wallet.\n", + "test.nodes[0].generate(101)\n", + "balance = test.nodes[0].getbalance()\n", + "print(balance)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**1) Construct taproot output with tweaked public key.**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create Tweaked Pubkey Output.\n", + "sec = ECKey()\n", + "sec.generate()\n", + "internal_pubkey = sec.get_pubkey()\n", + "\n", + "# Taptweak from example 2.3.1\n", + "taptweak = bytes.fromhex('2a2fb476ec9962f262ff358800db0e7364287340db73e5e48db36d1c9f374e30')\n", + "\n", + "# TODO: taproot_pubkey =\n", + "taproot_pubkey = internal_pubkey.tweak_add(taptweak) \n", + "taproot_pubkey_b = taproot_pubkey.get_bytes()\n", + "\n", + "# TODO: segwit_address =\n", + "taproot_pubkey_v1 = bytes([taproot_pubkey_b[0] & 1]) + taproot_pubkey_b[1:]\n", + "segwit_address = program_to_witness(1, taproot_pubkey_v1)\n", + "print(\"Segwit Address:\", segwit_address)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**2) Send funds from the wallet to the taproot output (Segwit Address).**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Send funds to taproot output.\n", + "txid = test.nodes[0].sendtoaddress(segwit_address, balance / 100000)\n", + "print(\"Funding tx:\", txid)\n", + "\n", + "# Deserialize wallet transaction.\n", + "tx = CTransaction()\n", + "tx_hex = test.nodes[0].getrawtransaction(txid)\n", + "tx.deserialize(BytesIO(bytes.fromhex(tx_hex)))\n", + "tx.rehash()\n", + "\n", + "# Determine Output Index of Segwit V1 Output.\n", + "# (Wallet places change output at a random txout index.)\n", + "outputs = iter(tx.vout)\n", + "output = next(outputs)\n", + "index = 0\n", + "\n", + "while (output.scriptPubKey != CScript([OP_1, taproot_pubkey_v1])):\n", + " output = next(outputs)\n", + " index += 1\n", + "output_value = output.nValue" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**3) Spend taproot output with key path.**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "tx_schnorr = CTransaction()\n", + "tx_schnorr.nVersion = 1\n", + "tx_schnorr.nLockTime = 0\n", + "outpoint = COutPoint(tx.sha256, index)\n", + "tx_schnorr_in = CTxIn(outpoint = outpoint)\n", + "tx_schnorr.vin = [tx_schnorr_in]\n", + "\n", + "# Generate new Bitcoin Core wallet address to send funds back to.\n", + "dest_addr = test.nodes[0].getnewaddress(address_type=\"bech32\")\n", + "scriptpubkey = bytes.fromhex(test.nodes[0].getaddressinfo(dest_addr)['scriptPubKey'])\n", + "\n", + "# Determine minimum fee required for mempool acceptance.\n", + "min_fee = int(test.nodes[0].getmempoolinfo()['mempoolminfee'] * 100000000)\n", + "\n", + "# Complete output which returns funds to Bitcoin Core wallet.\n", + "dest_output= CTxOut(nValue=output_value-min_fee, scriptPubKey=scriptpubkey)\n", + "tx_schnorr.vout = [dest_output]\n", + "\n", + "# Sign transaction with tweaked private key.\n", + "# TODO: sig =\n", + "hash_types = [0,1,2,3,0x81,0x82,0x83]\n", + "sighash = TaprootSignatureHash(tx_schnorr, [output], hash_types[0])\n", + "tweaked_sec = sec.add(taptweak)\n", + "sig = tweaked_sec.sign_schnorr(sighash)\n", + "\n", + "# Construct transaction witness.\n", + "witness = CScriptWitness()\n", + "witness.stack.append(sig)\n", + "witness_in = CTxInWitness()\n", + "witness_in.scriptWitness = witness\n", + "tx_schnorr.wit.vtxinwit.append(witness_in)\n", + "\n", + "# Serialize Schnorr transaction for broadcast.\n", + "tx_schnorr_str = tx_schnorr.serialize().hex()\n", + "\n", + "# Test mempool acceptance.\n", + "print(test.nodes[0].testmempoolaccept([tx_schnorr_str]))\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Shutdown TestNodes**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Shutdown TestNodes.\n", + "test.shutdown()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.5" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/images/taptweak0.jpg b/images/taptweak0.jpg new file mode 100644 index 0000000000000000000000000000000000000000..739fbded5e823083452553a9798df9f981758d22 GIT binary patch literal 71412 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 literal 0 HcmV?d00001 diff --git a/images/taptweak0.svg b/images/taptweak0.svg new file mode 100644 index 000000000..9030f7643 --- /dev/null +++ b/images/taptweak0.svg @@ -0,0 +1,114 @@ + + + + + + + + + + Commitments with Pubkey Tweaks + + + + + + + + + + Commitment Scheme + + + + Q = x’G + c’G + + + + Cannot solvefor x + + + + Solve for x’ + + + + + + + Q = P + cG + + + + x + + + + + + + Q = P + H(P|c)G + + + + Q != x’G + H(x’G|c’)G + + + + + + + + + + + + + + Modify c’ + + + + + + + + Modify c’ + + + + + + + + Public Key Tweak + + + + + + + + + + + + + + + + + + + diff --git a/images/taptweak1.jpg b/images/taptweak1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..dd1e667a70b933e6c489959796f56da2c60ff5e5 GIT binary patch literal 85150 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 D%AF2o literal 0 HcmV?d00001 diff --git a/images/taptweak1.svg b/images/taptweak1.svg new file mode 100644 index 000000000..03904285d --- /dev/null +++ b/images/taptweak1.svg @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + Tagged Hashes in Taproot (No Tapbranch/Tapleaf Ambiguity) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + C + + + + ABC + + + + t + + + + A + + + + B + + + + AB + + + + Q = P + tG + + + + Taproot PubKey + + + + TaggedHash(’TapBranch’,AB & D) + + + + TaggedHash(’TapTweak’,P|ABC) + + + + Lexicographic Ordering of Children in Hash. + + + + TaggedHash(’TapLeaf’,ver|size|script_A) + + + + TaggedHash(’TapLeaf’,ver|size|script_C) + + + + TaggedHash(’TapLeaf’,ver|size|script_B) + + + + + + + TaggedHash(’TapBranch’|A & B) + + + + + + + + From 57106061b6ca420885c3e06f97d7af7f575ecf12 Mon Sep 17 00:00:00 2001 From: Mike Schmidt Date: Fri, 20 Sep 2019 06:35:57 -0500 Subject: [PATCH 2/5] moved solutions to txt file --- Solutions/2.2-TapTweak-Solutions.ipynb | 646 ------------------------- Solutions/2.2-TapTweak-Solutions.txt | 95 ++++ 2 files changed, 95 insertions(+), 646 deletions(-) delete mode 100644 Solutions/2.2-TapTweak-Solutions.ipynb create mode 100644 Solutions/2.2-TapTweak-Solutions.txt diff --git a/Solutions/2.2-TapTweak-Solutions.ipynb b/Solutions/2.2-TapTweak-Solutions.ipynb deleted file mode 100644 index 91c99c66f..000000000 --- a/Solutions/2.2-TapTweak-Solutions.ipynb +++ /dev/null @@ -1,646 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import sys\n", - "from io import BytesIO\n", - "import hashlib\n", - "import random\n", - "\n", - "sys.path.insert(0, \"../\")\n", - "import util\n", - "from test_framework.key import ECKey, ECPubKey, SECP256K1_ORDER, generate_schnorr_nonce\n", - "from test_framework.musig import generate_musig_key, aggregate_schnorr_nonces, sign_musig, aggregate_musig_signatures\n", - "from test_framework.script import CScript, OP_1, OP_CHECKSIG, TaprootSignatureHash, TapLeaf, TapTree, Node\n", - "from test_framework.messages import CTransaction, COutPoint, CTxIn, CTxOut, CScriptWitness, CTxInWitness, ser_string\n", - "from test_framework.address import program_to_witness\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# 2.2 TapTweak\n", - "\n", - "* Part 1 - Tweaking the Public Key\n", - "* Part 2 - Commitment Schemes with Tweaks\n", - "* Part 3 - TapTweak Script Commitments\n", - "\n", - "\n", - "## Part 1: Tweaking the Public Key\n", - "\n", - "The script commitment scheme of taproot is based on tweaking the public key. \n", - "\n", - "* `[01] [33B Tweaked Public Key]`\n", - "\n", - "Tweaking a public key means to alter it with a value (the tweak) so that it remains spendable with knowledge of the original private key and tweak. \n", - "\n", - "* Output Script: `[01] [P + T]` = `[01] [xG + tG]`\n", - "* Spendable by: `x + t`\n", - "* `P`: Internal Key\n", - "* `t`: TapTweak\n", - "* `T`: TapTweak Point\n", - "\n", - "\n", - "Importantly, an observer cannot distinguish between a tweaked and untweaked public key." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Example 1.1 - Signing with a tweaked keypair\n", - "\n", - "* A) Key pair generation: `xG = P`\n", - "* B) A tweak is positive scalar value where: `t < SECP256K1 Order` \n", - "* C) A tweak has a corresponding point: `T = t*G`\n", - "* D) The private key is tweaked by the tweak scalar: `x' = x + t`\n", - "* E) The public key is tweaked by the tweak point: `P' = P + T`\n", - "* F) Tweaked keypair `(x', P')` will produce a valid signature." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# A) Generate Key Pair.\n", - "privatekey = ECKey()\n", - "privatekey.generate()\n", - "publickey = privatekey.get_pubkey()\n", - "\n", - "# B) Tweak: t < SECP256K1 Order\n", - "tweak = hashlib.sha256(b'tweak').digest()\n", - "assert(int.from_bytes(tweak, 'big') < SECP256K1_ORDER)\n", - "\n", - "# C) Tweak point.\n", - "tweak_private = ECKey()\n", - "tweak_private.set(tweak, True)\n", - "tweak_point = tweak_private.get_pubkey()\n", - "\n", - "# D) Derive tweaked private key.\n", - "privatekey_tweaked = privatekey + tweak_private\n", - "\n", - "# E) Derive public key point.\n", - "publickey_tweaked = publickey + tweak_point\n", - "\n", - "# F) Sign message with tweaked key pair and verify signature.\n", - "msg = hashlib.sha256(b'msg').digest()\n", - "sig = privatekey_tweaked.sign_schnorr(msg)\n", - "print(publickey_tweaked.verify_schnorr(sig, msg))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Programming Exercise 1.2 - Signing with a tweaked 2-of-2 Musig key pairs.\n", - "\n", - "* A. 2-of-2 Musig key generation.\n", - " * Key pair generation for all participants: `xG = P`\n", - " * Aggregate all public keys: `pk_musig`\n", - " * Apply challenge factors to all private keys: `x' = c * x`\n", - "* B. Tweak the `pk_musig`.\n", - "* C. Signing\n", - " * Generate indidividual nonces & aggregate: `R_agg`\n", - " * Sign individually & aggregate: `sig_agg`\n", - " * _Question: Which participant(s) need to tweak keys?_\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# A1) Generate Key Pairs.\n", - "privkey0 = ECKey()\n", - "privkey1 = ECKey()\n", - "privkey0.generate()\n", - "privkey1.generate()\n", - "pk0 = privkey0.get_pubkey()\n", - "pk1 = privkey1.get_pubkey()\n", - "\n", - "# A2) Aggregate all public keys: \n", - "c_map, pk_musig = generate_musig_key([pk0, pk1])\n", - "\n", - "# A3) Apply challenge factors to keys.\n", - "privkey0_c = privkey0.mul(c_map[pk0])\n", - "privkey1_c = privkey1.mul(c_map[pk1])\n", - "pk0_c = pk0.mul(c_map[pk0])\n", - "pk1_c = pk1.mul(c_map[pk1])\n", - " \n", - "# B) Tweak musig public key.\n", - "# Given: Tweak.\n", - "tweak = hashlib.sha256(b'tweak').digest()\n", - "pk_musig_tweaked = pk_musig.tweak_add(tweak)\n", - "\n", - "# C1) Nonce generation & aggregation.\n", - "k0 = generate_schnorr_nonce()\n", - "k1 = generate_schnorr_nonce()\n", - "R0 = k0.get_pubkey()\n", - "R1 = k1.get_pubkey()\n", - "R_agg, negated = aggregate_schnorr_nonces([R0, R1])\n", - "if negated:\n", - " k0.negate()\n", - " k1.negate()\n", - "\n", - "# C2) Signing and signature aggregation.\n", - "msg = hashlib.sha256(b'msg').digest()\n", - "\n", - "# One person must tweak keys.\n", - "privkey0_c_tweaked = privkey0_c.add(tweak) \n", - "\n", - "sig0 = sign_musig(privkey0_c_tweaked, k0, R_agg, pk_musig_tweaked, msg)\n", - "sig1 = sign_musig(privkey1_c, k1, R_agg, pk_musig_tweaked, msg)\n", - "sig_agg = aggregate_musig_signatures([sig0, sig1])\n", - "pk_musig_tweaked.verify_schnorr(sig_agg, msg)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Part 2: Commitment Schemes with Tweaks\n", - "\n", - "Taproot uses the tweak as a commitment for spending script paths. However, simply applying the committed value as a public key tweak is not sufficient, as this does not represent a cryptographic commitment.\n", - "\n", - "![test](../images/taptweak0.jpg)\n", - "\n", - "Instead, the committed value must first be hashed with the untweaked public key point. \n", - "\n", - "**This prevents modification of both untweaked secret and tweak for a given pubkey point Q.**" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Example 2.1- Modifying the tweak for a tweaked public key Q.\n", - "\n", - "* A) Tweaking the public key to obtain: `Point Q`\n", - "* B) Create a new tweak for the same point Q: `t'`\n", - "* C) Solve for `x'` so that `x'G + t'G = Q`" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# A) Tweaking the public key.\n", - "x = ECKey()\n", - "x.generate()\n", - "pk = x.get_pubkey()\n", - "t = hashlib.sha256(b'tweak').digest()\n", - "t_int = int.from_bytes(t, \"big\")\n", - "Q = pk.tweak_add(t)\n", - "\n", - "# B) Modifying the tweak.\n", - "t2 = hashlib.sha256(b'tweak2').digest()\n", - "t2_int = int.from_bytes(t2, \"big\")\n", - "\n", - "# C) Solving for: x` = x - (t' - t)\n", - "x_int = int.from_bytes(x.get_bytes(),\"big\")\n", - "s = (t2_int + (SECP256K1_ORDER - t_int)% SECP256K1_ORDER) % SECP256K1_ORDER\n", - "x2_int = (x_int + (SECP256K1_ORDER - s)% SECP256K1_ORDER) % SECP256K1_ORDER\n", - "\n", - "print((x2_int + t2_int)% SECP256K1_ORDER == (x_int + t_int)% SECP256K1_ORDER)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Example 2.2 - Tweaking Pubkey with `H(P|msg)`\n", - "\n", - "* A) Key pair generation: \n", - "* B) The tweak is the hash of both P and message: **`t = H(P|msg)`**\n", - "* C) A tweak has a corresponding point: `T = t*G`\n", - " * A private key is tweaked by the tweak scalar: `x' = x + t`\n", - " * The public key can be tweaked by the tweak point: `P' = P + T`\n", - "* D) We can verify that signature with tweaked key pair is valid." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from test_framework.key import ECKey, ECPubKey\n", - "import hashlib\n", - "\n", - "# A) Key pair generation.\n", - "privkey = ECKey()\n", - "privkey.generate()\n", - "publickey = privkey.get_pubkey()\n", - "\n", - "# B) Compute tweak from H(P|msg)\n", - "# Note: Taproot/Taptweak actualy uses tagged hashes (See Below).\n", - "tag = \"TapTweak\"\n", - "ss = hashlib.sha256(tag.encode('utf-8')).digest()\n", - "ss += ss\n", - "ss += hashlib.sha256(b'commitment').digest()\n", - "t = hashlib.sha256(ss).digest()\n", - "\n", - "# C) Determine Tweak point.\n", - "tweak_private = ECKey()\n", - "tweak_private.set(t, True)\n", - "tweak_point = tweak_private.get_pubkey()\n", - "\n", - "privkey_tweaked = privkey + tweak_private\n", - "publickey_tweaked = publickey + tweak_point\n", - "\n", - "# F) Sign message and verify signature.\n", - "msg = hashlib.sha256(b'msg').digest()\n", - "sig = privkey_tweaked.sign_schnorr(msg)\n", - "print(publickey_tweaked.verify_schnorr(sig, msg))\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Taproot: Tagged Hashes.\n", - "\n", - "The Taproot Proposal describes tagged hashes for both the taptree and taptweak. \n", - "\n", - "The TapTweak uses this double nested hashing function because it already used in TapBranches and TapLeafs, where it provides context uniqueness across the Bitcoin protocol. The 64B length of the two sha256 digest concatenation lends itself to optimization in implementations. \n", - "\n", - "**Tagged Hash:**\n", - "* `tagged_hash` = `sha256(sha256(\"Tag\") + sha256(\"Tag\") + data)`\n", - "\n", - "\n", - "**TapTree Node Hashes:**\n", - "* `TapTweak` \n", - " * `= sha256(sha256(\"TapTweak\") + sha256(\"TapTweak\") + node_hash)`\n", - "* `TapBranch` \n", - " * `= sha256(sha256(\"TapBranch\") + sha256(\"TapBranch\") + node_hash_left|node_hash_right)`\n", - "* `TapLeaf` \n", - " * `= sha256(sha256(\"TapLeaf\") + sha256(\"TapLeaf\") + node_hash_left|node_hash_right)`\n", - " \n", - "_Ordering of left and right node hash data is determined lexicographically, see next section._" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Part 3 - TapTweak Script Commitments\n", - "\n", - "The TapTweak commits a Taptree to the segwit version 1 public key. It does so with a commitment structure resembling familiar merkle tree construction.\n", - "\n", - "_Please note that the taptree uses tagged hashes which prevent node height ambiguity currently found in the transaction merkle tree, which allow an attacker to create a node which can be reinterpreted as either a leaf or internal node._\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**The TapTree is different than the header merkle tree in the following ways:**\n", - "\n", - "* Tapleafs can be located at different heights.\n", - "* Ordering of TapLeafs is determined lexicograpically.\n", - "* Location of nodes are tagged (No ambiguity of node type).\n", - " \n", - "![test](../images/taptweak1.jpg)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Programming Exercise 3.1 - Constructing a TapTweak from TapScripts.\n", - "\n", - "In the cell below, we will commit three pay-to-pubkey scripts to a taptweak and then derive the segwit address which can be spent by fulfilling these scriptpaths and the internal. We will use the same merkle tree structure as in the previous illustration.\n", - "\n", - "* 1. Compute TapLeafs A, B and C.\n", - "* 2. Compute Internal node TapBranch AB.\n", - "* 3. Compute TapTweak\n", - "* 4. Derive the segwit output address.\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "TAPSCRIPT_VER = bytes([0xc0]) # See TapScript chapter for more details.\n", - "internal_pubkey = ECPubKey()\n", - "internal_pubkey.set(bytes.fromhex('03af455f4989d122e9185f8c351dbaecd13adca3eef8a9d38ef8ffed6867e342e3'))\n", - "\n", - "# Derive pay-to-pubkey scripts.\n", - "privkeyA = ECKey()\n", - "privkeyB = ECKey()\n", - "privkeyC = ECKey()\n", - "privkeyA.generate()\n", - "privkeyB.generate()\n", - "privkeyC.generate()\n", - "pkA = privkeyA.get_pubkey()\n", - "pkB = privkeyA.get_pubkey()\n", - "pkC = privkeyA.get_pubkey()\n", - "scriptA = CScript([pkA.get_bytes(), OP_CHECKSIG])\n", - "scriptB = CScript([pkB.get_bytes(), OP_CHECKSIG])\n", - "scriptC = CScript([pkC.get_bytes(), OP_CHECKSIG])\n", - "\n", - "# Method: Returns Tagged Hash.\n", - "def tagged_hash(tag, input_data):\n", - " data = hashlib.sha256(tag.encode('utf-8')).digest()\n", - " data += data\n", - " data += input_data\n", - " return hashlib.sha256(data).digest()\n", - "\n", - "# Method: Returns TapBranch hash.\n", - "def tapbranch(taggedhash_left, taggedhash_right):\n", - " if taggedhash_left > taggedhash_right:\n", - " taggedhash_left, taggedhash_right = taggedhash_right, taggedhash_left\n", - " return tagged_hash(\"TapBranch\", taggedhash_left + taggedhash_right) \n", - "\n", - "# 1) Compute TapLeafs A, B and C.\n", - "# Note: ser_string(data) is a function which adds compactsize to input data.\n", - "hash_inputA = TAPSCRIPT_VER + ser_string(scriptA)\n", - "hash_inputB = TAPSCRIPT_VER + ser_string(scriptB)\n", - "hash_inputC = TAPSCRIPT_VER + ser_string(scriptC)\n", - "taggedhash_leafA = tagged_hash(\"TapLeaf\", hash_inputA)\n", - "taggedhash_leafB = tagged_hash(\"TapLeaf\", hash_inputB)\n", - "taggedhash_leafC = tagged_hash(\"TapLeaf\", hash_inputC)\n", - "\n", - "# 2) Compute Internal node TapBranch AB.\n", - "internal_nodeAB = tapbranch(taggedhash_leafA, taggedhash_leafB)\n", - "\n", - "# 3) Compute TapTweak.\n", - "rootABC = tapbranch(internal_nodeAB, taggedhash_leafC)\n", - "taptweak = tagged_hash(\"TapTweak\", internal_pubkey.get_bytes() + rootABC)\n", - "print(\"TapTweak:\", taptweak.hex())\n", - "\n", - "# 4) Derive the segwit output address.\n", - "taproot_pubkey_b = internal_pubkey.tweak_add(taptweak).get_bytes()\n", - "taproot_pubkey_v1 = bytes([taproot_pubkey_b[0] & 1]) + taproot_pubkey_b[1:]\n", - "segwit_address = program_to_witness(1, taproot_pubkey_v1)\n", - "print('Segwit address:', segwit_address)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Run the cell below to check if you have correctly computed the TapTweak.**" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# This code uses the TapTree and TapLeaf classes to construct the same tweak as above\n", - "\n", - "tapleafA = TapLeaf()\n", - "tapleafB = TapLeaf()\n", - "tapleafC = TapLeaf()\n", - "taptree = TapTree()\n", - "\n", - "tapleafA.from_script(scriptA)\n", - "tapleafB.from_script(scriptB)\n", - "tapleafC.from_script(scriptC)\n", - "\n", - "tapbranchAB = Node()\n", - "tapbranchAB.left = tapleafA\n", - "tapbranchAB.right = tapleafB\n", - "\n", - "tapbranchABC = Node()\n", - "tapbranchABC.left = tapbranchAB\n", - "tapbranchABC.right = tapleafC\n", - "\n", - "taptree.root = tapbranchABC\n", - "taptree.key = internal_pubkey\n", - "\n", - "script_v1, tweak, c_map = taptree.construct()\n", - "print(\"TapTweak:\", tweak.hex())" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Programming Exercise 3.2 - Spending a Taproot Output along the Key Path.\n", - "\n", - "Now that we have understood how public keys can be tweaked to commit pay-to-pubkey scripts to a Segwit version 1 output, let us spend this output along the key path. Such as spend does not reveal the script commitments to the observer and is indistinguishable any other key path spend.\n", - "\n", - "* 1. Construct taproot output with tweaked public key.\n", - "* 2. Send funds from the wallet to the taproot output (Segwit Address).\n", - "* 3. Create and sign transaction which sends funds back to wallet with the tweaked private key.\n", - "\n", - "**Note: Most of the cells have been populated already. Simply tweak the pubkey and signing key.**" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Start TestNodes**" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Start TestNodes.\n", - "test = util.TestWrapper()\n", - "test.setup()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Generate Wallet Balance**" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Generate Coins for Bitcoin Node Wallet.\n", - "test.nodes[0].generate(101)\n", - "balance = test.nodes[0].getbalance()\n", - "print(balance)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**1) Construct taproot output with tweaked public key.**" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Create Tweaked Pubkey Output.\n", - "sec = ECKey()\n", - "sec.generate()\n", - "internal_pubkey = sec.get_pubkey()\n", - "\n", - "# Taptweak from example 2.3.1\n", - "taptweak = bytes.fromhex('2a2fb476ec9962f262ff358800db0e7364287340db73e5e48db36d1c9f374e30')\n", - "\n", - "# TODO: taproot_pubkey =\n", - "taproot_pubkey = internal_pubkey.tweak_add(taptweak) \n", - "taproot_pubkey_b = taproot_pubkey.get_bytes()\n", - "\n", - "# TODO: segwit_address =\n", - "taproot_pubkey_v1 = bytes([taproot_pubkey_b[0] & 1]) + taproot_pubkey_b[1:]\n", - "segwit_address = program_to_witness(1, taproot_pubkey_v1)\n", - "print(\"Segwit Address:\", segwit_address)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**2) Send funds from the wallet to the taproot output (Segwit Address).**" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Send funds to taproot output.\n", - "txid = test.nodes[0].sendtoaddress(segwit_address, balance / 100000)\n", - "print(\"Funding tx:\", txid)\n", - "\n", - "# Deserialize wallet transaction.\n", - "tx = CTransaction()\n", - "tx_hex = test.nodes[0].getrawtransaction(txid)\n", - "tx.deserialize(BytesIO(bytes.fromhex(tx_hex)))\n", - "tx.rehash()\n", - "\n", - "# Determine Output Index of Segwit V1 Output.\n", - "# (Wallet places change output at a random txout index.)\n", - "outputs = iter(tx.vout)\n", - "output = next(outputs)\n", - "index = 0\n", - "\n", - "while (output.scriptPubKey != CScript([OP_1, taproot_pubkey_v1])):\n", - " output = next(outputs)\n", - " index += 1\n", - "output_value = output.nValue" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**3) Spend taproot output with key path.**" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "tx_schnorr = CTransaction()\n", - "tx_schnorr.nVersion = 1\n", - "tx_schnorr.nLockTime = 0\n", - "outpoint = COutPoint(tx.sha256, index)\n", - "tx_schnorr_in = CTxIn(outpoint = outpoint)\n", - "tx_schnorr.vin = [tx_schnorr_in]\n", - "\n", - "# Generate new Bitcoin Core wallet address to send funds back to.\n", - "dest_addr = test.nodes[0].getnewaddress(address_type=\"bech32\")\n", - "scriptpubkey = bytes.fromhex(test.nodes[0].getaddressinfo(dest_addr)['scriptPubKey'])\n", - "\n", - "# Determine minimum fee required for mempool acceptance.\n", - "min_fee = int(test.nodes[0].getmempoolinfo()['mempoolminfee'] * 100000000)\n", - "\n", - "# Complete output which returns funds to Bitcoin Core wallet.\n", - "dest_output= CTxOut(nValue=output_value-min_fee, scriptPubKey=scriptpubkey)\n", - "tx_schnorr.vout = [dest_output]\n", - "\n", - "# Sign transaction with tweaked private key.\n", - "# TODO: sig =\n", - "hash_types = [0,1,2,3,0x81,0x82,0x83]\n", - "sighash = TaprootSignatureHash(tx_schnorr, [output], hash_types[0])\n", - "tweaked_sec = sec.add(taptweak)\n", - "sig = tweaked_sec.sign_schnorr(sighash)\n", - "\n", - "# Construct transaction witness.\n", - "witness = CScriptWitness()\n", - "witness.stack.append(sig)\n", - "witness_in = CTxInWitness()\n", - "witness_in.scriptWitness = witness\n", - "tx_schnorr.wit.vtxinwit.append(witness_in)\n", - "\n", - "# Serialize Schnorr transaction for broadcast.\n", - "tx_schnorr_str = tx_schnorr.serialize().hex()\n", - "\n", - "# Test mempool acceptance.\n", - "print(test.nodes[0].testmempoolaccept([tx_schnorr_str]))\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Shutdown TestNodes**" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Shutdown TestNodes.\n", - "test.shutdown()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.6.5" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/Solutions/2.2-TapTweak-Solutions.txt b/Solutions/2.2-TapTweak-Solutions.txt new file mode 100644 index 000000000..a14a59c8a --- /dev/null +++ b/Solutions/2.2-TapTweak-Solutions.txt @@ -0,0 +1,95 @@ +#### 1.3 Commutative property of scalar operations + +``` +a = random.randrange(1, SECP256K1_ORDER) +a_key = ECKey() +a_key.set(a.to_bytes(32,'big'), True) + +b = random.randrange(1, SECP256K1_ORDER) +b_key = ECKey() +b_key.set(b.to_bytes(32,'big'), True) + +# Left: Compute a + b +left_ab = (a + b) % SECP256K1_ORDER + +# Right: Compute b + a +right_ba = int().from_bytes((b_key + a_key).get_bytes(),'big') + +# Left/Right: Assert equality +assert left_ab == right_ba + +# Left: Compute a * b +left_ab = (a * b) % SECP256K1_ORDER + +# Right: Compute b * a +right_ba = int().from_bytes((b_key * a_key).get_bytes(),'big') + +# Left/Right: Assert equality +assert left_ab == right_ba +``` + +#### 1.4 Distributivity of scalar operations + +``` +a = random.randrange(1, SECP256K1_ORDER) +a_key = ECKey() +a_key.set(a.to_bytes(32,'big'), True) + +b = random.randrange(1, SECP256K1_ORDER) +b_key = ECKey() +b_key.set(b.to_bytes(32,'big'), True) + +c = random.randrange(1, SECP256K1_ORDER) +c_key = ECKey() +c_key.set(c.to_bytes(32,'big'), True) + +# Left: Compute (a - b) * c +ab = (a + (SECP256K1_ORDER - b)) % SECP256K1_ORDER +left_abc = (ab * c) % SECP256K1_ORDER + +# Right: Compute -b * c +# Negate a ECKey with negate() method. +b_key.negate() + +# Right: Compute a * c +ac_key = a_key * c_key +bc_key = b_key * c_key + +# Right: Compute a * c - b * c +ac_bc_key = ac_key + bc_key +right_abc = int().from_bytes(ac_bc_key.get_bytes(),'big') + +# Left/Right: Assert equality +assert left_abc == right_abc +print("Success!") +``` + +#### 1.6 Distributivity over scalars and points + +``` +a = ECKey() +b = ECKey() +c = ECKey() +a.generate() +b.generate() +c.generate() +C = c.get_pubkey() + +# Left: Compute a - b +a_minus_b = a - b + +# Left: Compute (a - b) * C +left = a_minus_b * C + +# Right: Compute a * C and (-b) * C +aC = a * C +bC = b * C + +# Right: Compute aC - bC +right = aC - bC + +# Left/Right: Assert equality +assert left.get_bytes() == right.get_bytes() +print("Success!") +``` + From a6446c071cef7596a0292531d4c7d5680d79714e Mon Sep 17 00:00:00 2001 From: Mike Schmidt Date: Fri, 20 Sep 2019 10:34:21 -0500 Subject: [PATCH 3/5] fixup solutions text --- Solutions/2.2-TapTweak-Solutions.txt | 238 ++++++++++++++++++--------- 1 file changed, 156 insertions(+), 82 deletions(-) diff --git a/Solutions/2.2-TapTweak-Solutions.txt b/Solutions/2.2-TapTweak-Solutions.txt index a14a59c8a..809478152 100644 --- a/Solutions/2.2-TapTweak-Solutions.txt +++ b/Solutions/2.2-TapTweak-Solutions.txt @@ -1,95 +1,169 @@ -#### 1.3 Commutative property of scalar operations +#### 1.2 - Signing with a tweaked 2-of-2 Musig key pairs ``` -a = random.randrange(1, SECP256K1_ORDER) -a_key = ECKey() -a_key.set(a.to_bytes(32,'big'), True) - -b = random.randrange(1, SECP256K1_ORDER) -b_key = ECKey() -b_key.set(b.to_bytes(32,'big'), True) - -# Left: Compute a + b -left_ab = (a + b) % SECP256K1_ORDER - -# Right: Compute b + a -right_ba = int().from_bytes((b_key + a_key).get_bytes(),'big') - -# Left/Right: Assert equality -assert left_ab == right_ba - -# Left: Compute a * b -left_ab = (a * b) % SECP256K1_ORDER - -# Right: Compute b * a -right_ba = int().from_bytes((b_key * a_key).get_bytes(),'big') - -# Left/Right: Assert equality -assert left_ab == right_ba +# A1) Generate Key Pairs. +privkey0 = ECKey() +privkey1 = ECKey() +privkey0.generate() +privkey1.generate() +pk0 = privkey0.get_pubkey() +pk1 = privkey1.get_pubkey() + +# A2) Aggregate all public keys: +c_map, pk_musig = generate_musig_key([pk0, pk1]) + +# A3) Apply challenge factors to keys. +privkey0_c = privkey0.mul(c_map[pk0]) +privkey1_c = privkey1.mul(c_map[pk1]) +pk0_c = pk0.mul(c_map[pk0]) +pk1_c = pk1.mul(c_map[pk1]) + +# B) Tweak musig public key. +# Given: Tweak. +tweak = hashlib.sha256(b'tweak').digest() +pk_musig_tweaked = pk_musig.tweak_add(tweak) + +# C1) Nonce generation & aggregation. +k0 = generate_schnorr_nonce() +k1 = generate_schnorr_nonce() +R0 = k0.get_pubkey() +R1 = k1.get_pubkey() +R_agg, negated = aggregate_schnorr_nonces([R0, R1]) +if negated: + k0.negate() + k1.negate() + +# C2) Signing and signature aggregation. +msg = hashlib.sha256(b'msg').digest() + +# One person must tweak keys. +privkey0_c_tweaked = privkey0_c.add(tweak) + +sig0 = sign_musig(privkey0_c_tweaked, k0, R_agg, pk_musig_tweaked, msg) +sig1 = sign_musig(privkey1_c, k1, R_agg, pk_musig_tweaked, msg) +sig_agg = aggregate_musig_signatures([sig0, sig1]) +pk_musig_tweaked.verify_schnorr(sig_agg, msg) ``` -#### 1.4 Distributivity of scalar operations +#### 3.1 - Constructing a TapTweak from TapScripts ``` -a = random.randrange(1, SECP256K1_ORDER) -a_key = ECKey() -a_key.set(a.to_bytes(32,'big'), True) - -b = random.randrange(1, SECP256K1_ORDER) -b_key = ECKey() -b_key.set(b.to_bytes(32,'big'), True) - -c = random.randrange(1, SECP256K1_ORDER) -c_key = ECKey() -c_key.set(c.to_bytes(32,'big'), True) - -# Left: Compute (a - b) * c -ab = (a + (SECP256K1_ORDER - b)) % SECP256K1_ORDER -left_abc = (ab * c) % SECP256K1_ORDER - -# Right: Compute -b * c -# Negate a ECKey with negate() method. -b_key.negate() +TAPSCRIPT_VER = bytes([0xc0]) # See TapScript chapter for more details. +internal_pubkey = ECPubKey() +internal_pubkey.set(bytes.fromhex('03af455f4989d122e9185f8c351dbaecd13adca3eef8a9d38ef8ffed6867e342e3')) + +# Derive pay-to-pubkey scripts. +privkeyA = ECKey() +privkeyB = ECKey() +privkeyC = ECKey() +privkeyA.generate() +privkeyB.generate() +privkeyC.generate() +pkA = privkeyA.get_pubkey() +pkB = privkeyA.get_pubkey() +pkC = privkeyA.get_pubkey() +scriptA = CScript([pkA.get_bytes(), OP_CHECKSIG]) +scriptB = CScript([pkB.get_bytes(), OP_CHECKSIG]) +scriptC = CScript([pkC.get_bytes(), OP_CHECKSIG]) + +# Method: Returns Tagged Hash. +def tagged_hash(tag, input_data): + data = hashlib.sha256(tag.encode('utf-8')).digest() + data += data + data += input_data + return hashlib.sha256(data).digest() + +# Method: Returns TapBranch hash. +def tapbranch(taggedhash_left, taggedhash_right): + if taggedhash_left > taggedhash_right: + taggedhash_left, taggedhash_right = taggedhash_right, taggedhash_left + return tagged_hash("TapBranch", taggedhash_left + taggedhash_right) + +# 1) Compute TapLeafs A, B and C. +# Note: ser_string(data) is a function which adds compactsize to input data. +hash_inputA = TAPSCRIPT_VER + ser_string(scriptA) +hash_inputB = TAPSCRIPT_VER + ser_string(scriptB) +hash_inputC = TAPSCRIPT_VER + ser_string(scriptC) +taggedhash_leafA = tagged_hash("TapLeaf", hash_inputA) +taggedhash_leafB = tagged_hash("TapLeaf", hash_inputB) +taggedhash_leafC = tagged_hash("TapLeaf", hash_inputC) + +# 2) Compute Internal node TapBranch AB. +internal_nodeAB = tapbranch(taggedhash_leafA, taggedhash_leafB) + +# 3) Compute TapTweak. +rootABC = tapbranch(internal_nodeAB, taggedhash_leafC) +taptweak = tagged_hash("TapTweak", internal_pubkey.get_bytes() + rootABC) +print("TapTweak:", taptweak.hex()) + +# 4) Derive the segwit output address. +taproot_pubkey_b = internal_pubkey.tweak_add(taptweak).get_bytes() +taproot_pubkey_v1 = bytes([taproot_pubkey_b[0] & 1]) + taproot_pubkey_b[1:] +segwit_address = program_to_witness(1, taproot_pubkey_v1) +print('Segwit address:', segwit_address) +``` -# Right: Compute a * c -ac_key = a_key * c_key -bc_key = b_key * c_key +#### 3.2 - Spending a Taproot Output along the Key Path -# Right: Compute a * c - b * c -ac_bc_key = ac_key + bc_key -right_abc = int().from_bytes(ac_bc_key.get_bytes(),'big') +##### 1) Construct taproot output with tweaked public key -# Left/Right: Assert equality -assert left_abc == right_abc -print("Success!") +``` +# Create Tweaked Pubkey Output. +sec = ECKey() +sec.generate() +internal_pubkey = sec.get_pubkey() + +# Taptweak from example 2.3.1 +taptweak = bytes.fromhex('2a2fb476ec9962f262ff358800db0e7364287340db73e5e48db36d1c9f374e30') + +# TODO: taproot_pubkey = +taproot_pubkey = internal_pubkey.tweak_add(taptweak) +taproot_pubkey_b = taproot_pubkey.get_bytes() + +# TODO: segwit_address = +taproot_pubkey_v1 = bytes([taproot_pubkey_b[0] & 1]) + taproot_pubkey_b[1:] +segwit_address = program_to_witness(1, taproot_pubkey_v1) +print("Segwit Address:", segwit_address) ``` -#### 1.6 Distributivity over scalars and points +##### 3) Spend taproot output with key path ``` -a = ECKey() -b = ECKey() -c = ECKey() -a.generate() -b.generate() -c.generate() -C = c.get_pubkey() - -# Left: Compute a - b -a_minus_b = a - b - -# Left: Compute (a - b) * C -left = a_minus_b * C - -# Right: Compute a * C and (-b) * C -aC = a * C -bC = b * C - -# Right: Compute aC - bC -right = aC - bC - -# Left/Right: Assert equality -assert left.get_bytes() == right.get_bytes() -print("Success!") -``` - +tx_schnorr = CTransaction() +tx_schnorr.nVersion = 1 +tx_schnorr.nLockTime = 0 +outpoint = COutPoint(tx.sha256, index) +tx_schnorr_in = CTxIn(outpoint = outpoint) +tx_schnorr.vin = [tx_schnorr_in] + +# Generate new Bitcoin Core wallet address to send funds back to. +dest_addr = test.nodes[0].getnewaddress(address_type="bech32") +scriptpubkey = bytes.fromhex(test.nodes[0].getaddressinfo(dest_addr)['scriptPubKey']) + +# Determine minimum fee required for mempool acceptance. +min_fee = int(test.nodes[0].getmempoolinfo()['mempoolminfee'] * 100000000) + +# Complete output which returns funds to Bitcoin Core wallet. +dest_output= CTxOut(nValue=output_value-min_fee, scriptPubKey=scriptpubkey) +tx_schnorr.vout = [dest_output] + +# Sign transaction with tweaked private key. +# TODO: sig = +hash_types = [0,1,2,3,0x81,0x82,0x83] +sighash = TaprootSignatureHash(tx_schnorr, [output], hash_types[0]) +tweaked_sec = sec.add(taptweak) +sig = tweaked_sec.sign_schnorr(sighash) + +# Construct transaction witness. +witness = CScriptWitness() +witness.stack.append(sig) +witness_in = CTxInWitness() +witness_in.scriptWitness = witness +tx_schnorr.wit.vtxinwit.append(witness_in) + +# Serialize Schnorr transaction for broadcast. +tx_schnorr_str = tx_schnorr.serialize().hex() + +# Test mempool acceptance. +print(test.nodes[0].testmempoolaccept([tx_schnorr_str])) +``` \ No newline at end of file From c5a8637163f862ba91baed8eaaa506cff8dad406 Mon Sep 17 00:00:00 2001 From: John Newbery Date: Sat, 21 Sep 2019 15:18:56 -0700 Subject: [PATCH 4/5] Chapter 2.2: address elichai feedback --- 2.2-TapTweak.ipynb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/2.2-TapTweak.ipynb b/2.2-TapTweak.ipynb index 255990915..c3438449c 100644 --- a/2.2-TapTweak.ipynb +++ b/2.2-TapTweak.ipynb @@ -6,16 +6,16 @@ "metadata": {}, "outputs": [], "source": [ - "from io import BytesIO\n", "import hashlib\n", + "from io import BytesIO\n", "import random\n", "\n", "import util\n", + "from test_framework.address import program_to_witness\n", "from test_framework.key import ECKey, ECPubKey, SECP256K1_ORDER, generate_schnorr_nonce\n", - "from test_framework.musig import generate_musig_key, aggregate_schnorr_nonces, sign_musig, aggregate_musig_signatures\n", - "from test_framework.script import CScript, OP_1, OP_CHECKSIG, TaprootSignatureHash, TapLeaf, TapTree, Node\n", "from test_framework.messages import CTransaction, COutPoint, CTxIn, CTxOut, CScriptWitness, CTxInWitness, ser_string\n", - "from test_framework.address import program_to_witness" + "from test_framework.musig import generate_musig_key, aggregate_schnorr_nonces, sign_musig, aggregate_musig_signatures\n", + "from test_framework.script import CScript, OP_1, OP_CHECKSIG, TaprootSignatureHash, TapLeaf, TapTree, Node" ] }, { @@ -35,7 +35,7 @@ "\n", "* `[01] [33B Tweaked Public Key]`\n", "\n", - "Tweaking a public key means to alter it with a value (the tweak) so that it remains spendable with knowledge of the original private key and tweak. \n", + "Tweaking a public key means to alter it with a value (the tweak) such that it remains spendable with knowledge of the original private key and tweak. \n", "\n", "* Output Script: `[01] [P + T]` = `[01] [xG + tG]`\n", "* Spendable by: `x + t`\n", @@ -161,7 +161,7 @@ "\n", "* A) Tweaking the public key to obtain: `Point Q`\n", "* B) Create a new tweak for the same point Q: `t'`\n", - "* C) Solve for `x'` so that `x'G + t'G = Q`" + "* C) Solve for `x'` such that `x'G + t'G = Q`" ] }, { From 719bdef20ffb00768e89b7118cde5f61819d5b50 Mon Sep 17 00:00:00 2001 From: John Newbery Date: Sat, 21 Sep 2019 15:42:27 -0700 Subject: [PATCH 5/5] chapter 2.2: remove empty last cell --- 2.2-TapTweak.ipynb | 7 ------- 1 file changed, 7 deletions(-) diff --git a/2.2-TapTweak.ipynb b/2.2-TapTweak.ipynb index c3438449c..d94dc5cf5 100644 --- a/2.2-TapTweak.ipynb +++ b/2.2-TapTweak.ipynb @@ -572,13 +572,6 @@ "# Shutdown TestNodes.\n", "test.shutdown()" ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": {