Skip to content

Commit 3550b38

Browse files
author
Vizeet Srivastava
committed
Added public key compress and uncompress
1 parent 96cfcd6 commit 3550b38

File tree

1 file changed

+158
-5
lines changed

1 file changed

+158
-5
lines changed

BitcoinEllipticCurveCryptography.ipynb

+158-5
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
{
3131
"data": {
3232
"application/vnd.jupyter.widget-view+json": {
33-
"model_id": "9ece5999755e498b90475d64ba6270f2"
33+
"model_id": "92eefc2b63a1450e927aeec68465492e"
3434
}
3535
},
3636
"metadata": {},
@@ -209,9 +209,14 @@
209209
"λ = (yq-yp)/(xq-xp) % P<br>\n",
210210
"To obtain λ we need to find multiplicative-inverse of (xq-xp) in finite field<br>\n",
211211
"=> (yq-yp) \\* Multiplicate-Inverse(xq-xp) % P<br>\n",
212-
"In Python Multiplicative inverse of x in finite field by modulo prime P is:<br>\n",
213-
"pow(x, P-2, P)<br>\n",
214-
"=> (yq-yp) \\* pow(xq-xp, P - 2, P) % P<br>\n",
212+
"########### <br>\n",
213+
"Multiplicative inverse i of a number N in finite field is calculated by :<br>\n",
214+
"N * i % P = 1 <br>\n",
215+
"since N^(P-1) % P = 1 <br>\n",
216+
"=> i = N^(P-2) <br>\n",
217+
"=> (1/N) % P = N^(P-2) % P <br>\n",
218+
"########## <br>\n",
219+
"=> ((yq-yp) \\* ((xq-xp)^(P - 2) % P)) % P<br>\n",
215220
"From (7)<br>\n",
216221
"xr = (λ^2 - xp - xq) % P <br>\n",
217222
"From (6)<br>\n",
@@ -442,7 +447,155 @@
442447
"cell_type": "markdown",
443448
"metadata": {},
444449
"source": [
445-
"<h2> Compressing Point on Elliptic Curve </h2>"
450+
"<h2> Compressing/Uncompressing Point on Elliptic Curve secp256k1 </h2>"
451+
]
452+
},
453+
{
454+
"cell_type": "markdown",
455+
"metadata": {},
456+
"source": [
457+
"<h3> Compressing Point </h3>\n",
458+
"<p>\n",
459+
"For a given x0 there are two values of y i.e. y0, -y0 <br>\n",
460+
"In finite field Ƒp: <br>\n",
461+
"The two values of y are y0 and P - y0 <br>\n",
462+
"This gives us equation: y1 = P - y0 <br>\n",
463+
"Since P is odd in secp256k1 for any given x: y is either odd or even. <br>\n",
464+
"So y is removed by adding prefix denoting whether y is odd or even. <br>\n",
465+
"0x02 prefix denote y is even and 0x03 prefix denote y is odd. <br>\n",
466+
"0x04 prefix denote point is uncompressed.\n",
467+
"</p>"
468+
]
469+
},
470+
{
471+
"cell_type": "code",
472+
"execution_count": 14,
473+
"metadata": {},
474+
"outputs": [
475+
{
476+
"data": {
477+
"application/vnd.jupyter.widget-view+json": {
478+
"model_id": "6e81e321819442e68344276458ce1050"
479+
}
480+
},
481+
"metadata": {},
482+
"output_type": "display_data"
483+
}
484+
],
485+
"source": [
486+
"import ipywidgets as widgets\n",
487+
"from IPython.display import display \n",
488+
"import binascii\n",
489+
"\n",
490+
"def compressPubkey(pubkey: bytes):\n",
491+
" if pubkey[0:1] == b'\\x04':\n",
492+
" x_b = pubkey[1:33]\n",
493+
" y_b = pubkey[33:65]\n",
494+
" if (y_b[31] & 0x01) == 0: # even\n",
495+
" compressed_pubkey = b'\\x02' + x_b\n",
496+
" else:\n",
497+
" compressed_pubkey = b'\\x03' + x_b\n",
498+
" elif pubkey[0:1] == b'\\x02' or pubkey[0:1] == b'\\x03':\n",
499+
" compressed_pubkey = pubkey\n",
500+
" else:\n",
501+
" raise ValueError('Invalid Elliptic Curve Point prefix %s' % pubkey[0])\n",
502+
" return compressed_pubkey\n",
503+
"\n",
504+
"pubkey_s = widgets.Text(description = 'Public Key')\n",
505+
"pubkey_s"
506+
]
507+
},
508+
{
509+
"cell_type": "code",
510+
"execution_count": 15,
511+
"metadata": {},
512+
"outputs": [
513+
{
514+
"name": "stdout",
515+
"output_type": "stream",
516+
"text": [
517+
"0250863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b2352\n"
518+
]
519+
}
520+
],
521+
"source": [
522+
"compressed_pubkey = compressPubkey(binascii.unhexlify(pubkey_s.value))\n",
523+
"compressed_pubkey_s = bytes.decode(binascii.hexlify(compressed_pubkey))\n",
524+
"print(compressed_pubkey_s)"
525+
]
526+
},
527+
{
528+
"cell_type": "markdown",
529+
"metadata": {},
530+
"source": [
531+
"<h3> Uncompressing Point </h3>\n",
532+
"<p>\n",
533+
"Curve E: y^2 = x^3 + 7 over Ƒp <br>\n",
534+
"and P % 4 = 3 <br>\n",
535+
"=> y % p = y^(2*(p + 1)/4) % p <br>\n",
536+
"</p>"
537+
]
538+
},
539+
{
540+
"cell_type": "code",
541+
"execution_count": 20,
542+
"metadata": {},
543+
"outputs": [
544+
{
545+
"data": {
546+
"application/vnd.jupyter.widget-view+json": {
547+
"model_id": "e5e6ade26d2e4d989461d337f05fe47d"
548+
}
549+
},
550+
"metadata": {},
551+
"output_type": "display_data"
552+
}
553+
],
554+
"source": [
555+
"import ipywidgets as widgets\n",
556+
"from IPython.display import display \n",
557+
"import binascii\n",
558+
"\n",
559+
"# field prime\n",
560+
"P = 2 ** 256 - 2 ** 32 - 2 ** 9 - 2 ** 8 - 2 ** 7 - 2 ** 6 - 2 ** 4 - 1\n",
561+
"\n",
562+
"def uncompressPubkey(x_b: bytes):\n",
563+
" prefix = x_b[0:1]\n",
564+
" x_b = x_b[1:33]\n",
565+
" x = int.from_bytes(x_b, byteorder='big')\n",
566+
"\n",
567+
" y_square = (pow(x, 3, P) + 7) % P\n",
568+
" y_square_square_root = pow(y_square, ((P+1) >> 2), P)\n",
569+
" if (prefix == b\"\\x02\" and y_square_square_root & 1) or (prefix == b\"\\x03\" and not y_square_square_root & 1):\n",
570+
" y = (-y_square_square_root) % P\n",
571+
" else:\n",
572+
" y = y_square_square_root\n",
573+
"\n",
574+
" y_b = y.to_bytes(32, 'big')\n",
575+
" full_pubkey_b = b''.join([b'\\x04', x_b, y_b])\n",
576+
" return full_pubkey_b\n",
577+
" \n",
578+
"pubkey_s = widgets.Text(description = 'Public Key')\n",
579+
"pubkey_s"
580+
]
581+
},
582+
{
583+
"cell_type": "code",
584+
"execution_count": 21,
585+
"metadata": {},
586+
"outputs": [
587+
{
588+
"name": "stdout",
589+
"output_type": "stream",
590+
"text": [
591+
"0450863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b23522cd470243453a299fa9e77237716103abc11a1df38855ed6f2ee187e9c582ba6\n"
592+
]
593+
}
594+
],
595+
"source": [
596+
"uncompressed_pubkey = uncompressPubkey(binascii.unhexlify(pubkey_s.value))\n",
597+
"uncompressed_pubkey_s = bytes.decode(binascii.hexlify(uncompressed_pubkey))\n",
598+
"print(uncompressed_pubkey_s)"
446599
]
447600
},
448601
{

0 commit comments

Comments
 (0)