eosnewyork / eospy

eos python library
MIT License
150 stars 66 forks source link

long sign time and eosjs verify #52

Closed dengboren86 closed 5 years ago

dengboren86 commented 5 years ago

Dear EOSPY developers,

Your project is very important to me! Thanks for the great work on the ECC algo.

1, Sometimes sign is quick, while sometimes it takes long to sign. (minutes) It will keep poping: Still searching for a signature. Tried 10 times. Still searching for a signature. Tried 10 times. Still searching for a signature. Tried 10 times.

My recent occurence takes 4min to sign 4 strings.

Does it matter that time randomization is added or removed? I already removed it, before this I even got as long as 18mins to sign 10 strings.

2, is the signature algo same as eosjs-cc? The signature I got here seems to fail eosjs-cc verify. Not sure if they have any difference.

Thank you!

deckb commented 5 years ago

I'm not sure why you would be seeing issues with long signing times. Can you run and post the output of running https://github.com/eosnewyork/eospy/blob/master/examples/sign_trx.py.

There have been issues verifying signatures between eosjs-ecc, eosio, and eospy. This might be what you have been experiencing. That being said the EOS mainnet accepts trx signed by eospy. I will start to investigate this issue.

dengboren86 commented 5 years ago

sign_trx.py", line 16, in results=timeit.timeit('k.sign(digest)', setup=setup_str, number=number) File "/root/anaconda3/lib/python3.7/timeit.py", line 232, in timeit return Timer(stmt, setup, timer, globals).timeit(number) File "/root/anaconda3/lib/python3.7/timeit.py", line 176, in timeit timing = self.inner(it, self.timer) File "", line 7, in inner TypeError: a bytes-like object is required, not 'str'

It has above error.

deckb commented 5 years ago

apologizes I hadn't upgraded that script to work with python 3. It should work now. For reference my box got .3235 seconds per sign.

dengboren86 commented 5 years ago

First time: Creating Key: Ran 10 times and averaged 0.14165934999473392 seconds/run Signing: Ran 10 times and averaged 0.6755306199891493 seconds/run

Second time: Creating Key: Ran 10 times and averaged 0.1335108600091189 seconds/run Still searching for a signature. Tried 10 times. Still searching for a signature. Tried 10 times. Signing: Ran 10 times and averaged 0.6848020400153473 seconds/run

Changed number=1000:

Creating Key: Ran 1000 times and averaged 0.13385966360010207 seconds/run Still searching for a signature. Tried 10 times. Still searching for a signature. Tried 20 times. Still searching for a signature. Tried 10 times. ... Still searching for a signature. Tried 10 times. Signing: Ran 1000 times and averaged 0.6733627530999947 seconds/run

1, looks avg time is okay. Have you encountered below? Still searching for a signature. Tried 10 times.

Does this affect signing time?

2, For eosjs-ecc issue, I raised this because an exchange is using it to verify transactions, which doesn't accept eospy. I have to use execjs in python to pass it, much slower than eospy. Wondering if can find help here...

dengboren86 commented 5 years ago

Change number to 3, and loop 1000 times:

max avg sign time is 1.3775968333551039 min is 0.3622123666573316

deckb commented 5 years ago

1, looks avg time is okay. Have you encountered below? Still searching for a signature. Tried 10 times.

Does this affect signing time? I have seen the "Still searching" warning and it just means the lib is taking some time to generate k. I usually only see it occasionally and it shouldn't greatly prolong the sign times.

So it looks like your average sign times are pretty good using this test so I'm not 100% sure why it would take minutes to sign 4 strings. Can you share your signing code so I can see if anything weird is happening?

2, For eosjs-ecc issue, I raised this because an exchange is using it to verify transactions, which doesn't accept eospy. I have to use execjs in python to pass it, much slower than eospy. Wondering if can find help here...

I am taking a look at the eosjs-ecc verification today. Hopefully should have a fix soon.

dengboren86 commented 5 years ago

1 is resolved. It's because other part failure of my code. Sorry for misreporting. Thank you and looking forward to eosjs-ecc! :):)

deckb commented 5 years ago

Good news. Will report back re: eosjs-ecc

deckb commented 5 years ago

I figured out the issue to be the randomization of k in the sign function and possibly the fact that eosjs-ecc sign when taking a string takes the sha256sum of the string and signs that. I created a sign_string method for EOSKeys and made the sign method take a 32 byte string much like eosjs-ecc. NOTE this may break programs.

You can check out examples/verify_trx.py to see an example of the sign methods.

I verified the sigs with this app:

const ecc = require("eosjs-ecc");

console.log(
  ecc
    .signHash(
      "9d8815193d76ee236ef08e8b9fb675e6def3af8d8209d7665540ab9e17944e19",
      "5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3"
    )
    .toString()
);

console.log(
  ecc.verifyHash(
    "SIG_K1_K1uqsnHJNSWf5s7sobyXz6ogpWNF4CoPQt8ht2WRE8wKuoH9jB4nDiPCqfXqbTHiF91vkqv6g8UBZv1j1bwMtYDWy3bWFH",
    "9d8815193d76ee236ef08e8b9fb675e6def3af8d8209d7665540ab9e17944e19",
    "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV"
  )
);

console.log(
  ecc.verify(
    "SIG_K1_JzyoDELfj6iHHHmKVjPkpWmEU8V5GcQ7gF5evLHpsWpTZ2wW14ADQH8vk7YyuqatW1RtMV39BVpp3SePkJ3n7oFA17utrw",
    "i am a string",
    "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV"
  )
);

Please try out master and let me know if this issue is fixed.

dengboren86 commented 5 years ago

Sure, will check and get back.

NOTE this may break programs. Would you kindly elaborate under what circumstance the program will be broken? :)

deckb commented 5 years ago

The sign method now works like the eosjs-ecc sign which only takes a 32 byte buffer/digest. So if someone was passing arbitrary data it would most likely fail

dengboren86 commented 5 years ago

How shall I upgrade to master? :)

I used below, still get 2.0.1 build.

create virtual environment

mkdir -p ~/envs/eospy ... pip install libeospy

deckb commented 5 years ago

I would run

pip uninstall libeospy
pip install git+https://github.com/eosnewyork/eospy.git
dengboren86 commented 5 years ago

Upgrade finished!

It cannot pass verify on my side. Actually I am using eospy to sign strings for below project: https://github.com/WhaleEx/API/blob/master/sample/java/src/main/java/com/whaleex/api/client/util/crypto/ec/EcDsa.java

Strings signed by both this .java and eosjs-ecc can pass it, while eospy cannot...

deckb commented 5 years ago

You are using the sign_string function now correct?

dengboren86 commented 5 years ago

Yes, I've tried 1, sign_string(string) 2, sign(sha256(string.encode()))

Neither works..

deckb commented 5 years ago

I am a bit at a loss. I can successfully use eosjs-ecc to verify a string signed with eospy. Here is how I did it. Does it line up with how you are verifying.

python signing script sign_string.py:

from eospy.keys import EOSKey
import argparse

parser = argparse.ArgumentParser(description='check espn fantasy scores')
parser.add_argument(type=str, action='store', dest='string')
args = parser.parse_args()
k = EOSKey("5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3")

print(k.sign_string(args.string))

eosjs-ecc script verify.js:

const ecc = require("eosjs-ecc");

const args = process.argv.slice(2);
const str = args[0];
const sig = args[1];
console.log(args);
console.log(
  ecc.verify(sig, str, "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV")
);

Steps to run the scripts

npm install -g eosjs-ecc
virtualenv -p /usr/bin/python3.7 ~/envs/testeospy
source ~/envs/testeospy/bin/activate
pip install git+https://github.com/eosnewyork/eospy.git
export INPUT="this is some string"
python ./sign_string.py "${INPUT}" | xargs -I % node ./verify.js "${INPUT}" %
## OUTPUT
[ 'this is some string',
  'SIG_K1_K44onaqorkFHoEvsPBED5zC5LoBrfo15m27gFkLfwCPKZ8ww9Gpx1rJLqWndEdgoV7cEz5PbW2yoeV1T1VJ8ZavSx3PEWj' ]
true

The output of true above indicates the sig was successfully verified.

failed output:

export INPUT="testing string sign"
python ./sign_string.py "${INPUT}" | xargs -I % node ./sign.js "test" %
[ 'test',
  'SIG_K1_KZyMkeKYJGue4XC2rRJ1u27bWJvMPncryUo8U9otZwVDPYoT9YeYyqr7o6Z2sGNATWSGJu5wz9VRZS7qQURFNnMtoXCPfU' ]
false
dengboren86 commented 5 years ago

Hi deckb,

Sincerely thank you for your testing! I think it's a lot of work on your side.

I've used pure python code like below, and run through your code without bugs. I found simple strings can pass tests, while strings with '\n' cannot.

I have tried 'test\\n' and r'test\n', neither passed. 'test\n' will fail eosjs-ecc.


part 1, simple string, success:

` import os import execjs from eospy.cleos import EOSKey

os.environ["NODE_PATH"] = "/usr/local/lib/node_modules"

k = EOSKey('5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3') pk = k.to_public() string = 'test' print(k.sign_string(string)) k_sign = k.sign_string(string)

verify = execjs.eval(f'require("eosjs-ecc").verify("{k_sign}", "{string}", "{pk}")')

print(verify) ` btw, how do I insert code with \n?

Output

SIG_K1_K9zr68XBA6eSiss65ihwm15Xj7qXun9HaJgN8vRNH2YTmCtzivzcMhUbgXLj1W22zVQpMZhbN8nfRaNMf3MSfnyXFxMNJa True


part 2, \n string, fail:

... string = 'test\\n' # or r'test\n' ...

Output

SIG_K1_KZJZeL2qyyw5fNsKaKgKpGEkuRtsHYSL8VKHzLmN4VsDr8Xk4aCiWy3wnxMEG3ZQc9jVsSjnKCPyLy6eZEgSF4QMdc7ktd False

deckb commented 5 years ago

Hmm something else is going on. When I run your test it works:

export INPUT="test\n"
python ./sign_string.py "${INPUT}" | xargs -I % node ./verify.js "${INPUT}" %
[ 'test\\n',
  'SIG_K1_KZJZeL2qyyw5fNsKaKgKpGEkuRtsHYSL8VKHzLmN4VsDr8Xk4aCiWy3wnxMEG3ZQc9jVsSjnKCPyLy6eZEgSF4QMdc7ktd' ]
true
dengboren86 commented 5 years ago

That's it. \n vs \n. First inside second outside works. Thank you so much all the way down here!