Skip to content

Commit

Permalink
Add support for BIP32; use mustache; 7 more bits of randomness
Browse files Browse the repository at this point in the history
  • Loading branch information
Arachnid committed Oct 12, 2016
1 parent 53c00b4 commit 0e8927d
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 18 deletions.
67 changes: 57 additions & 10 deletions cardprint.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import argparse
from bitmerchant.wallet import Wallet
import cStringIO
import cups
import ethereum.keys
from mnemonic import Mnemonic
import os
from PIL import Image
import pystache
from reportlab.pdfgen import canvas
from reportlab.lib import units
from reportlab.lib.utils import ImageReader
Expand All @@ -16,6 +18,49 @@
CARD_WIDTH = 54 * units.mm
CARD_HEIGHT = 85 * units.mm


def _addressFromWallet(wallet):
return to_checksum_address(ethereum.keys.sha3(wallet.public_key.get_key().decode('hex')[1:])[12:].encode('hex'))


class BIPWallet(object):
@classmethod
def from_seed(cls, seed):
return cls(Wallet.from_master_secret(seed))

def __init__(self, wallet, derived=False):
self.wallet = wallet
self.derived = derived

@property
def derive(self):
return BIPWallet(self.wallet, True)

def address(self):
if self.derived:
def deriver(path):
return _addressFromWallet(self.wallet.get_child_for_path(path))
return deriver
else:
return _addressFromWallet(self.wallet)

def pubkey(self):
if self.derived:
def deriver(path):
return self.wallet.get_child_for_path(path).public_key.get_key()
return deriver
else:
return self.wallet.public_key.get_key()

def privkey(self):
if self.derived:
def deriver(path):
return self.wallet.get_child_for_path(path).private_key.get_key()
return deriver
else:
return self.wallet.private_key.get_key()


mnemonic = Mnemonic('english')

parser = argparse.ArgumentParser(description='Generate and print ECDSA keypairs.')
Expand All @@ -37,15 +82,16 @@ def __init__(self, format):
self.format = format

def _makeKeypair(self):
pdata = '\0' + os.urandom(15)
pdata = os.urandom(16)
pdata = chr(ord(pdata[0]) & 0x7F) + pdata[1:]
words = mnemonic.to_mnemonic(pdata)
privkey = mnemonic.to_seed(words)[:32]
address = to_checksum_address(ethereum.keys.privtoaddr(privkey).encode('hex'))
seed = mnemonic.to_seed(words)
privkey = seed[:32]
address = ethereum.keys.privtoaddr(privkey).encode('hex')

return {
'keyphrase': words,
'private': privkey.encode('hex'),
'address': address,
'wallet': BIPWallet.from_seed(seed),
}

def generate(self, count):
Expand All @@ -57,8 +103,9 @@ def generate(self, count):
c.rotate(90)

context = self._makeKeypair()
context['address'] = pystache.render(self.format['address'], context)
addresses.append(context['address'])
for element in self.format:
for element in self.format['card']:
self.FORMATTERS[element['type']](c, element, context)

c.showPage()
Expand All @@ -77,7 +124,7 @@ def QR(c, element, context):
}[element.get('eclevel', 'L')]

version, pixels, qr = qrencode.encode(
element['text'] % context,
pystache.render(element['text'], context),
0,
eclevel,
qrencode.QR_MODE_8,
Expand Down Expand Up @@ -108,12 +155,12 @@ def text(c, element, context):
element,
float(element['x']) * units.mm,
-float(element['y']) * units.mm,
element['text'] % context)
pystache.render(element['text'], context))


@CardPrinter.formatter
def textArray(c, element, context):
data = (element['text'] % context).split(element['split'])
data = pystache.render(element['text'], context).split(element['split'])
cols = int(element['columns'])
startX = float(element['x']) * units.mm
startY = -float(element['y']) * units.mm
Expand All @@ -134,7 +181,7 @@ def printCards(printerName, cards):

def main(args):
formatter = yaml.load(open(args.template))
generator = CardPrinter(formatter['card'])
generator = CardPrinter(formatter)
addresses, cards = generator.generate(args.count)
print '\n'.join(addresses)
if args.test:
Expand Down
17 changes: 9 additions & 8 deletions mnemonic.yaml
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
address: "{{#wallet.derive.address}}m/44'/60'/0'/0/0{{/wallet.derive.address}}"
card:
- type: QR
text: "%(address)s"
x: 7
y: 12
text: "{{address}}"
x: 8
y: 13.75
size: 16
eclevel: M
caseSensitive: true
- type: text
text: "%(address)s"
text: "{{address}}"
x: 7
y: 40
y: 41.5
font: Courier
size: 8
- type: textArray
text: "%(keyphrase)s"
text: "{{keyphrase}}"
split: " "
x: 33
y: 16
x: 34.75
y: 17.75
size: 8
columnSpacing: 15
rowSpacing: 3
Expand Down

0 comments on commit 0e8927d

Please sign in to comment.