Skip to content

Commit

Permalink
Merge pull request JoinMarket-Org#486 from AdamISZ/newsecp256k1
Browse files Browse the repository at this point in the history
New re-integration of secp256k1 via ludbb binding; no longer using
  • Loading branch information
AdamISZ committed Apr 1, 2016
2 parents 4d3bf40 + 71e93f4 commit 47b49d2
Show file tree
Hide file tree
Showing 17 changed files with 1,299 additions and 148 deletions.
25 changes: 14 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,19 +31,26 @@ Widespread use of JoinMarket could improve bitcoin's fungibility as a commodity.
make check
sudo make install
```
+ (optional, recommended): Install the libsecp256k1 Python library:
```
pip install secp256k1
```
Note that this requires `pip`. This library will make use of libsecp256k1 if you already have it installed on your system. Most likely you won't, and it will try to build libsecp256k1 automatically for you. This requires some development packages; please read the installation details [here](https://github.com/ludbb/secp256k1-py#installation), provided for Debian/Ubuntu and OS X. Please also note that if you can't complete this step, Joinmarket will still run correctly, with two disadvantages: wallet loading is much slower without libsecp256k1, and the ECC crypto code is far less robust and well tested.
+ Matplotlib for displaying the graphs in orderbook-watcher (optional)
###DEBIAN / UBUNTU QUICK INSTALL FOR USERS:
1. `sudo apt-get update -y && sudo apt-get upgrade -y && sudo apt-get install python libsodium-dev -y`
2. `pip install secp256k1` (optional but recommended)
2. `sudo apt-get install python-matplotlib -y` (optional)
3. Download JoinMarket 0.1.2 source from [here](https://github.com/joinmarket-org/joinmarket/releases/tag/v0.1.3)
4. Extract or unzip and `cd joinmarket-0.1.2`
3. Download JoinMarket 0.1.3 source from [here](https://github.com/joinmarket-org/joinmarket/releases/tag/v0.1.3)
4. Extract or unzip and `cd joinmarket-0.1.3`
4. Generating your first wallet will populate the configuration file: `joinmarket.cfg`.
Check if the default settings suit your needs.
###[INSTALL FOR WINDOWS USERS](https://github.com/joinmarket-org/joinmarket/wiki/Installing-JoinMarket-on-Windows-7-(temporary))
###[INSTALL FOR WINDOWS USERS](https://github.com/JoinMarket-Org/joinmarket/wiki/Installing-JoinMarket-on-Windows)
###[WIKI PAGES FOR DETAILED ARTICLES/GUIDES](https://github.com/joinmarket-org/joinmarket/wiki)
Expand All @@ -53,24 +60,20 @@ Clone the repo, then read the notes [here](./CONTRIBUTING.md).
###TESTING
Install the developement requirements:
Install the development requirements:
```
pip install -r requirements-dev.txt
```
Run the tests:
```
PYTHONPATH=.:$PYTHONPATH py.test
```
Generating html code coverage reports:
```
PYTHONPATH=.:$PYTHONPATH py.test --cov-report html
PYTHONPATH=.:$PYTHONPATH py.test --cov-report html --btcroot=/path/to/bitcoin/bin/ --btcconf=/path/to/bitcoin.conf --btcpwd=123456abcdef
open htmlcov/index.html
```
See more information on testing in the [Wiki page](https://github.com/JoinMarket-Org/joinmarket/wiki/Testing)
---
Expand Down
14 changes: 11 additions & 3 deletions bitcoin/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
from bitcoin.py2specials import *
from bitcoin.py3specials import *
from bitcoin.main import *
from bitcoin.transaction import *
from bitcoin.deterministic import *
secp_present = False
try:
import secp256k1
secp_present = True
from bitcoin.secp256k1_main import *
from bitcoin.secp256k1_transaction import *
from bitcoin.secp256k1_deterministic import *
except ImportError:
from bitcoin.main import *
from bitcoin.deterministic import *
from bitcoin.transaction import *
from bitcoin.bci import *
105 changes: 105 additions & 0 deletions bitcoin/secp256k1_deterministic.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
from bitcoin.secp256k1_main import *
import hmac
import hashlib
from binascii import hexlify

# Below code ASSUMES binary inputs and compressed pubkeys
MAINNET_PRIVATE = b'\x04\x88\xAD\xE4'
MAINNET_PUBLIC = b'\x04\x88\xB2\x1E'
TESTNET_PRIVATE = b'\x04\x35\x83\x94'
TESTNET_PUBLIC = b'\x04\x35\x87\xCF'
PRIVATE = [MAINNET_PRIVATE, TESTNET_PRIVATE]
PUBLIC = [MAINNET_PUBLIC, TESTNET_PUBLIC]

# BIP32 child key derivation


def raw_bip32_ckd(rawtuple, i):
vbytes, depth, fingerprint, oldi, chaincode, key = rawtuple
i = int(i)

if vbytes in PRIVATE:
priv = key
pub = privtopub(key, False)
else:
pub = key

if i >= 2**31:
if vbytes in PUBLIC:
raise Exception("Can't do private derivation on public key!")
I = hmac.new(chaincode, b'\x00' + priv[:32] + encode(i, 256, 4),
hashlib.sha512).digest()
else:
I = hmac.new(chaincode, pub + encode(i, 256, 4),
hashlib.sha512).digest()

if vbytes in PRIVATE:
newkey = add_privkeys(I[:32] + B'\x01', priv, False)
fingerprint = bin_hash160(privtopub(key, False))[:4]
if vbytes in PUBLIC:
newkey = add_pubkeys([privtopub(I[:32] + '\x01', False), key], False)
fingerprint = bin_hash160(key)[:4]

return (vbytes, depth + 1, fingerprint, i, I[32:], newkey)


def bip32_serialize(rawtuple):
vbytes, depth, fingerprint, i, chaincode, key = rawtuple
i = encode(i, 256, 4)
chaincode = encode(hash_to_int(chaincode), 256, 32)
keydata = b'\x00' + key[:-1] if vbytes in PRIVATE else key
bindata = vbytes + from_int_to_byte(
depth % 256) + fingerprint + i + chaincode + keydata
return changebase(bindata + bin_dbl_sha256(bindata)[:4], 256, 58)


def bip32_deserialize(data):
dbin = changebase(data, 58, 256)
if bin_dbl_sha256(dbin[:-4])[:4] != dbin[-4:]:
raise Exception("Invalid checksum")
vbytes = dbin[0:4]
depth = from_byte_to_int(dbin[4])
fingerprint = dbin[5:9]
i = decode(dbin[9:13], 256)
chaincode = dbin[13:45]
key = dbin[46:78] + b'\x01' if vbytes in PRIVATE else dbin[45:78]
return (vbytes, depth, fingerprint, i, chaincode, key)


def raw_bip32_privtopub(rawtuple):
vbytes, depth, fingerprint, i, chaincode, key = rawtuple
newvbytes = MAINNET_PUBLIC if vbytes == MAINNET_PRIVATE else TESTNET_PUBLIC
return (newvbytes, depth, fingerprint, i, chaincode, privtopub(key, False))


def bip32_privtopub(data):
return bip32_serialize(raw_bip32_privtopub(bip32_deserialize(data)))


def bip32_ckd(data, i):
return bip32_serialize(raw_bip32_ckd(bip32_deserialize(data), i))


def bip32_master_key(seed, vbytes=MAINNET_PRIVATE):
I = hmac.new(
from_string_to_bytes("Bitcoin seed"), seed, hashlib.sha512).digest()
return bip32_serialize((vbytes, 0, b'\x00' * 4, 0, I[32:], I[:32] + b'\x01'
))


def bip32_bin_extract_key(data):
return bip32_deserialize(data)[-1]


def bip32_extract_key(data):
return safe_hexlify(bip32_deserialize(data)[-1])


def bip32_descend(*args):
if len(args) == 2:
key, path = args
else:
key, path = args[0], map(int, args[1:])
for p in path:
key = bip32_ckd(key, p)
return bip32_extract_key(key)
Loading

0 comments on commit 47b49d2

Please sign in to comment.