findftp (OP)
Legendary
Offline
Activity: 1022
Merit: 1008
Delusional crypto obsessionist
|
|
August 27, 2015, 11:36:49 AM |
|
So I'm planning to throw 99 times with a dice and punch the number into a metal strip or engrave it into marble to produce some bullet proof single address wallet. Before I go such lengths I want to make sure this approach works. So I want to test each step and even fill this address with a few satoshis and spend them as well before I fill it with more serious amounts. Throwing a dice is easy, but converting it into a WIF private key isn't. The only way I found is through www.bitaddress.org, but I am not able to review the source and I don't want to rely at one source only. Is there anyone who can give me some other suggestions?
|
|
|
|
hexafraction
Sr. Member
Offline
Activity: 392
Merit: 268
Tips welcomed: 1CF4GhXX1RhCaGzWztgE1YZZUcSpoqTbsJ
|
|
August 27, 2015, 01:32:06 PM |
|
While I have not validated the source of bitaddress myself, it has been validated by others. You can also just generate a private exponent from dice rolls and encode it into Base58Check using an appropriate library and programming language. You'd only need to audit a single function, namely that for Base58Check encoding.
|
|
|
|
tspacepilot
Legendary
Offline
Activity: 1456
Merit: 1081
I may write code in exchange for bitcoins.
|
|
August 27, 2015, 03:17:41 PM |
|
So I'm planning to throw 99 times with a dice and punch the number into a metal strip or engrave it into marble to produce some bullet proof single address wallet. Wow, seriously? Marble engraving? Before I go such lengths I want to make sure this approach works. So I want to test each step and even fill this address with a few satoshis and spend them as well before I fill it with more serious amounts. Throwing a dice is easy, but converting it into a WIF private key isn't. The only way I found is through www.bitaddress.org, but I am not able to review the source and I don't want to rely at one source only. Is there anyone who can give me some other suggestions? I assume you can figure out how to convert your number into 256bit hex? If so, the following works fine for me: b58 = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
def base58encode(n): result = '' while n > 0: result = b58[n%58] + result n /= 58 return result
# https://en.bitcoin.it/wiki/Base58Check_encoding def base58CheckEncode(version, payload): s = chr(version) + payload checksum = hashlib.sha256(hashlib.sha256(s).digest()).digest()[0:4] result = s + checksum leadingZeros = countLeadingChars(result, '\0') return '1' * leadingZeros + base58encode(base256decode(result))
def privateKeyToWif(key_hex, compressed=False): if compressed: key_hex=key_hex+'01' return base58CheckEncode(0x80, key_hex.decode('hex'))
^^^ That's python, but you could use another language if you want. In the above, key_hex is a string. Here's an example of me using it.: >>> k="1111111111111111111111111111111111111111111111111111111111111111" >>> privateKeyToWif(k) '5HwoXVkHoRM8sL2KmNRS217n1g8mPPBomrY7yehCuXC1115WWsh' >>> privateKeyToWif(k, compressed=True) 'KwntMbt59tTsj8xqpqYqRRWufyjGunvhSyeMo3NTYpFYzZbXJ5Hp'
|
|
|
|
dserrano5
Legendary
Offline
Activity: 1974
Merit: 1029
|
|
August 27, 2015, 07:05:19 PM |
|
Throwing a dice is easy, but converting it into a WIF private key isn't. […]
Is there anyone who can give me some other suggestions?
You're on a real operating system, right? If so, you can use bc, the calculator. $ bc bc 1.06.95 Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc. This is free software with ABSOLUTELY NO WARRANTY. For details type `warranty'. obase=16 ibase=6 10 6 11 7 12 8 13 9 14 A 15 B 16 B 36212631625312563 9FEE7990BF5 My paper wallets have been created from dice rolls. Chinese ones, so I'm free from any tinkering from the NSA .
|
|
|
|
findftp (OP)
Legendary
Offline
Activity: 1022
Merit: 1008
Delusional crypto obsessionist
|
|
August 28, 2015, 08:08:05 AM |
|
So I'm planning to throw 99 times with a dice and punch the number into a metal strip or engrave it into marble to produce some bullet proof single address wallet. Wow, seriously? Marble engraving? I should expand on this. I own a metal detector and for a hobby I go to public or private places to scan the soil for historic metallic artifacts. Very often I find metal discs which people used as some sort of value token (coins ) I would like to bury this marble engraved bitcoin address in a public place (a park, a forest, a field) and make sure it's not detectable with a metal detector. If I use metal I'm not so sure about my hobby collegues not finding it. I think it would be pretty safe if only I know where it is burried (and some trusties). It's not like I want to put all my coins on that address, just a few. I like the idea that whatever happens to me or my trusties the address is still accesible. I like the idea that it is possible for someone (a kid digging a hole) to find this thing in let's say 200 years and know what it is and what to do with it. Before I go such lengths I want to make sure this approach works. So I want to test each step and even fill this address with a few satoshis and spend them as well before I fill it with more serious amounts. Throwing a dice is easy, but converting it into a WIF private key isn't. The only way I found is through www.bitaddress.org, but I am not able to review the source and I don't want to rely at one source only. Is there anyone who can give me some other suggestions? I assume you can figure out how to convert your number into 256bit hex? If so, the following works fine for me: b58 = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
def base58encode(n): result = '' while n > 0: result = b58[n%58] + result n /= 58 return result
# https://en.bitcoin.it/wiki/Base58Check_encoding def base58CheckEncode(version, payload): s = chr(version) + payload checksum = hashlib.sha256(hashlib.sha256(s).digest()).digest()[0:4] result = s + checksum leadingZeros = countLeadingChars(result, '\0') return '1' * leadingZeros + base58encode(base256decode(result))
def privateKeyToWif(key_hex, compressed=False): if compressed: key_hex=key_hex+'01' return base58CheckEncode(0x80, key_hex.decode('hex'))
^^^ That's python, but you could use another language if you want. In the above, key_hex is a string. Here's an example of me using it.: >>> k="1111111111111111111111111111111111111111111111111111111111111111" >>> privateKeyToWif(k) '5HwoXVkHoRM8sL2KmNRS217n1g8mPPBomrY7yehCuXC1115WWsh' >>> privateKeyToWif(k, compressed=True) 'KwntMbt59tTsj8xqpqYqRRWufyjGunvhSyeMo3NTYpFYzZbXJ5Hp'
Thanks for the code, I go and play with it.
|
|
|
|
findftp (OP)
Legendary
Offline
Activity: 1022
Merit: 1008
Delusional crypto obsessionist
|
|
August 28, 2015, 08:09:22 AM |
|
Throwing a dice is easy, but converting it into a WIF private key isn't. […]
Is there anyone who can give me some other suggestions?
You're on a real operating system, right? If so, you can use bc, the calculator. Well, I hope linux mint 17.2 is real enough $ bc bc 1.06.95 Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc. This is free software with ABSOLUTELY NO WARRANTY. For details type `warranty'. obase=16 ibase=6 10 6 11 7 12 8 13 9 14 A 15 B 16 B 36212631625312563 9FEE7990BF5 My paper wallets have been created from dice rolls. Chinese ones, so I'm free from any tinkering from the NSA . Great! This looks even more promising to me. Thanks.
|
|
|
|
findftp (OP)
Legendary
Offline
Activity: 1022
Merit: 1008
Delusional crypto obsessionist
|
|
September 04, 2015, 12:30:00 PM |
|
I assume you can figure out how to convert your number into 256bit hex?
Yes, I could do it manually but dserrano5 above pointed me to function 'bc' which I can use on my linux machine. If so, the following works fine for me: b58 = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
def base58encode(n): result = '' while n > 0: result = b58[n%58] + result n /= 58 return result
# https://en.bitcoin.it/wiki/Base58Check_encoding def base58CheckEncode(version, payload): s = chr(version) + payload checksum = hashlib.sha256(hashlib.sha256(s).digest()).digest()[0:4] result = s + checksum leadingZeros = countLeadingChars(result, '\0') return '1' * leadingZeros + base58encode(base256decode(result))
def privateKeyToWif(key_hex, compressed=False): if compressed: key_hex=key_hex+'01' return base58CheckEncode(0x80, key_hex.decode('hex'))
^^^ That's python, but you could use another language if you want. In the above, key_hex is a string. Here's an example of me using it.: So I've put that code into a file called 'bitoin.py' Then I entered python and figured I had to import that code as a module(?) I did this No problem so far. >>> k="1111111111111111111111111111111111111111111111111111111111111111" >>> privateKeyToWif(k) '5HwoXVkHoRM8sL2KmNRS217n1g8mPPBomrY7yehCuXC1115WWsh' >>> privateKeyToWif(k, compressed=True) 'KwntMbt59tTsj8xqpqYqRRWufyjGunvhSyeMo3NTYpFYzZbXJ5Hp'
This is where I'm stuck. I can enter the 'k', but then I get this: >>> privateKeyToWif(k) Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'privateKeyToWif' is not defined
What am I doing wrong? I don't have any experience with python. (too many languages to know them all)
|
|
|
|
siameze
Legendary
Offline
Activity: 1064
Merit: 1000
|
|
September 04, 2015, 01:28:44 PM |
|
Throwing a dice is easy, but converting it into a WIF private key isn't. […]
Is there anyone who can give me some other suggestions?
You're on a real operating system, right? If so, you can use bc, the calculator. $ bc bc 1.06.95 Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc. This is free software with ABSOLUTELY NO WARRANTY. For details type `warranty'. obase=16 ibase=6 10 6 11 7 12 8 13 9 14 A 15 B 16 B 36212631625312563 9FEE7990BF5 My paper wallets have been created from dice rolls. Chinese ones, so I'm free from any tinkering from the NSA . I like the bc method best, it reeks of simplicity. Thanks for the share.
|
|
|
|
tspacepilot
Legendary
Offline
Activity: 1456
Merit: 1081
I may write code in exchange for bitcoins.
|
|
September 04, 2015, 03:05:47 PM |
|
findftp, if I recall corrctly, to import a python script as a module you need to have it in a directory along with a file calld __init__.py (which is sometimes empty but can include init routines for classes). To run the code snippet I sent you, you could do one of two things pretty easily: 1) open a python intepreter and just copy/paste in the function defs 2) run the python executable with the -i flag But, actually, I went ahead and tried it and realized there were two missing methods (countLeadingChars, base256decode) and a missing import (hashlib) in the snippet I gave you. Here's the entire snippet again with the missing methods included and a shebang line for good measure. #!/usr/bin/env python
import hashlib b58 = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
def countLeadingChars(s, ch): count = 0 for c in s: if c == ch: count += 1 else: break return count
def base256decode(s): result = 0 for c in s: result = result * 256 + ord(c) return result
def base58encode(n): result = '' while n > 0: result = b58[n%58] + result n /= 58 return result
# https://en.bitcoin.it/wiki/Base58Check_encoding def base58CheckEncode(version, payload): s = chr(version) + payload checksum = hashlib.sha256(hashlib.sha256(s).digest()).digest()[0:4] result = s + checksum leadingZeros = countLeadingChars(result, '\0') return '1' * leadingZeros + base58encode(base256decode(result))
def privateKeyToWif(key_hex, compressed=False): if compressed: key_hex=key_hex+'01' return base58CheckEncode(0x80, key_hex.decode('hex'))
^^That should work for defining methods, if, say, you put that into a file called bitcoin.py you should now be able to do this to load those definitions and play at the intepreter: tsp@computer:/tmp$ python -i bitcoin.py >>> k="1111111111111111111111111111111111111111111111111111111111111111" >>> privateKeyToWif(k) '5HwoXVkHoRM8sL2KmNRS217n1g8mPPBomrY7yehCuXC1115WWsh' >>> privateKeyToWif(k,compressed=True) 'KwntMbt59tTsj8xqpqYqRRWufyjGunvhSyeMo3NTYpFYzZbXJ5Hp' >>>
Let me know if you're still stuck.
|
|
|
|
findftp (OP)
Legendary
Offline
Activity: 1022
Merit: 1008
Delusional crypto obsessionist
|
|
September 04, 2015, 03:54:07 PM |
|
Let me know if you're still stuck.
Excellent. I already found out the hashlib myself but you greatly helped me with the rest. I tested it with a Base6 number, converted to 256hex through 'bc' and then your script. The result was the same when I used the strings at bitaddress.org. I'll donate you and dserrano5 some symbolic satoshis, thanks again.
|
|
|
|
tspacepilot
Legendary
Offline
Activity: 1456
Merit: 1081
I may write code in exchange for bitcoins.
|
|
September 04, 2015, 04:01:58 PM |
|
Excellent. I already found out the hashlib myself but you greatly helped me with the rest. I tested it with a Base6 number, converted to 256hex through 'bc' and then your script. The result was the same when I used the strings at bitaddress.org. I'll donate you and dserrano5 some symbolic satoshis, thanks again. Glad you got it working! I find that -i (to drop you into the interpreter after execution) particularly helpful when debugging python programs. Satoshis always apprecated (profile address works fine), symbolic or otherwise
|
|
|
|
findftp (OP)
Legendary
Offline
Activity: 1022
Merit: 1008
Delusional crypto obsessionist
|
|
September 04, 2015, 07:40:56 PM Last edit: September 04, 2015, 08:15:51 PM by findftp |
|
Excellent. I already found out the hashlib myself but you greatly helped me with the rest. I tested it with a Base6 number, converted to 256hex through 'bc' and then your script. The result was the same when I used the strings at bitaddress.org. I'll donate you and dserrano5 some symbolic satoshis, thanks again. Glad you got it working! I find that -i (to drop you into the interpreter after execution) particularly helpful when debugging python programs. Satoshis always apprecated (profile address works fine), symbolic or otherwise Do you also have a routine to create a bitcoin public address with python? edit: I think this is what I was looking forToo bad, way too much source code. I'm still interested in a routine for public key generation
|
|
|
|
tspacepilot
Legendary
Offline
Activity: 1456
Merit: 1081
I may write code in exchange for bitcoins.
|
|
September 04, 2015, 08:21:14 PM |
|
Sure, to be fair, most of this code was from Ken Sherrif's bitcoins the hard way blog and the linked repo. I did some modifications myself to make it generate both the compressed and compressed versions and I started modifying it to work on testnet. Here's the entire script I've been playing with. You can see that if you just run it it's going to generate a random bitcoin address. However, if you do as we discussed before, calling it with python -i then you can call the methods you're interested in one-at-time. Or, you could make your own script at the bottom. Or, you could go ahead and convert it into a python module. In any case, here's all the methods I've been using/playing around with. The method you're looking for are privateKeyToPublicKey, see the bottom of the script for how I call it. #!/usr/bin/env python2.7 # for my education, following along with bitcoins the hard way blog post: # http://www.righto.com/2014/02/bitcoins-hard-way-using-raw-bitcoin.html import random import hashlib import ecdsa import struct
b58 = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
# Input is a hex-encoded, DER-encoded signature # Output is a 64-byte hex-encoded signature def derSigToHexSig(s): s, junk = ecdsa.der.remove_sequence(s.decode('hex')) if junk != '': print 'JUNK', junk.encode('hex') assert(junk == '') x, s = ecdsa.der.remove_integer(s) y, s = ecdsa.der.remove_integer(s) return '%064x%064x' % (x, y)
# Substitutes the scriptPubKey into the transaction, appends SIGN_ALL to make # the version of the transaction that can be signed def getSignableTxn(parsed): first, sig, pub, rest = parsed inputAddr = base58CheckDecode(pubKeyToAddr(pub)) return first + "1976a914" + inputAddr.encode('hex') + "88ac" + rest + "01000000"
# Returns [first, sig, pub, rest] def parseTxn(txn): first = txn[0:41*2] scriptLen = int(txn[41*2:42*2], 16) script = txn[42*2:42*2+2*scriptLen] sigLen = int(script[0:2], 16) sig = script[2:2+sigLen*2] pubLen = int(script[2+sigLen*2:2+sigLen*2+2], 16) pub = script[2+sigLen*2+2:] assert(len(pub) == pubLen*2) rest = txn[42*2+2*scriptLen:] return [first, sig, pub, rest]
# Verifies that a transaction is properly signed, assuming the generated scriptPubKey matches # the one in the previous transaction's output def verifyTxnSignature(txn): parsed = parseTxn(txn) signableTxn = getSignableTxn(parsed) hashToSign = hashlib.sha256(hashlib.sha256(signableTxn.decode('hex')).digest()).digest().encode('hex') assert(parsed[1][-2:] == '01') # hashtype sig = keyUtils.derSigToHexSig(parsed[1][:-2]) public_key = parsed[2] vk = ecdsa.VerifyingKey.from_string(public_key[2:].decode('hex'), curve=ecdsa.SECP256k1) assert(vk.verify_digest(sig.decode('hex'), hashToSign.decode('hex')))
# Verifies that a transaction is properly signed, assuming the generated scriptPubKey matches # the one in the previous transaction's output def verifyTxnSignature(txn): parsed = parseTxn(txn) signableTxn = getSignableTxn(parsed) hashToSign = hashlib.sha256(hashlib.sha256(signableTxn.decode('hex')).digest()).digest().encode('hex') assert(parsed[1][-2:] == '01') # hashtype sig = derSigToHexSig(parsed[1][:-2]) public_key = parsed[2] vk = ecdsa.VerifyingKey.from_string(public_key[2:].decode('hex'), curve=ecdsa.SECP256k1) assert(vk.verify_digest(sig.decode('hex'), hashToSign.decode('hex')))
# Takes and returns byte string value, not hex string def varstr(s): return varint(len(s)) + s
# Returns byte string value, not hex string def varint(n): if n < 0xfd: return struct.pack('<B', n) elif n < 0xffff: return struct.pack('<cH', '\xfd', n) elif n < 0xffffffff: return struct.pack('<cL', '\xfe', n) else: return struct.pack('<cQ', '\xff', n)
def base58encode(n): result = '' while n > 0: result = b58[n%58] + result n /= 58 return result
def base58decode(s): result = 0 for i in range(0, len(s)): result = result * 58 + b58.index(s[i]) return result
def base256encode(n): result = '' while n > 0: result = chr(n % 256) + result n /= 256 return result
def base256decode(s): result = 0 for c in s: result = result * 256 + ord(c) return result
def countLeadingChars(s, ch): count = 0 for c in s: if c == ch: count += 1 else: break return count
# https://en.bitcoin.it/wiki/Base58Check_encoding def base58CheckEncode(version, payload): s = chr(version) + payload checksum = hashlib.sha256(hashlib.sha256(s).digest()).digest()[0:4] result = s + checksum leadingZeros = countLeadingChars(result, '\0') return '1' * leadingZeros + base58encode(base256decode(result))
def base58CheckDecode(s): leadingOnes = countLeadingChars(s, '1') s = base256encode(base58decode(s)) result = '\0' * leadingOnes + s[:-4] chk = s[-4:] checksum = hashlib.sha256(hashlib.sha256(result).digest()).digest()[0:4] assert(chk == checksum) version = result[0] return result[1:]
def privateKeyToWif(key_hex, compressed=False): if compressed: key_hex=key_hex+'01' return base58CheckEncode(0x80, key_hex.decode('hex'))
def wifToPrivateKey(s): b = base58CheckDecode(s) return b.encode('hex')
def privateKeyToPublicKey(s, compressed=False):
sk = ecdsa.SigningKey.from_string(s.decode('hex'), curve=ecdsa.SECP256k1) vk = sk.verifying_key
if compressed: from ecdsa.util import number_to_string order = vk.pubkey.order # print "order", order x_str = number_to_string(vk.pubkey.point.x(), order).encode('hex') # print "x_str", x_str sign = '02' if vk.pubkey.point.y() % 2 == 0 else '03' # print "sign", sign return (sign+x_str) else: return ('\04' + vk.to_string()).encode('hex')
def pubKeyToAddr(s,testnet=False): ripemd160 = hashlib.new('ripemd160') ripemd160.update(hashlib.sha256(s.decode('hex')).digest()) if testnet: return base58CheckEncode(0x6F, ripemd160.digest()) return base58CheckEncode(0, ripemd160.digest())
def makeRawTransaction(outputTransactionHash, sourceIndex, scriptSig, outputs): def makeOutput(data): redemptionSatoshis, outputScript = data return (struct.pack("<Q", redemptionSatoshis).encode('hex') + '%02x' % len(outputScript.decode('hex')) + outputScript) formattedOutputs = ''.join(map(makeOutput, outputs)) return ( "01000000" + # 4 bytes version "01" + # variant for number of inputs outputTransactionHash.decode('hex')[::-1].encode('hex') + # reverse OutputTransactionHash struct.pack('<L', sourceIndex).encode('hex') + '%02x' % len(scriptSig.decode('hex')) + scriptSig + "ffffffff" + # sequence "%02x" % len(outputs) + # number of outputs formattedOutputs + "00000000" # lockTime )
def makeSignedTransaction(privateKey, outputTransactionHash, sourceIndex, scriptPubKey, outputs, compressed=False): myTxn_forSig = (makeRawTransaction(outputTransactionHash, sourceIndex, scriptPubKey, outputs) + "01000000") # hash code s256 = hashlib.sha256(hashlib.sha256(myTxn_forSig.decode('hex')).digest()).digest() sk = ecdsa.SigningKey.from_string(privateKey.decode('hex'), curve=ecdsa.SECP256k1) sig = sk.sign_digest(s256, sigencode=ecdsa.util.sigencode_der) + '\01' # 01 is hashtype pubKey = privateKeyToPublicKey(privateKey,compressed) scriptSig = varstr(sig).encode('hex') + varstr(pubKey.decode('hex')).encode('hex') signed_txn = makeRawTransaction(outputTransactionHash, sourceIndex, scriptSig, outputs) # verifyTxnSignature(signed_txn) return signed_txn
def addrHashToScriptPubKey(b58str): assert(len(b58str) == 34) # 76 A9 14 (20 bytes) 88 AC return '76a914' + base58CheckDecode(b58str).encode('hex') + '88ac'
# private_key = hex(i) #for i in range(1,100): # private_key = hex(i)[2:].zfill(64) # print privateKeyToWif(private_key), "2011-09-04T00:00:01Z"
import sys import getopt
private_key = None
try: opts, args = getopt.gnu_getopt(sys.argv[1:], "dtr:", ["dec","testnet","mrt"]) except getopt.GetoptError as err: print(err) sys.exit(2)
testnet=False deckey=False mrt=False
for o,a in opts: if o in ("-t", "--testnet"): testnet=True if o in ("-d","--dec"): deckey=True if o in ("-r","--mrt"): mrt=True
if len(args)>0: if deckey: private_key = args[0].zfill(64) else: private_key = '%064x' % int(args[0],16) else: private_key = ''.join(['%x' % random.randrange(16) for x in range(0,64)])
print "A private key: ", private_key
print "The uncompressed WIF: ",privateKeyToWif(private_key) print "The WIF: ",privateKeyToWif(private_key, compressed=True)
public_key = privateKeyToPublicKey(private_key) cpublic_key = privateKeyToPublicKey(private_key,compressed=True) print "The uncompressed bitcoin pubkey: ", public_key print "The bitcoin pubkey: ", cpublic_key print "The uncompressed bitcoin address: ", pubKeyToAddr(public_key,testnet=testnet) print "The bitcoin address: ", pubKeyToAddr(cpublic_key,testnet=testnet)
|
|
|
|
findftp (OP)
Legendary
Offline
Activity: 1022
Merit: 1008
Delusional crypto obsessionist
|
|
September 04, 2015, 09:46:02 PM |
|
Lol, bussy for hours reading stuff and trying things. Nice to figure out you can just feed this script a private hex key as an argument But, always nice to learn the inner workings of bitcoin. Thanks again, this was precisely what I wanted.
|
|
|
|
dserrano5
Legendary
Offline
Activity: 1974
Merit: 1029
|
|
September 05, 2015, 07:27:45 AM |
|
I'll donate you and dserrano5 some symbolic satoshis, thanks again.
Thank you!
|
|
|
|
|