|
30 | 30 | {
|
31 | 31 | "data": {
|
32 | 32 | "application/vnd.jupyter.widget-view+json": {
|
33 |
| - "model_id": "9ece5999755e498b90475d64ba6270f2" |
| 33 | + "model_id": "92eefc2b63a1450e927aeec68465492e" |
34 | 34 | }
|
35 | 35 | },
|
36 | 36 | "metadata": {},
|
|
209 | 209 | "λ = (yq-yp)/(xq-xp) % P<br>\n",
|
210 | 210 | "To obtain λ we need to find multiplicative-inverse of (xq-xp) in finite field<br>\n",
|
211 | 211 | "=> (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", |
215 | 220 | "From (7)<br>\n",
|
216 | 221 | "xr = (λ^2 - xp - xq) % P <br>\n",
|
217 | 222 | "From (6)<br>\n",
|
|
442 | 447 | "cell_type": "markdown",
|
443 | 448 | "metadata": {},
|
444 | 449 | "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)" |
446 | 599 | ]
|
447 | 600 | },
|
448 | 601 | {
|
|
0 commit comments