this replaces https://github.com/spesmilo/electrum/pull/8320
see f6bef03c0a/CHANGELOG.md
I am not yet sure how this will look like going forward, but unless there will
be lots of libsecp256k1 releases with ~invisible harmless ABI changes, I think
conceptually this is the right approach.
note: low R grinding would not have to be duplicated if we trusted the caller
to have done it already (as is the case with the classes in ecc.py), and if
we propagated the choice of "random_k" as part of the nonce_function passed
to libsecp256k1 (which is not currently done)
time taken to add points changes to around 35% of what it was with python-ecdsa
-----
# benchmark runs before:
> python3.7-64 ..\wspace\201909_libsecp256k1_point_addition\bench.py
time taken: 3.7693 seconds
> python3.7-64 ..\wspace\201909_libsecp256k1_point_addition\bench.py
time taken: 3.8123 seconds
> python3.7-64 ..\wspace\201909_libsecp256k1_point_addition\bench.py
time taken: 3.7937 seconds
# benchmark runs after:
> python3.7-64 ..\wspace\201909_libsecp256k1_point_addition\bench.py
time taken: 1.3127 seconds
> python3.7-64 ..\wspace\201909_libsecp256k1_point_addition\bench.py
time taken: 1.3000 seconds
> python3.7-64 ..\wspace\201909_libsecp256k1_point_addition\bench.py
time taken: 1.3128 seconds
-----
# benchmark script:
import os
import time
from electrum.ecc import generator
from electrum.crypto import sha256
rand_bytes = os.urandom(32)
#rand_bytes = bytes.fromhex('d3d88983b91ee6dfd546ccf89b9a1ffb23b01bf2eef322c2808cb3d951a3c116')
point_pairs = []
for i in range(30000):
rand_bytes = sha256(rand_bytes)
rand_int = int.from_bytes(rand_bytes, "big")
a = generator() * rand_int
rand_bytes = sha256(rand_bytes)
rand_int = int.from_bytes(rand_bytes, "big")
b = generator() * rand_int
point_pairs.append((a,b))
t0 = time.time()
for a, b in point_pairs:
c = a + b
t = time.time() - t0
print(f"time taken: {t:.4f} seconds")