Skip to content

Commit

Permalink
Replace secp256k1-py with coincurve
Browse files Browse the repository at this point in the history
  • Loading branch information
jameshilliard committed Nov 22, 2018
1 parent 7c6b4f1 commit abad597
Show file tree
Hide file tree
Showing 11 changed files with 65 additions and 70 deletions.
2 changes: 1 addition & 1 deletion docs/INSTALL.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ is actually newer in version number, than what was there already.

To install everything (client and server), install these packages:

sudo apt-get install python-dev python-pip git build-essential automake pkg-config libtool libffi-dev libssl-dev
sudo apt-get install python-dev python-pip git build-essential automake pkg-config libtool libffi-dev libssl-dev libgmp-dev

(+ `libsodium-dev` if you can find it, else build after)

Expand Down
24 changes: 12 additions & 12 deletions install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ sha256_verify ()
deps_install ()
{
if [[ ${install_os} == 'debian' ]]; then
if deb_deps_install "python-virtualenv curl python-dev python-pip build-essential automake pkg-config libtool"; then
if deb_deps_install "python-virtualenv curl python-dev python-pip build-essential automake pkg-config libtool libgmp-dev"; then
return 0
else
return 1
Expand Down Expand Up @@ -204,7 +204,7 @@ libffi_install ()
popd
}

libsecp256k1-py_build ()
coincurve_build ()
{
if [[ -d "${jm_deps}/secp256k1-${secp256k1_version}" ]]; then
unlink ./libsecp256k1
Expand All @@ -216,19 +216,19 @@ libsecp256k1-py_build ()
return "$?"
}

secp256k1-py_install ()
coincurve_install ()
{
secp256k1_py_version='0.13.2.4'
secp256k1_py_lib_tar="${secp256k1_py_version}.tar.gz"
secp256k1_py_lib_sha='f7920b1b887fe6745c49aebea40cefe867adddf11eb2c164624f1f2729f74657'
secp256k1_py_url='https://github.com/ludbb/secp256k1-py/archive'
coincurve_version='9.0.0'
coincurve_lib_tar="${coincurve_version}.tar.gz"
coincurve_lib_sha='81561e954b4a978231e6611ae6153740bfbaebb214caff7a7b4e71fe9affbe09'
coincurve_url='https://github.com/ofek/coincurve/archive'

rm -rf "./secp256k1-py-${secp256k1_py_version}"
if ! dep_get "${secp256k1_py_lib_tar}" "${secp256k1_py_lib_sha}" "${secp256k1_py_url}"; then
rm -rf "./coincurve-${coincurve_version}"
if ! dep_get "${coincurve_lib_tar}" "${coincurve_lib_sha}" "${coincurve_url}"; then
return 1
fi
pushd "secp256k1-py-${secp256k1_py_version}"
if ! libsecp256k1-py_build; then
pushd "coincurve-${coincurve_version}"
if ! coincurve_build; then
return 1
fi
popd
Expand All @@ -250,7 +250,7 @@ libsecp256k1_install ()
if ! dep_get "${secp256k1_lib_tar}" "${secp256k1_lib_sha}" "${secp256k1_url}"; then
return 1
fi
if ! secp256k1-py_install; then
if ! coincurve_install; then
return 1
fi
}
Expand Down
2 changes: 1 addition & 1 deletion jmbitcoin/jmbitcoin/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import secp256k1
import coincurve as secp256k1
from jmbitcoin.secp256k1_main import *
from jmbitcoin.secp256k1_transaction import *
from jmbitcoin.secp256k1_deterministic import *
Expand Down
61 changes: 28 additions & 33 deletions jmbitcoin/jmbitcoin/secp256k1_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,10 @@
import re
import sys
import base64
import secp256k1
import coincurve as secp256k1

#Required only for PoDLE calculation:
N = 115792089237316195423570985008687907852837564279074904382605163141518161494337
#Global context for secp256k1 operations (helps with performance)
ctx = secp256k1.lib.secp256k1_context_create(secp256k1.ALL_FLAGS)
#required for point addition
dummy_pub = secp256k1.PublicKey(ctx=ctx)

#Standard prefix for Bitcoin message signing.
BITCOIN_MESSAGE_MAGIC = '\x18' + 'Bitcoin Signed Message:\n'
Expand Down Expand Up @@ -103,7 +99,7 @@ def getG(compressed=True):
representation of secp256k1 G
"""
priv = "\x00"*31 + "\x01"
G = secp256k1.PrivateKey(priv, ctx=ctx).pubkey.serialize(compressed)
G = secp256k1.PrivateKey(priv).public_key.format(compressed)
return G

podle_PublicKey_class = secp256k1.PublicKey
Expand All @@ -112,12 +108,12 @@ def getG(compressed=True):
def podle_PublicKey(P):
"""Returns a PublicKey object from a binary string
"""
return secp256k1.PublicKey(P, raw=True, ctx=ctx)
return secp256k1.PublicKey(P)

def podle_PrivateKey(priv):
"""Returns a PrivateKey object from a binary string
"""
return secp256k1.PrivateKey(priv, ctx=ctx)
return secp256k1.PrivateKey(priv)


def privkey_to_address(priv, from_hex=True, magicbyte=0):
Expand Down Expand Up @@ -290,8 +286,8 @@ def privkey_to_pubkey_inner(priv, usehex):
and return compressed/uncompressed public key as appropriate.'''
compressed, priv = read_privkey(priv)
#secp256k1 checks for validity of key value.
newpriv = secp256k1.PrivateKey(privkey=priv, ctx=ctx)
return newpriv.pubkey.serialize(compressed=compressed)
newpriv = secp256k1.PrivateKey(secret=priv)
return newpriv.public_key.format(compressed)

def privkey_to_pubkey(priv, usehex=True):
'''To avoid changing the interface from the legacy system,
Expand All @@ -313,25 +309,20 @@ def multiply(s, pub, usehex, rawpub=True, return_serialized=True):
of the scalar s.
('raw' options passed in)
'''
newpub = secp256k1.PublicKey(pub, raw=rawpub, ctx=ctx)
newpub = secp256k1.PublicKey(pub)
#see note to "tweak_mul" function in podle.py
res = secp256k1._tweak_public(newpub,
secp256k1.lib.secp256k1_ec_pubkey_tweak_mul,
s)
res = newpub.multiply(s)
if not return_serialized:
return res
return res.serialize()
return res.format()

@hexbin
def add_pubkeys(pubkeys, usehex):
'''Input a list of binary compressed pubkeys
and return their sum as a binary compressed pubkey.'''
r = secp256k1.PublicKey(ctx=ctx) #dummy holding object
pubkey_list = [secp256k1.PublicKey(x,
raw=True,
ctx=ctx).public_key for x in pubkeys]
r.combine(pubkey_list)
return r.serialize()
pubkey_list = [secp256k1.PublicKey(x) for x in pubkeys]
r = secp256k1.PublicKey.combine_keys(pubkey_list)
return r.format()

@hexbin
def add_privkeys(priv1, priv2, usehex):
Expand All @@ -345,8 +336,8 @@ def add_privkeys(priv1, priv2, usehex):
else:
compressed = y[0]
newpriv1, newpriv2 = (y[1], z[1])
p1 = secp256k1.PrivateKey(newpriv1, raw=True, ctx=ctx)
res = p1.tweak_add(newpriv2)
p1 = secp256k1.PrivateKey(newpriv1)
res = p1.add(newpriv2).secret
if compressed:
res += '\x01'
return res
Expand Down Expand Up @@ -376,13 +367,12 @@ def ecdsa_raw_sign(msg,
raise Exception("Invalid hash input to ECDSA raw sign.")
if rawpriv:
compressed, p = read_privkey(priv)
newpriv = secp256k1.PrivateKey(p, raw=True, ctx=ctx)
newpriv = secp256k1.PrivateKey(p)
else:
newpriv = secp256k1.PrivateKey(priv, raw=False, ctx=ctx)
newpriv = secp256k1.PrivateKey.from_hex(priv)
if formsg:
sig = newpriv.ecdsa_sign_recoverable(msg, raw=rawmsg)
s, rid = newpriv.ecdsa_recoverable_serialize(sig)
return chr(31+rid) + s
sig = newpriv.sign_recoverable(msg)
return sig
#Donations, thus custom nonce, currently disabled, hence not covered.
elif usenonce: #pragma: no cover
raise NotImplementedError
Expand All @@ -396,8 +386,11 @@ def ecdsa_raw_sign(msg,
else:
#partial fix for secp256k1-transient not including customnonce;
#partial because donations will crash on windows in the "if".
sig = newpriv.ecdsa_sign(msg, raw=rawmsg)
return newpriv.ecdsa_serialize(sig)
if rawmsg:
sig = newpriv.sign(msg, hasher=None)
else:
sig = newpriv.sign(msg)
return sig

@hexbin
def ecdsa_raw_verify(msg, pub, sig, usehex, rawmsg=False):
Expand All @@ -415,9 +408,11 @@ def ecdsa_raw_verify(msg, pub, sig, usehex, rawmsg=False):
try:
if rawmsg:
assert len(msg) == 32
newpub = secp256k1.PublicKey(pubkey=pub, raw=True, ctx=ctx)
sigobj = newpub.ecdsa_deserialize(sig)
retval = newpub.ecdsa_verify(msg, sigobj, raw=rawmsg)
newpub = secp256k1.PublicKey(pub)
if rawmsg:
retval = newpub.verify(sig, msg, hasher=None)
else:
retval = newpub.verify(sig, msg)
except:
return False
return retval
Expand Down
2 changes: 1 addition & 1 deletion jmbitcoin/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@
author_email='',
license='GPL',
packages=['jmbitcoin'],
install_requires=['future', 'secp256k1',],
install_requires=['future', 'coincurve',],
zip_safe=False)
34 changes: 17 additions & 17 deletions jmclient/jmclient/podle.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def __init__(self,
if len(priv) == 66 and priv[-2:] == '01':
priv = priv[:-2]
self.priv = podle_PrivateKey(binascii.unhexlify(priv))
self.P = self.priv.pubkey
self.P = self.priv.public_key
if P2:
self.P2 = podle_PublicKey(binascii.unhexlify(P2))
else:
Expand All @@ -83,7 +83,7 @@ def get_commitment(self):
raise PoDLEError("Cannot construct commitment, no P2 available")
if not isinstance(self.P2, podle_PublicKey_class):
raise PoDLEError("Cannot construct commitment, P2 is not a pubkey")
self.commitment = hashlib.sha256(self.P2.serialize()).digest()
self.commitment = hashlib.sha256(self.P2.format()).digest()
return binascii.hexlify(self.commitment)

def generate_podle(self, index=0, k=None):
Expand Down Expand Up @@ -119,14 +119,14 @@ def generate_podle(self, index=0, k=None):
if not k:
k = os.urandom(32)
J = getNUMS(index)
KG = podle_PrivateKey(k).pubkey
KJ = multiply(k, J.serialize(), False, return_serialized=False)
KG = podle_PrivateKey(k).public_key
KJ = multiply(k, J.format(), False, return_serialized=False)
self.P2 = getP2(self.priv, J)
self.get_commitment()
self.e = hashlib.sha256(''.join([x.serialize(
self.e = hashlib.sha256(''.join([x.format(
) for x in [KG, KJ, self.P, self.P2]])).digest()
k_int = decode(k, 256)
priv_int = decode(self.priv.private_key, 256)
priv_int = decode(self.priv.secret, 256)
e_int = decode(self.e, 256)
sig_int = (k_int + priv_int * e_int) % N
self.s = encode(sig_int, 256, minlen=32)
Expand All @@ -142,7 +142,7 @@ def reveal(self):
self.get_commitment()
Phex, P2hex, shex, ehex, commit = [
binascii.hexlify(x)
for x in [self.P.serialize(), self.P2.serialize(), self.s, self.e,
for x in [self.P.format(), self.P2.format(), self.s, self.e,
self.commitment]
]
return {'used': str(self.used),
Expand Down Expand Up @@ -180,17 +180,17 @@ def verify(self, commitment, index_range):
return False
for J in [getNUMS(i) for i in index_range]:
sig_priv = podle_PrivateKey(self.s)
sG = sig_priv.pubkey
sJ = multiply(self.s, J.serialize(), False)
sG = sig_priv.public_key
sJ = multiply(self.s, J.format(), False)
e_int = decode(self.e, 256)
minus_e = encode(-e_int % N, 256, minlen=32)
minus_e_P = multiply(minus_e, self.P.serialize(), False)
minus_e_P2 = multiply(minus_e, self.P2.serialize(), False)
KGser = add_pubkeys([sG.serialize(), minus_e_P], False)
minus_e_P = multiply(minus_e, self.P.format(), False)
minus_e_P2 = multiply(minus_e, self.P2.format(), False)
KGser = add_pubkeys([sG.format(), minus_e_P], False)
KJser = add_pubkeys([sJ, minus_e_P2], False)
#check 2: e =?= H(K_G || K_J || P || P2)
e_check = hashlib.sha256(KGser + KJser + self.P.serialize() +
self.P2.serialize()).digest()
e_check = hashlib.sha256(KGser + KJser + self.P.format() +
self.P2.format()).digest()
if e_check == self.e:
return True
#commitment fails for any NUMS in the provided range
Expand Down Expand Up @@ -242,7 +242,7 @@ def verify_all_NUMS(write=False):
"""
nums_points = {}
for i in range(256):
nums_points[i] = binascii.hexlify(getNUMS(i).serialize())
nums_points[i] = binascii.hexlify(getNUMS(i).format())
if write:
with open("nums_basepoints.txt", "wb") as f:
from pprint import pformat
Expand All @@ -258,9 +258,9 @@ def getP2(priv, nums_pt):
just the most easy way to manipulate it in the
library), calculate priv*nums_pt
"""
priv_raw = priv.private_key
priv_raw = priv.secret
return multiply(priv_raw,
nums_pt.serialize(),
nums_pt.format(),
False,
return_serialized=False)

Expand Down
2 changes: 1 addition & 1 deletion test/Dockerfiles/bionic.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ SHELL ["/bin/bash", "-c"]
RUN apt-get update
RUN apt-get install -y build-essential
RUN apt-get install -y \
automake pkg-config libtool
automake pkg-config libtool libgmp-dev
RUN apt-get install -y \
python-dev python-pip python-virtualenv python-qt4 python-sip

Expand Down
2 changes: 1 addition & 1 deletion test/Dockerfiles/centos7.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ RUN yum -y groups install 'Development tools'
RUN yum -y install epel-release && \
yum -y update
RUN yum -y install \
python-devel python2-pip python-virtualenv
python-devel python2-pip python-virtualenv gmp-devel

RUN useradd --home-dir /home/chaum --create-home --shell /bin/bash --skel /etc/skel/ chaum
ARG core_version
Expand Down
2 changes: 1 addition & 1 deletion test/Dockerfiles/fedora27.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ SHELL ["/bin/bash", "-c"]
RUN dnf -y groups install 'Development tools'
RUN dnf -y install \
autoconf libtool pkgconfig \
python-devel python-pip python2-virtualenv
python-devel python-pip python2-virtualenv gmp-devel

# needed for build time
# https://stackoverflow.com/questions/34624428/g-error-usr-lib-rpm-redhat-redhat-hardened-cc1-no-such-file-or-directory
Expand Down
2 changes: 1 addition & 1 deletion test/Dockerfiles/stretch.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ SHELL ["/bin/bash", "-c"]
RUN apt-get update
RUN apt-get install -y build-essential
RUN apt-get install -y \
automake pkg-config libtool
automake pkg-config libtool libgmp-dev
RUN apt-get install -y \
python-dev python-pip python-virtualenv python-qt4 python-sip

Expand Down
2 changes: 1 addition & 1 deletion test/Dockerfiles/xenial.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ SHELL ["/bin/bash", "-c"]
RUN apt-get update
RUN apt-get install -y build-essential
RUN apt-get install -y \
automake pkg-config libtool
automake pkg-config libtool libgmp-dev
RUN apt-get install -y \
python-dev python-pip python-virtualenv python-qt4 python-sip

Expand Down

0 comments on commit abad597

Please sign in to comment.