From c8db052b4283a61ebcda48d016a9b82a7442ba82 Mon Sep 17 00:00:00 2001 From: Tanishk Goyal Date: Wed, 16 Feb 2022 15:46:16 +0530 Subject: [PATCH 1/3] Signing Complete --- pybtc/__init__.py | 10 - pyflo/__init__.py | 10 + .../__pycache__/__init__.cpython-36.pyc | Bin pyflo/__pycache__/__init__.cpython-38.pyc | Bin 0 -> 370 bytes .../__pycache__/address.cpython-36.pyc | Bin pyflo/__pycache__/address.cpython-38.pyc | Bin 0 -> 8533 bytes .../__pycache__/block.cpython-36.pyc | Bin pyflo/__pycache__/block.cpython-38.pyc | Bin 0 -> 3166 bytes .../__pycache__/consensus.cpython-36.pyc | Bin pyflo/__pycache__/consensus.cpython-38.pyc | Bin 0 -> 1055 bytes .../__pycache__/constants.cpython-36.pyc | Bin pyflo/__pycache__/constants.cpython-38.pyc | Bin 0 -> 2740 bytes .../__pycache__/opcodes.cpython-36.pyc | Bin pyflo/__pycache__/opcodes.cpython-38.pyc | Bin 0 -> 5477 bytes .../__pycache__/transaction.cpython-36.pyc | Bin pyflo/__pycache__/transaction.cpython-38.pyc | Bin 0 -> 29290 bytes .../__pycache__/wallet.cpython-36.pyc | Bin pyflo/__pycache__/wallet.cpython-38.pyc | Bin 0 -> 4661 bytes {pybtc => pyflo}/__to_remove_blockchain__.py | 0 {pybtc => pyflo}/address.py | 14 +- .../bip39_word_list/chinese_simplified.txt | 0 .../bip39_word_list/chinese_traditional.txt | 0 {pybtc => pyflo}/bip39_word_list/english.txt | 0 {pybtc => pyflo}/bip39_word_list/french.txt | 0 {pybtc => pyflo}/bip39_word_list/italian.txt | 0 {pybtc => pyflo}/bip39_word_list/japanese.txt | 0 {pybtc => pyflo}/bip39_word_list/korean.txt | 0 {pybtc => pyflo}/bip39_word_list/spanish.txt | 0 {pybtc => pyflo}/block.py | 8 +- {pybtc => pyflo}/consensus.py | 0 {pybtc => pyflo}/constants.py | 0 pyflo/ellipticcurve/__init__.py | 6 + .../__pycache__/__init__.cpython-38.pyc | Bin 0 -> 432 bytes .../__pycache__/curve.cpython-38.pyc | Bin 0 -> 2663 bytes .../__pycache__/ecdsa.cpython-38.pyc | Bin 0 -> 1807 bytes .../__pycache__/math.cpython-38.pyc | Bin 0 -> 5457 bytes .../__pycache__/point.cpython-38.pyc | Bin 0 -> 826 bytes .../__pycache__/privateKey.cpython-38.pyc | Bin 0 -> 3165 bytes .../__pycache__/publicKey.cpython-38.pyc | Bin 0 -> 3316 bytes .../__pycache__/signature.cpython-38.pyc | Bin 0 -> 2109 bytes pyflo/ellipticcurve/curve.py | 79 ++++++++ pyflo/ellipticcurve/ecdsa.py | 46 +++++ pyflo/ellipticcurve/math.py | 177 ++++++++++++++++++ pyflo/ellipticcurve/point.py | 14 ++ pyflo/ellipticcurve/privateKey.py | 72 +++++++ pyflo/ellipticcurve/publicKey.py | 88 +++++++++ pyflo/ellipticcurve/signature.py | 48 +++++ pyflo/ellipticcurve/utils/__init__.py | 0 .../utils/__pycache__/__init__.cpython-38.pyc | Bin 0 -> 197 bytes .../utils/__pycache__/binary.cpython-38.pyc | Bin 0 -> 1477 bytes .../__pycache__/compatibility.cpython-38.pyc | Bin 0 -> 1405 bytes .../utils/__pycache__/der.cpython-38.pyc | Bin 0 -> 4227 bytes .../utils/__pycache__/file.cpython-38.pyc | Bin 0 -> 544 bytes .../utils/__pycache__/integer.cpython-38.pyc | Bin 0 -> 761 bytes .../utils/__pycache__/oid.cpython-38.pyc | Bin 0 -> 1069 bytes .../utils/__pycache__/pem.cpython-38.pyc | Bin 0 -> 818 bytes pyflo/ellipticcurve/utils/binary.py | 37 ++++ pyflo/ellipticcurve/utils/compatibility.py | 40 ++++ pyflo/ellipticcurve/utils/der.py | 159 ++++++++++++++++ pyflo/ellipticcurve/utils/file.py | 9 + pyflo/ellipticcurve/utils/integer.py | 16 ++ pyflo/ellipticcurve/utils/oid.py | 35 ++++ pyflo/ellipticcurve/utils/pem.py | 14 ++ {pybtc => pyflo}/functions/__init__.py | 0 .../__pycache__/__init__.cpython-36.pyc | Bin .../__pycache__/__init__.cpython-38.pyc | Bin 0 -> 355 bytes .../__pycache__/address.cpython-36.pyc | Bin .../__pycache__/address.cpython-38.pyc | Bin 0 -> 7540 bytes .../__pycache__/bip32.cpython-36.pyc | Bin .../__pycache__/bip32.cpython-38.pyc | Bin 0 -> 8287 bytes .../__pycache__/bip39_mnemonic.cpython-36.pyc | Bin .../__pycache__/bip39_mnemonic.cpython-38.pyc | Bin 0 -> 5949 bytes .../__pycache__/block.cpython-36.pyc | Bin .../__pycache__/block.cpython-38.pyc | Bin 0 -> 4151 bytes .../__pycache__/encode.cpython-36.pyc | Bin .../__pycache__/encode.cpython-38.pyc | Bin 0 -> 3895 bytes .../functions/__pycache__/hash.cpython-36.pyc | Bin .../functions/__pycache__/hash.cpython-38.pyc | Bin 0 -> 1335 bytes .../functions/__pycache__/key.cpython-36.pyc | Bin .../functions/__pycache__/key.cpython-38.pyc | Bin 0 -> 5134 bytes .../__pycache__/script.cpython-36.pyc | Bin .../__pycache__/script.cpython-38.pyc | Bin 0 -> 13962 bytes .../__pycache__/tools.cpython-36.pyc | Bin .../__pycache__/tools.cpython-38.pyc | Bin 0 -> 8555 bytes {pybtc => pyflo}/functions/address.py | 10 +- {pybtc => pyflo}/functions/bip32.py | 8 +- {pybtc => pyflo}/functions/bip39_mnemonic.py | 6 +- {pybtc => pyflo}/functions/block.py | 4 +- {pybtc => pyflo}/functions/encode.py | 4 +- {pybtc => pyflo}/functions/hash.py | 0 {pybtc => pyflo}/functions/key.py | 6 +- {pybtc => pyflo}/functions/script.py | 107 ++++++----- {pybtc => pyflo}/functions/tools.py | 0 {pybtc => pyflo}/opcodes.py | 0 {pybtc => pyflo}/test/__init__.py | 0 {pybtc => pyflo}/test/address_class.py | 0 {pybtc => pyflo}/test/address_functions.py | 0 {pybtc => pyflo}/test/block.py | 0 {pybtc => pyflo}/test/create_transaction.py | 0 {pybtc => pyflo}/test/ecdsa.py | 0 {pybtc => pyflo}/test/hash_functions.py | 0 {pybtc => pyflo}/test/integer.py | 0 {pybtc => pyflo}/test/mnemonic.py | 0 {pybtc => pyflo}/test/raw_block.txt | 0 {pybtc => pyflo}/test/script_deserialize.py | 0 {pybtc => pyflo}/test/script_functions.py | 0 {pybtc => pyflo}/test/sighash.py | 0 .../test/transaction_constructor.py | 0 .../test/transaction_deserialize.py | 0 {pybtc => pyflo}/transaction.py | 18 +- {pybtc => pyflo}/wallet.py | 0 tanishktests.py | 20 ++ 112 files changed, 971 insertions(+), 94 deletions(-) delete mode 100644 pybtc/__init__.py create mode 100644 pyflo/__init__.py rename {pybtc => pyflo}/__pycache__/__init__.cpython-36.pyc (100%) create mode 100644 pyflo/__pycache__/__init__.cpython-38.pyc rename {pybtc => pyflo}/__pycache__/address.cpython-36.pyc (100%) create mode 100644 pyflo/__pycache__/address.cpython-38.pyc rename {pybtc => pyflo}/__pycache__/block.cpython-36.pyc (100%) create mode 100644 pyflo/__pycache__/block.cpython-38.pyc rename {pybtc => pyflo}/__pycache__/consensus.cpython-36.pyc (100%) create mode 100644 pyflo/__pycache__/consensus.cpython-38.pyc rename {pybtc => pyflo}/__pycache__/constants.cpython-36.pyc (100%) create mode 100644 pyflo/__pycache__/constants.cpython-38.pyc rename {pybtc => pyflo}/__pycache__/opcodes.cpython-36.pyc (100%) create mode 100644 pyflo/__pycache__/opcodes.cpython-38.pyc rename {pybtc => pyflo}/__pycache__/transaction.cpython-36.pyc (100%) create mode 100644 pyflo/__pycache__/transaction.cpython-38.pyc rename {pybtc => pyflo}/__pycache__/wallet.cpython-36.pyc (100%) create mode 100644 pyflo/__pycache__/wallet.cpython-38.pyc rename {pybtc => pyflo}/__to_remove_blockchain__.py (100%) rename {pybtc => pyflo}/address.py (97%) rename {pybtc => pyflo}/bip39_word_list/chinese_simplified.txt (100%) rename {pybtc => pyflo}/bip39_word_list/chinese_traditional.txt (100%) rename {pybtc => pyflo}/bip39_word_list/english.txt (100%) rename {pybtc => pyflo}/bip39_word_list/french.txt (100%) rename {pybtc => pyflo}/bip39_word_list/italian.txt (100%) rename {pybtc => pyflo}/bip39_word_list/japanese.txt (100%) rename {pybtc => pyflo}/bip39_word_list/korean.txt (100%) rename {pybtc => pyflo}/bip39_word_list/spanish.txt (100%) rename {pybtc => pyflo}/block.py (94%) rename {pybtc => pyflo}/consensus.py (100%) rename {pybtc => pyflo}/constants.py (100%) create mode 100644 pyflo/ellipticcurve/__init__.py create mode 100644 pyflo/ellipticcurve/__pycache__/__init__.cpython-38.pyc create mode 100644 pyflo/ellipticcurve/__pycache__/curve.cpython-38.pyc create mode 100644 pyflo/ellipticcurve/__pycache__/ecdsa.cpython-38.pyc create mode 100644 pyflo/ellipticcurve/__pycache__/math.cpython-38.pyc create mode 100644 pyflo/ellipticcurve/__pycache__/point.cpython-38.pyc create mode 100644 pyflo/ellipticcurve/__pycache__/privateKey.cpython-38.pyc create mode 100644 pyflo/ellipticcurve/__pycache__/publicKey.cpython-38.pyc create mode 100644 pyflo/ellipticcurve/__pycache__/signature.cpython-38.pyc create mode 100644 pyflo/ellipticcurve/curve.py create mode 100644 pyflo/ellipticcurve/ecdsa.py create mode 100644 pyflo/ellipticcurve/math.py create mode 100644 pyflo/ellipticcurve/point.py create mode 100644 pyflo/ellipticcurve/privateKey.py create mode 100644 pyflo/ellipticcurve/publicKey.py create mode 100644 pyflo/ellipticcurve/signature.py create mode 100644 pyflo/ellipticcurve/utils/__init__.py create mode 100644 pyflo/ellipticcurve/utils/__pycache__/__init__.cpython-38.pyc create mode 100644 pyflo/ellipticcurve/utils/__pycache__/binary.cpython-38.pyc create mode 100644 pyflo/ellipticcurve/utils/__pycache__/compatibility.cpython-38.pyc create mode 100644 pyflo/ellipticcurve/utils/__pycache__/der.cpython-38.pyc create mode 100644 pyflo/ellipticcurve/utils/__pycache__/file.cpython-38.pyc create mode 100644 pyflo/ellipticcurve/utils/__pycache__/integer.cpython-38.pyc create mode 100644 pyflo/ellipticcurve/utils/__pycache__/oid.cpython-38.pyc create mode 100644 pyflo/ellipticcurve/utils/__pycache__/pem.cpython-38.pyc create mode 100644 pyflo/ellipticcurve/utils/binary.py create mode 100644 pyflo/ellipticcurve/utils/compatibility.py create mode 100644 pyflo/ellipticcurve/utils/der.py create mode 100644 pyflo/ellipticcurve/utils/file.py create mode 100644 pyflo/ellipticcurve/utils/integer.py create mode 100644 pyflo/ellipticcurve/utils/oid.py create mode 100644 pyflo/ellipticcurve/utils/pem.py rename {pybtc => pyflo}/functions/__init__.py (100%) rename {pybtc => pyflo}/functions/__pycache__/__init__.cpython-36.pyc (100%) create mode 100644 pyflo/functions/__pycache__/__init__.cpython-38.pyc rename {pybtc => pyflo}/functions/__pycache__/address.cpython-36.pyc (100%) create mode 100644 pyflo/functions/__pycache__/address.cpython-38.pyc rename {pybtc => pyflo}/functions/__pycache__/bip32.cpython-36.pyc (100%) create mode 100644 pyflo/functions/__pycache__/bip32.cpython-38.pyc rename {pybtc => pyflo}/functions/__pycache__/bip39_mnemonic.cpython-36.pyc (100%) create mode 100644 pyflo/functions/__pycache__/bip39_mnemonic.cpython-38.pyc rename {pybtc => pyflo}/functions/__pycache__/block.cpython-36.pyc (100%) create mode 100644 pyflo/functions/__pycache__/block.cpython-38.pyc rename {pybtc => pyflo}/functions/__pycache__/encode.cpython-36.pyc (100%) create mode 100644 pyflo/functions/__pycache__/encode.cpython-38.pyc rename {pybtc => pyflo}/functions/__pycache__/hash.cpython-36.pyc (100%) create mode 100644 pyflo/functions/__pycache__/hash.cpython-38.pyc rename {pybtc => pyflo}/functions/__pycache__/key.cpython-36.pyc (100%) create mode 100644 pyflo/functions/__pycache__/key.cpython-38.pyc rename {pybtc => pyflo}/functions/__pycache__/script.cpython-36.pyc (100%) create mode 100644 pyflo/functions/__pycache__/script.cpython-38.pyc rename {pybtc => pyflo}/functions/__pycache__/tools.cpython-36.pyc (100%) create mode 100644 pyflo/functions/__pycache__/tools.cpython-38.pyc rename {pybtc => pyflo}/functions/address.py (98%) rename {pybtc => pyflo}/functions/bip32.py (98%) rename {pybtc => pyflo}/functions/bip39_mnemonic.py (98%) rename {pybtc => pyflo}/functions/block.py (97%) rename {pybtc => pyflo}/functions/encode.py (97%) rename {pybtc => pyflo}/functions/hash.py (100%) rename {pybtc => pyflo}/functions/key.py (97%) rename {pybtc => pyflo}/functions/script.py (89%) rename {pybtc => pyflo}/functions/tools.py (100%) rename {pybtc => pyflo}/opcodes.py (100%) rename {pybtc => pyflo}/test/__init__.py (100%) rename {pybtc => pyflo}/test/address_class.py (100%) rename {pybtc => pyflo}/test/address_functions.py (100%) rename {pybtc => pyflo}/test/block.py (100%) rename {pybtc => pyflo}/test/create_transaction.py (100%) rename {pybtc => pyflo}/test/ecdsa.py (100%) rename {pybtc => pyflo}/test/hash_functions.py (100%) rename {pybtc => pyflo}/test/integer.py (100%) rename {pybtc => pyflo}/test/mnemonic.py (100%) rename {pybtc => pyflo}/test/raw_block.txt (100%) rename {pybtc => pyflo}/test/script_deserialize.py (100%) rename {pybtc => pyflo}/test/script_functions.py (100%) rename {pybtc => pyflo}/test/sighash.py (100%) rename {pybtc => pyflo}/test/transaction_constructor.py (100%) rename {pybtc => pyflo}/test/transaction_deserialize.py (100%) rename {pybtc => pyflo}/transaction.py (99%) rename {pybtc => pyflo}/wallet.py (100%) create mode 100644 tanishktests.py diff --git a/pybtc/__init__.py b/pybtc/__init__.py deleted file mode 100644 index a8e288c1..00000000 --- a/pybtc/__init__.py +++ /dev/null @@ -1,10 +0,0 @@ -from pybtc.constants import * -from pybtc.opcodes import * -from pybtc.consensus import * -from pybtc.functions import * - - -from .transaction import * -from .block import * -from .address import * -from .wallet import * diff --git a/pyflo/__init__.py b/pyflo/__init__.py new file mode 100644 index 00000000..a88e7b11 --- /dev/null +++ b/pyflo/__init__.py @@ -0,0 +1,10 @@ +from pyflo.constants import * +from pyflo.opcodes import * +from pyflo.consensus import * +from pyflo.functions import * + + +from .transaction import * +from .block import * +from .address import * +from .wallet import * diff --git a/pybtc/__pycache__/__init__.cpython-36.pyc b/pyflo/__pycache__/__init__.cpython-36.pyc similarity index 100% rename from pybtc/__pycache__/__init__.cpython-36.pyc rename to pyflo/__pycache__/__init__.cpython-36.pyc diff --git a/pyflo/__pycache__/__init__.cpython-38.pyc b/pyflo/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..76df823fba2c7f5fd611bc1145a3467d2e9a3be7 GIT binary patch literal 370 zcmYk1y-ve05XbE#Z6hGC@Bm%I(7XUb2z6lqA-)DLk!w4Og>#N#2h>O6U07MVGW8Xh zxFi=z`Pa$j8~HOhhZdo8joYnJB$3pR=ZQ2h3XG8v=99o#;5=}F zjGsuJ?C~a&(;dCoQ#{@0DLZSom9Z;f!Fdkev1|(1R#>UrVP1jj{{vMI!fWhe$G+p> z_~^0O##r&j7F^0sImhN7+!*CQNtfV*qx`-W4fsM9H$$nYxrXIhy(?qeMq%QSgQ)c# x_APJ0s}5YP+oICI&BHKjF%B5CEH!9fmaBHVOD`KMd!w#~zqwPCl#VN&_y>(eWQ+g+ literal 0 HcmV?d00001 diff --git a/pybtc/__pycache__/address.cpython-36.pyc b/pyflo/__pycache__/address.cpython-36.pyc similarity index 100% rename from pybtc/__pycache__/address.cpython-36.pyc rename to pyflo/__pycache__/address.cpython-36.pyc diff --git a/pyflo/__pycache__/address.cpython-38.pyc b/pyflo/__pycache__/address.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9e8cc81dca47d8d830cf22aed2ccb45e82f93112 GIT binary patch literal 8533 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 OX@UMi(ob5VKmG#u^AJ=3 literal 0 HcmV?d00001 diff --git a/pybtc/__pycache__/constants.cpython-36.pyc b/pyflo/__pycache__/constants.cpython-36.pyc similarity index 100% rename from pybtc/__pycache__/constants.cpython-36.pyc rename to pyflo/__pycache__/constants.cpython-36.pyc diff --git a/pyflo/__pycache__/constants.cpython-38.pyc b/pyflo/__pycache__/constants.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4450685ba137bbf600e39acf16ec8187cd08d415 GIT binary patch literal 2740 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 IWRE2O54u0TPXGV_ literal 0 HcmV?d00001 diff --git a/pybtc/__pycache__/wallet.cpython-36.pyc b/pyflo/__pycache__/wallet.cpython-36.pyc similarity index 100% rename from pybtc/__pycache__/wallet.cpython-36.pyc rename to pyflo/__pycache__/wallet.cpython-36.pyc diff --git a/pyflo/__pycache__/wallet.cpython-38.pyc b/pyflo/__pycache__/wallet.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2649863d01dd2daf87e78e3beba0181a687d4bf4 GIT binary patch literal 4661 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 literal 0 HcmV?d00001 diff --git a/pyflo/ellipticcurve/__pycache__/curve.cpython-38.pyc b/pyflo/ellipticcurve/__pycache__/curve.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1ce4ba4f40892930da3f8b244446baecdb2bb9ab GIT binary patch literal 2663 zcmaJ@NpBoQ6t3!R7LS)Wj_m|UIuRimoYINg z7GrUcY+wnPX)Nfh=|(iIfF_1*?8|BnI^aT!9BfJ3#>iIF@&G7m?+f#JI9@aDD zc)97^WY%`gg$r3XH))^CI*xh94K3~lleXWJx81BWx{!Cg9>0cKj$`|w zoy#FOJ(70&3nH4y*sdLBGI)4^jzXxh_9W!H)Ut+WcU3fp*R3|>@n#a&GBAvm=@d+< zWSa7a%Vdf&r4#sIkE>Adw2Ku9WldtBM&fu?0(Jmj+zK|DB20%jnNpE&BOSo=ER{6Z#)d0&xN{exGt-WAzJHKGsc{7}}OdmbW9QVgfJ1{+0&Pf#F>mQ{2EYB8A zKV?dHG=1}Mh1)-Wz+6af$Z;#2;cm*D@I1%Ly6X$82nt7^KDmmxtfIqRO6r2nOPdS2 zu;B$sg(qNHP+uCmLeKyrn)BQcj2&!)QP2d0M0Qe*Vt)eqhDEA^IXtu4kYBe*I}8{N zArJM6yw2Jc&W?XLa^JuDVy<~Me(1n*lhxnYE5?4h zGO$>_aP#pyJHAcJ{b~XD&;1bO^LxLYZ|M5rk&(%J6L!~9@Kse2wBeDOgWnzM?d`B) zdz(}F!)M38rgQwI(>J$0Q+VzA>FC+M-zGbzC3e4@zvkVdpIy1*bmhg^_Ci;C|E{~q z^x)5Z_eNeByt@1Li1bhUH28ykcpqRFt6+yXZUoduTHOR-U3AptD|9~_GRc*eC5REo zFmxHR*IUX}?PA3lAtv;2#&;}fiH{YbbUz_qCapFwv|3>5QRhu z2bD>k5*VWBvodK80aGR+nU3&ONExO+<(A5zysf}Imdy_+(_zNInNVAsiQG_@>C31# z*^c2H9WEUkbEjQz&NZci=A0c)noxnvMIcMhnU^39<~_&p=4`iMX1Qf@s{p0S;ucGp zix`)|lAzsns#fv32wDc{!Ue=DQNe4OzEOh}6>1Q2$ZLB+Oc?G=al+#NhRJ~=B}~ub zmgxToQ)zd>3S}-CS{SiecR$p;tP>0XQ z4bva*#qmKT_({#xk^|9QvI7RFB{pf0LGM zQtXwQA9D$T^>S7WxqK!k#gn<_hg#<4F~sS^42QjaIpFL##@d!2I^ z-VVnRdK+ZnS8nCQ=Y{tB~q$)b%G#!npiYt?4%ClJ%C zFhT&HcW%Rv`n|-Kxc;^D8WSN%979V(9~*jLXz$9xkZq_mRGF6K+2oYV`5sHwjISrS z5z2ThKjunHTqEOVGYKic7%~2k>mNBUWelElF%%Rtq4TMj8~R+fF^sEg=uZFz&m`Bz z&dXCn=Mr}yiHw~IW&DCGl^%1`n#%k%)%6E1!<S<17MD z;EK^IaEMJ#sC-)az#`oQTYXhpSiOf(`&GE?XSe#t*Zsg>PyyRx;IAeaZD6-*0gVvd zs1>X>w20ZjavL}gVJ0yU`2SfEWOb@`72Uk+oI8uSiZ50!iTo4iR>foBxc)|P0)FE5 zBvShpa4QV%ACDv=kk~Mh;Gw!0`()|aG*N{rw6S;wM59MY!<4$X8?36JR7rnH+!CCX3_-A|03@(1+F7$`9qmE+`dFkQ zA2uUB#22uzjZ?reUmpqmc&2lqcAy;bq_0noe$>Q94vR6P&O&1sm_PFz-7k| c-!KFo+=Mi!VkdQ4$PpsANcWHp#i6{kxa4Zc zmA#A6$vN~NaL>`DX#R*Ed+4G60Ixmi-cv8_?+v-sO0t`@K!64f7c={2=FQ`9-tT?P zJnD3s7M{*u+xxZGE$eU8n15_Eeu0wSKqW27B5TNcj9I_5B$xIVmb9Pq9+%FZ)pgGp zn7S-?cat#Ad^9dRm8=Nefz@Nu>hZvqO!6MAL zwWHlr7llI#^ZtSlY>M*v&`UG%)SHMb5yNqmh0#Qe=);8GC%>DY)ac9oQ|7x)SO%#3QOT|4je4^%SzmFFk>p%>>X{U;^4L;8dY@>V}fX5(Mg za@&v6oQ-l8=j>t5wsW@om8BMeo_~D4IgGPSx%qyS_=o<$!(QGGj)N!}4Y9DzPrTS4 zggagoiH~A@e4Gx#(dI!Id(rOXAWAkzbM*`|1~HpMK=;mQlGhE&uquLXT1REI9ky=q ze@;6D?>n<`-=(qgA)0s%&ToRaf^)(<2i}49QwOEM`su5%?nx=Kr%8eJ^uIv(BpJhQ z01Lnv!YYN7_HYE4&*@8i4g3E&hLr=A=Isi(+fpjRN7q%Pbww^NXGf|{jSf|W)}mUX zF&ipa2T=g3<**F`RNVjyLq2)!*+a2{+6GJeAT*QgkgK+2dx!@o@Z~3thUZ+jPF&4T zYTA|j&`~`NYQs8NfIqeM!kTr>I;m4%NjJ0$UK?{8m{&isj|BK21zy*l{<%WP2hXw~ zmVp!>jQuE-fftMI=y9ULY%shdKFV$t_J2!;$6*SWb?cj;^VycTPyC6h-cuqGPG$%0 z?I2NNCh?qQ=7xUbMdRSy1BLNp?t~IgI}6sN48a+hH|cY7!HCjv2FuXhM$B z^q;ns6O^y5+4UDE5jSicIFa=pTM2NiDh3O*j{PJvz;s)I{fBK zrO(2y*}|@^=nE857NC35<>z3(v{%L$w!xN~&#zCH4YKFl`UQlO=~Vmj9va45($4Tx z;G6bG1Ldz-YnDMd(Eh|m53hRM3_cXNx6Lj()4#uB7xz8?P*C`J`R7)%UY;eqax;sZ z;#+WvSF|L90}o;H0t9ACI-|`#BUho;P{A4f0Dn1~8jYz98X%T#ZBB8~4oK9>8W#MwgzRw?xlXh3O5W#PEiGdM8%k+MuL6sc{v zFGm_>L(L8f^|+Fh&1b46#Y>yi{zfrg(={5CT)X7p%$$Y7$z21NbhT5=EywEM#5y1y zlFD~9GNu=FT{jGPYMwtIgzqQgeWYbxX@=h{wJeNk9xl>|xs0!G0Wk#>zYD3L0jYWu z$T%aMsOv;g`0P68SS?UV_$+<5iLK{>wP#P#qnz#KY$xaOGn5I+^pZcym#R=*=(7ib z=_)F#*<@`_kQQu>U1w{2x>f*tmX#J0E@XErm`53&@#7mn3qi_2dr>2g)4Xh5*ND&< zgCDCP>=aSD^!kMdqrMu+Fnk8yn)((<68drGGoFt6>WJSp7}4(uvWK?%T}Ed)CLLo; z)|ZqCP)+g1M(LtBw%*pj$%$pN3rSJ3D|B(KNOjj zBIK(DsxFxXvAjS@$zH7XDgqT9HkR2sr=!N2#c^nK9EaT?iVl$L7mZS$>E?>B&N*u?p)8`jiP9+P*YSUoGsFE57enrdF7k>q21%IPk4ki2f45ltd$g_Q Ic+s~11x~R!#Q*>R literal 0 HcmV?d00001 diff --git a/pyflo/ellipticcurve/__pycache__/point.cpython-38.pyc b/pyflo/ellipticcurve/__pycache__/point.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c19b031736d5a051879087a16b111f1a9e6aa44f GIT binary patch literal 826 zcmZWn%Wj-76!ilbG8$4Ti>_x?6{!k8P*r_NQ5Ho}s&3d=6f+u6JU|T-1wvMxZ9gO* z(;r~lRo2~g)q6ohNosTtwy*Ew9Q%vs%?S+e=i;kF3HgPK>EN(<3s#;0oDoSR-GhB+ z5s~aO@p%IKkH#4B0=82UQAr{uk0g_PPa`fZY41s7Nk`7$Z%Y@l%scxcS6TIdnG$P~ z59bW*16cVSprtJlq-B7#<$z2Q$Uwt;-qD+m)*WqptFy{fuM9>T8^Hm%C&q=}pE%fN zRUm`+I!~^Wb*!@G$MibYd9h8waT#aHT78POUY=)FYO->zieRO(SYOmDod?APQ>|4| zsU+E%>oh2k#A#7?t`I6yl@M6G#NvcH@HNLh&(niD0nNvOb38wCm2^W|vH`{$;Je|H z{ots1*gSiAdvo_{d0QhicfLW@fwr^C%{H!{5~pSc{+|5+N3iT>LX?#e0$)IhA`{wp zhyHrcf9;J|fich$JcTQK1}rq_^68-V0_IPvEmZlgI?q5yRn;CGIFvjYN>1IO&-;A; zz;{s7EZ(LTktmbKB+pUI@*j TZ_@V|)VZ&Rf^RVLHyHT~eg~z6 literal 0 HcmV?d00001 diff --git a/pyflo/ellipticcurve/__pycache__/privateKey.cpython-38.pyc b/pyflo/ellipticcurve/__pycache__/privateKey.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f0c0070ee5d656dec43d6a02df5596c1ca0b0071 GIT binary patch literal 3165 zcmZuzTXWmS6~^L10=(&B`Pxp4Njg=TCQ{v|dFXW7M7HdDJYhA7+L`Wjh5@ll6EZ-s zi=}NUSiAIvKp_MzMIxFpZi(BgRH?D zS(7)j7H^q3FKuTX-pMxjMz+Z}vn{@rZS!q2S4(eXJA5a*$#0r|J-wCP=C_&k*b=@7 z&Mgs~+5C=Z@Vlb| z#7ah5Vx;SpTO;}Ek;=1!nU-H_m5iU2TZ2`bX8s^wm5pSqFWNhUsF0t0d~MOr)kO!! z2KzUb`@@^kn?$OR<(3@BxsY(D&}tfMDazJEsU9UV700uQEH^5HBb8){PF_eHAt+=# z`Q@)ad4AuV=D}3GkO#9rCIaUTj;4b&iJ!_@3?QyNE_$D$6a!S!;!IfFmX2UUTiC)m zXWSL8@XjsniJGY6U8^wWb#dD(S6JB2?kN*n zuk>O%v7$}N`atTJQjSa3D{H_-N!@iyw~*;j?Z80YM)j?w?&9_D;eIyO`(pnf&Ex0s zC`!iRL-|6c`6L4u_Cb|+lzbkgX-Irg<6@Ld_J_$hN{?p4G~b`B)iO3_ z(7nm5^!xo}oalbPg|8NbyTxkk^u{F|dlwclo$2DC6V*`+EWbcwZk<>QrrC*2fS~8% z?V;3A>Vm!Y7Pj{1m=*SG8z4D7(2Pw=HdeQ=zGR=3?5JyVZ<2$x29a)10b|p=pG{Mp zOww7&9vi64GW8?OsUK6djjHRYJJcpTd2?b2c4YP=R1LK19$IBk%^}>I=oYk=4(?w5 z{!^=;?ySMET5tsi!i3y2IFKM|LITXf30bdet0u;byIoefcFhrA=hglF0SpV;%DM{w z#r&1e68r&*`RrF{%&j-pTYOj$ybOV`wWHk=PdH~)tETI4%s*qxeqiPs7;B!i&g|uA z+l+SRu)@zp$TsG-IgHyo{+982b;U)+?@dJ)LcLE_o2m_}I;eOZF(et|%^XUht0P{5 z!CQGENZ3GZsmfYDIFWG`bnak^-(JCO!nZQz!63QVjrg|=c)78%U#ejf0u~7wCs~wM zaW}x5;CniUa1nC~ioV4*navugZ?WzFy0z2IwXhr0E7((v=%N_xiES13M1Bo=pD_(R zFch~z0A7!m`t56(O;Tt~*Hu5mGDWhYD2ipPKatt-#k6gR!W|*iJ3NQ})9U42_1QIV zF&!Hg!G<1U%F0_hJqQX<$-@N{>kZgJ5q?XAHU2tqMRj2aH))~z099EZBBcN{MI480 zIdNJ*#Z2bm?MqF;=db&0mSX%vtgO7YTkLdu4P)B-y5EG$%5Q}Z`F+N~NJjn&cGvo= zyKoln!dukljSK-M0P%5z`x>_2FzwDgvcx)Kzc+X1b>ZRU{@j04!+oh!`gqOe zHL}7EW9)!C@(r8&z$55=hYwqZ?59tc4u{X>tO$!yK21ef=t$}CWuix66z<;N4Tov; z?89&{)ztr*dW+rgWmJU2d^#3kg4`)1WIyiG9Q0w2K0tDHtbT&}R2+|FSdp2&6bf0y zDj7(#HW4z^G+$}BF&HMP3`H)B@vaWDNXH{%62*ENrRzK8!)k4msIISS^j#ADGB|t{ zOXP=qT-JuU!WL?a#v2rt<;7jyb4c<>w9>e}ix%%(2LBO`#3|(?wc+mv4@|~+7y+c8 z(jq!$*|@a7#uP;ixsOs%La=O~?JysrZ2!-9TCBtFp!YrAfRo?L*DK!8?ba3;12)W& zt5>(ON+9G9LU02wLsn*sJ3b7b9{$BlG`?O6)}k^z z>^*#^S+9GqbU~JpBDvx1sZP>jZz=oc9}f?zF%lG`BqVseRSgdCUq#I-8j_Hk02nni z5_7SZG|;3_qH2|7D8E#h#)QbgNQA9mq)c8#lyvJ|P?i2~tBCxLlDEkKE!Kki{}8`T J)^a+(`9JT$>P!Ft literal 0 HcmV?d00001 diff --git a/pyflo/ellipticcurve/__pycache__/publicKey.cpython-38.pyc b/pyflo/ellipticcurve/__pycache__/publicKey.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..96e3a8a3f96fe705d0f7e7b0fa52499afd866f37 GIT binary patch literal 3316 zcmZuz>uwvz72cV>aF-WJl;t>fU1XD@t+#a~Cvc23NYX@>6{|^Tp;3T#QGi(P49%r> zNp^PViqi5=qyj|&y@T{KKwqUVFn1q+)$nar`_2gJF9`?~5M_NE$sYXMyTfE41FF27$D<=NxmK=Of9UMzSdIjjV>s`mK7wisqRuwjoPk#kkw;$l1DDchTjxN7o2 zJY*c0b1BBLOS>Y;5}CZlm} zSD-6MVYH2cLJy((pdT|rF9}RH}{{G81vVq)S8=L7c z-j91xGVr(f3!V-~8F*{s_t7BkCErGA>VuEC805WVw9!olQMx#OMEWFEMJ1oAWLKwelD?~T{Os?G{&Hte<*MTnzqNMFp&5olJ-q$9n*3I zHnIE8F`dmTFn1B3rv%rgM0y3_Oj}?tAi{@Zf~r8z2uMeU!0e=)VW-bysaD%OW_h%5 z6a;l?DRY=G<#iHSY9xM!tf*2zOC!}FDkH|@B#Y9khOp%j;v8+FA#4x|zbaXJMXlBU zS(U@(#eM6V@|qD4LfQy;Mq!*8=LRSShCtP%$;c@M1!)TsP$izF9#`^gltS_eED->k zKuZb?AysdWc(ym+o+)55F5VzGq^|dXXNF>M+9hFO_Y#6lAYBN12PP5%RuU9&3g|tf z(k$pPIY)nJaZQj!{2B;BN`$|-51p!XAyt9NL=$&RWyWbPP>is?2sF6*s<@gB)_(z% zrNFdK4x6v7i^pCS8L@9e)Arqk0g8M~AlwLw%E)cwPjqTdA++G%o;rms>AopG0lU+_ z1wOEuc?y(25NQ_>ic^H3Q&>fXS=ujl>m?j(96sOcalaJChdk#$)0p#j804O$n{eUZ zd$zL`_<3(QPMP1~{?RowPVf7jvGk9kSdOC<;5qgG66Jn(I36%Rfx5vXC_`cM8e`}! zSOBtUOATzu1PvT}*!>(jKsnu^$Ra7wJgSPuE72dg;sd1Dr`*#_Ity+^ zG74)t6_kuUxO6Ud(wg9Wmu1?~j5!iu$K>|5gF0?G%Yf2Fq#X6{oxr_8|l6eyWdSb7YZ zw6JFDjzs+07;@-nbnmnx!O;a}HjLfE%nu3|GH&I}J~zbQq{D#j2b7{xRL)8M4_K-6 z-J;U>pj8XnuQB)3)ZnT28+cNGY1WqEe}#FcHlCIL8#t?P=ENI=T1#NOy+nJ6pFjs* z{wa>%!R`ihhwog#o_3O-c#5OtR_uMq9?7bYb34U zwz44C^t9i~mzzcaI;T`YXCZGalQdt)s-epThP#?AVgb`H8J*0quD>qxs$Md7;4vpA wWzNI$T_OytqOLVsS)B)UA$pU=l>2Gvlh4s2x}bxvAz7`EyX3C9^wcu{55U(OGXMYp literal 0 HcmV?d00001 diff --git a/pyflo/ellipticcurve/__pycache__/signature.cpython-38.pyc b/pyflo/ellipticcurve/__pycache__/signature.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0daf63a184feb3c962b0cce65d2d7d14b77f871b GIT binary patch literal 2109 zcmZuxOK;mo5Z+yq5=F@m`4QWF1VPfGV1ZhfqUfOr0w-{r0u_SDy$}Hin!C2>@}VqO zZe-9WxySs6`sg3iKd{%H{1@?hoPBX;zWHW;U0Lx6w3WX)$D;-zf8$`W zSul73z5E#jC!D6_2)`_)84Flu1y*JUcIE^Q#d#}jWX+(Nxq+Ltf>!1Q9wk2#Zgb~~ zaA(SbHg61w-@K*pL!WB;wQp-@6vo_XKci%qPxV60T!0d^^uBB$f z=mqrh9SA`J%1OX@mosi%(ZJ#x+~Ez-Y`)2x+y%`M4Zg)&+`FPv8Z=?F&D*?VMlN6B zt5+mw!R#Zx#@EfP$0>laqg#XIG>_C+ihhju&Kl|r`b+5LBM=p>NJuIMl2#T-#>s%( z(Eg33snoR8o)mF$F687j2bkmY83+jNw z{%E4zFii49g`o?VmOwT_Xak;$jk(kNvn_`)dOK_AJ$B>$J}4FWlU$Qarf9{c^wO$m zxm#HSqL{KcAaiE#kSSnaSv!D=&-%BY!YSX;txy#;OC(yMo2o$Kl-i1i(tzUIvWqLL zzb9(=b`GI#1J5EZ;v|dG;Et7iAl{FGpu*r-i%mT2r~+uZ0%~c}i@NaG@La6j`)c+q z`H4Qy{lr))^psZg8hjZL*?}pa$rgO1aflgPKm{!860>EtoG2noCH}mSfED zS#v;{8*l^zP5@jcpMxQk(>kFqrId|pa=l-gm#l$VX{Mz3dv;?PU&`d0-0S$ z62fZ5X(=D$LTAQ$46FH@`~Zfqn<(I=$FluyTP)wC~fyg}3jwv2Nv2Cc;pAVVD(s zoTABBuXmn09}ty?&1TGKJfvyL8w34{?0U{{R30 literal 0 HcmV?d00001 diff --git a/pyflo/ellipticcurve/curve.py b/pyflo/ellipticcurve/curve.py new file mode 100644 index 00000000..ef7f4f65 --- /dev/null +++ b/pyflo/ellipticcurve/curve.py @@ -0,0 +1,79 @@ +# +# Elliptic Curve Equation +# +# y^2 = x^3 + A*x + B (mod P) +# +from .point import Point + + +class CurveFp: + + def __init__(self, A, B, P, N, Gx, Gy, name, oid, nistName=None): + self.A = A + self.B = B + self.P = P + self.N = N + self.G = Point(Gx, Gy) + self.name = name + self.nistName = nistName + self.oid = oid # ASN.1 Object Identifier + + def contains(self, p): + """ + Verify if the point `p` is on the curve + + :param p: Point p = Point(x, y) + :return: boolean + """ + if not 0 <= p.x <= self.P - 1: + return False + if not 0 <= p.y <= self.P - 1: + return False + if (p.y**2 - (p.x**3 + self.A * p.x + self.B)) % self.P != 0: + return False + return True + + def length(self): + return (1 + len("%x" % self.N)) // 2 + + +secp256k1 = CurveFp( + name="secp256k1", + A=0x0000000000000000000000000000000000000000000000000000000000000000, + B=0x0000000000000000000000000000000000000000000000000000000000000007, + P=0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f, + N=0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141, + Gx=0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798, + Gy=0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8, + oid=[1, 3, 132, 0, 10] +) + +prime256v1 = CurveFp( + name="prime256v1", + nistName="P-256", + A=0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc, + B=0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b, + P=0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff, + N=0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551, + Gx=0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296, + Gy=0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5, + oid=[1, 2, 840, 10045, 3, 1, 7], +) + +p256 = prime256v1 + +supportedCurves = [ + secp256k1, + prime256v1, +] + +_curvesByOid = {tuple(curve.oid): curve for curve in supportedCurves} + + +def getCurveByOid(oid): + if oid not in _curvesByOid: + raise Exception("Unknown curve with oid {oid}; The following are registered: {names}".format( + oid=".".join([str(number) for number in oid]), + names=", ".join([curve.name for curve in supportedCurves]), + )) + return _curvesByOid[oid] diff --git a/pyflo/ellipticcurve/ecdsa.py b/pyflo/ellipticcurve/ecdsa.py new file mode 100644 index 00000000..ea809e4f --- /dev/null +++ b/pyflo/ellipticcurve/ecdsa.py @@ -0,0 +1,46 @@ +from hashlib import sha256 +from .signature import Signature +from .math import Math +from .utils.integer import RandomInteger +from .utils.binary import numberFromByteString +from .utils.compatibility import * + + +class Ecdsa: + + @classmethod + def sign(cls, message, privateKey, hashfunc=sha256): + byteMessage = hashfunc(toBytes(message)).digest() + numberMessage = numberFromByteString(byteMessage) + curve = privateKey.curve + + r, s, randSignPoint = 0, 0, None + while r == 0 or s == 0: + randNum = RandomInteger.between(1, curve.N - 1) + randSignPoint = Math.multiply(curve.G, n=randNum, A=curve.A, P=curve.P, N=curve.N) + r = randSignPoint.x % curve.N + s = ((numberMessage + r * privateKey.secret) * (Math.inv(randNum, curve.N))) % curve.N + recoveryId = randSignPoint.y & 1 + if randSignPoint.y > curve.N: + recoveryId += 2 + + return Signature(r=r, s=s, recoveryId=recoveryId) + + @classmethod + def verify(cls, message, signature, publicKey, hashfunc=sha256): + byteMessage = hashfunc(toBytes(message)).digest() + numberMessage = numberFromByteString(byteMessage) + curve = publicKey.curve + r = signature.r + s = signature.s + if not 1 <= r <= curve.N - 1: + return False + if not 1 <= s <= curve.N - 1: + return False + inv = Math.inv(s, curve.N) + u1 = Math.multiply(curve.G, n=(numberMessage * inv) % curve.N, N=curve.N, A=curve.A, P=curve.P) + u2 = Math.multiply(publicKey.point, n=(r * inv) % curve.N, N=curve.N, A=curve.A, P=curve.P) + v = Math.add(u1, u2, A=curve.A, P=curve.P) + if v.isAtInfinity(): + return False + return v.x % curve.N == r diff --git a/pyflo/ellipticcurve/math.py b/pyflo/ellipticcurve/math.py new file mode 100644 index 00000000..0ef78d1a --- /dev/null +++ b/pyflo/ellipticcurve/math.py @@ -0,0 +1,177 @@ +from .point import Point + + +class Math: + + @classmethod + def multiply(cls, p, n, N, A, P): + """ + Fast way to multily point and scalar in elliptic curves + + :param p: First Point to mutiply + :param n: Scalar to mutiply + :param N: Order of the elliptic curve + :param P: Prime number in the module of the equation Y^2 = X^3 + A*X + B (mod p) + :param A: Coefficient of the first-order term of the equation Y^2 = X^3 + A*X + B (mod p) + :return: Point that represents the sum of First and Second Point + """ + return cls._fromJacobian( + cls._jacobianMultiply(cls._toJacobian(p), n, N, A, P), P + ) + + @classmethod + def add(cls, p, q, A, P): + """ + Fast way to add two points in elliptic curves + + :param p: First Point you want to add + :param q: Second Point you want to add + :param P: Prime number in the module of the equation Y^2 = X^3 + A*X + B (mod p) + :param A: Coefficient of the first-order term of the equation Y^2 = X^3 + A*X + B (mod p) + :return: Point that represents the sum of First and Second Point + """ + return cls._fromJacobian( + cls._jacobianAdd(cls._toJacobian(p), cls._toJacobian(q), A, P), P, + ) + + @classmethod + def inv(cls, x, n): + """ + Extended Euclidean Algorithm. It's the 'division' in elliptic curves + + :param x: Divisor + :param n: Mod for division + :return: Value representing the division + """ + if x == 0: + return 0 + + lm = 1 + hm = 0 + low = x % n + high = n + + while low > 1: + r = high // low + nm = hm - lm * r + nw = high - low * r + high = low + hm = lm + low = nw + lm = nm + + return lm % n + + @classmethod + def _toJacobian(cls, p): + """ + Convert point to Jacobian coordinates + + :param p: First Point you want to add + :return: Point in Jacobian coordinates + """ + return Point(p.x, p.y, 1) + + @classmethod + def _fromJacobian(cls, p, P): + """ + Convert point back from Jacobian coordinates + + :param p: First Point you want to add + :param P: Prime number in the module of the equation Y^2 = X^3 + A*X + B (mod p) + :return: Point in default coordinates + """ + z = cls.inv(p.z, P) + x = (p.x * z ** 2) % P + y = (p.y * z ** 3) % P + + return Point(x, y, 0) + + @classmethod + def _jacobianDouble(cls, p, A, P): + """ + Double a point in elliptic curves + + :param p: Point you want to double + :param P: Prime number in the module of the equation Y^2 = X^3 + A*X + B (mod p) + :param A: Coefficient of the first-order term of the equation Y^2 = X^3 + A*X + B (mod p) + :return: Point that represents the sum of First and Second Point + """ + if p.y == 0: + return Point(0, 0, 0) + + ysq = (p.y ** 2) % P + S = (4 * p.x * ysq) % P + M = (3 * p.x ** 2 + A * p.z ** 4) % P + nx = (M**2 - 2 * S) % P + ny = (M * (S - nx) - 8 * ysq ** 2) % P + nz = (2 * p.y * p.z) % P + + return Point(nx, ny, nz) + + @classmethod + def _jacobianAdd(cls, p, q, A, P): + """ + Add two points in elliptic curves + + :param p: First Point you want to add + :param q: Second Point you want to add + :param P: Prime number in the module of the equation Y^2 = X^3 + A*X + B (mod p) + :param A: Coefficient of the first-order term of the equation Y^2 = X^3 + A*X + B (mod p) + :return: Point that represents the sum of First and Second Point + """ + if p.y == 0: + return q + if q.y == 0: + return p + + U1 = (p.x * q.z ** 2) % P + U2 = (q.x * p.z ** 2) % P + S1 = (p.y * q.z ** 3) % P + S2 = (q.y * p.z ** 3) % P + + if U1 == U2: + if S1 != S2: + return Point(0, 0, 1) + return cls._jacobianDouble(p, A, P) + + H = U2 - U1 + R = S2 - S1 + H2 = (H * H) % P + H3 = (H * H2) % P + U1H2 = (U1 * H2) % P + nx = (R ** 2 - H3 - 2 * U1H2) % P + ny = (R * (U1H2 - nx) - S1 * H3) % P + nz = (H * p.z * q.z) % P + + return Point(nx, ny, nz) + + @classmethod + def _jacobianMultiply(cls, p, n, N, A, P): + """ + Multily point and scalar in elliptic curves + + :param p: First Point to mutiply + :param n: Scalar to mutiply + :param N: Order of the elliptic curve + :param P: Prime number in the module of the equation Y^2 = X^3 + A*X + B (mod p) + :param A: Coefficient of the first-order term of the equation Y^2 = X^3 + A*X + B (mod p) + :return: Point that represents the sum of First and Second Point + """ + if p.y == 0 or n == 0: + return Point(0, 0, 1) + + if n == 1: + return p + + if n < 0 or n >= N: + return cls._jacobianMultiply(p, n % N, N, A, P) + + if (n % 2) == 0: + return cls._jacobianDouble( + cls._jacobianMultiply(p, n // 2, N, A, P), A, P + ) + + return cls._jacobianAdd( + cls._jacobianDouble(cls._jacobianMultiply(p, n // 2, N, A, P), A, P), p, A, P + ) diff --git a/pyflo/ellipticcurve/point.py b/pyflo/ellipticcurve/point.py new file mode 100644 index 00000000..b960a3a6 --- /dev/null +++ b/pyflo/ellipticcurve/point.py @@ -0,0 +1,14 @@ + + +class Point: + + def __init__(self, x=0, y=0, z=0): + self.x = x + self.y = y + self.z = z + + def __str__(self): + return "({x}, {y}, {z})".format(x=self.x, y=self.y, z=self.z) + + def isAtInfinity(self): + return self.y == 0 diff --git a/pyflo/ellipticcurve/privateKey.py b/pyflo/ellipticcurve/privateKey.py new file mode 100644 index 00000000..9a416254 --- /dev/null +++ b/pyflo/ellipticcurve/privateKey.py @@ -0,0 +1,72 @@ +from .math import Math +from .utils.integer import RandomInteger +from .utils.pem import getPemContent, createPem +from .utils.binary import hexFromByteString, byteStringFromHex, intFromHex, base64FromByteString, byteStringFromBase64 +from .utils.der import hexFromInt, parse, encodeConstructed, DerFieldType, encodePrimitive +from .curve import secp256k1, getCurveByOid +from .publicKey import PublicKey + + +class PrivateKey: + + def __init__(self, curve=secp256k1, secret=None): + self.curve = curve + self.secret = secret or RandomInteger.between(1, curve.N - 1) + + def publicKey(self): + curve = self.curve + publicPoint = Math.multiply( + p=curve.G, + n=self.secret, + N=curve.N, + A=curve.A, + P=curve.P, + ) + return PublicKey(point=publicPoint, curve=curve) + + def toString(self): + return hexFromInt(self.secret) + + def toDer(self): + publicKeyString = self.publicKey().toString(encoded=True) + hexadecimal = encodeConstructed( + encodePrimitive(DerFieldType.integer, 1), + encodePrimitive(DerFieldType.octetString, hexFromInt(self.secret)), + encodePrimitive(DerFieldType.oidContainer, encodePrimitive(DerFieldType.object, self.curve.oid)), + encodePrimitive(DerFieldType.publicKeyPointContainer, encodePrimitive(DerFieldType.bitString, publicKeyString)) + ) + return byteStringFromHex(hexadecimal) + + def toPem(self): + der = self.toDer() + return createPem(content=base64FromByteString(der), template=_pemTemplate) + + @classmethod + def fromPem(cls, string): + privateKeyPem = getPemContent(pem=string, template=_pemTemplate) + return cls.fromDer(byteStringFromBase64(privateKeyPem)) + + @classmethod + def fromDer(cls, string): + hexadecimal = hexFromByteString(string) + privateKeyFlag, secretHex, curveData, publicKeyString = parse(hexadecimal)[0] + if privateKeyFlag != 1: + raise Exception("Private keys should start with a '1' flag, but a '{flag}' was found instead".format( + flag=privateKeyFlag + )) + curve = getCurveByOid(curveData[0]) + privateKey = cls.fromString(string=secretHex, curve=curve) + if privateKey.publicKey().toString(encoded=True) != publicKeyString[0]: + raise Exception("The public key described inside the private key file doesn't match the actual public key of the pair") + return privateKey + + @classmethod + def fromString(cls, string, curve=secp256k1): + return PrivateKey(secret=intFromHex(string), curve=curve) + + +_pemTemplate = """ +-----BEGIN EC PRIVATE KEY----- +{content} +-----END EC PRIVATE KEY----- +""" diff --git a/pyflo/ellipticcurve/publicKey.py b/pyflo/ellipticcurve/publicKey.py new file mode 100644 index 00000000..cebdd5e4 --- /dev/null +++ b/pyflo/ellipticcurve/publicKey.py @@ -0,0 +1,88 @@ +from .math import Math +from .point import Point +from .curve import secp256k1, getCurveByOid +from .utils.pem import getPemContent, createPem +from .utils.der import hexFromInt, parse, DerFieldType, encodeConstructed, encodePrimitive +from .utils.binary import hexFromByteString, byteStringFromHex, intFromHex, base64FromByteString, byteStringFromBase64 + + +class PublicKey: + + def __init__(self, point, curve): + self.point = point + self.curve = curve + + def toString(self, encoded=False): + baseLength = 2 * self.curve.length() + xHex = hexFromInt(self.point.x).zfill(baseLength) + yHex = hexFromInt(self.point.y).zfill(baseLength) + string = xHex + yHex + if encoded: + return "0004" + string + return string + + def toDer(self): + hexadecimal = encodeConstructed( + encodeConstructed( + encodePrimitive(DerFieldType.object, _ecdsaPublicKeyOid), + encodePrimitive(DerFieldType.object, self.curve.oid), + ), + encodePrimitive(DerFieldType.bitString, self.toString(encoded=True)), + ) + return byteStringFromHex(hexadecimal) + + def toPem(self): + der = self.toDer() + return createPem(content=base64FromByteString(der), template=_pemTemplate) + + @classmethod + def fromPem(cls, string): + publicKeyPem = getPemContent(pem=string, template=_pemTemplate) + return cls.fromDer(byteStringFromBase64(publicKeyPem)) + + @classmethod + def fromDer(cls, string): + hexadecimal = hexFromByteString(string) + curveData, pointString = parse(hexadecimal)[0] + publicKeyOid, curveOid = curveData + if publicKeyOid != _ecdsaPublicKeyOid: + raise Exception("The Public Key Object Identifier (OID) should be {ecdsaPublicKeyOid}, but {actualOid} was found instead".format( + ecdsaPublicKeyOid=_ecdsaPublicKeyOid, + actualOid=publicKeyOid, + )) + curve = getCurveByOid(curveOid) + return cls.fromString(string=pointString, curve=curve) + + @classmethod + def fromString(cls, string, curve=secp256k1, validatePoint=True): + baseLength = 2 * curve.length() + if len(string) > 2 * baseLength and string[:4] == "0004": + string = string[4:] + + xs = string[:baseLength] + ys = string[baseLength:] + + p = Point( + x=intFromHex(xs), + y=intFromHex(ys), + ) + publicKey = PublicKey(point=p, curve=curve) + if not validatePoint: + return publicKey + if p.isAtInfinity(): + raise Exception("Public Key point is at infinity") + if not curve.contains(p): + raise Exception("Point ({x},{y}) is not valid for curve {name}".format(x=p.x, y=p.y, name=curve.name)) + if not Math.multiply(p=p, n=curve.N, N=curve.N, A=curve.A, P=curve.P).isAtInfinity(): + raise Exception("Point ({x},{y}) * {name}.N is not at infinity".format(x=p.x, y=p.y, name=curve.name)) + return publicKey + + +_ecdsaPublicKeyOid = (1, 2, 840, 10045, 2, 1) + + +_pemTemplate = """ +-----BEGIN PUBLIC KEY----- +{content} +-----END PUBLIC KEY----- +""" diff --git a/pyflo/ellipticcurve/signature.py b/pyflo/ellipticcurve/signature.py new file mode 100644 index 00000000..3084f8f8 --- /dev/null +++ b/pyflo/ellipticcurve/signature.py @@ -0,0 +1,48 @@ +from .utils.compatibility import * +from .utils.der import parse, encodeConstructed, encodePrimitive, DerFieldType +from .utils.binary import hexFromByteString, byteStringFromHex, base64FromByteString, byteStringFromBase64 + + +class Signature: + + def __init__(self, r, s, recoveryId=None): + self.r = r + self.s = s + self.recoveryId = recoveryId + + def toDer(self, withRecoveryId=False): + hexadecimal = self._toString() + encodedSequence = byteStringFromHex(hexadecimal) + if not withRecoveryId: + return encodedSequence + return toBytes(chr(27 + self.recoveryId)) + encodedSequence + + def toBase64(self, withRecoveryId=False): + return base64FromByteString(self.toDer(withRecoveryId)) + + @classmethod + def fromDer(cls, string, recoveryByte=False): + recoveryId = None + if recoveryByte: + recoveryId = string[0] if isinstance(string[0], intTypes) else ord(string[0]) + recoveryId -= 27 + string = string[1:] + + hexadecimal = hexFromByteString(string) + return cls._fromString(string=hexadecimal, recoveryId=recoveryId) + + @classmethod + def fromBase64(cls, string, recoveryByte=False): + der = byteStringFromBase64(string) + return cls.fromDer(der, recoveryByte) + + def _toString(self): + return encodeConstructed( + encodePrimitive(DerFieldType.integer, self.r), + encodePrimitive(DerFieldType.integer, self.s), + ) + + @classmethod + def _fromString(cls, string, recoveryId=None): + r, s = parse(string)[0] + return Signature(r=r, s=s, recoveryId=recoveryId) diff --git a/pyflo/ellipticcurve/utils/__init__.py b/pyflo/ellipticcurve/utils/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/pyflo/ellipticcurve/utils/__pycache__/__init__.cpython-38.pyc b/pyflo/ellipticcurve/utils/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b881de15f727c6e323b1ac3e8e3a08063639d59a GIT binary patch literal 197 zcmWIL<>g`k0^YMcNg(<$h(HF6K#l_t7qb9~6oz01O-8?!3`HPe1o10NKR2&LKSkdu zCqFqmIU_MMPr)U%EHx*;AU72#5tNvhoRR69n3JR6nOBlplvkXQS)iYmnU|OoP??sK zuU~*frsm{i7L;TrCzlqLrRtZKWabp>$H!;pWtPOp>lIYq;;_lhPbtkwwF9}~GY~TX E0B#gDTmS$7 literal 0 HcmV?d00001 diff --git a/pyflo/ellipticcurve/utils/__pycache__/binary.cpython-38.pyc b/pyflo/ellipticcurve/utils/__pycache__/binary.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f869c0f51f17f4f6eaeecd3606a62a6360af91b3 GIT binary patch literal 1477 zcmb7DOK;Oa5Z<-(aPw%BHl@5IDuj@HAw5(*AcRmr2o6LD#Kq!bdp2a%wH>WDRa4qi z`61<)AHyH;l~eu#CuZ!VP1_v6mS<)k-fzBdX1_F>HHJ^~S0ngpGxnPX%a4VFSNNqv zG{Ar>7IBY9mS=GW7TC&;N?s`{d*!I&RdB8Zqp(vP8Z z%6Hfq&SGZe{z>`!-t*(L8J(a@XfnQsnN|jgj(n5ZO2n?^RpN0J2%Xi3;@HQuW#p?V z(@os}XV{Hm(}iwNCE;N>^kuyJMjQ#1j3R*xpZqu+$`8I$yYFKobes<5s5?M{>f>af zlJ0293Z>-8$S@r1BheijsnTwcYw>I}$!dsBI^a2FL{1$vjMsRJJ6vyId`%P5=TZ}D z3xkRPKev##)t|L+#^sqUV>9Ktfuo#GVb*b&)o^JpJ1wUq5#xFb?JXc$%f+Xh2^3+PfolE5(RCZtB>3NR~|LsO1=o6HTwPSH4ocEyf>7NGYq{(sOaLFFyG5;X8r zaj<_K^x+cd{Z*hVOSq7fWN^9HC{A8o#?EzhdwCMOORx`C!BTtVokIyO1g18+1!Ksjw zcxKHoiAKJWfmG5=@&+z?Dwmxu+EUf2n3}4nNmWf8H66Xw33*TCSIT)2B`{XvC0)*x OvTgB>?Npu8)%zFEq#m6B literal 0 HcmV?d00001 diff --git a/pyflo/ellipticcurve/utils/__pycache__/compatibility.cpython-38.pyc b/pyflo/ellipticcurve/utils/__pycache__/compatibility.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d49e07f3de07d36a2b6538fdedaa4b7f8323e2f4 GIT binary patch literal 1405 zcmbtU&2H2%5Vn)eZuYO;E%fJrP?3;O53rmN2ZT^T2o6+;0*72sHg>vh9Vc?URU<7Y z`UpG#9Q!c5K(3tj6?$UE$(B{w0|-m8KmW|kH{aO#(C>E$wEmCY*liH<6DP~fg~>Dc z@~_Y_!l)z(4IGNtk#5om8i^NplyK*`$=nl12fP*2z~^n=iJhR!Hkikn=QQZC8?42A zKz-I`opTbbu`cVuxUL@Y79YTAYsH7L3wAeIzqZ?CYqi~aZ8xaw*zl0-ZOwrh*`sCe zlXT4$y62Rw2|tq}F3R>))o_mKTzXRz-+vrAXjeDHxc3~s92J?7Z)8Tl(?fDW z55Reo@hD~d!YP}%(Lx=SK3A{;=z{1TSX`!~M41sA?aMSei6)^?yD#`DmuZ%8*mxJJ zXd>Q(QtrN1hHI5iL^g_r3gz1(mgy*4>baC6Ga`zn`jn5RM#y{=rAZbVF&0vo;z3rF zzDW-)moBol=}^4}_-|9wEjWzH*;Kf0!_?+db$ytYEtBpShUe&a5n}*2qR=fGVvKL) z+XY}iz%P{1Ex09cCw7=SBirONF%;LKYK?x71R81sFQO&2e9n!Ms?Lomvl&=ESIKGj=*{-AeNU96RV7P@cI~dwl0suC|n4?t&vzw7RWaW5;>J4^nM&!Qo| zs+`hw*@c}1P|_6n~k;Jx2o;pu6t?CN2obn_zD$UkUj z#mDOXm;M-TM;-}b%V{$xy(BzNHJmp(=vFWIeUb6JbcHgd2k$R5fe+ZOR+j;FvuSE% z6||;G;6ET}$W$FI$$>XY+sEQRNm4eI{3(i&--5132X4o0Qs3#o=zAT{r=1GBzW}lY B21)<` literal 0 HcmV?d00001 diff --git a/pyflo/ellipticcurve/utils/__pycache__/der.cpython-38.pyc b/pyflo/ellipticcurve/utils/__pycache__/der.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6910c9eb923df1c8cc30e099dc52b04656f60f97 GIT binary patch literal 4227 zcmbVPNpBp-74E8Drf1_ON?dHqv?LmtBo--4mYhTpZ0(9=S`g_VY1kMvrN0cdY{!%!raGzqEo`Q4v*?b7D-4qnsBLViM&$VoIDr`L382XHmW<&WRb6=f$j; zL;1d#7w@245buijP<|lJi}z7p5DVf1lo!PXaS`PuacR}6Egr*etH!i1LKUgF867if z;M#A;Vy*o!dag^T-Iwhq>NQ7~wxZ|s^r)qDDQ>C$8$G$cr=nFQ~o5otS(l&-)BciQM0w=nrkr@NlSjW43TCvA*Bd9hL((|*0)3Y$^A zu1ocLvn{#_)hqS-vu>E=Z)6!JOM;%Pk{Tm5PHKYGBq@N^l4nRwlR69a+LCirC-pac5~GZiUH{y^W;3 z)H$W2B#ApJZZx`bH(KhdI7yd8BrkXNBt?%0NzXy~++lD3O`lph;L9IFu0pOsK7m{h z_!T@~xe@TI%aAJp4^f6!8g%%BpN)zGxdSoF#8zf~JN6Clu^!KO#{R;eIjg5^ui2Vk zUe;_!v)wlyk@Fa@OE*Q_P>pu8bL#@lM|=11=axK=>JSQP6E5TdBqe_Ci|4rMV(TWy#+J>y4p+M4mnO;j>$Zkz3JIi=u{1J+}v#YW2|<>W1bZM(|LtT{^+ zs3l{9|JjBS_R9X$3l(nmUZnAU)O)c@TkOG&HX5}GeUTPNFGP6O|^9!jF8rNP{1-2osw)G@r+zRTMd#L zqGl!L8!_!eI4PhL^)WvAD=L|l`kU4&N+Rw*@j0r2MySRupa(w7K&e0y@8L)@8-G4y z-kT@XPkKA(%`yjG<2#lViVJ?gzGKQZzI8KK*mIW5;A`~hIm+GkQ~}yoMd*?$LswK4 zdQ6SS?%@PRI5>&PBi{2ek49}WjK+Ruu;-e)a!iN3Ki`bg6r8z0^qDSD7~gxk&1v#w0*rRZ*|jM>QI}CDPPtgyNz~HCd(RsY!nobiWgLXUiQElUs9iHzey+qc;3dXZa-no*4#Q?-W%Kyq|5*Uc+J1dsNOmOeUY56}Rk{!goEYhObKR@3ua%M2Zu7))>W z3^w-beMpTOL74gdsk!NSXl^p@| zea4#2!(7rvHCsNWiRDkB;C$jTStNCt8k`(rhIJjfG-)6DPP^Muqx=5^{lA5z1SvX% z3jPj6(wiYm2vsMR{04mFc94}!SjTIo#V!v@iPGb46K0FHX)S=ux~Y}&sgoi z>NVkJATrE@J~eN}SSjyf5o4le$o0$1FpLtgw!`(*SZZvpx!P-Wo9l>d6Iu7sB^XnG zXoKyV2nV{r$a^%^NHlziwhf3$))s}kv3{T>y&v*`hX!)Hfnx_1fy7DYDG(c!Ci-V- z@6fr~a+%H*o`9tp+d$;t*`Bp}ME`Ww4;9Xq(gOJ;bEmBv@PL^QE%|)I<3aPrAI3e$ zf5Z;GTWzWCBQ48cqKmHNT^<{<9rfc!=piBLEEEyw1U%_L`t%8}PBTfphP*ix8MpB^ zj|{=)$qVp+@g^=Ez}1HtKZGxjC^k6yA(>J?gDghKqC{-2Cb@rpgXs_#6b(6K-2II> zNd}Q|iQ369`30#FT+sF5J4in!2p4pTm|&9L4B0>qrMNJNc#2AH1L1gZiTK8*>q5_= zFF@hE;`DuIO4KvDWZ)tIL^z_bL#f@(Jj1oPF$(_`UAKxW#}sx!vD>1nVv77%4m%xu zFocwyajdkud;qmSVQA{P`Y7!nRc^$Mpny-3U7*0c#~saWBw?D$pV5$?L%~Z#9LUK? zu*mUiZF9A{L9Yt(B6XwK35Z8NHTs6p*O7$7%{y-<8*$`Av*3T)AE^+_oCy@LK zW3`LeX{PcgG|vT63#2HmOG?8gYnt4YCpn^c!;Xd^46Y3@i~*;xWE^6?BK({AhubaU n?v!v>0h(s*v5B`of6($zuR3M>j_><3(2nmKUGyvdgkStGVJB-F literal 0 HcmV?d00001 diff --git a/pyflo/ellipticcurve/utils/__pycache__/file.cpython-38.pyc b/pyflo/ellipticcurve/utils/__pycache__/file.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f2790ea56ce510809506bbd80e6e183a55186020 GIT binary patch literal 544 zcmY*Wu}72%Bv9FHl(6M2mu0J0pdUilqT}pUM0eDf}KU;v{XyaFMz1- zWB38Ld;%R6GYd$|Nbkinp7EQRocH@nfYyKM4WIG*O3u6`=q%oQB<`ynHbu7 z7=NkSwZ^so!IQ}QD6L$Z>U7uE>Pi)|bZh(O#@M>4Fe^QkP8H>mw07+e)_E6-vPnm! zllJ6xWb3q&<=HHAM8DKCBwB1B?JnnR79lCR Unaid{cq)nAtxv^ms(VAg2StT_5dZ)H literal 0 HcmV?d00001 diff --git a/pyflo/ellipticcurve/utils/__pycache__/integer.cpython-38.pyc b/pyflo/ellipticcurve/utils/__pycache__/integer.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a760eab5b94b1375e6babb06d072bd08bb441aad GIT binary patch literal 761 zcma)4y^ho{5cbdRv6tIzkPuWT?KYQwbsz*tCkjsJPBdvEpFMktu#;drOZIf#-h)6% z&uj1kX{qiNs2FF%DiRGN%@=z--{#$IUBr_Z&eHMKv)r zrIef##T36Mitkv;)Z~gRrw^Dzmb9B+ZJh^mDN0ot8G>UwNIt_Tkd!KtGT@3Tc29OR zohXiClWwu+zbif5fR%yv*TQ;={s!GWM(|`uzS28-#}s`^zA+SFw?CqIuuJfbE#qP@ z6}PyGeGah|5j2L)fc(s9hcg59BV-k?RR32G39rWn9?UId95q?N#+8d@)kCr ztJ(k_U=L+pycb%>p^>(9c~K|pq7?eWcCD+V9wBI5)V`3iu^UJlUuc&MFFdWc-J@&p zUjWJ@yw`>LNOb!IFTf!OZ5-0+ka4k`cC#!ig@G*VqAW9&YIIo7v+Q#t^l)+_wQ$aW z&nsn5P_Tc~2*S^4!?Y*pF2Ia2+D9(1B}bt@mFb(+2S?P<9UJ)F>}-Gi%h1}s@Hzhj Di0;6v literal 0 HcmV?d00001 diff --git a/pyflo/ellipticcurve/utils/__pycache__/oid.cpython-38.pyc b/pyflo/ellipticcurve/utils/__pycache__/oid.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0339956dd4d83286f742e1598ef533005871569b GIT binary patch literal 1069 zcmZWn%W4!s6s@X$OlLBaOd!T2WRZmn2gC_3qKJsZAi6M!k4=L}XR4BE(%sWj-4ilU zEkg7sT!=3H7=NI*uEtMr<+(M9j#^N+?ybkId+s@}+U+L8Xn$)R{%{!kPQm;T2p(V- zH((@_JYgvhc`8D|nH17_&q7DK(!=UXUpBCMGI+td3sa6KT~RmVtbC-0>0@2)%gZ2AtS>uB1ookV4|ALY5qWH+c60XmYZAE!|gE*! zqd1GRV+xC~_4^3zshwdgLmvh~=pNF823dq(nQq~qpQ@K;Wl#3@l41X(KR~YSeRZmm zVV)`+Jdd*eAbuJp$u=G-ofU&P?;XWilsuapCBt4mXH}BKc^UWnV|}W6<1$W)9zMUB zPwFPt3j&FwVhe`xO&;(LcX`Wt!tfcTw?X~rn&Gzf+Cv8IlOYXhDyl0qeNr#KL9qwp^ib)SLnscEEYclP zdF^NRz&3AY+O!?uiM@OUQ9)8wd}xL$$(9}@b=3YCyZR4oN61scfi7UT&$Ys?5j zWH=;5sGKcUk$}V~Fg(8_XCkUEU^I}Z7CSp#Zc(7<4t8wOVE_^BtE7znDO)e&3Q;M1& literal 0 HcmV?d00001 diff --git a/pyflo/ellipticcurve/utils/__pycache__/pem.cpython-38.pyc b/pyflo/ellipticcurve/utils/__pycache__/pem.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..43b8465cdd5394868cc2b0e2c1cda1a7546be5b2 GIT binary patch literal 818 zcmZWn&2AGh5cbdRCXJF(2_!%QDMyw=whs_R743xsQ3c`>iGx`?$ri77v7Jh-Hm4N9 zr3c<1J@#RE0be=g6*vH6M?sMoX~tuF=9`(%e&6eL5J>Mw_hW+*`sp|OLSSg zfLFrfHEjqmncRBjTI1Z)v=h&fe~O2o<{6k7YS4#AO8{zcgE@MPzL2NrJNX_~X^IQwy8s;4gfmSBX2%KH4 z_MPb?kAOP?GmTuVnVJblrBJ%%@7rKfsy#`%>to~auG{jVk{{8pHX%EYaFQgdx{=zU_+K&GMSX8-i literal 0 HcmV?d00001 diff --git a/pyflo/ellipticcurve/utils/binary.py b/pyflo/ellipticcurve/utils/binary.py new file mode 100644 index 00000000..348887f0 --- /dev/null +++ b/pyflo/ellipticcurve/utils/binary.py @@ -0,0 +1,37 @@ +from base64 import b64encode, b64decode +from .compatibility import safeHexFromBinary, safeBinaryFromHex, toString + + +def hexFromInt(number): + hexadecimal = "{0:x}".format(number) + if len(hexadecimal) % 2 == 1: + hexadecimal = "0" + hexadecimal + return hexadecimal + + +def intFromHex(hexadecimal): + return int(hexadecimal, 16) + + +def hexFromByteString(byteString): + return safeHexFromBinary(byteString) + + +def byteStringFromHex(hexadecimal): + return safeBinaryFromHex(hexadecimal) + + +def numberFromByteString(byteString): + return intFromHex(hexFromByteString(byteString)) + + +def base64FromByteString(byteString): + return toString(b64encode(byteString)) + + +def byteStringFromBase64(base64String): + return b64decode(base64String) + + +def bitsFromHex(hexadecimal): + return format(intFromHex(hexadecimal), 'b').zfill(4 * len(hexadecimal)) diff --git a/pyflo/ellipticcurve/utils/compatibility.py b/pyflo/ellipticcurve/utils/compatibility.py new file mode 100644 index 00000000..3b22dd3c --- /dev/null +++ b/pyflo/ellipticcurve/utils/compatibility.py @@ -0,0 +1,40 @@ +from sys import version_info as pyVersion +from binascii import hexlify, unhexlify + + +if pyVersion.major == 3: + # py3 constants and conversion functions + + stringTypes = (str,) + intTypes = (int, float) + + def toString(string, encoding="utf-8"): + return string.decode(encoding) + + def toBytes(string, encoding="utf-8"): + return string.encode(encoding) + + def safeBinaryFromHex(hexadecimal): + if len(hexadecimal) % 2 == 1: + hexadecimal = "0" + hexadecimal + return unhexlify(hexadecimal) + + def safeHexFromBinary(byteString): + return toString(hexlify(byteString)) +else: + # py2 constants and conversion functions + + stringTypes = (str, unicode) + intTypes = (int, float, long) + + def toString(string, encoding="utf-8"): + return string + + def toBytes(string, encoding="utf-8"): + return string + + def safeBinaryFromHex(hexadecimal): + return unhexlify(hexadecimal) + + def safeHexFromBinary(byteString): + return hexlify(byteString) diff --git a/pyflo/ellipticcurve/utils/der.py b/pyflo/ellipticcurve/utils/der.py new file mode 100644 index 00000000..84546aea --- /dev/null +++ b/pyflo/ellipticcurve/utils/der.py @@ -0,0 +1,159 @@ +from datetime import datetime +from .oid import oidToHex, oidFromHex +from .binary import hexFromInt, intFromHex, byteStringFromHex, bitsFromHex + + +class DerFieldType: + + integer = "integer" + bitString = "bitString" + octetString = "octetString" + null = "null" + object = "object" + printableString = "printableString" + utcTime = "utcTime" + sequence = "sequence" + set = "set" + oidContainer = "oidContainer" + publicKeyPointContainer = "publicKeyPointContainer" + + +_hexTagToType = { + "02": DerFieldType.integer, + "03": DerFieldType.bitString, + "04": DerFieldType.octetString, + "05": DerFieldType.null, + "06": DerFieldType.object, + "13": DerFieldType.printableString, + "17": DerFieldType.utcTime, + "30": DerFieldType.sequence, + "31": DerFieldType.set, + "a0": DerFieldType.oidContainer, + "a1": DerFieldType.publicKeyPointContainer, +} +_typeToHexTag = {v: k for k, v in _hexTagToType.items()} + + +def encodeConstructed(*encodedValues): + return encodePrimitive(DerFieldType.sequence, "".join(encodedValues)) + + +def encodePrimitive(tagType, value): + if tagType == DerFieldType.integer: + value = _encodeInteger(value) + if tagType == DerFieldType.object: + value = oidToHex(value) + return "{tag}{size}{value}".format(tag=_typeToHexTag[tagType], size=_generateLengthBytes(value), value=value) + + +def parse(hexadecimal): + if not hexadecimal: + return [] + typeByte, hexadecimal = hexadecimal[:2], hexadecimal[2:] + length, lengthBytes = _readLengthBytes(hexadecimal) + content, hexadecimal = hexadecimal[lengthBytes: lengthBytes + length], hexadecimal[lengthBytes + length:] + if len(content) < length: + raise Exception("missing bytes in DER parse") + + tagData = _getTagData(typeByte) + if tagData["isConstructed"]: + content = parse(content) + + valueParser = { + DerFieldType.null: _parseNull, + DerFieldType.object: _parseOid, + DerFieldType.utcTime: _parseTime, + DerFieldType.integer: _parseInteger, + DerFieldType.printableString: _parseString, + }.get(tagData["type"], _parseAny) + return [valueParser(content)] + parse(hexadecimal) + + +def _parseAny(hexadecimal): + return hexadecimal + + +def _parseOid(hexadecimal): + return tuple(oidFromHex(hexadecimal)) + + +def _parseTime(hexadecimal): + string = _parseString(hexadecimal) + return datetime.strptime(string, "%y%m%d%H%M%SZ") + + +def _parseString(hexadecimal): + return byteStringFromHex(hexadecimal).decode() + + +def _parseNull(_content): + return None + + +def _parseInteger(hexadecimal): + integer = intFromHex(hexadecimal) + bits = bitsFromHex(hexadecimal[0]) + if bits[0] == "0": # negative numbers are encoded using two's complement + return integer + bitCount = 4 * len(hexadecimal) + return integer - (2 ** bitCount) + + +def _encodeInteger(number): + hexadecimal = hexFromInt(abs(number)) + if number < 0: + bitCount = 4 * len(hexadecimal) + twosComplement = (2 ** bitCount) + number + return hexFromInt(twosComplement) + bits = bitsFromHex(hexadecimal[0]) + if bits[0] == "1": # if first bit was left as 1, number would be parsed as a negative integer with two's complement + hexadecimal = "00" + hexadecimal + return hexadecimal + + +def _readLengthBytes(hexadecimal): + lengthBytes = 2 + lengthIndicator = intFromHex(hexadecimal[0:lengthBytes]) + isShortForm = lengthIndicator < 128 # checks if first bit of byte is 1 (a.k.a. short-form) + if isShortForm: + length = lengthIndicator * 2 + return length, lengthBytes + + lengthLength = lengthIndicator - 128 # nullifies first bit of byte (only used as long-form flag) + if lengthLength == 0: + raise Exception("indefinite length encoding located in DER") + lengthBytes += 2 * lengthLength + length = intFromHex(hexadecimal[2:lengthBytes]) * 2 + return length, lengthBytes + + +def _generateLengthBytes(hexadecimal): + size = len(hexadecimal) // 2 + length = hexFromInt(size) + if size < 128: # checks if first bit of byte should be 0 (a.k.a. short-form flag) + return length.zfill(2) + lengthLength = 128 + len(length) // 2 # +128 sets the first bit of the byte as 1 (a.k.a. long-form flag) + return hexFromInt(lengthLength) + length + + +def _getTagData(tag): + bits = bitsFromHex(tag) + bit8, bit7, bit6 = bits[:3] + + tagClass = { + "0": { + "0": "universal", + "1": "application", + }, + "1": { + "0": "context-specific", + "1": "private", + }, + }[bit8][bit7] + isConstructed = bit6 == "1" + + return { + "class": tagClass, + "isConstructed": isConstructed, + "type": _hexTagToType.get(tag), + } diff --git a/pyflo/ellipticcurve/utils/file.py b/pyflo/ellipticcurve/utils/file.py new file mode 100644 index 00000000..c7b1df73 --- /dev/null +++ b/pyflo/ellipticcurve/utils/file.py @@ -0,0 +1,9 @@ + + +class File: + + @classmethod + def read(cls, path, mode="r"): + with open(path, mode) as blob: + content = blob.read() + return content diff --git a/pyflo/ellipticcurve/utils/integer.py b/pyflo/ellipticcurve/utils/integer.py new file mode 100644 index 00000000..180f200c --- /dev/null +++ b/pyflo/ellipticcurve/utils/integer.py @@ -0,0 +1,16 @@ +from random import SystemRandom + + +class RandomInteger: + + @classmethod + def between(cls, min, max): + """ + Return integer x in the range: min <= x <= max + + :param min: minimum value of the integer + :param max: maximum value of the integer + :return: + """ + + return SystemRandom().randrange(min, max + 1) diff --git a/pyflo/ellipticcurve/utils/oid.py b/pyflo/ellipticcurve/utils/oid.py new file mode 100644 index 00000000..dbfebe79 --- /dev/null +++ b/pyflo/ellipticcurve/utils/oid.py @@ -0,0 +1,35 @@ +from .binary import intFromHex, hexFromInt + + +def oidFromHex(hexadecimal): + firstByte, remainingBytes = hexadecimal[:2], hexadecimal[2:] + firstByteInt = intFromHex(firstByte) + oid = [firstByteInt // 40, firstByteInt % 40] + oidInt = 0 + while len(remainingBytes) > 0: + byte, remainingBytes = remainingBytes[0:2], remainingBytes[2:] + byteInt = intFromHex(byte) + if byteInt >= 128: + oidInt = (128 * oidInt) + (byteInt - 128) + continue + oidInt = (128 * oidInt) + byteInt + oid.append(oidInt) + oidInt = 0 + return oid + + +def oidToHex(oid): + hexadecimal = hexFromInt(40 * oid[0] + oid[1]) + for number in oid[2:]: + hexadecimal += _oidNumberToHex(number) + return hexadecimal + + +def _oidNumberToHex(number): + hexadecimal = "" + endDelta = 0 + while number > 0: + hexadecimal = hexFromInt((number % 128) + endDelta) + hexadecimal + number //= 128 + endDelta = 128 + return hexadecimal or "00" diff --git a/pyflo/ellipticcurve/utils/pem.py b/pyflo/ellipticcurve/utils/pem.py new file mode 100644 index 00000000..1e58b409 --- /dev/null +++ b/pyflo/ellipticcurve/utils/pem.py @@ -0,0 +1,14 @@ +from re import search + + +def getPemContent(pem, template): + pattern = template.format(content="(.*)") + return search("".join(pattern.splitlines()), "".join(pem.splitlines())).group(1) + + +def createPem(content, template): + lines = [ + content[start:start + 64] + for start in range(0, len(content), 64) + ] + return template.format(content="\n".join(lines)) diff --git a/pybtc/functions/__init__.py b/pyflo/functions/__init__.py similarity index 100% rename from pybtc/functions/__init__.py rename to pyflo/functions/__init__.py diff --git a/pybtc/functions/__pycache__/__init__.cpython-36.pyc b/pyflo/functions/__pycache__/__init__.cpython-36.pyc similarity index 100% rename from pybtc/functions/__pycache__/__init__.cpython-36.pyc rename to pyflo/functions/__pycache__/__init__.cpython-36.pyc diff --git a/pyflo/functions/__pycache__/__init__.cpython-38.pyc b/pyflo/functions/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e7bb9fc3c67b65a712ac56a153885a641d86ad44 GIT binary patch literal 355 zcmY+}o_ke9_`ABB3~9yHtF=hXbKBs5py+Pe@OajeklPaI96X>=CNqIq;4 zErQ82D$_3gS?gEX$noYuvqovQ_PGG2xu^~s zY0l2;9z?G}vMQVU(+@NhVefBzzmgst;pBQ6WF3{Tyb*6gY151F@I--i@}4TSyagu) xu$?rdl|a?w*eXp-%*HX&Zh$$d!IHX`AYEObn9&y(z2+MwE~n4fqYwq&JwJEBUUvWh literal 0 HcmV?d00001 diff --git a/pybtc/functions/__pycache__/address.cpython-36.pyc b/pyflo/functions/__pycache__/address.cpython-36.pyc similarity index 100% rename from pybtc/functions/__pycache__/address.cpython-36.pyc rename to pyflo/functions/__pycache__/address.cpython-36.pyc diff --git a/pyflo/functions/__pycache__/address.cpython-38.pyc b/pyflo/functions/__pycache__/address.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e3f19bfcb4ac4d376939303337cb87d93ab8103c GIT binary patch literal 7540 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 literal 0 HcmV?d00001 diff --git a/pybtc/functions/__pycache__/bip39_mnemonic.cpython-36.pyc b/pyflo/functions/__pycache__/bip39_mnemonic.cpython-36.pyc similarity index 100% rename from pybtc/functions/__pycache__/bip39_mnemonic.cpython-36.pyc rename to pyflo/functions/__pycache__/bip39_mnemonic.cpython-36.pyc diff --git a/pyflo/functions/__pycache__/bip39_mnemonic.cpython-38.pyc b/pyflo/functions/__pycache__/bip39_mnemonic.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e25b0e1ead1fe47961dc3a303675aa83eadab9b0 GIT binary patch literal 5949 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 literal 0 HcmV?d00001 diff --git a/pybtc/functions/__pycache__/block.cpython-36.pyc b/pyflo/functions/__pycache__/block.cpython-36.pyc similarity index 100% rename from pybtc/functions/__pycache__/block.cpython-36.pyc rename to pyflo/functions/__pycache__/block.cpython-36.pyc diff --git a/pyflo/functions/__pycache__/block.cpython-38.pyc b/pyflo/functions/__pycache__/block.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1fe871bebceea26b460a8c1c3e8ce18f5072b317 GIT binary patch literal 4151 zcmdT{OK;p%6u#H?cqZ;-(x%fiZGoB;N{y-nBEce*w1R?K38IPwQ3h3mXRaqR)MHPs z9cUttgp?w&=!QQ~wL7|F$q!(G1i!#rR+0DxY{GZ0=bb)afl!^?>+5^&~}EwGVFEUQiE(C+sMetzdI;^h{`f#kMbm9lF=` z9s7F2j=b28LwiGRgFi3cmH}STwja~MbY3HrZ8yG%OKjmaTt$i0`rg^uu9Yz%pU#wB z4<#|qs7G3=ExwWRrX-hA-Cwts+CjV|mfrKj`t5qt1?yM6 zuRTBPv^@|$!5Pig$FA?&*Mr!TLDXz@mKrVS@5WBU50^S4ePcUNHjS2QblPHPC$%n- z1?yqEvsxq}40I;b*zVcPDXQcYi>Hk%;?#yYSJ zOajX}VEJC3)-@HD)y{5y1j}YO-@|eaST>XV0LvfYW}}DY`@lTgT22i4Q=%uv@IIjX z=R{j)BB!E^Mo|XXUKS>>op-N25!*E&y50mHffx99E2z1VH^6HcJm=sh&!Yg;i(~_7 z|3{!_4xERRNy>i{{wzzFdkt-fxN|)Z?=$~6)X5n-icohb4iP9+93o_?I8^NNgg;;p zSr&N|2M$-rdm>BkV)KBdH76&Lv6(zh9idYmqmEGR6yymS(`}VPpXbUdHxQ2lq{_QvsGLwrFY8Vo_jHdR%eVb7pdxVZxc=NAGz?0Be{t}0k;olW zQaVU=R3efbB{kxmj;EYkc{QA$oTxJ0*NM_o1|P~Sk`m^m>&|EPAanPM$X?*Rg2fT- zU{iCvKv|2t^hJD+A(CycUzpj>deF zCRS7(meq4qhoPG8Rd-bLp_=wKJ&CHVgPIB@i>s( z26jdipjn>mROIKi0-xvdJZ8qMMS+-DQ`RE(1T=gG`gXM4FDCRTT8%~v1$VsDtFe_{ z$F!NJYODM?nnDqv20S@a&{33Jmkv5!ia=nd3gc-AwfyA zN>K9R7(Zjk8L9km`0l-D2uu1M6O|_ZE5~s(C4e#)^4&SGJE?)$zQKp`hgjB^-@*7< z@@J-2@*g&Krr^xb!z;!#@Q;lxsZ7AnP#x&N%Nm|HDOGt$8angNh+G#jUUT?H?|(Wy zp?)4L4t^Lc#$o73>c>ciBmz-do?Jyg{jxx*0wIM-70Q&#Gv$*CCEYi|q)PLunlD^x dhhp3JRtZ57)fi=7)T}es%T~E?tY8(azX6Mp7bE}x literal 0 HcmV?d00001 diff --git a/pybtc/functions/__pycache__/encode.cpython-36.pyc b/pyflo/functions/__pycache__/encode.cpython-36.pyc similarity index 100% rename from pybtc/functions/__pycache__/encode.cpython-36.pyc rename to pyflo/functions/__pycache__/encode.cpython-36.pyc diff --git a/pyflo/functions/__pycache__/encode.cpython-38.pyc b/pyflo/functions/__pycache__/encode.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3bec164c5cceef4579fd671114159e7fcf8fa519 GIT binary patch literal 3895 zcmbtXOK=p|6@9ON^U()c2q6K+6Fb-*0+J#j7;IUHj{sv(@&8P053PPJO-nP~Gp~Du zG}W`QaM`X(r7Brv2}`obB3WjiO;TQD*;QF(rL}jiRFQLE>%)MvNM%I7e!qU7d(J)g za<8v1&+z-p-+C8+)z8?!sPXF0Kw}P1_;(b730`A$Ugn(YT1~6#WgT_BYzU)l3bSmv znN3#Csxs&1U2~IPVqYBjTr2mKd)*#4>-Nqtx6kd}6>R4J%7Bs8_1)dh*dP zC#OzLpFUGMd;Y@3OY@hnT)p<$^&1N}Z{5Cg_ul;n4weAOvrVOLj z+LQH-c2a0I+H&LUdTDuSGFlT)Cc>!|fBMvF)p1YPTlSe+Qn+=qeEZSahovi*C-2_B z^kCx7)U}1_Q=eVEIDh)az4K?T-*pItonH?s)V_!({09obI|d#zVwb+V}QSUad%+kLs10hIfle4H12m4(;ie9X@=c{kF8zRADhu@UoG7UwUpI5)>S zMr_9X4C|P9YpbR#(Yr+L3}%|=Se%_>n;=EA)-1)k{9|m&@70(VnZIAl}T4~h` z|BCNk8I#{*XG8650UERY-WAt(rClpDf+wy#87!TgEG*igTW|t@&6S}S_+yge_FGi6 z`#gWmu6d%MkZbSTX*O&jJb$^UCpj9irL;E^%WgDWUnKeacCF>kOBu*wPhto=vXd-< zzUW0^Vnu;^>sTYvZO2KBv@P98=CEmE)a~`PB!jX-!zND9a$hic0E0h%IbQdpaWQ_O z7C5U;)%N_tC3nrO1&z9kf!nt4RJ|K^tycKdk6h`8Rj)C=X$CjAg}+`t#It;0`^n-xgb{-e^AXhLLCkeD z`eOS>brX*w6=Z-#EC#WNI-3Rn(HFL8cq@zIMf&{!IM|OU65DSlvCtN^5 zSB?0lCI@5oOnc5cEYjggJmxFLcdR}94O`-5ilPd^|s@5VTX1mAc({p(WbbM8Z9o zomltErSmg2FN~a^-k2@X>ZA%5(^&i6ZS!LVWsVte(5{8EV|yR84=e<}@~ElF0_Z7i z2P_PWR+9HZ&krN;(@jj}PKhO4qMao4Q|jmD*B!S(oGhj^NcduUvUh2YB0+!mDJJQN zL{-M~;2^P710OBk&t(z4U92E*cAk*nRN@9vTjAfaHvx%xcs$k!ygMw`6kq>O5Vipz zEC7Oh2SJasdjjr3x>sIm8D<5_1$>7x@LuYkt%m#<$jan7!E3K9wpNM0-cD3Q^ULAldas z3jq}^w{XFAs)};1vl_PQW8R-0tbFX%e{=JF@5j;SN4ZdrwkD3FQnR9EE?<|TR*G~~}vOO3jV9OAn=M5Phb zHtKyZ%~^biMtPW%ap`3#Bp-u*Y z)Lhl%T5O3dg0R(mj4$Kn%C)+dgITXgF*jDCb#!WOn*>zB&(u&xgJCpt2q)afnZt-)MLesQ`~5#BOINn<7O z{9;yqNS|{*(WM)vI`s?mluf7YBD_+JNVxMl4t?pNl-f;~ZedbL@qrnGI)$+;q@kY= zsh~!neM@fqL@i|C_ka*ITXnFi3SO;N>Zku&IQuou?@0^X(8#J%2fa@ z0h@)lsuic2s?}3`wv$*~L%r){wB{}m=g^?U0z~0B8=Z{P$@b2O zKJ-%GsxD9MCf>U)+&#pJK80z)nuPa~MPpvW~iof()0tOdaHlZ``U2h3;E@ zi}~9@CCh&f1mtz}EEM_Oy?-OgkjhBMcBDNVtJ+~zZJr!>eJBcoT9~qi2$l4u;gs@> z(2bIzu4bjxaKKX};GPr7qjY%67?Ygqx9a#m0P+$=I8yRN52R4(tI8xLWp^rjP;pS{ zbqcVu3_+ys@`^R~qCj>AV%Dm;vqY(ow(RA-N^A@Wjipic+z%$^_54WQ$Q#+-d?wqQ K9myWf8vg+)0BRrr literal 0 HcmV?d00001 diff --git a/pybtc/functions/__pycache__/hash.cpython-36.pyc b/pyflo/functions/__pycache__/hash.cpython-36.pyc similarity index 100% rename from pybtc/functions/__pycache__/hash.cpython-36.pyc rename to pyflo/functions/__pycache__/hash.cpython-36.pyc diff --git a/pyflo/functions/__pycache__/hash.cpython-38.pyc b/pyflo/functions/__pycache__/hash.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b0ba94b99106343b07e337c681a7b5449ea60259 GIT binary patch literal 1335 zcmZ`&&2G~`5Z<*N+xcyqmS1tGDh~Kkx0PCPKnMY<#DNG=xI{>mcQS2}x<+pok5?X5Z4-1YGOe8e56ecewkh-fysVW;5p-?VD_axvUPT$-1n;nt)nt zleJhIP@8SB4qF4%Vb%%pZvBF2#G}g0_!oHCMHCzy9?j9={z30JG;qs&AV#JyU>3Vz zBq@ocQ$uv6QIaV=CnXg-(nLJ7F31U);~L^i+VgDHh>JKYWRQhinS~UpGnhzToDM~v zo<{tu>O?^iCGp_2Vx#KdWbsE{NM%>gOGD8}nc%-9Vhwow`QWFS^qK!W$-}cS3gT@0 zCI8Hme3Wu{@fM;*@#`Q-wqIqEi>!#^kw1*HAbB$xCb>VF+kp)I;W!IroM(lPM0Q6L zfjPUFvkivO26d_S-CUeK*mrGl9!j$+34^j>d8*ZvLV1kdJI@jrLpW$Kq>dw6h%nL0 ztOHVQmX8MspI4~^u0?uXSck~_Y9Ow`)V+HIpftp7NoKT!o=M}voSC{`iyqxUfnRww zWkqQa3Y5T7hd?C)wJn;s%~a+YpD2q3G7!jVm30&Uf}G*IEqFiYY|$9Tg?IO17W#;5b+}-)e<_`%<8z%tGAYnaFv56 t7tUg(R}`M^WJL?3EEG&@Sj*RalICoj@TU}Z6!=w(;^i8)(XjR9{sk4v2|WM+ literal 0 HcmV?d00001 diff --git a/pybtc/functions/__pycache__/key.cpython-36.pyc b/pyflo/functions/__pycache__/key.cpython-36.pyc similarity index 100% rename from pybtc/functions/__pycache__/key.cpython-36.pyc rename to pyflo/functions/__pycache__/key.cpython-36.pyc diff --git a/pyflo/functions/__pycache__/key.cpython-38.pyc b/pyflo/functions/__pycache__/key.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..35b29ff1ea1bce4ca832ef4578ae81a7ef4ed01e GIT binary patch literal 5134 zcmcIo&2JmW72nzAw@68rCE0S?cxxcFX$Vqc*Qu)(ZWWnKgxZQB(O*o9#cF41u0`&$ zvqQTgs7saRP{8>Mda#eV=g;W9z}|}HqFaFW6clxTZ2rXWzV;dGmX} z_lEaNrGkd*>R*cc|6bO#ztcKxWms;aE-H;)@F6q*6TXcT>Yt0H&CYPDSXpg z=^DuxtxP*x&$e^*9HaMCE8i~E3#g}grZv+p){E#{dOBO50coDTT z{5&u5S=1Kz9H0MGtDog7{0v_}%OXF^7tylBm-e*sg%iw4E9;TbXn2v)^7hLtVpq{n za(yS@uC;H6?v0yKiMxqc2$guy-EX;8*tDjcv8WznzaeY_V(zRS)ilB2?t2(s) z;YIZ{?k(KmDvG`?&Pz=)&ba=9^|e0Z#tUOl>l@;dWXIax=o@C6vj3`UTEWD%C0vYR zc7*qgo(Jw>LA7smY+<)eCunzs8-_05Fs}q1=>@*sDx0;#j%x-DvxBL74)t0!_YY0( zHtcRonxQLA86-NdnMx@Q_{Qsg==o2~F03^iGNC>+y%6d#7YEbirstc!``p~CeE4v? zX4;&qNrtQc#W>y2HDwd(;^mlu-#RoKfiU-N=is?5xSF>uy?w9c$-^}>);TbUbVKR8 za>5#omiKi zuF^1VTb|ZT!V`*{?(hEx#UE83y+Ltu%JF12%zI<3(5$eAL1**I008Ax6B96Fj$T@em~xkwL99sC}V{c|5-PWWDXnb-w;VD{u~+rj3={ zcAvSepwotruJ78u)Aa7zt(Lj%OIP?|)9b7^JowAK!$vDu?V55)9cj{_CuawS zcvpQ*;p@9H&GlpU2L|4_B{O~PoOY!7Ihl=XeI|DMV9%eT75Z{YLyD*WsIO?$CiBz+ zCdt?q7)#l`qIfRJB(&KCE%?^%=EK33#sDUI7{hsOf^(W16H2aMn*b1$koHR>(`aX)(4MKxwl)XZa<1H-rd~Z`3?b*#RLRJtg;cY=Gf1aZ^gwK z5}8GD33rGLK+|RlEXS5{r&vL!G6zpkG7bXR=%PA#g7Si!s1VMNSvXJekWfDK1>kxW zxYoHrNPcO&LR=ibQ)KM@O@aBgiqZvM$~p z)=zC*v_PFerU?f7Ib=i9tz~oAxf~O;vkpOWc+swrdbM*eQ5o`A2>y!qj`n8-EOw9; zmpC$-UQwoKcaPXZ&7Wl&{T_p>_OwTo^$b|*2<)f&rDdj}A7n%e+y*T040y0l(*FFQ zB|B^Z&oShMDZ&OM(>zDDzK-vIrXD;GgcN$8DTHh_UFU$Zk|aJrcw^@sf&?m`ji`t0(_@{rdIJ$vdc@{FqvoP}ItKK~5yjQ9&CS zolClJ?77yR?Y)}X;pp--AHKh{_3>SZ?(J1>51sw;G&YzbC{}1>^8B(P=BQ5SsplLr zUD$1(f{-8teuO)uHE3D#{UUr`N10Le9MfNCbb6!qAK+GfCL$t5%n_pgiI)+gxT@)h zes4=;$P^p>s%kUP_L~@0;f74d-+sq|AO_@RWL6<)hwDd-Vj=Oz3th#_JWnZpDZHHF z=~wK?kVRSQQ^YlnQvFo;nVjVr6=#|FoM(NV=Z?~nr1SmsvW6ZR^;YPoU+G6csQ6OO z`MR7x%E>cwp`Ynzp)GfuK1xXj$+KvIB<7xn_OC|Tb@6pS|8i0B8KHE>E`bykP(MV9 zG|tmaqWTHUc2(Y8*}A>A31)ISIE5U%H^E^Em!1aM)nSlV)cC!JVzsC#r-7-eu{VL^zPZA5m=WNFb1gD4yI+V>f9w1~>osNd7ZrE`hui?c<5%T#di3kGfWD@@W z+-%Ihhi>I_aw91IX%LqT~{ z{L87liC8nmW|2V^6mt@<&f+ezdHg7=5)`W^A~T_dqO*$3Pf;22=#-NMwutL0lQLHD zAIkxqDdJN{8nN?M;#=lG4D=;cGy&*8b<=JbNy#l+jrZ6?>XvZER?Ti zDRzL=V*jMGs7l3S|5T1kC{oKv7=sSaf^z#P_ltJGyDj$?VJjq+^9bb`z;d3zsAr7A NQemY~%Dq*%{2zO|ZCU^T literal 0 HcmV?d00001 diff --git a/pybtc/functions/__pycache__/script.cpython-36.pyc b/pyflo/functions/__pycache__/script.cpython-36.pyc similarity index 100% rename from pybtc/functions/__pycache__/script.cpython-36.pyc rename to pyflo/functions/__pycache__/script.cpython-36.pyc diff --git a/pyflo/functions/__pycache__/script.cpython-38.pyc b/pyflo/functions/__pycache__/script.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..02458d3d6cfe1e299ae6e1366de9656a8ea77f18 GIT binary patch literal 13962 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 Ak^lez literal 0 HcmV?d00001 diff --git a/pybtc/functions/address.py b/pyflo/functions/address.py similarity index 98% rename from pybtc/functions/address.py rename to pyflo/functions/address.py index fb489ff8..708f263b 100644 --- a/pybtc/functions/address.py +++ b/pyflo/functions/address.py @@ -1,9 +1,9 @@ -from pybtc.opcodes import * -from pybtc.constants import * +from pyflo.opcodes import * +from pyflo.constants import * -from pybtc.functions.tools import bytes_from_hex -from pybtc.functions.hash import double_sha256, hash160 -from pybtc.functions.encode import (encode_base58, +from pyflo.functions.tools import bytes_from_hex +from pyflo.functions.hash import double_sha256, hash160 +from pyflo.functions.encode import (encode_base58, rebase_8_to_5, bech32_polymod, rebase_5_to_32, diff --git a/pybtc/functions/bip32.py b/pyflo/functions/bip32.py similarity index 98% rename from pybtc/functions/bip32.py rename to pyflo/functions/bip32.py index 624902aa..484093c6 100644 --- a/pybtc/functions/bip32.py +++ b/pyflo/functions/bip32.py @@ -1,11 +1,11 @@ from struct import pack from secp256k1 import ffi, lib -from pybtc.functions.key import private_to_public_key, private_key_to_wif -from pybtc.functions.hash import hmac_sha512, double_sha256, hash160 -from pybtc.functions.encode import (encode_base58, +from pyflo.functions.key import private_to_public_key, private_key_to_wif +from pyflo.functions.hash import hmac_sha512, double_sha256, hash160 +from pyflo.functions.encode import (encode_base58, decode_base58_with_checksum, encode_base58_with_checksum) -from pybtc.constants import * +from pyflo.constants import * def create_master_xprivate_key(seed, testnet=False, base58=True, hex=False): diff --git a/pybtc/functions/bip39_mnemonic.py b/pyflo/functions/bip39_mnemonic.py similarity index 98% rename from pybtc/functions/bip39_mnemonic.py rename to pyflo/functions/bip39_mnemonic.py index 43ad3917..df046b53 100644 --- a/pybtc/functions/bip39_mnemonic.py +++ b/pyflo/functions/bip39_mnemonic.py @@ -1,8 +1,8 @@ -from pybtc.constants import * +from pyflo.constants import * import time import hashlib -from pybtc.functions.hash import sha256 -from pybtc.functions.tools import int_from_bytes +from pyflo.functions.hash import sha256 +from pyflo.functions.tools import int_from_bytes def generate_entropy(strength=256, hex=True): """ diff --git a/pybtc/functions/block.py b/pyflo/functions/block.py similarity index 97% rename from pybtc/functions/block.py rename to pyflo/functions/block.py index 1cf84a24..d6c1f4b4 100644 --- a/pybtc/functions/block.py +++ b/pyflo/functions/block.py @@ -1,5 +1,5 @@ -from pybtc.functions.tools import s2rh, bytes_from_hex, int_from_bytes -from pybtc.functions.hash import double_sha256 +from pyflo.functions.tools import s2rh, bytes_from_hex, int_from_bytes +from pyflo.functions.hash import double_sha256 def merkle_root(tx_hash_list, hex=True): """ diff --git a/pybtc/functions/encode.py b/pyflo/functions/encode.py similarity index 97% rename from pybtc/functions/encode.py rename to pyflo/functions/encode.py index d26f3a51..6c55083d 100644 --- a/pybtc/functions/encode.py +++ b/pyflo/functions/encode.py @@ -1,5 +1,5 @@ -from pybtc.functions.hash import double_sha256 -from pybtc.functions.tools import bytes_from_hex +from pyflo.functions.hash import double_sha256 +from pyflo.functions.tools import bytes_from_hex b58_digits = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' base32charset = "qpzry9x8gf2tvdw0s3jn54khce6mua7l" diff --git a/pybtc/functions/hash.py b/pyflo/functions/hash.py similarity index 100% rename from pybtc/functions/hash.py rename to pyflo/functions/hash.py diff --git a/pybtc/functions/key.py b/pyflo/functions/key.py similarity index 97% rename from pybtc/functions/key.py rename to pyflo/functions/key.py index b00e81f9..d44503bf 100644 --- a/pybtc/functions/key.py +++ b/pyflo/functions/key.py @@ -2,9 +2,9 @@ secp256k1_ec_pubkey_create = lib.secp256k1_ec_pubkey_create secp256k1_ec_pubkey_serialize = lib.secp256k1_ec_pubkey_serialize -from pybtc.constants import * -from pybtc.functions.encode import encode_base58, decode_base58 -from pybtc.functions.hash import double_sha256 +from pyflo.constants import * +from pyflo.functions.encode import encode_base58, decode_base58 +from pyflo.functions.hash import double_sha256 from .bip39_mnemonic import generate_entropy bytes_from_hex = bytes.fromhex diff --git a/pybtc/functions/script.py b/pyflo/functions/script.py similarity index 89% rename from pybtc/functions/script.py rename to pyflo/functions/script.py index e73c6f67..8392953c 100644 --- a/pybtc/functions/script.py +++ b/pyflo/functions/script.py @@ -1,5 +1,9 @@ from struct import unpack - +import hashlib +from pyflo.ellipticcurve.privateKey import PrivateKey +from pyflo.ellipticcurve.signature import Signature +from pyflo.ellipticcurve.math import Math +from pyflo.ellipticcurve.utils.integer import RandomInteger from secp256k1 import ffi, lib secp256k1_ecdsa_signature_parse_der = lib.secp256k1_ecdsa_signature_parse_der secp256k1_ec_pubkey_parse = lib.secp256k1_ec_pubkey_parse @@ -11,13 +15,13 @@ secp256k1_ecdsa_recover = lib.secp256k1_ecdsa_recover secp256k1_ec_pubkey_serialize = lib.secp256k1_ec_pubkey_serialize -from pybtc.opcodes import * -from pybtc.constants import * +from pyflo.opcodes import * +from pyflo.constants import * -from pybtc.functions.tools import bytes_from_hex, int_to_bytes, get_stream -from pybtc.functions.hash import hash160, sha256 -from pybtc.functions.address import hash_to_address -from pybtc.functions.key import is_wif_valid, wif_to_private_key +from pyflo.functions.tools import bytes_from_hex, int_to_bytes, get_stream +from pyflo.functions.hash import hash160, sha256 +from pyflo.functions.address import hash_to_address +from pyflo.functions.key import is_wif_valid, wif_to_private_key def public_key_to_pubkey_script(key, hex=True): @@ -400,51 +404,64 @@ def verify_signature(sig, pub_key, msg): result = secp256k1_ecdsa_verify(ECDSA_CONTEXT_VERIFY, raw_sig, msg, raw_pubkey) return True if result else False - -def sign_message(msg, private_key, hex=True): +def to_base(n, base): + if base == 10: + return n + result = 0 + counter = 0 + while n: + r = n % base + n //= base + result += r * 10 ** counter + counter += 1 + return result + +# https://raw.githubusercontent.com/starkbank/ecdsa-python/master/ellipticcurve/ecdsa.py +def modSign(message, privateKey, hashfunc=sha256): + # byteMessage = toBytes(message).digest() + # byteMessage = hashfunc(toBytes(message)).digest() + + byteMessage = hashlib.sha256(message.encode("utf-8")).hexdigest() + # byteMessage = '0x' + byteMessage + + # byteMessage = script_to_hash("686579", True) + numberMessage = int(byteMessage, base=16) + numberMessage = to_base(numberMessage, 16) + curve = privateKey.curve + r, s, randSignPoint = 0, 0, None + while r == 0 or s == 0: + randNum = RandomInteger.between(1, curve.N - 1) + randSignPoint = Math.multiply( + curve.G, n=randNum, A=curve.A, P=curve.P, N=curve.N + ) + r = randSignPoint.x % curve.N + s = ( + (numberMessage + r * privateKey.secret) * (Math.inv(randNum, curve.N)) + ) % curve.N + recoveryId = randSignPoint.y & 1 + if randSignPoint.y > curve.N: + recoveryId += 2 + + return Signature(r=r, s=s, recoveryId=recoveryId) + +def sign_message(msg, private_key): """ Sign message - :param msg: message to sign bytes or HEX encoded string. - :param private_key: private key (bytes, hex encoded string or WIF format) + :param msg: message to sign in string. + :param private_key: private key (WIF format) :param hex: (optional) If set to True return key in HEX format, by default is True. :return: DER encoded signature in bytes or HEX encoded string. """ - if isinstance(msg, bytearray): - msg = bytes(msg) - if isinstance(msg, str): - try: - msg = bytes_from_hex(msg) - except: - pass - if not isinstance(msg, bytes): - raise TypeError("message must be a bytes or hex encoded string") - - if isinstance(private_key, bytearray): - private_key = bytes(private_key) - if isinstance(private_key, str): - try: - private_key = bytes_from_hex(private_key) - except: - if is_wif_valid(private_key): - private_key = wif_to_private_key(private_key, hex=False) - if not isinstance(private_key, bytes): - raise TypeError("private key must be a bytes, hex encoded string or in WIF format") + if(is_wif_valid(private_key)): + hexKey = wif_to_private_key(private_key) + else: + raise TypeError("Invalid Private_Key, must be in WIF format") + pk = PrivateKey.fromString(hexKey) + signature = modSign(msg, pk) + toDer = int.from_bytes(signature.toDer(), 'big') + return hex(toDer)[2:] - raw_sig = ffi.new('secp256k1_ecdsa_signature *') - signed = secp256k1_ecdsa_sign(ECDSA_CONTEXT_SIGN, raw_sig, msg, - private_key, ffi.NULL, ffi.NULL) - if not signed: - raise RuntimeError("secp256k1 error") - len_sig = 74 - output = ffi.new('unsigned char[%d]' % len_sig) - outputlen = ffi.new('size_t *', len_sig) - res = secp256k1_ecdsa_signature_serialize_der(ECDSA_CONTEXT_SIGN, - output, outputlen, raw_sig) - if not res: - raise RuntimeError("secp256k1 error") - signature = bytes(ffi.buffer(output, outputlen[0])) - return signature.hex() if hex else signature def public_key_recovery(signature, messsage, rec_id, compressed=True, hex=True): diff --git a/pybtc/functions/tools.py b/pyflo/functions/tools.py similarity index 100% rename from pybtc/functions/tools.py rename to pyflo/functions/tools.py diff --git a/pybtc/opcodes.py b/pyflo/opcodes.py similarity index 100% rename from pybtc/opcodes.py rename to pyflo/opcodes.py diff --git a/pybtc/test/__init__.py b/pyflo/test/__init__.py similarity index 100% rename from pybtc/test/__init__.py rename to pyflo/test/__init__.py diff --git a/pybtc/test/address_class.py b/pyflo/test/address_class.py similarity index 100% rename from pybtc/test/address_class.py rename to pyflo/test/address_class.py diff --git a/pybtc/test/address_functions.py b/pyflo/test/address_functions.py similarity index 100% rename from pybtc/test/address_functions.py rename to pyflo/test/address_functions.py diff --git a/pybtc/test/block.py b/pyflo/test/block.py similarity index 100% rename from pybtc/test/block.py rename to pyflo/test/block.py diff --git a/pybtc/test/create_transaction.py b/pyflo/test/create_transaction.py similarity index 100% rename from pybtc/test/create_transaction.py rename to pyflo/test/create_transaction.py diff --git a/pybtc/test/ecdsa.py b/pyflo/test/ecdsa.py similarity index 100% rename from pybtc/test/ecdsa.py rename to pyflo/test/ecdsa.py diff --git a/pybtc/test/hash_functions.py b/pyflo/test/hash_functions.py similarity index 100% rename from pybtc/test/hash_functions.py rename to pyflo/test/hash_functions.py diff --git a/pybtc/test/integer.py b/pyflo/test/integer.py similarity index 100% rename from pybtc/test/integer.py rename to pyflo/test/integer.py diff --git a/pybtc/test/mnemonic.py b/pyflo/test/mnemonic.py similarity index 100% rename from pybtc/test/mnemonic.py rename to pyflo/test/mnemonic.py diff --git a/pybtc/test/raw_block.txt b/pyflo/test/raw_block.txt similarity index 100% rename from pybtc/test/raw_block.txt rename to pyflo/test/raw_block.txt diff --git a/pybtc/test/script_deserialize.py b/pyflo/test/script_deserialize.py similarity index 100% rename from pybtc/test/script_deserialize.py rename to pyflo/test/script_deserialize.py diff --git a/pybtc/test/script_functions.py b/pyflo/test/script_functions.py similarity index 100% rename from pybtc/test/script_functions.py rename to pyflo/test/script_functions.py diff --git a/pybtc/test/sighash.py b/pyflo/test/sighash.py similarity index 100% rename from pybtc/test/sighash.py rename to pyflo/test/sighash.py diff --git a/pybtc/test/transaction_constructor.py b/pyflo/test/transaction_constructor.py similarity index 100% rename from pybtc/test/transaction_constructor.py rename to pyflo/test/transaction_constructor.py diff --git a/pybtc/test/transaction_deserialize.py b/pyflo/test/transaction_deserialize.py similarity index 100% rename from pybtc/test/transaction_deserialize.py rename to pyflo/test/transaction_deserialize.py diff --git a/pybtc/transaction.py b/pyflo/transaction.py similarity index 99% rename from pybtc/transaction.py rename to pyflo/transaction.py index 85e437b7..c6325906 100644 --- a/pybtc/transaction.py +++ b/pyflo/transaction.py @@ -2,21 +2,21 @@ from struct import unpack, pack from math import ceil from io import BytesIO -from pybtc.constants import * -from pybtc.opcodes import * -from pybtc.functions.tools import (int_to_var_int, +from pyflo.constants import * +from pyflo.opcodes import * +from pyflo.functions.tools import (int_to_var_int, read_var_int, var_int_to_int, rh2s, s2rh, bytes_from_hex, get_stream) -from pybtc.functions.script import op_push_data, decode_script, parse_script, sign_message -from pybtc.functions.script import get_multisig_public_keys, read_opcode, is_valid_signature_encoding -from pybtc.functions.script import public_key_recovery, delete_from_script -from pybtc.functions.hash import hash160, sha256, double_sha256 -from pybtc.functions.address import hash_to_address, address_net_type, address_to_script -from pybtc.address import PrivateKey, Address, ScriptAddress, PublicKey +from pyflo.functions.script import op_push_data, decode_script, parse_script, sign_message +from pyflo.functions.script import get_multisig_public_keys, read_opcode, is_valid_signature_encoding +from pyflo.functions.script import public_key_recovery, delete_from_script +from pyflo.functions.hash import hash160, sha256, double_sha256 +from pyflo.functions.address import hash_to_address, address_net_type, address_to_script +from pyflo.address import PrivateKey, Address, ScriptAddress, PublicKey diff --git a/pybtc/wallet.py b/pyflo/wallet.py similarity index 100% rename from pybtc/wallet.py rename to pyflo/wallet.py diff --git a/tanishktests.py b/tanishktests.py new file mode 100644 index 00000000..7fec64c5 --- /dev/null +++ b/tanishktests.py @@ -0,0 +1,20 @@ +import pyflo + +# pk = pybtc.create_private_key() +# print("pk = " + pk) +# pk = "RCJ9Q6kH5ywdRhchVKrxPUFiJE7cGMKFEB8n9zd4VgdNVYzHNedz" + + +# a = pybtc.sign_message_tanishk("hey", pk, hex=True) +# print(a) +# b = pybtc.verify_signature(a, public, "6865790D0A") +# print(b) +# pybtc.test_function() +msg = "hey" +pk = "RCJ9Q6kH5ywdRhchVKrxPUFiJE7cGMKFEB8n9zd4VgdNVYzHNedz" +public = pyflo.private_to_public_key(pk) +print("public = " + public) +sig = '30460221008b30bdc5039264abb40b686b1bdb9db0900e0b6c50dea793c0c1b1bde654119a022100b51e25bc73c274a5f3cd8bcdb11143921a2b1595c3b62f1cffcbe3bc5e876b65' +sig = pyflo.sign_message(msg, pk) +print(sig) + From 96275b117986145808a3ae35f39b5b3f5588a74c Mon Sep 17 00:00:00 2001 From: Vivek Teega Date: Sat, 9 Jul 2022 08:49:33 +0000 Subject: [PATCH 2/3] Update Readme --- README.md | 86 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 50 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index 94742d6c..66d5c3ff 100644 --- a/README.md +++ b/README.md @@ -1,26 +1,11 @@ - - -## Python bitcoin library - -Current version is 2.0 - - -### Feature Support - -* Basic functions -* Supports addresses types PUBKEY, P2PKH, P2SH, P2SH-PWPKH, P2WPKH, P2WSH. -* Supports BIP32(Hierarchical Deterministic Wallets), BIP39(Mnemonic code generation) -* Supports BIP141(Segregated Witness) -* Transaction constructor - +## Python bitcoin library modified for FLO ### Installation +To install pyflo, -To install pybtc, simply use pip - - $ git clone https://github.com/bitaps-com/pybtc - $ cd pybtc - $ python3 setup.py install + $ git clone https://github.com/ranchimall/pyflo + $ cd pyflo + $ sudo python3 setup.py install ### Dependencies @@ -28,22 +13,51 @@ To install pybtc, simply use pip * secp256k1 -### Documentation - -Documentation is available at https://pybtc.readthedocs.io - - -### How to Contribute - -In order to make a clone of the GitHub repo: open the link and press the “Fork” button on the upper-right menu of the web page. - -Workflow is pretty straightforward: +#### Message signing and verification + +Every message sent to the Blockchain is in hash format, and not in plain string. So we convert the message we are signing into a SHA256 hash before. + +``` +>>> import pyflo + +# ADDRESS GENERATION +>>> a = pyflo.Address(address_type="P2PKH") +>>> a.address +'FTP7LL7QjhgKfqYX1pis18bCqEpZaGSRzZ' +>>> a.private_key.wif +'R8Gw2Mr3n2fY1ydB2X5gEehxHkdhboeUD6yw4wRtVKHaqAd9gdkK' +>>> a.private_key.hex +'16b6aca5ff6a3bf3a1332dd4edf87880b2883cb4fe16effd073e2e866aa141aa' +>>> a.public_key.hex +'033c30b269e2d5df229f3f0ce294b19c4f0a3a8d12280415ce41e7bd3784a619c4' + +# CONVERT MESSAGE INTO SHA-256 HASH +>>> pyflo.sha256(b'vivek'.hex()) +b'\xa3\xdas\x97e\x01\x81,\xd7\xb8!\xa2\x0b\xfb\t\xaf\nj\x89\x1eA\x9c\xdf\xb7a\xfb\x19\xa9,\x91BB' +>>> pyflo.sha256(b'vivek'.hex()).hex() +'a3da73976501812cd7b821a20bfb09af0a6a891e419cdfb761fb19a92c914242' +>>> msg = b'vivek'.hex() +>>> msg_hash_hex = pyflo.sha256(msg).hex() +>>> msg_hash_bytes = pyflo.sha256(msg) +>>> msg +'766976656b' +>>> msg_hash_hex +'a3da73976501812cd7b821a20bfb09af0a6a891e419cdfb761fb19a92c914242' +>>> msg_hash_bytes +b'\xa3\xdas\x97e\x01\x81,\xd7\xb8!\xa2\x0b\xfb\t\xaf\nj\x89\x1eA\x9c\xdf\xb7a\xfb\x19\xa9,\x91BB' + +# SIGN AND VERIFY THE MESSAGE +>>> sig_msg_hex = pyflo.sign_message(msg_hash_hex, a.private_key.wif) +>>> pyflo.verify_signature(sig_msg_hex, a.public_key.hex, msg_hash_hex) +True + +# SIGN AND VERIFY MESSAGE IN STANDARD OPERATION +sig_msg_hex = pyflo.sign_message_standard_ops('vivek', a.private_key.wif) + +# To verify the above signature, run the following in the console of any Standard Ops app +floCrypto.verifySign('vivek', sig_msg_hex, a.public_key.hex) + +``` -1. Clone the GitHub -2. Make a change -3. Make sure all tests passed -4. Add a record into file into change.log. -5. Commit changes to own pybtc clone -6. Make pull request from github page for your clone against master branch From b55a5353a3dc87d3f7320bef27a9538752c6cebf Mon Sep 17 00:00:00 2001 From: Vivek Teega Date: Sat, 9 Jul 2022 08:50:58 +0000 Subject: [PATCH 3/3] Remove extra files --- .gitignore | 2 +- tanishktests.py | 20 -------------------- 2 files changed, 1 insertion(+), 21 deletions(-) delete mode 100644 tanishktests.py diff --git a/.gitignore b/.gitignore index 6f804fc4..f6160690 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,4 @@ build/ dist/ .github/ pybtc.egg-info/ - +*.pyc diff --git a/tanishktests.py b/tanishktests.py deleted file mode 100644 index 7fec64c5..00000000 --- a/tanishktests.py +++ /dev/null @@ -1,20 +0,0 @@ -import pyflo - -# pk = pybtc.create_private_key() -# print("pk = " + pk) -# pk = "RCJ9Q6kH5ywdRhchVKrxPUFiJE7cGMKFEB8n9zd4VgdNVYzHNedz" - - -# a = pybtc.sign_message_tanishk("hey", pk, hex=True) -# print(a) -# b = pybtc.verify_signature(a, public, "6865790D0A") -# print(b) -# pybtc.test_function() -msg = "hey" -pk = "RCJ9Q6kH5ywdRhchVKrxPUFiJE7cGMKFEB8n9zd4VgdNVYzHNedz" -public = pyflo.private_to_public_key(pk) -print("public = " + public) -sig = '30460221008b30bdc5039264abb40b686b1bdb9db0900e0b6c50dea793c0c1b1bde654119a022100b51e25bc73c274a5f3cd8bcdb11143921a2b1595c3b62f1cffcbe3bc5e876b65' -sig = pyflo.sign_message(msg, pk) -print(sig) -