Bitcoin Forum
May 06, 2024, 10:25:50 AM *
News: Latest Bitcoin Core release: 27.0 [Torrent]
 
   Home   Help Search Login Register More  
Pages: « 1 [2] 3 »  All
  Print  
Author Topic: Python code for validating bitcoin address  (Read 47510 times)
nima
Full Member
***
Offline Offline

Activity: 176
Merit: 100


View Profile WWW
December 09, 2012, 10:07:13 PM
 #21

This bitcoind address validator is a subclass of the Django forms.CharField class, but could easily be adapted to other frameworks or to be standalone code.

It does a "deep" validation, checking that the checksum built into every bitcoin address matches the address. It needs the PyCrypto library for the SHA256 function.

I hereby release this code into the public domain, do with it what you will.  And please let me know if you find any bugs in it.

BCAddressField.py:
Code:
#
# 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
October 20: Fixed bug with bitcoin addresses with leading-1's.
Hi Gavin,
Thanks for the code. I used it in a python script to validate a bunch of addresses. One invalid address managed to escape the validation (miwxGypTcHDXT3m4avmrMMC4co7XWqbG9r). Would you please confirm if the address says to be valid when you check it with your code?
Thank you

Coin Reaper @ http://coinreaper.com - Your expressway to FREE Bitcoins!
Bunny Run @ http://bunnyrun.us and win every time. No Bets required
1714991150
Hero Member
*
Offline Offline

Posts: 1714991150

View Profile Personal Message (Offline)

Ignore
1714991150
Reply with quote  #2

1714991150
Report to moderator
1714991150
Hero Member
*
Offline Offline

Posts: 1714991150

View Profile Personal Message (Offline)

Ignore
1714991150
Reply with quote  #2

1714991150
Report to moderator
1714991150
Hero Member
*
Offline Offline

Posts: 1714991150

View Profile Personal Message (Offline)

Ignore
1714991150
Reply with quote  #2

1714991150
Report to moderator
You get merit points when someone likes your post enough to give you some. And for every 2 merit points you receive, you can send 1 merit point to someone else!
Advertised sites are not endorsed by the Bitcoin Forum. They may be unsafe, untrustworthy, or illegal in your jurisdiction.
1714991150
Hero Member
*
Offline Offline

Posts: 1714991150

View Profile Personal Message (Offline)

Ignore
1714991150
Reply with quote  #2

1714991150
Report to moderator
1714991150
Hero Member
*
Offline Offline

Posts: 1714991150

View Profile Personal Message (Offline)

Ignore
1714991150
Reply with quote  #2

1714991150
Report to moderator
cande
Member
**
Offline Offline

Activity: 107
Merit: 10


https://bt.cx


View Profile WWW
February 17, 2013, 10:23:46 AM
Last edit: February 18, 2013, 09:08:17 AM by cande
 #22

I too have PHP and Java code for validating and generating Bitcoin addresses that have been tested and known to work.

PHP Example Link: https://github.com/Xenland/Bitcoin-Pseudocode-Client/blob/gh-pages/examples/php/verify_bitcoin_address.php

Java Example Source Link: https://github.com/Xenland/Bitcoin-Pseudocode-Client/blob/gh-pages/examples/java/Commandline%20Generate%20Bitcoin%20Address/src/commandline/CommandLine.java

I Also have an English explanation of how to verify a Bitcoin address (Part of the Bitcoin Pseudocode client project)
http://xenland.github.com/Bitcoin-Pseudocode-Client/verifyaddress.html


Thanks for this contribution! I ran the test fixtures for valid and invalid public keys listed below, with a few of my own known keys added; I got the following result:

There was 1 failure:

1) Lmh\BitcoinTransferBundle\Tests\BitcoinAddressValidatorTest::testInvalid
Test invalid public key '37qgekLpCCHrQuSjvX3fs496FWTGsHFHizjJAs6NPcR47aefnnCWECAhHV6E3g4YN7u7Yuwod5Y' returns 1 error.
Failed asserting that 0 matches expected 1.

/Users/matmar10/Projects/bitcoinbymobile/src/Lmh/BitcoinTransferBundle/Tests/BitcoinAddressValidatorTest.php:69

FAILURES!
Tests: 2, Assertions: 22, Failures: 1.

By the way, your PHP code had an undefined variable throwing an error and also an unused variable; I'll send you a git push request.

Hi, using the PHP code I can see that there has been no update on that gitrepo for the past 8 months, what correction did you find? can you post it here?

false negative address I found: 13saQdsv2XbkL9ef9FFT92m2zDaBGKwVGM

BTCX "more Private than Swiss banking"
https://bt.cx
Rotsor
Full Member
***
Offline Offline

Activity: 309
Merit: 102


Presale is live!


View Profile
May 03, 2013, 06:10:52 PM
 #23

Haskell translation:
Code:
module Main where

import Data.List
import Data.Maybe
import Data.Word
import Data.Tuple
import Control.Arrow
import Control.Monad
import qualified Crypto.Hash.SHA256 as SHA256
import qualified Data.ByteString as B

fromBase :: Integral a => Integer -> [a] -> Integer
fromBase b = foldl (\a c -> fromIntegral c + a * b) 0

toBase :: Num a => Integer -> Integer -> [a]
toBase b = reverse . unfoldr f where
 f 0 = Nothing
 f n = Just $ first fromInteger $ swap $ n `divMod` b


b58chars = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"

b58encode :: [Word8] -> [Char]
b58encode l = replicate (length $ takeWhile(==0) l) '1' ++
  (map (b58chars!!) . toBase 58 . fromBase 256) l

fromb58char c = fst . fromJust . find ((==c) . snd) $ zip [0..] b58chars

b58decode v =
  case span (== b58chars !! 0) v of
    (ones, v) ->
      replicate (length ones) 0 ++
        (toBase 256 . fromBase 58 . map fromb58char) v

b58decodeL l v =
  let
    res = b58decode v
  in
    guard (length res == l) >> return res

sha256x2 = B.unpack . SHA256.hash . SHA256.hash . B.pack where

checksum = take 4 . sha256x2

mkAddress :: Word8 -> [Word8] -> [Char]
mkAddress v d = b58encode $ v : d ++ checksum (v : d)

validateAddress :: [Char] -> Maybe (Word8, [Word8])
validateAddress addr = do
  (version : d) <- b58decodeL 25 addr
  case splitAt 20 d of
    (d, check) -> do
      guard $ checksum (version : d) == check
      return (version, d)
The code is under WTFPL.

grondilu
Legendary
*
Offline Offline

Activity: 1288
Merit: 1076


View Profile
May 03, 2013, 06:15:42 PM
 #24


BTW did I tell you guys that there is a rosetta code entry for bitcoin address validation?

Viceroy
Hero Member
*****
Offline Offline

Activity: 924
Merit: 501


View Profile
May 07, 2013, 05:05:44 PM
Last edit: May 09, 2013, 09:02:09 PM by Viceroy
 #25

I REALLY did want to use your code, grondilu, but it lacks documentation.  I tried to use the perl version and the bash version but couldn't get either to work.  I'm sure it's a lack of understanding on my part.  

Instead I grabbed Xenland's modification of MagicalTux's php script and made a couple changes:

EDIT:
THIS CODE GIVES FALSE NEGATIVES SHOWING PERFECTLY GOOD ADDRESSES AS BAD!!!

[code retracted]


working code a few posts down the thread

that way
|
|
|
V
grondilu
Legendary
*
Offline Offline

Activity: 1288
Merit: 1076


View Profile
May 07, 2013, 10:22:33 PM
 #26

I REALLY did want to use your code, grondilu, but it lacks documentation.  I tried to use the perl version and the bash version but couldn't get either to work.  I'm sure it's a lack of understanding on my part.  

Could you report your error message here or on the rosettacode talk page please?

Viceroy
Hero Member
*****
Offline Offline

Activity: 924
Merit: 501


View Profile
May 08, 2013, 11:25:37 PM
 #27

I REALLY did want to use your code, grondilu, but it lacks documentation.  I tried to use the perl version and the bash version but couldn't get either to work.  I'm sure it's a lack of understanding on my part.  

Could you report your error message here or on the rosettacode talk page please?

lol, it would look like this:

I'm too dumb to figure out how to use a bash script and I forget what issue it was that caused me to not want to use the perl, oh yea... I had no idea how to"feed" the address into the program.  So I gave up.  No reason to noise up your page with that.

now I'm looking at  http://blockexplorer.com/q/checkaddress as I found the above php useless.... it just gives false negatives.

why is there no simple tool like  http://blockexplorer.com/q/checkaddress

oh, wait, maybe there is over at  http://blockexplorer.com/q/checkaddress.. I'll report back (unless I just get lost in smoke and code).

Oh, I should probably start with my objective.... but finishing with it will suffice:

I am trying to figure out how to check bitcoin addresses and make bitcoin addresses and valid data in an online php form.

theymos
Administrator
Legendary
*
Offline Offline

Activity: 5194
Merit: 12972


View Profile
May 08, 2013, 11:48:35 PM
 #28

why is there no simple tool like  http://blockexplorer.com/q/checkaddress

/q/checkaddress uses this plus some extra checking. Note that the checkAddress function assumes that the input is valid base58. Do something like:

Code:
if(preg_match('/^[1-9A-HJ-NP-Za-km-z]+$/', $address) && strlen($address) <= 34 && checkAddress($address))
    address is valid

1NXYoJ5xU91Jp83XfVMHwwTUyZFK64BoAD
Viceroy
Hero Member
*****
Offline Offline

Activity: 924
Merit: 501


View Profile
May 09, 2013, 12:24:48 AM
Last edit: May 09, 2013, 09:01:49 PM by Viceroy
 #29

thanks!

EDIT
working code:

Shows Good Addresses as bad.

[retracted code]

working code a few posts down the thread

that way
|
|
|
V
jackjack
Legendary
*
Offline Offline

Activity: 1176
Merit: 1233


May Bitcoin be touched by his Noodly Appendage


View Profile
May 09, 2013, 02:21:08 PM
 #30

Did you try pywallet's code?
Look for DecodeBase58Check or something like that

Own address: 19QkqAza7BHFTuoz9N8UQkryP4E9jHo4N3 - Pywallet support: 1AQDfx22pKGgXnUZFL1e4UKos3QqvRzNh5 - Bitcointalk++ script support: 1Pxeccscj1ygseTdSV1qUqQCanp2B2NMM2
Pywallet: instructions. Encrypted wallet support, export/import keys/addresses, backup wallets, export/import CSV data from/into wallet, merge wallets, delete/import addresses and transactions, recover altcoins sent to bitcoin addresses, sign/verify messages and files with Bitcoin addresses, recover deleted wallets, etc.
Viceroy
Hero Member
*****
Offline Offline

Activity: 924
Merit: 501


View Profile
May 09, 2013, 02:21:19 PM
Last edit: May 09, 2013, 02:37:06 PM by Viceroy
 #31

I'm not getting the same results I see from http://blockexplorer.com/q/checkaddress/ with the above php code.  Checking further...

Are there any commercial use restrictions on grabbing data from blockexplore.com? 



ps. got a link for that, jack?
jackjack
Legendary
*
Offline Offline

Activity: 1176
Merit: 1233


May Bitcoin be touched by his Noodly Appendage


View Profile
May 09, 2013, 02:36:15 PM
 #32

https://github.com/joric/pywallet/blob/master/pywallet.py

Own address: 19QkqAza7BHFTuoz9N8UQkryP4E9jHo4N3 - Pywallet support: 1AQDfx22pKGgXnUZFL1e4UKos3QqvRzNh5 - Bitcointalk++ script support: 1Pxeccscj1ygseTdSV1qUqQCanp2B2NMM2
Pywallet: instructions. Encrypted wallet support, export/import keys/addresses, backup wallets, export/import CSV data from/into wallet, merge wallets, delete/import addresses and transactions, recover altcoins sent to bitcoin addresses, sign/verify messages and files with Bitcoin addresses, recover deleted wallets, etc.
Viceroy
Hero Member
*****
Offline Offline

Activity: 924
Merit: 501


View Profile
May 09, 2013, 02:37:18 PM
Last edit: May 09, 2013, 02:56:31 PM by Viceroy
 #33

thank you thank you.  dang dude, I can't dive into a 1700 line program right now.  what's that do with all those lines?

fwiw my code is down to 7 lines, and two of those are comments.

Code:
<?php // use with validator.php?refund=btc-address-here
$validateBTCURL 'http://blockexplorer.com/q/checkaddress/' $_GET["refund"];
//echo $validateBTCURL;
$validBTC file_get_contents($validateBTCURL);
//echo $validBTC;
if($validBTC == "00"){
//do something
} else {
//do something else
}
?>

jackjack
Legendary
*
Offline Offline

Activity: 1176
Merit: 1233


May Bitcoin be touched by his Noodly Appendage


View Profile
May 09, 2013, 03:45:08 PM
 #34

That's why I told you to look for the definition of DecodeBase58Check in the code, that's the function to decode address to hash160

Own address: 19QkqAza7BHFTuoz9N8UQkryP4E9jHo4N3 - Pywallet support: 1AQDfx22pKGgXnUZFL1e4UKos3QqvRzNh5 - Bitcointalk++ script support: 1Pxeccscj1ygseTdSV1qUqQCanp2B2NMM2
Pywallet: instructions. Encrypted wallet support, export/import keys/addresses, backup wallets, export/import CSV data from/into wallet, merge wallets, delete/import addresses and transactions, recover altcoins sent to bitcoin addresses, sign/verify messages and files with Bitcoin addresses, recover deleted wallets, etc.
theymos
Administrator
Legendary
*
Offline Offline

Activity: 5194
Merit: 12972


View Profile
May 09, 2013, 08:15:36 PM
 #35

I'm not getting the same results I see from http://blockexplorer.com/q/checkaddress/ with the above php code.  Checking further...

In what cases? It should be identical other than /q/checkaddress's additional info about why the address failed.

1NXYoJ5xU91Jp83XfVMHwwTUyZFK64BoAD
Viceroy
Hero Member
*****
Offline Offline

Activity: 924
Merit: 501


View Profile
May 09, 2013, 08:57:53 PM
 #36

after further testing it appears to be working as expected.  Here's the working code:


called with:

http://yourdomain/btcvalidate.php?address="btc-address-here"



btcvalidate.php:

Code:
<?php include("base58.php"); ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<!---  - - - - - - - - - - - - - - - - - - - - -  --->
<!--- name this file btcvalidate.php on webserver --->
<!---                                             --->
<!--- place base58.php in same directory          --->
<!---                                             --->
<!--- call with btc address as get function:      --->
<!--- btcvalidate.php?address="btc-address-here"      --->
<!---                                             --->
<!--- warning: no checking on input               --->
<!---  - - - - - - - - - - - - - - - - - - - - -  --->
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>btc address validator</title>
</head>
<body>
<?php
$address 
$_GET["address"];
if(
preg_match('/^[1-9A-HJ-NP-Za-km-z]+$/'$address) && strlen($address) <= 34 && checkAddress($address)){
echo    "<p>address is valid</p>";
} else {
echo    "<p>address is NOT valid</p>";
}
?>
 
</body>
</html>


base58.php:

Code:
<?php
/*
<!---  - - - - - - - - - - - - - - - - - - - - -  --->
<!--- name this file base58.php on webserver      --->
<!---  - - - - - - - - - - - - - - - - - - - - -  --->
*/
//hex input must be in uppercase, with no leading 0x
define("ADDRESSVERSION","00"); //this is a hex byte

function decodeHex($hex){
$hex=strtoupper($hex);
$chars="0123456789ABCDEF";
$return="0";
for($i=0;$i<strlen($hex);$i++){
$current=(string)strpos($chars,$hex[$i]);
$return=(string)bcmul($return,"16",0);
$return=(string)bcadd($return,$current,0);
}
return $return;
}

function 
encodeHex($dec){
$chars="0123456789ABCDEF";
$return="";
while (bccomp($dec,0)==1){
$dv=(string)bcdiv($dec,"16",0);
$rem=(integer)bcmod($dec,"16");
$dec=$dv;
$return=$return.$chars[$rem];
}
return strrev($return);
}

function 
decodeBase58($base58){
$origbase58=$base58;

$chars="123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
$return="0";
for($i=0;$i<strlen($base58);$i++){
$current=(string)strpos($chars,$base58[$i]);
$return=(string)bcmul($return,"58",0);
$return=(string)bcadd($return,$current,0);
}

$return=encodeHex($return);

//leading zeros
for($i=0;$i<strlen($origbase58)&&$origbase58[$i]=="1";$i++){
$return="00".$return;
}

if(strlen($return)%2!=0){
$return="0".$return;
}

return $return;
}

function 
encodeBase58($hex){
if(strlen($hex)%2!=0){
die("encodeBase58: uneven number of hex characters");
}
$orighex=$hex;

$chars="123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
$hex=decodeHex($hex);
$return="";
while (bccomp($hex,0)==1){
$dv=(string)bcdiv($hex,"58",0);
$rem=(integer)bcmod($hex,"58");
$hex=$dv;
$return=$return.$chars[$rem];
}
$return=strrev($return);

//leading zeros
for($i=0;$i<strlen($orighex)&&substr($orighex,$i,2)=="00";$i+=2){
$return="1".$return;
}

return $return;
}

function 
hash160ToAddress($hash160,$addressversion=ADDRESSVERSION){
$hash160=$addressversion.$hash160;
$check=pack("H*" $hash160);
$check=hash("sha256",hash("sha256",$check,true));
$check=substr($check,0,8);
$hash160=strtoupper($hash160.$check);
return encodeBase58($hash160);
}

function 
addressToHash160($addr){
$addr=decodeBase58($addr);
$addr=substr($addr,2,strlen($addr)-10);
return $addr;
}

function 
checkAddress($addr,$addressversion=ADDRESSVERSION){
$addr=decodeBase58($addr);
if(strlen($addr)!=50){
return false;
}
$version=substr($addr,0,2);
if(hexdec($version)>hexdec($addressversion)){
return false;
}
$check=substr($addr,0,strlen($addr)-8);
$check=pack("H*" $check);
$check=strtoupper(hash("sha256",hash("sha256",$check,true)));
$check=substr($check,0,8);
return $check==substr($addr,strlen($addr)-8);
}

function 
hash160($data){
$data=pack("H*" $data);
return strtoupper(hash("ripemd160",hash("sha256",$data,true)));
}

function 
pubKeyToAddress($pubkey){
return hash160ToAddress(hash160($pubkey));
}

function 
remove0x($string){
if(substr($string,0,2)=="0x"||substr($string,0,2)=="0X"){
$string=substr($string,2);
}
return $string;
}

?>

Eisenhower34
Legendary
*
Offline Offline

Activity: 906
Merit: 1002



View Profile
May 27, 2013, 12:16:27 PM
 #37

The code mentioned in the original post returns true for BTC and LTC addresses, because
Code:
get_bcaddress_version(address)

returns 0 for BTC addresses and 48 for LTC addresses, so both is not None. I wouldnt call this a bug, more a feature that allowes to check other coin addresses.
Melbustus
Legendary
*
Offline Offline

Activity: 1722
Merit: 1003



View Profile
July 08, 2013, 08:29:18 AM
 #38

why is there no simple tool like  http://blockexplorer.com/q/checkaddress

/q/checkaddress uses this plus some extra checking. Note that the checkAddress function assumes that the input is valid base58. Do something like:

Code:
if(preg_match('/^[1-9A-HJ-NP-Za-km-z]+$/', $address) && strlen($address) <= 34 && checkAddress($address))
    address is valid

theymos - that pastebin-linked code is yours, right, from: http://code.gogulski.com/bitcoin-php/

Just want to make sure the public domain license applies before I integrate.

Thanks!

Bitcoin is the first monetary system to credibly offer perfect information to all economic participants.
theymos
Administrator
Legendary
*
Offline Offline

Activity: 5194
Merit: 12972


View Profile
July 08, 2013, 01:37:29 PM
 #39

The pastebin code is mine and public domain. That bitcoin-php library is a separate thing that I wasn't involved with.

1NXYoJ5xU91Jp83XfVMHwwTUyZFK64BoAD
Melbustus
Legendary
*
Offline Offline

Activity: 1722
Merit: 1003



View Profile
July 08, 2013, 08:07:42 PM
 #40

The pastebin code is mine and public domain. That bitcoin-php library is a separate thing that I wasn't involved with.


Great, thanks. I just glanced at the function sigs and assumed they were by the same author. In any event, I just integrated your code from that pastebin link. That was easy - thanks very much!

Bitcoin is the first monetary system to credibly offer perfect information to all economic participants.
Pages: « 1 [2] 3 »  All
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.19 | SMF © 2006-2009, Simple Machines Valid XHTML 1.0! Valid CSS!