|
10 | 10 | "import random\n",
|
11 | 11 | "\n",
|
12 | 12 | "import util\n",
|
13 |
| - "from test_framework.key import generate_key_pair, generate_schnorr_nonce, ECKey, ECPubKey, SECP256K1_FIELD_SIZE\n", |
| 13 | + "from test_framework.key import generate_key_pair, generate_bip340_key_pair, generate_schnorr_nonce, ECKey, ECPubKey, SECP256K1_FIELD_SIZE, SECP256K1, SECP256K1_ORDER\n", |
14 | 14 | "from test_framework.musig import aggregate_musig_signatures, aggregate_schnorr_nonces, generate_musig_key, musig_digest, sign_musig\n",
|
15 | 15 | "from test_framework.script import TapLeaf, TapTree, TaprootSignatureHash, SIGHASH_ALL_TAPROOT\n",
|
16 | 16 | "from test_framework.address import program_to_witness\n",
|
|
104 | 104 | "outputs": [],
|
105 | 105 | "source": [
|
106 | 106 | "# Generate main wallet key pairs\n",
|
107 |
| - "main_privkeyA, main_pubkeyA = generate_key_pair()\n", |
108 |
| - "main_privkeyB, main_pubkeyB = generate_key_pair()\n", |
109 |
| - "main_privkeyC, main_pubkeyC = generate_key_pair()\n", |
| 107 | + "main_privkeyA, main_pubkeyA = generate_bip340_key_pair()\n", |
| 108 | + "main_privkeyB, main_pubkeyB = generate_bip340_key_pair()\n", |
| 109 | + "main_privkeyC, main_pubkeyC = generate_bip340_key_pair()\n", |
110 | 110 | "main_pubkeys = [main_pubkeyA.get_bytes().hex(),\n",
|
111 | 111 | " main_pubkeyB.get_bytes().hex(), \n",
|
112 | 112 | " main_pubkeyC.get_bytes().hex()]\n",
|
113 | 113 | "\n",
|
114 | 114 | "print(\"Main pubkeys: {}\\n\".format(main_pubkeys))\n",
|
115 | 115 | "\n",
|
116 | 116 | "# Generate back-up wallet key pairs\n",
|
117 |
| - "backup_privkeyD, backup_pubkeyD = generate_key_pair()\n", |
118 |
| - "backup_privkeyE, backup_pubkeyE = generate_key_pair()\n", |
| 117 | + "backup_privkeyD, backup_pubkeyD = generate_bip340_key_pair()\n", |
| 118 | + "backup_privkeyE, backup_pubkeyE = generate_bip340_key_pair()\n", |
119 | 119 | "backup_pubkeys = [backup_pubkeyD.get_bytes().hex(),\n",
|
120 | 120 | " backup_pubkeyE.get_bytes().hex()]\n",
|
121 | 121 | "\n",
|
|
130 | 130 | "main_pubkeyB_c = main_pubkeyA.mul(c_map[main_pubkeyB])\n",
|
131 | 131 | "main_pubkeyC_c = main_pubkeyA.mul(c_map[main_pubkeyC])\n",
|
132 | 132 | "\n",
|
| 133 | + "if musig_ABC.get_y()%2 != 0:\n", |
| 134 | + " musig_ABC.negate()\n", |
| 135 | + " main_privkeyA_c.negate()\n", |
| 136 | + " main_privkeyB_c.negate()\n", |
| 137 | + " main_privkeyC_c.negate()\n", |
| 138 | + " main_pubkeyA_c.negate()\n", |
| 139 | + " main_pubkeyB_c.negate()\n", |
| 140 | + " main_pubkeyC_c.negate()\n", |
| 141 | + "\n", |
133 | 142 | "print(\"MuSig pubkey: {}\".format(musig_ABC.get_bytes().hex()))"
|
134 | 143 | ]
|
135 | 144 | },
|
|
180 | 189 | "taptweak = int.from_bytes(taptweak, 'big')\n",
|
181 | 190 | "output_pubkey = musig_ABC.tweak_add(taptweak)\n",
|
182 | 191 | "output_pubkey_b = output_pubkey.get_bytes()\n",
|
183 |
| - "taproot_pubkey_v1 = bytes([output_pubkey_b[0] & 1]) + output_pubkey_b[1:]\n", |
184 | 192 | "segwit_address = # TODO: implement\n",
|
185 | 193 | "print(\"Segwit Address:\", segwit_address)"
|
186 | 194 | ]
|
|
234 | 242 | "outputs": [],
|
235 | 243 | "source": [
|
236 | 244 | "# Send funds to taproot output.\n",
|
237 |
| - "txid = test.nodes[0].sendtoaddress(segwit_address, 0.5)\n", |
| 245 | + "txid = test.nodes[0].sendtoaddress(address=segwit_address, amount=0.5, fee_rate=25)\n", |
238 | 246 | "print(\"Funding tx:\", txid)\n",
|
239 | 247 | "\n",
|
240 | 248 | "# Deserialize wallet transaction.\n",
|
|
243 | 251 | "tx.deserialize(BytesIO(bytes.fromhex(tx_hex)))\n",
|
244 | 252 | "tx.rehash()\n",
|
245 | 253 | "\n",
|
| 254 | + "print(tapscript.hex())\n", |
| 255 | + "\n", |
| 256 | + "print(tx.vout)\n", |
| 257 | + "\n", |
246 | 258 | "# The wallet randomizes the change output index for privacy\n",
|
247 | 259 | "# Loop through the outputs and return the first where the scriptPubKey matches the segwit v1 output\n",
|
248 | 260 | "output_index, output = next(out for out in enumerate(tx.vout) if out[1].scriptPubKey == tapscript)\n",
|
|
333 | 345 | "source": [
|
334 | 346 | "#### 3.1.4 _Programming Exercise:_ Create a valid key path output\n",
|
335 | 347 | "\n",
|
336 |
| - "In this exercise, we'll spend the taproot output using the key path." |
| 348 | + "In this exercise, we'll spend the taproot output using the key path. Since the key path is used, there is no control block to indicate whether or not the public key (Q) has an even or odd y-coordinate and so it is assumed that the y-coordinate is odd. Therefore, if Q needs to be negated, then so do all the private keys as well as the tweak." |
337 | 349 | ]
|
338 | 350 | },
|
339 | 351 | {
|
|
342 | 354 | "metadata": {},
|
343 | 355 | "outputs": [],
|
344 | 356 | "source": [
|
| 357 | + "# Negate keys if necessary\n", |
| 358 | + "output_keyPath = output_pubkey\n", |
| 359 | + "privKeyA_keyPath = main_privkeyA_c\n", |
| 360 | + "privKeyB_keyPath = main_privkeyB_c\n", |
| 361 | + "privKeyC_keyPath = main_privkeyC_c\n", |
| 362 | + "tweak_keyPath = taptweak\n", |
| 363 | + "\n", |
| 364 | + "if output_keyPath.get_y()%2 != 0:\n", |
| 365 | + " output_keyPath.negate()\n", |
| 366 | + " privKeyA_keyPath.negate()\n", |
| 367 | + " privKeyB_keyPath.negate()\n", |
| 368 | + " privKeyC_keyPath.negate()\n", |
| 369 | + " tweak_keyPath = SECP256K1_ORDER - taptweak\n", |
| 370 | + "\n", |
345 | 371 | "# Create sighash for ALL\n",
|
346 | 372 | "sighash_musig = # TODO: implement\n",
|
347 | 373 | " \n",
|
|
354 | 380 | "sig_agg = # TODO: implement\n",
|
355 | 381 | "print(\"Aggregate signature is {}\\n\".format(sig_agg.hex()))\n",
|
356 | 382 | "\n",
|
357 |
| - "assert output_pubkey.verify_schnorr(sig_agg, sighash_musig)\n", |
| 383 | + "assert output_keyPath.verify_schnorr(sig_agg, sighash_musig)\n", |
358 | 384 | "\n",
|
359 | 385 | "# Construct transaction witness\n",
|
360 | 386 | "spending_tx.wit.vtxinwit.append( # TODO: implement\n",
|
|
395 | 421 | "spending_tx.vin = [spending_tx_in]\n",
|
396 | 422 | "spending_tx.vout = [dest_output]\n",
|
397 | 423 | "\n",
|
398 |
| - "sighash = TaprootSignatureHash(spending_tx, [output], SIGHASH_ALL_TAPROOT, 0, scriptpath=True, tapscript=tapscript_2a.script)\n", |
| 424 | + "sighash = TaprootSignatureHash(spending_tx, [output], SIGHASH_ALL_TAPROOT, 0, scriptpath=True, script=tapscript_2a.script)\n", |
399 | 425 | "\n",
|
400 | 426 | "witness_elements = []\n",
|
401 | 427 | "\n",
|
|
412 | 438 | "\n",
|
413 | 439 | "# Test timelock\n",
|
414 | 440 | "assert_equal(\n",
|
415 |
| - " [{'txid': spending_tx.rehash(), 'allowed': False, 'reject-reason': '64: non-BIP68-final'}],\n", |
| 441 | + " [{'txid': spending_tx.rehash(), 'allowed': False, 'reject-reason': 'non-BIP68-final'}],\n", |
416 | 442 | " test.nodes[0].testmempoolaccept([spending_tx_str])\n",
|
417 | 443 | ")\n",
|
418 | 444 | "\n",
|
|
474 | 500 | "spending_tx.vin = [spending_tx_in]\n",
|
475 | 501 | "spending_tx.vout = [dest_output]\n",
|
476 | 502 | "\n",
|
477 |
| - "# Derive the sighash. Use tapscript_3a\n", |
| 503 | + "# Derive the sighash. Use tapscript_3a.\n", |
478 | 504 | "sighash = # TODO: implement\n",
|
479 | 505 | "\n",
|
480 | 506 | "witness_elements = []\n",
|
|
483 | 509 | "# Remember to reverse the order of signatures\n",
|
484 | 510 | "witness_elements = # TODO: implement\n",
|
485 | 511 | "\n",
|
486 |
| - "# Add witness to transaction\n", |
| 512 | + "# Construct transaction witness\n", |
487 | 513 | "spending_tx.wit.vtxinwit.append(CTxInWitness(witness_elements))\n",
|
488 | 514 | "spending_tx_str = spending_tx.serialize().hex()\n",
|
489 | 515 | "\n",
|
490 | 516 | "# Test timelock\n",
|
491 | 517 | "assert_equal(\n",
|
492 |
| - " [{'txid': spending_tx.rehash(), 'allowed': False, 'reject-reason': '64: non-BIP68-final'}],\n", |
| 518 | + " [{'txid': spending_tx.rehash(), 'allowed': False, 'reject-reason': 'non-BIP68-final'}],\n", |
493 | 519 | " test.nodes[0].testmempoolaccept([spending_tx_str])\n",
|
494 | 520 | ")\n",
|
495 | 521 | "\n",
|
|
0 commit comments