sol: Schnorr signature

Signed-off-by: Vincenzo Palazzo <vincenzopalazzodev@gmail.com>
This commit is contained in:
Vincenzo Palazzo 2023-10-18 16:10:09 +02:00
parent b0ecc1583e
commit 8e89ab0b18
Signed by: vincenzopalazzo
GPG Key ID: 8B6DC2B870B80D5F
4 changed files with 721 additions and 147 deletions

View File

@ -19,7 +19,7 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 1,
"id": "8dadf5e6",
"metadata": {
"slideshow": {
@ -41,14 +41,22 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 2,
"id": "1e49bfe0",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"233a1e9353c5f782c96c1c08323fe9fca47ad161ee69d008846b68625c221113\n"
]
}
],
"source": [
"# Example Tagged Hashes\n",
"from hash import sha256\n",
@ -76,10 +84,18 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 3,
"id": "f5b2d003",
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"1d721a19d161e978e7436d9e73bb810a0a32cbdffc7a9b29e11713b1940a4126\n"
]
}
],
"source": [
"# Exercise 1\n",
"\n",
@ -113,10 +129,22 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 4,
"id": "24346452",
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
".\n",
"----------------------------------------------------------------------\n",
"Ran 1 test in 0.000s\n",
"\n",
"OK\n"
]
}
],
"source": [
"# Exercise 2\n",
"\n",
@ -143,14 +171,23 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 5,
"id": "87fa62d1",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"f01d6b9018ab421dd410404cb869072065522bf85734008f105cf385a023a80f\n",
"True\n"
]
}
],
"source": [
"# Example X-only pubkey\n",
"from ecc import PrivateKey, S256Point\n",
@ -178,10 +215,18 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 6,
"id": "1d4b0f3b",
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"e79c4eb45764bd015542f6779cc70fef44b7a2432f839264768288efab886291\n"
]
}
],
"source": [
"# Exercise 3\n",
"\n",
@ -215,10 +260,22 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 7,
"id": "c3c8ebf9",
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
".\n",
"----------------------------------------------------------------------\n",
"Ran 1 test in 0.000s\n",
"\n",
"OK\n"
]
}
],
"source": [
"# Exercise 4\n",
"\n",
@ -243,14 +300,22 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 8,
"id": "fc90c449",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"True\n"
]
}
],
"source": [
"from ecc import S256Point, SchnorrSignature, G, N\n",
"from helper import sha256, big_endian_to_int\n",
@ -293,10 +358,18 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 9,
"id": "1f3c774d",
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"True\n"
]
}
],
"source": [
"# Exercise 5\n",
"\n",
@ -335,10 +408,22 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 10,
"id": "9d511cfd",
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
".\n",
"----------------------------------------------------------------------\n",
"Ran 1 test in 0.111s\n",
"\n",
"OK\n"
]
}
],
"source": [
"# Exercise 6\n",
"\n",
@ -364,14 +449,22 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 11,
"id": "3eb5a3c9",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"f3626c99fe36167e5fef6b95e5ed6e5687caa4dc828986a7de8f9423c0f77f9bc73091ed86085ce43de0e255b3d0afafc7eee41ddc9970c3dc8472acfcdfd39a\n"
]
}
],
"source": [
"# Example Signing\n",
"from ecc import PrivateKey, N, G\n",
@ -413,10 +506,18 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 12,
"id": "7914103c",
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"5ad2703f5b4f4b9dea4c28fa30d86d3781d28e09dd51aae1208de80bb6155bee7d9dee36de5540efd633445a8d743816cbbc15fb8a1c7768984190d5b873a341\n"
]
}
],
"source": [
"# Exercise 7\n",
"\n",
@ -475,10 +576,22 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 13,
"id": "b6b3bc50",
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
".\n",
"----------------------------------------------------------------------\n",
"Ran 1 test in 0.230s\n",
"\n",
"OK\n"
]
}
],
"source": [
"# Exercise 8\n",
"\n",
@ -530,10 +643,18 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 14,
"id": "0af3fd1e",
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"True\n"
]
}
],
"source": [
"# Exercise 9\n",
"\n",
@ -587,14 +708,22 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 15,
"id": "8792cf7d",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"OP_1 578444b411276eee17e2f69988d192b7e728f4375525a868f4a9c2b78e12af16\n"
]
}
],
"source": [
"# Example Q calculation for a single-key\n",
"from ecc import S256Point, G\n",
@ -626,10 +755,18 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 16,
"id": "2b2607d1",
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"OP_1 a6b9f4b7999f9c6de76165342c9feac354d5d3062a41761ed1616eaf9e3c38ec\n"
]
}
],
"source": [
"# Exercise 10\n",
"\n",
@ -669,10 +806,22 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 17,
"id": "a64dbec3",
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
".\n",
"----------------------------------------------------------------------\n",
"Ran 1 test in 0.001s\n",
"\n",
"OK\n"
]
}
],
"source": [
"# Exercise 11\n",
"\n",
@ -699,10 +848,22 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 18,
"id": "677255f7",
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
".\n",
"----------------------------------------------------------------------\n",
"Ran 1 test in 0.057s\n",
"\n",
"OK\n"
]
}
],
"source": [
"# Exercise 12\n",
"\n",
@ -729,10 +890,22 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 19,
"id": "b6de5731",
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
".\n",
"----------------------------------------------------------------------\n",
"Ran 1 test in 0.057s\n",
"\n",
"OK\n"
]
}
],
"source": [
"# Exercise 13\n",
"\n",
@ -760,14 +933,23 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 20,
"id": "cb17ebfd",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"bc1p27zyfdq3yahwu9lz76vc35vjklnj3aph25j6s68548pt0rsj4utql46j72\n",
"tb1p27zyfdq3yahwu9lz76vc35vjklnj3aph25j6s68548pt0rsj4utqgavay9\n"
]
}
],
"source": [
"# Example of getting a p2tr address\n",
"from ecc import S256Point\n",
@ -796,10 +978,18 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 21,
"id": "fb7d63c5",
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"tb1pfx2ys8pzcg0mdufk9v25hphv85zgjpv5kyn6uevdmfmvdsw0ea0qyvv87u\n"
]
}
],
"source": [
"# Exercise 14\n",
"\n",
@ -832,14 +1022,22 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 22,
"id": "f4442ec9",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"010000000001019569365ed633a71a12ad889235f2f0e7509ffa53e510c25f46241063d76418870000000000ffffffff012c4c0000000000002251205f401f8ef325e3601e93f357ba33014416b7e5877a6ae69e68c8438bd522e1f601403697a0f0f49a451668b9b0361ec7c3b857299f0f80b8ce8c50e1d3cc87f44382de2b6eeccabe0efda3b1639841c342fce64ba28a2a018d4a9a69f5e7a0d43f6b00000000\n"
]
}
],
"source": [
"# Spending from a p2tr\n",
"from ecc import PrivateKey, N\n",
@ -883,10 +1081,22 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 23,
"id": "adececcf",
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
".\n",
"----------------------------------------------------------------------\n",
"Ran 1 test in 0.104s\n",
"\n",
"OK\n"
]
}
],
"source": [
"# Exercise 15\n",
"\n",
@ -915,10 +1125,18 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 24,
"id": "76abb9c7",
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"01000000000101376afebcc53dd694c99c5674846909881f790145948cb820b1f61f89486309250000000000ffffffff02409c000000000000160014f5a74a3131dedb57a092ae86aad3ee3f9b8d72146ce80000000000002251204994481c22c21fb6f1362b154b86ec3d04890594b127ae658dda76c6c1cfcf5e014002de2a8a88783937f10742235dfdf6a0f9526f4e8eee9d3d4cd11d5813269a0d1b56b5028b81735dae9d3dd9b9f2fe2193474dba0569cff087c2575f0f8f5b5f00000000\n"
]
}
],
"source": [
"# Exercise 16\n",
"\n",
@ -989,10 +1207,22 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 25,
"id": "54fcb4e1",
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
".\n",
"----------------------------------------------------------------------\n",
"Ran 1 test in 0.666s\n",
"\n",
"OK\n"
]
}
],
"source": [
"# Exercise 17\n",
"\n",
@ -1018,14 +1248,25 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 26,
"id": "d2e4b852",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"331a8f6a14e1b41a6b523ddb505fbc0662a6446bd42408692497297d3474aeec OP_CHECKSIG\n",
"331a8f6a14e1b41a6b523ddb505fbc0662a6446bd42408692497297d3474aeec OP_CHECKSIGVERIFY 158a49d62c384c539a453e41a70214cfb85184954ae5c8df4b47eb74d58ff16f OP_CHECKSIG\n",
"331a8f6a14e1b41a6b523ddb505fbc0662a6446bd42408692497297d3474aeec OP_CHECKSIGVERIFY 158a49d62c384c539a453e41a70214cfb85184954ae5c8df4b47eb74d58ff16f OP_CHECKSIGADD 582662e8e47df59489d6756615aa3db3fa3bbaa75a424b9c78036265858f5544 OP_CHECKSIGADD OP_2 OP_EQUAL\n",
"40d10c OP_CHECKLOCKTIMEVERIFY OP_DROP 331a8f6a14e1b41a6b523ddb505fbc0662a6446bd42408692497297d3474aeec OP_CHECKSIG\n"
]
}
],
"source": [
"# Example TapScripts\n",
"from ecc import PrivateKey\n",
@ -1065,10 +1306,18 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 27,
"id": "24f90fb9",
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"134ba4d9c35a66017e9d525a879700a9fb9209a3f43a651fdaf71f3a085a77d3 OP_CHECKSIGVERIFY 027aa71d9cdb31cd8fe037a6f441e624fe478a2deece7affa840312b14e971a4 OP_CHECKSIGVERIFY 165cfd87a31d8fab4431c955b0462804f1ba79b41970ab7e8b0e4e4686f5f8b4 OP_CHECKSIGVERIFY 9e5f5a5c29d33c32185a3dc0a9ccb3e72743744dd869dd40b6265a23fd84a402 OP_CHECKSIG\n"
]
}
],
"source": [
"# Exercise 18\n",
"\n",
@ -1102,14 +1351,22 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 28,
"id": "b5262af4",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"d1b3ee8e8c175e5db7e2ff7a87435e8f751d148b77fb1f00e14ff8ffa1c09a40\n"
]
}
],
"source": [
"# Example of making a TapLeaf and calculating the hash\n",
"from ecc import PrivateKey\n",
@ -1141,10 +1398,18 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 29,
"id": "65e33b7f",
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"0787f5aba506f118a90cefaf00ccfdb2785cf5998d40c3d43ebfaa5b4c6bcb7d\n"
]
}
],
"source": [
"# Exercise 19\n",
"\n",
@ -1185,10 +1450,22 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 30,
"id": "bfb6dad1",
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
".\n",
"----------------------------------------------------------------------\n",
"Ran 1 test in 0.000s\n",
"\n",
"OK\n"
]
}
],
"source": [
"# Exercise 20\n",
"\n",
@ -1214,14 +1491,22 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 31,
"id": "aeee7a5a",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"60f57015577d9cc2326d980355bc0896c80a9f94dc692d8738069bc05895634c\n"
]
}
],
"source": [
"from ecc import PrivateKey\n",
"from hash import hash_tapbranch\n",
@ -1262,10 +1547,18 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 32,
"id": "b1719cda",
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"f938d6fa5e3335e540f07a4007ee296640a977c89178aca79f15f2ec6acc14b6\n"
]
}
],
"source": [
"# Exercise 21\n",
"\n",
@ -1316,10 +1609,22 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 33,
"id": "90998eb1",
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
".\n",
"----------------------------------------------------------------------\n",
"Ran 1 test in 0.001s\n",
"\n",
"OK\n"
]
}
],
"source": [
"# Exercise 22\n",
"\n",
@ -1345,14 +1650,22 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 34,
"id": "e6775fbc",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"f53fab2e9cf0a458609226b4c42d5c0264700cdf33850c2b1423543a44ad4234\n"
]
}
],
"source": [
"# Example of Comupting the Merkle Root\n",
"from ecc import PrivateKey\n",
@ -1391,10 +1704,18 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 35,
"id": "59b96bf1",
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"8b9f09cd4a33e62b0c9d086056bbdeb7a218c1e4830291b9be56841b31d94ccb\n"
]
}
],
"source": [
"# Exercise 23\n",
"\n",
@ -1462,14 +1783,23 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 36,
"id": "4eba16fa",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"True\n",
"tb1pe0jrx2y2u8hdu8eysx8ssprdfej8lmuq3namllrazrey56vwan7s5j2wr8\n"
]
}
],
"source": [
"# Example of Control Block Validation\n",
"from ecc import PrivateKey, S256Point\n",
@ -1510,10 +1840,18 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 37,
"id": "9f876c91",
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"True\n"
]
}
],
"source": [
"# Exercise 24\n",
"\n",
@ -1562,10 +1900,22 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 38,
"id": "b689f58b",
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
".\n",
"----------------------------------------------------------------------\n",
"Ran 1 test in 0.043s\n",
"\n",
"OK\n"
]
}
],
"source": [
"# Exercise 25\n",
"\n",
@ -1597,10 +1947,18 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 39,
"id": "a14e3ae5",
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"tb1pxh7kypwsvxnat0z6588pufhx43r2fnqjyn846qj5kx8mgqcamvjsyn5cjg\n"
]
}
],
"source": [
"# Exercise 26\n",
"\n",
@ -1651,10 +2009,18 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 40,
"id": "2062d3a2",
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"010000000001019c5a863b077030fd35b0c8170ae698d23c9a2f1e0873c466621739c4954480690100000000ffffffff0178e600000000000022512035fd6205d061a7d5bc5aa1ce1e26e6ac46a4cc1224cf5d0254b18fb4031ddb250140b33905727e316ab7fc8c2816761d61af9f1c535cee632a210642f07d619af632c6df51d63099be31e6d12ecd2a465543861eab6e53feb09ccd49288bda1cb8f600000000\n"
]
}
],
"source": [
"# Exercise 27\n",
"\n",
@ -1706,10 +2072,19 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 41,
"id": "fb786518",
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"True\n",
"01000000000101a2b85a1372be6bc9a3d53110a4f142819d653fa6d07fbd4367138145030914200000000000ffffffff0184e4000000000000160014f5a74a3131dedb57a092ae86aad3ee3f9b8d721403403b1681a67f40e6767b2db64744ad3f005d3971645135d58a3e1826d5c960bc281ce187bc9270c51ed7833fcf5e8415501862d51b0ebd051917d9878104778f292220cd04c1bf88ca891af152fc57c36523ab59efb16b7ec07caca0cfc4a1f2051d9eac61c0cd04c1bf88ca891af152fc57c36523ab59efb16b7ec07caca0cfc4a1f2051d9e76f5c1cdfc8b07dc8edca5bef2b4991201c5a0e18b1dbbcfe00ef2295b8f6dffaf5548715217f7a892c7c5ff787a97b6e2f123287a1a354fe3ccda09c39d5d7300000000\n"
]
}
],
"source": [
"# Exercise 28\n",
"\n",
@ -1761,7 +2136,25 @@
]
}
],
"metadata": {},
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"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.11.5"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View File

@ -271,9 +271,12 @@ class S256Point(Point):
def xonly(self):
"""returns the binary version of X-only pubkey"""
# if x is None, return 32 0 bytes
if self.x is None:
return b"\x00" * 32
# otherwise, convert the x coordinate to Big Endian 32 bytes
raise NotImplementedError
return int_to_big_endian(self.x.num, 32)
def tweak(self, merkle_root=b""):
"""returns the tweak for use in p2tr if there's no script path"""
# take the hash_taptweak of the xonly and the merkle root
@ -657,7 +660,35 @@ class PrivateKey:
# create a SchnorrSignature object using the R and s
# check that this schnorr signature verifies
# return the signature
raise NotImplementedError
# set d (working secret) to N - secret if odd, secret otherwise
if self.point.parity:
d = N - self.secret
else:
d = self.secret
# get k using the self.bip340_k method
k = self.bip340_k(msg, aux)
# get the resulting R=kG point
r = k * G
# if R's y coordinate is odd, flip the k
if r.parity:
# set k to N - k
k = N - k
# recalculate R
r = k * G
# calculate the commitment which is: R || P || msg
commitment = r.xonly() + self.point.xonly() + msg
# hash_challenge the result and interpret as a big endian integer
# mod the result by N and this is your e
e = big_endian_to_int(hash_challenge(commitment)) % N
# calculate s which is (k+ed) mod N
s = (k + e * d) % N
# create a SchnorrSignature object using the R and s
sig = SchnorrSignature(r, s)
# check that this schnorr signature verifies
if not self.point.verify_schnorr(msg, sig):
raise RuntimeError("Bad Signature")
# return the signature
return sig
def deterministic_k(self, z):
k = b"\x00" * 32

View File

@ -10,7 +10,8 @@ def sha256(x):
def tagged_hash(tag, msg):
# compute the sha256 of the tag using hashlib.sha256
# compute the tagged hash by getting the sha256 of the tag hash + tag hash + message
raise NotImplementedError
challenge_hash = sha256(tag)
return sha256(challenge_hash + challenge_hash + msg)
def hash_aux(msg):

View File

@ -19,7 +19,7 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 31,
"id": "8dadf5e6",
"metadata": {
"slideshow": {
@ -41,14 +41,22 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 32,
"id": "1e49bfe0",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"233a1e9353c5f782c96c1c08323fe9fca47ad161ee69d008846b68625c221113\n"
]
}
],
"source": [
"# Example Tagged Hashes\n",
"from hash import sha256\n",
@ -76,21 +84,28 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 33,
"id": "2787e08e",
"metadata": {},
"outputs": [],
"metadata": {
"scrolled": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"1d721a19d161e978e7436d9e73bb810a0a32cbdffc7a9b29e11713b1940a4126\n"
]
}
],
"source": [
"# Exercise 1\n",
"\n",
"from hash import sha256\n",
"# define the challenge tag and the message\n",
"\n",
"\n",
"# calculate the challenge tag hash using sha256\n",
"\n",
"# calculate the hash of the challenge\n",
"\n"
"challenge_hash = sha256(b\"BIP0340/aux\")\n",
"msg = b\"hello world\"\n",
"hash_challenge = sha256(challenge_hash + challenge_hash + msg)\n",
"print(hash_challenge.hex())\n"
]
},
{
@ -112,10 +127,22 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 38,
"id": "24346452",
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
".\n",
"----------------------------------------------------------------------\n",
"Ran 1 test in 0.001s\n",
"\n",
"OK\n"
]
}
],
"source": [
"# Exercise 2\n",
"\n",
@ -142,18 +169,28 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 41,
"id": "87fa62d1",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"f01d6b9018ab421dd410404cb869072065522bf85734008f105cf385a023a80f\n",
"True\n"
]
}
],
"source": [
"# Example X-only pubkey\n",
"from ecc import PrivateKey, S256Point\n",
"from helper import int_to_big_endian\n",
"\n",
"pubkey = PrivateKey(12345).point\n",
"xonly = int_to_big_endian(pubkey.x.num, 32)\n",
"print(xonly.hex())\n",
@ -177,19 +214,32 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 42,
"id": "7179e7c0",
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"e79c4eb45764bd015542f6779cc70fef44b7a2432f839264768288efab886291\n",
"True\n"
]
}
],
"source": [
"# Exercise 3\n",
"\n",
"from ecc import PrivateKey\n",
"from ecc import PrivateKey, S256Point\n",
"from helper import int_to_big_endian\n",
"secret = 21000000\n",
"# create a private key with the secret\n",
"\n",
"pubkey = PrivateKey(secret).point\n",
"# get the public point for the private key\n",
"\n",
"xonly = int_to_big_endian(pubkey.x.num, 32)\n",
"print(xonly.hex())\n",
"pubkey2 = S256Point.parse(xonly)\n",
"print(pubkey.xonly() == pubkey2.xonly())\n",
"# convert the x coordinate to a big-endian integer 32 bytes\n",
"\n"
]
@ -213,10 +263,22 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 40,
"id": "c3c8ebf9",
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
".\n",
"----------------------------------------------------------------------\n",
"Ran 1 test in 0.001s\n",
"\n",
"OK\n"
]
}
],
"source": [
"# Exercise 4\n",
"\n",
@ -241,14 +303,22 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 43,
"id": "fc90c449",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"True\n"
]
}
],
"source": [
"from ecc import S256Point, SchnorrSignature, G, N\n",
"from helper import sha256, big_endian_to_int\n",
@ -291,10 +361,18 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 44,
"id": "9e5fb728",
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"True\n"
]
}
],
"source": [
"# Exercise 5\n",
"\n",
@ -307,10 +385,11 @@
"sig = SchnorrSignature.parse(sig_raw)\n",
"msg = bytes.fromhex(\"1a84547db188f0b1d2c9f0beac230afebbd5e6e6c1a46fc69841815194bf8612\")\n",
"# create the commitment: R || P || m (points should be xonly)\n",
"\n",
"commitment = sig.r.xonly() + pubkey.xonly() + msg\n",
"# hash the commitment with hash_challenge and then big_endian_to_int it\n",
"\n",
"# check that -hP+sG=R\n"
"h = big_endian_to_int(hash_challenge(commitment))\n",
"# check that -hP+sG=R\n",
"print(-h*pubkey + sig.s*G == sig.r)"
]
},
{
@ -332,10 +411,22 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 45,
"id": "9d511cfd",
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
".\n",
"----------------------------------------------------------------------\n",
"Ran 1 test in 0.071s\n",
"\n",
"OK\n"
]
}
],
"source": [
"# Exercise 6\n",
"\n",
@ -361,14 +452,22 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 46,
"id": "3eb5a3c9",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"f3626c99fe36167e5fef6b95e5ed6e5687caa4dc828986a7de8f9423c0f77f9bc73091ed86085ce43de0e255b3d0afafc7eee41ddc9970c3dc8472acfcdfd39a\n"
]
}
],
"source": [
"# Example Signing\n",
"from ecc import PrivateKey, N, G\n",
@ -410,46 +509,56 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 47,
"id": "6adb7529",
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"5ad2703f5b4f4b9dea4c28fa30d86d3781d28e09dd51aae1208de80bb6155bee7d9dee36de5540efd633445a8d743816cbbc15fb8a1c7768984190d5b873a341\n"
]
}
],
"source": [
"# Exercise 7\n",
"\n",
"from ecc import PrivateKey, N, G\n",
"from helper import sha256\n",
"# create the private key\n",
"\n",
"priv = PrivateKey(21000000)\n",
"# calculate d (working secret) based on whether the y is even or odd\n",
"if priv.point.y.num % 2 == 1:\n",
" d = N - priv.secret\n",
"else:\n",
" d = priv.secret\n",
"# create the message\n",
"\n",
"msg = sha256(b\"I'm learning Taproot!\")\n",
"# We'll learn more about k later, for now use 987654321\n",
"k = 987654321\n",
"# get the resulting R=kG point\n",
"\n",
"r = k * G\n",
"# if R's y coordinate is odd, flip the k\n",
"\n",
"if r.y.num % 2 == 1:\n",
" # set k to N - k\n",
"\n",
" k = N - k\n",
" # recalculate R\n",
" r = k * G\n",
"\n",
"# calculate the commitment which is: R || P || msg\n",
"\n",
"commitment = r.xonly() + priv.point.xonly() + msg\n",
"# hash_challenge the result and interpret as a big endian integer mod the result by N and this is your e\n",
"\n",
"e = big_endian_to_int(hash_challenge(commitment)) % N\n",
"# calculate s which is (k+ed) mod N\n",
"\n",
"s = (k + e * d) % N\n",
"# create a SchnorrSignature object using the R and s\n",
"\n",
"sig = SchnorrSignature(r, s)\n",
"# check that this schnorr signature verifies\n",
"\n",
"\n",
"# print the serialized hex of the signature\n"
"if not priv.point.verify_schnorr(msg, sig):\n",
" raise RuntimeError(\"Bad Signature\")\n",
"# print the serialized hex of the signature\n",
"print(sig.serialize().hex())"
]
},
{
@ -471,10 +580,22 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 49,
"id": "b6b3bc50",
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
".\n",
"----------------------------------------------------------------------\n",
"Ran 1 test in 0.137s\n",
"\n",
"OK\n"
]
}
],
"source": [
"# Exercise 8\n",
"\n",
@ -526,16 +647,25 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 51,
"id": "501b6994",
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"True\n"
]
}
],
"source": [
"# Exercise 9\n",
"\n",
"from ecc import SchnorrSignature, S256Point, N, G\n",
"from hash import hash_challenge\n",
"from helper import big_endian_to_int\n",
"\n",
"p1_raw = bytes.fromhex(\"cbaa648dbfe734646ce958e2f14a874149fae4010fdeabde4bae6a732537fd91\")\n",
"p2_raw = bytes.fromhex(\"e79c4eb45764bd015542f6779cc70fef44b7a2432f839264768288efab886291\")\n",
"p1 = S256Point.parse(p1_raw)\n",
@ -547,18 +677,19 @@
"msg1 = bytes.fromhex(\"1a84547db188f0b1d2c9f0beac230afebbd5e6e6c1a46fc69841815194bf8612\")\n",
"msg2 = bytes.fromhex(\"af1c325abcb0cced3a4166ce67be1db659ae1dd574fe49b0f2941d8d4882d62c\")\n",
"# define s as the s_i sum (make sure to mod by N)\n",
"\n",
"s = (sig1.s + sig2.s) % N\n",
"# define r as the signatures' r sum\n",
"\n",
"r = sig1.r + sig2.r\n",
"# create the commitments: R_i||P_i||m_i\n",
"\n",
"\n",
"commitment_1 = sig1.r.xonly() + p1.xonly() + msg1\n",
"commitment_2 = sig2.r.xonly() + p2.xonly() + msg2\n",
"# define the h's as the hash_challenge of the commitment as a big endian integer\n",
"\n",
"\n",
"h1 = big_endian_to_int(hash_challenge(commitment_1))\n",
"h2 = big_endian_to_int(hash_challenge(commitment_2))\n",
"# compute the sum of the h_i P_i's\n",
"\n",
"# check that sG=R+h\n"
"h = h1*p1 + h2*p2\n",
"# check that sG=R+h\n",
"print(s*G == r+h)"
]
},
{
@ -1747,7 +1878,25 @@
]
}
],
"metadata": {},
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"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.11.5"
}
},
"nbformat": 4,
"nbformat_minor": 5
}