Pages:
Author

Topic: Python code for validating bitcoin address - page 2. (Read 47496 times)

legendary
Activity: 1288
Merit: 1076
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?
hero member
Activity: 924
Merit: 501
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
legendary
Activity: 1288
Merit: 1076

BTW did I tell you guys that there is a rosetta code entry for bitcoin address validation?
full member
Activity: 309
Merit: 102
Presale is live!
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.
member
Activity: 107
Merit: 10
https://bt.cx
February 17, 2013, 06:23:46 AM
#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
full member
Activity: 176
Merit: 100
December 09, 2012, 06:07:13 PM
#21
newbie
Activity: 47
Merit: 0
November 28, 2012, 05:02:58 AM
#20
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.
legendary
Activity: 1288
Merit: 1076
November 27, 2012, 07:59:25 PM
#18
By the way I've created a rosetta code draft task for validating a bitcoin address:

http://rosettacode.org/wiki/Bitcoin/address_validation

Don't hesitate to put your solution in your language.   But please make it short.
legendary
Activity: 1596
Merit: 1091
November 27, 2012, 04:00:11 PM
#17

Has anyone written a test-suite for key generation-validation?

I mean, a text/json/whatever file where you'd have a couple of address/private key pairs?

And in all possible formats (test network, compressed/uncompressed and so on...).

That would be useful.

There is some JSON test data at https://github.com/bitcoin/bitcoin/tree/master/src/test/data

I'm using this for a C-based "libccoin" bitcoin library testing https://github.com/jgarzik/picocoin/

legendary
Activity: 1288
Merit: 1076
November 27, 2012, 03:23:50 PM
#16

Has anyone written a test-suite for key generation-validation?

I mean, a text/json/whatever file where you'd have a couple of address/private key pairs?

And in all possible formats (test network, compressed/uncompressed and so on...).

That would be useful.
newbie
Activity: 47
Merit: 0
November 27, 2012, 01:18:21 PM
#15
legendary
Activity: 980
Merit: 1003
I'm not just any shaman, I'm a Sha256man
November 17, 2012, 06:03:13 AM
#14
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
sr. member
Activity: 314
Merit: 251
November 15, 2012, 10:38:58 AM
#13
.NET 4.0 version of bitcoin address validation, Translated by YogaFan:

Code:
Imports System.Security.Cryptography
Imports System.Numerics

Module ValidateBitCoinAddress

Function isValidBitcoinAddress(s As String) As Boolean
    Dim regExPattern As String = "[a-zA-Z1-9]{27,35}$"
    If MatchString(s, regExPattern) Then
        If get_bcaddress_version(s) <> "" Then
            isValidBitcoinAddress = True
        Else
            isValidBitcoinAddress = False
        End If
    Else
        isValidBitcoinAddress = False
    End If
End Function


Function MatchString(ByVal str As String, ByVal regexstr As String) As Boolean
    str = str.Trim()
    Dim pattern As New System.Text.RegularExpressions.Regex(regexstr)
    Return pattern.IsMatch(str)
End Function

Function get_bcaddress_version(strAddress) As String

    Dim addr As Byte()
    Dim version As Byte
    Dim checksum(3) As Byte
    Dim h3(3) As Byte
    Dim x As Integer

    addr = b58decode(strAddress, 25)

    If IsNothing(addr) Then
        'fail
        get_bcaddress_version = ""
        Exit Function
    End If

    Dim lenAddr As Integer = addr.GetLength(0)
    Dim vh160(lenAddr - 5) As Byte
    Dim sha As New SHA256Managed()

    version = addr(0)
    checksum = {addr(lenAddr - 4), addr(lenAddr - 3), addr(lenAddr - 2), addr(lenAddr - 1)}

    For x = 0 To vh160.GetLength(0) - 1
        vh160(x) = addr(x)
    Next

    Dim Hash() As Byte = sha.ComputeHash(vh160)
    Dim SecondHash() As Byte = sha.ComputeHash(Hash)

    h3 = {SecondHash(0), SecondHash(1), SecondHash(2), SecondHash(3)}

    If h3(0) = checksum(0) And h3(1) = checksum(1) And h3(2) = checksum(2) And h3(3) = checksum(3) Then
        get_bcaddress_version = version.ToString
    Else
        'fail
        get_bcaddress_version = ""
    End If

End Function

Function b58encode(b() As Byte) As String


    Dim b58chars As String = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
    Dim b58base As BigInteger = 58
    Dim x As BigInteger
    Dim long_value As BigInteger = 0
    Dim result As String = ""
    Dim iMod As BigInteger = 0
    Dim iDiv As BigInteger = 0
    Dim b256base As BigInteger = 256

    Dim c As Integer
    Dim lv As Integer

    lv = b.GetLength(0) - 1
    c = 0
    For x = lv To 0 Step -1
        long_value = long_value + BigInteger.Pow(b256base, x) * b(c)
        c = c + 1
    Next

    Do While long_value >= b58base
        iMod = long_value Mod b58base
        iDiv = long_value / b58base

        result = b58chars(iMod) & result
        long_value = iDiv
    Loop
    result = b58chars(long_value) & result

    For x = 0 To lv
        If b(x) = CByte(0) Then
            result = b58chars(0) & result
        Else
            Exit For
        End If
    Next

    Return result
    End Function

Function insertat(b As Byte, bArr As Byte(), pos As Integer) As Byte()

    If IsNothing(bArr) Then
        'empty array; return single celled array
        Dim tmpsomeOtherBarr(0) As Byte
        tmpsomeOtherBarr(0) = b
        insertat = tmpsomeOtherBarr
        Exit Function
    End If

    Dim x As Integer
    Dim tmpbArr(bArr.GetLength(0)) As Byte

    If pos = -1 Then
        'insert at end of array
        For x = 0 To bArr.GetLength(0) - 1
            tmpbArr(x) = bArr(x)
        Next
        tmpbArr(bArr.GetLength(0)) = b

        Return tmpbArr
    ElseIf pos = 0 Then
        'insert at beginning
        tmpbArr(0) = b
        For x = 1 To bArr.GetLength(0)
            tmpbArr(x) = bArr(x - 1)
        Next
        Return tmpbArr
    Else
        'insert in the middle
        For x = 0 To pos - 1
            tmpbArr(x) = bArr(x)
        Next
        tmpbArr(pos) = b
        For x = pos + 1 To bArr.GetLength(0)
            tmpbArr(x) = bArr(x)
        Next
        Return tmpbArr

    End If
End Function

Function b58decode(v As String, l As Integer) As Byte()

    Dim b58chars As String = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
    Dim b58base As BigInteger = 58
    Dim long_value As BigInteger = 0
    Dim lv As Integer
    Dim c As Integer
    Dim x As BigInteger
    Dim biPos As BigInteger = 0
    Dim iMod As BigInteger = 0
    Dim iDiv As BigInteger = 0
    Dim result() As Byte

    lv = Len(v) - 1

    For x = lv To 0 Step -1
        c = c + 1
        biPos = b58chars.IndexOf(Mid(v, c, 1))
        long_value = long_value + BigInteger.Pow(b58base, x) * biPos
    Next

    Do While long_value >= 256
        iMod = long_value Mod 256
        iDiv = long_value / 256
        result = insertat(CByte(iMod), result, 0)
        long_value = iDiv
    Loop
    result = insertat(CByte(long_value), result, 0)

    For x = 1 To Len(v)
        If Mid(v, x, 1) = b58chars(0) Then
            result = insertat(CByte(0), result, 0)
        Else
            Exit For
        End If
    Next

    If l > 0 And result.GetLength(0) <> l Then
        Return Nothing
    Else
        Return result
    End If

End Function

End Module


legendary
Activity: 1288
Merit: 1076

It's kind of frustrating that nobody seems to want to use my bash functions to check bitcoin addresses.

It only requires basic unix tools such as xxd, dc and openssl.

This is beautiful and concise shell scripting.  Nice job.

Ah, finally!   Thanks!    Cheesy
newbie
Activity: 5
Merit: 0

It's kind of frustrating that nobody seems to want to use my bash functions to check bitcoin addresses.

It only requires basic unix tools such as xxd, dc and openssl.

This is beautiful and concise shell scripting.  Nice job.
legendary
Activity: 1288
Merit: 1076

It's kind of frustrating that nobody seems to want to use my bash functions to check bitcoin addresses.

It only requires basic unix tools such as xxd, dc and openssl.

Code:
base58=({1..9} {A..H} {J..N} {P..Z} {a..k} {m..z})
bitcoinregex="^[$(printf "%s" "${base58[@]}")]{34}$"

decodeBase58() {
    local s=$1
    for i in {0..57}
    do s="${s//${base58[i]}/ $i}"
    done
    dc <<< "16o0d${s// /+58*}+f"
}

checksum() {
    xxd -p -r <<<"$1" |
    openssl dgst -sha256 -binary |
    openssl dgst -sha256 -binary |
    xxd -p -c 80 |
    head -c 8
}

checkBitcoinAddress() {
    if [[ "$1" =~ $bitcoinregex ]]
    then
        h=$(decodeBase58 "$1")
        checksum "00${h::${#h}-8}" |
        grep -qi "^${h: -8}$"
    else return 2
    fi
}
sr. member
Activity: 266
Merit: 250
  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'])

Gavin,
I'm trying to understand your usage of default.error_messages (first line in the snippet), vs. self.error_messages (last line in the snippet, above),  in your code.
Does Django somehow link those two together?  Or is that a bug in the code?  (I'm sure this code has been tested a lot since October!)

Seems to me that you should be using the same dictionary in both places.

vip
Activity: 608
Merit: 501
-
November 15, 2010, 03:01:46 PM
#8
For those interested, I rewrote base58_encode/base58_decode in PHP, and added a "decode_btc" function (that will return an array containing "version" and "hash" for a given bitcoin address).

This code requires the following php extensions:
  • gmp (for bignum values, we could use bc, or even the php-native implementation in pear, I'm just too lazy and I got gmp installed on all my servers anyway)
  • hash (or mhash, someone could insert a php-native sha256 implementation to fallback to)

Here's the code, largely inspired from the code of the previous authors of this thread:
Code:
$btc decode_btc('1Eym7pyJcaambv8FG4ZoU8A4xsiL9us2zz');
var_dump($btc);
var_dump(encode_btc($btc));
$btc decode_btc('1111111111111111111114oLvT2');
var_dump($btc);
var_dump(encode_btc($btc));

function 
hash_sha256($string) {
  if (
function_exists('hash')) return hash('sha256'$stringtrue);
  if (
function_exists('mhash')) return mhash(MHASH_SHA256$string);
  
// insert native php implementation of sha256 here
  
throw new Exception('Too lazy to fallback when the guy who configured php was lazy too');
}

function 
encode_btc($btc) {
  
$btc chr($btc['version']).pack('H*'$btc['hash']);
  if (
strlen($btc) != 21) return false;
  
$cksum substr(hash_sha256(hash_sha256($btc)), 04);
  return 
base58_encode($btc.$cksum);
}

function 
decode_btc($btc) {
  
$btc base58_decode($btc);
  if (
strlen($btc) != 25) return false// invalid
  
$version ord($btc[0]);
  
$cksum substr($btc, -4);
  
// checksum is double sha256 (take 4 first bytes of result)
  
$good_cksum substr(hash_sha256(hash_sha256(substr($btc0, -4))), 04);
  if (
$cksum != $good_cksum) return false;
  return array(
'version' => $version'hash' => bin2hex(substr($btc120)));
}

function 
base58_encode($string) {
  
$table '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';

  
$long_value gmp_init(bin2hex($string), 16);

  
$result '';
  while(
gmp_cmp($long_value58) > 0) {
    list(
$long_value$mod) = gmp_div_qr($long_value58);
    
$result .= $table[gmp_intval($mod)];
  }
  
$result .= $table[gmp_intval($long_value)];

  for(
$nPad 0$string[$nPad] == "\0"; ++$nPad);

  return 
str_repeat($table[0], $nPad).strrev($result);
}

function 
base58_decode($string) {
  
$table '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
  static 
$table_rev null;
  if (
is_null($table_rev)) {
    
$table_rev = array();
    for(
$i=0;$i<58;++$i$table_rev[$table[$i]]=$i;
  }

  
$l strlen($string);
  
$long_value gmp_init('0');
  for(
$i=0;$i<$l;++$i) {
    
$c=$string[$l-$i-1];
    
$long_value gmp_add($long_valuegmp_mul($table_rev[$c], gmp_pow(58$i)));
  }

  
// php is lacking binary output for gmp
  
$res pack('H*'gmp_strval($long_value16));

  for(
$nPad 0$string[$nPad] == $table[0]; ++$nPad);
  return 
str_repeat("\0"$nPad).$res;
}

This outputs:
Quote
array(2) {
  ["version"]=>
  int(0)
  ["hash"]=>
  string(40) "9955c1b44fa66688d27aaa06ba4ad02c6dd91088"
}
string(34) "1Eym7pyJcaambv8FG4ZoU8A4xsiL9us2zz"
array(2) {
  ["version"]=>
  int(0)
  ["hash"]=>
  string(40) "0000000000000000000000000000000000000000"
}
string(27) "1111111111111111111114oLvT2"

sr. member
Activity: 428
Merit: 253
October 25, 2010, 03:46:52 AM
#7
Are you working on a Django bitcoin project ? I'm highly interested, thinking about it myself too.
Pages:
Jump to: