Skip to content

Instantly share code, notes, and snippets.

@savasadar
Last active February 20, 2019 14:17
Show Gist options
  • Save savasadar/4e12f4d008c2f91f4c836339b7bb99a4 to your computer and use it in GitHub Desktop.
Save savasadar/4e12f4d008c2f91f4c836339b7bb99a4 to your computer and use it in GitHub Desktop.
Python code for validating bitcoin address
#
# DJango field type for a Bitcoin Address
#
import re
from django import forms
from django.forms.util import ValidationError
from Crypto.Hash import SHA256
class BCAddressField(forms.CharField):
default_error_messages = {
'invalid': 'Invalid Bitcoin address.',
}
def __init__(self, *args, **kwargs):
super(BCAddressField, self).__init__(*args, **kwargs)
def clean(self, value):
value = value.strip()
if re.match(r"[a-zA-Z1-9]{27,35}$", value) is None:
raise ValidationError(self.error_messages['invalid'])
version = get_bcaddress_version(value)
if version is None:
raise ValidationError(self.error_messages['invalid'])
return value
import math
__b58chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
__b58base = len(__b58chars)
def b58encode(v):
""" encode v, which is a string of bytes, to base58.
"""
long_value = 0L
for (i, c) in enumerate(v[::-1]):
long_value += (256**i) * ord(c)
result = ''
while long_value >= __b58base:
div, mod = divmod(long_value, __b58base)
result = __b58chars[mod] + result
long_value = div
result = __b58chars[long_value] + result
# Bitcoin does a little leading-zero-compression:
# leading 0-bytes in the input become leading-1s
nPad = 0
for c in v:
if c == '\0': nPad += 1
else: break
return (__b58chars[0]*nPad) + result
def b58decode(v, length):
""" decode v into a string of len bytes
"""
long_value = 0L
for (i, c) in enumerate(v[::-1]):
long_value += __b58chars.find(c) * (__b58base**i)
result = ''
while long_value >= 256:
div, mod = divmod(long_value, 256)
result = chr(mod) + result
long_value = div
result = chr(long_value) + result
nPad = 0
for c in v:
if c == __b58chars[0]: nPad += 1
else: break
result = chr(0)*nPad + result
if length is not None and len(result) != length:
return None
return result
def get_bcaddress_version(strAddress):
""" Returns None if strAddress is invalid. Otherwise returns integer version of address. """
addr = b58decode(strAddress,25)
if addr is None: return None
version = addr[0]
checksum = addr[-4:]
vh160 = addr[:-4] # Version plus hash160 is what is checksummed
h3=SHA256.new(SHA256.new(vh160).digest()).digest()
if h3[0:4] == checksum:
return ord(version)
return None
@savasadar
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment