# |
# DJango field type for a Bitcoin Address |
# |
importre |
fromdjangoimportforms |
fromdjango.forms.utilimportValidationError |
fromCrypto.HashimportSHA256 |
|
classBCAddressField(forms.CharField): |
default_error_messages= { |
'invalid': 'Invalid Bitcoin address.', |
} |
|
def__init__(self, *args, **kwargs): |
super(BCAddressField, self).__init__(*args, **kwargs) |
|
defclean(self, value): |
value=value.strip() |
ifre.match(r"[a-zA-Z1-9]{27,35}$", value) isNone: |
raiseValidationError(self.error_messages['invalid']) |
version=get_bcaddress_version(value) |
ifversionisNone: |
raiseValidationError(self.error_messages['invalid']) |
returnvalue |
|
importmath |
|
__b58chars='123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' |
__b58base=len(__b58chars) |
|
defb58encode(v): |
""" encode v, which is a string of bytes, to base58. |
""" |
|
long_value=0L |
for (i, c) inenumerate(v[::-1]): |
long_value+= (256**i) *ord(c) |
|
result='' |
whilelong_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 |
forcinv: |
ifc=='\0': nPad+=1 |
else: break |
|
return (__b58chars[0]*nPad) +result |
|
defb58decode(v, length): |
""" decode v into a string of len bytes |
""" |
long_value=0L |
for (i, c) inenumerate(v[::-1]): |
long_value+=__b58chars.find(c) * (__b58base**i) |
|
result='' |
whilelong_value>=256: |
div, mod=divmod(long_value, 256) |
result=chr(mod) +result |
long_value=div |
result=chr(long_value) +result |
|
nPad=0 |
forcinv: |
ifc==__b58chars[0]: nPad+=1 |
else: break |
|
result=chr(0)*nPad+result |
iflengthisnotNoneandlen(result) !=length: |
returnNone |
|
returnresult |
|
defget_bcaddress_version(strAddress): |
""" Returns None if strAddress is invalid. Otherwise returns integer version of address. """ |
addr=b58decode(strAddress,25) |
ifaddrisNone: returnNone |
version=addr[0] |
checksum=addr[-4:] |
vh160=addr[:-4] # Version plus hash160 is what is checksummed |
h3=SHA256.new(SHA256.new(vh160).digest()).digest() |
ifh3[0:4] ==checksum: |
returnord(version) |
returnNone |
-
-
-