Author

Topic: A full shell script implementation of bitcoin ? (Read 14321 times)

legendary
Activity: 1288
Merit: 1080
February 18, 2022, 04:49:42 PM
#66
Sorry for necro-posting, but a github user pointed me to that thread so I felt like updating subscribers.


This project is still alive, though updates are rare.

Feel free to check it out : https://github.com/grondilu/bitcoin-bash-tools/
full member
Activity: 158
Merit: 100
aquí dice algo personal.
All of this is very impressive. Someone made a wiki?
legendary
Activity: 1288
Merit: 1080
I see on your github only a small subset of the things discussed in this thread.  How is this going?  Have you put it up somewhere?  I want to see it!

Sorry but I haven't got used to github as I basically don't like using it.  Also I don't have a permanent internet access, and I don't think about updating it when I connect.

Sorry but you'll have to extract the code from this thread.
newbie
Activity: 34
Merit: 0
I see on your github only a small subset of the things discussed in this thread.  How is this going?  Have you put it up somewhere?  I want to see it!
bji
member
Activity: 112
Merit: 10
I've been rediscovering Perl recently.  It's the coolest programming language I know.

Do I like Perl?  No, I hate perl.  It is sometimes acceptable when used in a very limited way for short-lived scripts intended to accomplish an immediate goal.  Perl code should be written, used once or twice, and then thrown away.
legendary
Activity: 1288
Merit: 1080
I've been rediscovering Perl recently.  It's the coolest programming language I know.

Code:
#!/usr/bin/perl
use strict;
use warnings;

use Digest::SHA qw(sha256);

my @base58 = (1 .. 9, 'A' .. 'H', 'J' .. 'N', 'P' .. 'Z', 'a' .. 'k', 'm' .. 'z');
my $base58 = join '', @base58;

sub decodeBase58($) {
    my $_ = shift;
    die "wrong format" if not m{^[$base58]+$};
    for my $c (0..57) { s/$base58[$c]/ $c/g }
    s/ /+58*/g;
    return qx{dc -e "16o0d$_+n"};
}

sub encodeBase58($) {
    my $_ = uc shift;
    open my $bc, qq[echo "ibase=16; n=$_; while(n>0) { n%3A; n/=3A }" | bc |];
    return join '', map { $base58[$_] } (reverse <$bc>);
}

sub checksum($) { return uc unpack 'H8', sha256 sha256 pack 'H*', shift }

sub checkBitcoinAddress($) {
    my $address = shift;
    die "wrong format" if $address !~ qr(^[$base58]{34,35}$);
    (my $h = sprintf "%50s", decodeBase58 $address) =~ tr/ /0/;

    (checksum substr $h, 0, -8) eq substr $h, -8;
}

sub hash160($) {
    # I have to use the shell here for there is no rmd160 in Digest:: :-(
    my $h = shift;
    open my $sh, qq{
    echo -n "$h" |
    openssl dgst -sha256 -binary |
    openssl dgst -rmd160 -binary |
    };
    return uc unpack 'H*', <$sh>;
}

sub hash160ToAddress($) {
    my $_ = shift;
    my $checksum = checksum "00$_";
    $_ = sprintf "%34s", encodeBase58 "00$_$checksum";
    tr/ /1/;
    return $_;
}

sub publicKeyToAddress($) {
    # Couldn't find a Perl library for ECDSA,
    # so I use the shell here.
    my $_ = shift;
    return hash160ToAddress hash160 qx{
    echo "$_" |
    openssl ec -pubin -pubout -outform DER 2>&- |
    tail -c 65
    }
}
legendary
Activity: 1288
Merit: 1080

Could someone write a C/C++ program that could allow me to test this portion of code in irc.cpp ?

Code:
#pragma pack(push, 1)
struct ircaddr
{
    int ip;
    short port;
};
#pragma pack(pop)

string EncodeAddress(const CAddress& addr)
{
    struct ircaddr tmp;
tmp.ip    = addr.ip;
    tmp.port  = addr.port;

    vector vch(UBEGIN(tmp), UEND(tmp));
    return string("u") + EncodeBase58Check(vch);
}

I need to do some trial and error testing of the bash equivalent.
legendary
Activity: 3920
Merit: 2349
Eadem mutata resurgo
Post #35 in this thread.

Quote
grondilu:
Quote
I also wonder if all communications could not be done using HTTP.  Blocks would be published via http GET method (giving the hash of the preceding block), and transactions could be sent via POST method.

One advantage of using http would be that it would be very hard for governments to forbid.

Where did you get to with the network connection side of this, netcat could be an option.
legendary
Activity: 1288
Merit: 1080
You should use the wildly available "netcat" ("nc") to connect to the IRC server !

Thanks for the tip about netcat, I didn't know about it.  So many things to
know and only one life ;(
hero member
Activity: 826
Merit: 500
nice development. cant wait to see all the tools finished
member
Activity: 83
Merit: 10
The French Pool
Hi,

Warning ! "/dev/tcp/" is not available everywhere !
Disabled on some new Linux OS (Debian 6, ...) for more security.

You should use the wildly available "netcat" ("nc") to connect to the IRC server !

By the way, your script is very interesting !

(Sorry for my English, I'm french)

macman31
full member
Activity: 182
Merit: 100
Subscribing, very interesting Wink
legendary
Activity: 1288
Merit: 1080

Connecting to IRC is actually much easier than I thought.  I still have to request my IP and format my nick, though.

Code:
#!/bin/bash
#
# This is free and unencumbered software released into the public domain.
#
# Anyone is free to copy, modify, publish, use, compile, sell, or
# distribute this software, either in source code form or as a compiled
# binary, for any purpose, commercial or non-commercial, and by any
# means.
#
# In jurisdictions that recognize copyright laws, the author or authors
# of this software dedicate any and all copyright interest in the
# software to the public domain. We make this dedication for the benefit
# of the public at large and to the detriment of our heirs and
# successors. We intend this dedication to be an overt act of
# relinquishment in perpetuity of all present and future rights to this
# software under copyright law.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
# OTHER DEALINGS IN THE SOFTWARE.
#
#

################################################################################
#
#                                 BASE 58 encoding/decoding
#
# Requires bc, dc, openssl, xxd
################################################################################

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"
}

encodeBase58() {
    # 58 = 0x3A
    bc <<<"ibase=16; n=${1^^}; while(n>0) { n%3A ; n/=3A }" |
    tac |
    while read n
    do echo -n ${base58[n]}
    done
}

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
}

hash160() {
    # binary data expected on stdin
    openssl dgst -sha256 -binary |
    openssl dgst -rmd160 -binary |
    xxd -p -c 80
}

hash160ToAddress() {
    printf "%34s\n" "$(encodeBase58 "00$1$(checksum "00$1")")" |
    sed "y/ /1/"
}

publicKeyToAddress() {
    hash160ToAddress $(
    openssl ec -pubin -pubout -outform DER 2>/dev/null |
    tail -c 65 |
    hash160
    )
}

bigEndianHex2littleEndianHex() {
    local s
    while read -n 2 c
    do s=$c$s
    done
    echo $s
}

bitcoinHash() {
    bigEndianHex2littleEndianHex |
    xxd -p -r |
    openssl dgst -sha256 -binary |
    openssl dgst -sha256 -binary |
    xxd -p -c 80 |
    bigEndianHex2littleEndianHex
}

################################################################################
#
#                                 IRC communication
#
# most of this comes from http://shudder.daemonette.org/source/BashNP-Guide.txt
################################################################################

host="irc.lfnet.org" port=6667 channel="#bitcoinTEST" mode="+i"

nick="$USER$$"
name="$USER's bitcoin bot script"

if
    # try to connect
    ! exec 3<> /dev/tcp/$host/$port
then
    echo "$(basename $0): unable to connect to $host:$port" 1>&2
    exit 1
else
    # duplicate standard input and output with the newly created socket
    exec 0<&3 1>&3-

    # register to the server
    echo "USER $nick ${mode:-+iw} $nick :$name"
    echo "NICK $nick"
    # join channel
    echo "JOIN $channel"

    while read
    do
set -- ${REPLY//$'\r'/}

# answer the critical ping request
# otherwise the server will disconnect us
[[ "$1" == "PING" ]] && echo "PONG $2"

echo $REPLY >&2

    done

    exec 1<&-
fi
legendary
Activity: 1288
Merit: 1080
how far are we from a total implementation?

Very far.
hero member
Activity: 616
Merit: 500
Firstbits.com/1fg4i :)
how far are we from a total implementation?
legendary
Activity: 1288
Merit: 1080
The last hash is doubled.

Indeed.  I thought I had tried that but I guess I did it wrong.

Thanks.
administrator
Activity: 5222
Merit: 13032
The last hash is doubled.
legendary
Activity: 1288
Merit: 1080
Here is the Merkle tree for block 95002, which had three transactions:

Code:
"mrkl_tree":[
"4fa598026d9be1ca0c2bff1b531e566b7ea7f90b72e75fda0c1795bc2dfa375c",
"186640daf908156e2616790d7c816235b0c43f668c3c38351b348c08ca44d457",
"ef3928700309b4deceac9a992a19a7481b4e520cbc0b1ab74e2645eee39c8da0",
"688c53517f62f7a65c0e87519c18a4de98f2ccafbf389b269d0bb867f88d166a",
"01889506f7fe9210045f588361881e2d16a034a62bc48ebd7b6b0a3edeaf5a6d",
"74f3a7df861d6a58957b84a3e425a8cf57e1e2e3a3def046dd200baeb8714f00"
]

I rewrote the two bash functions:

Code:
bigEndianHex2littleEndianHex() {
    local s=''
    while read -n 2 char
        do s=$char$s
    done
    echo $s
}

bitcoinHash() {
    bigEndianHex2littleEndianHex |
    xxd -p -r |
    openssl dgst -sha256 -binary |
    openssl dgst -sha256 -binary |
    xxd -p -c 80 |
    bigEndianHex2littleEndianHex
}


The fourth entry of the Merkle tree is easy to reconstitute.  It's obviously made out of the first two.

bitcoinHash <<<"186640daf908156e2616790d7c816235b0c43f668c3c38351b348c08ca44d457
4fa598026d9be1ca0c2bff1b531e566b7ea7f90b72e75fda0c1795bc2dfa375c"


But then, I don't know how to get the fith out of the third.
hero member
Activity: 566
Merit: 500
Unselfish actions pay back better
different version of openssl I guess.

$ openssl version
OpenSSL 1.0.0c 2 Dec 2010

Yes, I'm running OpenSSL 0.9.8k 25 Mar 2009 (from Ubuntu Lucid).

Cheers,
legendary
Activity: 1288
Merit: 1080
Code:
$ openssl dgst -sha256 -hex <<< "hello, world"
853ff93762a06ddbf722c4ebe9ddd66d8f63ddaea97f521c3ecc20da7c976020
$

Cheers,

different version of openssl I guess.

$ openssl version
OpenSSL 1.0.0c 2 Dec 2010
hero member
Activity: 566
Merit: 500
Unselfish actions pay back better
Well, when I run openssl dgst -sha1 -hex <<<"hello, world", I get an annoying:

(stdin)= cd50d19784897085a8d0e3e413f8612b097c03f1


I wish there was an option not to display this "(...)= " before my result.  Anyway that's why I had to add a 'sed "s/^.* //"'.

Ah, this doesn't happen here — I only see that SHA256 digest:

Code:
$ openssl dgst -sha256 -hex <<< "hello, world"
853ff93762a06ddbf722c4ebe9ddd66d8f63ddaea97f521c3ecc20da7c976020
$

Cheers,
legendary
Activity: 1288
Merit: 1080
But you have to get rid of the annoying 'std(...)= ':

Huh?  I don't get you…

Well, when I run openssl dgst -sha1 -hex <<<"hello, world", I get an annoying:

(stdin)= cd50d19784897085a8d0e3e413f8612b097c03f1


I wish there was an option not to display this "(...)= " before my result.  Anyway that's why I had to add a 'sed "s/^.* //"'.
hero member
Activity: 616
Merit: 500
Firstbits.com/1fg4i :)
(just subscribing to the thread)
hero member
Activity: 566
Merit: 500
Unselfish actions pay back better
But you have to get rid of the annoying 'std(...)= ':

Huh?  I don't get you…

Quote
I didn't know that there were actually 2 sha256 passes, just like for the hash of the block itself.

Neither did I, but it was worth a try.

Quote
(also, you can use '|' at the end of line without using '\')

(I know, but I think explicit line continuations are more legible.)

Quote
Now how to deal with blocks with a number of transactions that are not a power of 2?

You tell me. Wink

Cheers,
legendary
Activity: 1288
Merit: 1080
How about

Code:
{ bigEndianHex2littleEndianHex <<<"$a" | xxd -p -r ;
   bigEndianHex2littleEndianHex <<<"$b" | xxd -p -r ; } \
   | openssl dgst -sha256 -binary \
   | openssl dgst -sha256 -hex \
   | bigEndianHex2littleEndianHex

That would give the third hash, wouldn't it?

It does indeed!   But you have to get rid of the annoying 'std(...)= ':

I didn't know that there were actually 2 sha256 passes, just like for the hash of the block itself.

Code:
{ bigEndianHex2littleEndianHex <<<"$a" | xxd -p -r ;
   bigEndianHex2littleEndianHex <<<"$b" | xxd -p -r ; }  |
   openssl dgst -sha256 -binary |
   openssl dgst -sha256 -hex |
   sed 's/.* //' |
   bigEndianHex2littleEndianHex

(also, you can use '|' at the end of line without using '\')

Now how to deal with blocks with a number of transactions that are not a power of 2?
hero member
Activity: 566
Merit: 500
Unselfish actions pay back better
Code:
{ bigEndianHex2littleEndianHex <<<"$a" |xxd -p -r ; bigEndianHex2littleEndianHex <<<"$b" |xxd -p -r ; } |openssl dgst -sha256 -hex

How about

Code:
{ bigEndianHex2littleEndianHex <<<"$a" | xxd -p -r ;
   bigEndianHex2littleEndianHex <<<"$b" | xxd -p -r ; } \
   | openssl dgst -sha256 -binary \
   | openssl dgst -sha256 -hex \
   | bigEndianHex2littleEndianHex

That would give the third hash, wouldn't it?

Cheers,
hero member
Activity: 566
Merit: 500
Unselfish actions pay back better

I'm pretty sure it doesn't matter, since xxd does only read hexadecimal characters.

Code:
echo "A 1" |xxd -p -r |xxd -p
a1
echo -n "A 1" |xxd -p -r |xxd -p
a1

Oh, great, I should have checked that, of course…

Cheers,
legendary
Activity: 1288
Merit: 1080
You are aware that the bashism <<< appends a LF (ASCII 10) to its argument, right?

Code:
$ sha256sum e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855  -
$ sha256sum <<< ''
01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b  -
$ printf '\n' | sha256sum
01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b  -
$ hexdump -C <<< a
00000000  61 0a                                             |a.|
00000002
$

In the same vein: perhaps bigEndianHex2littleEndianHex() should use echo -n or printf instead of just echo

I'm pretty sure it doesn't matter, since xxd -p -r does only read hexadecimal characters.


echo "A 1" |xxd -p -r |xxd -p
a1
echo -n "A 1" |xxd -p -r |xxd -p
a1
hero member
Activity: 566
Merit: 500
Unselfish actions pay back better
My first attempt is this code:

Code:
{ bigEndianHex2littleEndianHex <<<"$a" |xxd -p -r ; bigEndianHex2littleEndianHex <<<"$b" |xxd -p -r ; } |openssl dgst -sha256 -hex

Needless to say, the version without bigEndianHex2littleEndianHex didn't work either.

You are aware that the bashism <<< appends a LF (ASCII 10) to its argument, right?

Code:
$ sha256sum e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855  -
$ sha256sum <<< ''
01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b  -
$ printf '\n' | sha256sum
01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b  -
$ hexdump -C <<< a
00000000  61 0a                                             |a.|
00000002
$

In the same vein: perhaps bigEndianHex2littleEndianHex() should use echo -n or printf instead of just echo

Cheers,
legendary
Activity: 1288
Merit: 1080

Ok now, let's try to make the Merkle tree.

The first block with more than one transaction is the block 170.  It has two transactions and its Merkle tree is:

{
"b1fea52486ce0c62bb442b530a3f0132b826c74e473d1f2c220bfa78111c5082",
"f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
"7dac2c5666815c17a3b36427de37bb9d2e2c5ccec3f8633eb91a4205cb4c10ff"
}

The third is the Merkle root.

My first attempt is this code:

Code:
{ bigEndianHex2littleEndianHex <<<"$a" |xxd -p -r ; bigEndianHex2littleEndianHex <<<"$b" |xxd -p -r ; } |openssl dgst -sha256 -hex

Needless to say, the version without bigEndianHex2littleEndianHex didn't work either.
legendary
Activity: 3920
Merit: 2349
Eadem mutata resurgo
grondilu:
Quote
I also wonder if all communications could not be done using HTTP.  Blocks would be published via http GET method (giving the hash of the preceding block), and transactions could be sent via POST method.

One advantage of using http would be that it would be very hard for governments to forbid.

Where did you get to with the network connection side of this, netcat could be an option.

I agree that a Busybox dependency limitation would be a good place to put some boundaries to begin with.
hero member
Activity: 566
Merit: 500
Unselfish actions pay back better
(we actually don't need tr either, by the way)

(You're right, I suppose we can always take for granted that the strings are 64 characters wide…)

Cheers,
legendary
Activity: 1288
Merit: 1080
yep, I've edited (we actually don't need tr either, by the way).

I also tested on the second block.  I worked fine.
hero member
Activity: 566
Merit: 500
Unselfish actions pay back better
Thanks, that helped!

Cool!  Smiley

The following patch might make the script a tad more computationally efficient:

Code:
diff --git a/bashhash.sh b/bashhash.sh
index a99bf9d..1bddd92 100644
--- a/bashhash.sh
+++ b/bashhash.sh
@@ -24,8 +24,8 @@ time=1231006505
 bits=486604799
 nonce=2083236893
 
-printf "%8x%8x%8x%64s%64s%8x" $nonce $bits $time $mrkl_root $prev_block $ver |
-sed 's/ /0/g' |
+printf "%08x%08x%08x%64s%64s%08x" $nonce $bits $time $mrkl_root $prev_block $ver |
+tr ' ' '0' |
 bigEndianHex2littleEndianHex |
 xxd -r -p |
 openssl dgst -sha256 -binary |

If basically uses printf to format the numbers, and uses tr instead of sed.

Cheers,
legendary
Activity: 1288
Merit: 1080
Thanks, that helped!

Code:
#{
#  "hash":"000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f",
#  "ver":1,
#  "prev_block":"0000000000000000000000000000000000000000000000000000000000000000",
#  "mrkl_root":"4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b",
#  "time":1231006505,
#  "bits":486604799,
#  "nonce":2083236893,

bigEndianHex2littleEndianHex() {
    local s=''
    while read -n 2 char
    do s=$char$s
    done
    echo $s
}

ver=1
prev_block=0000000000000000000000000000000000000000000000000000000000000000
mrkl_root=4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b
time=1231006505
bits=486604799
nonce=2083236893

printf "%08x%08x%08x%064s%064s%08x" $nonce $bits $time $mrkl_root $prev_block $ver |
bigEndianHex2littleEndianHex |
xxd -r -p |
openssl dgst -sha256 -binary |
openssl dgst -sha256 -hex |
sed 's/^.* //' |
bigEndianHex2littleEndianHex

I can't really give the bounty since the solution was not complete.  But thanks again.
hero member
Activity: 566
Merit: 500
Unselfish actions pay back better
Code:
  xxd -pr

Am I right when I assume that xxd is supposed to produce a binary block that corresponds to the hex stream?  If so, then ‘xxd -p -r’ might be what you're looking for.  E.g.

Code:
# A=0x41, B=0x42, C=0x43
$ echo 414243 | xxd -r -p && echo
ABC
$

Not that it helps much in the actual situation…

Cheers,
full member
Activity: 144
Merit: 100
Perhaps this will help:

printf "%s%s%s%s%s%s" 01000000 0000000000000000000000000000000000000000000000000000000000000000 3ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a 29ab5f49 ffff001d 1dac2b7c | xxd -r -p | openssl dgst -sha256 -binary | openssl dgst -sha256 -hex

6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000

A key thing you were missing is byte swapping.  I manually byte-swapped all the inputs.  You'll have to figure out how to script that.
legendary
Activity: 1288
Merit: 1080

I know this is a poor programming method, but I've tried a whole bunch of combinations for the size of each value:

Code:
#{
#  "hash":"000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f",
#  "ver":1,
#  "prev_block":"0000000000000000000000000000000000000000000000000000000000000000",
#  "mrkl_root":"4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b",
#  "time":1231006505,
#  "bits":486604799,
#  "nonce":2083236893,

ver=1
prev_block=0000000000000000000000000000000000000000000000000000000000000000
 mrkl_root=4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b
time=1231006505
bits=486604799
nonce=2083236893

for s in - ''
do for a in 2 4
do for b in 64 128
do for c in 16 24 32
do
    printf "%$s${a}x%$s${b}s%$s${b}s%$s${c}x%$s${c}x%$s${c}x" $ver $prev_block $mrkl_root $time $bits $nonce |
    sed 's/ /0/g' |
    xxd -pr |
    openssl dgst -sha256 -binary |
    openssl dgst -sha256 -hex |
    sed 's/^.* //'
done
done
done
done

None of them works.


I pledge 5 BTC to whoever finds the correct way.
legendary
Activity: 3920
Merit: 2349
Eadem mutata resurgo

Would that be a bash hash or a hash bash?

Bang hash bash

Hash bang boom!
legendary
Activity: 1232
Merit: 1076
If you manage to figure out that (recomputing the hashes through shell) then that'd be great for everybody. I'm also curious how to do this.
legendary
Activity: 1288
Merit: 1080
Here is my first attempt to recompute the hash of the Genesis block:

Code:
#{
#  "hash":"000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f",
#  "ver":1,
#  "prev_block":"0000000000000000000000000000000000000000000000000000000000000000",
#  "mrkl_root":"4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b",
#  "time":1231006505,
#  "bits":486604799,
#  "nonce":2083236893,

ver=1
prev_block=0000000000000000000000000000000000000000000000000000000000000000
mrkl_root=4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b
time=1231006505
bits=486604799
nonce=2083236893

printf "%2x%64s%64s%16x%16x%16x" $ver $prev_block $mrkl_root $time $bits $nonce |
sed 's/ /0/g' |
xxd -pr |
openssl dgst -sha256 -binary |
openssl dgst -sha256 -hex |
sed 's/^.* //'

So far it doesn't work.  Any help appreciated.
hero member
Activity: 602
Merit: 513
GLBSE Support [email protected]
What is it with you and bash scripts?  Roll Eyes
Can you do nothing else?


Well actually, no, I can't.  I'm not good at anything else indeed.

I'm not a very good programmer and bash is the only language in which I manage to do usefull stuffs.




Well then I join you, except I use Ruby, and pretty much nothing else, I'm also very slow.
legendary
Activity: 1288
Merit: 1080
What is it with you and bash scripts?  Roll Eyes
Can you do nothing else?


Well actually, no, I can't.  I'm not good at anything else indeed.

I'm not a very good programmer and bash is the only language in which I manage to do usefull stuffs.


hero member
Activity: 602
Merit: 513
GLBSE Support [email protected]
What is it with you and bash scripts?  Roll Eyes
Can you do nothing else?


I think the scripts are rather useful. They are far more portable than having to mess with wxwidgets or whatever the hell else just to get what should be a simple console application to work. They are also easy to understand.

I would love to see many perl, python, and shell implementations of bitcoin.

I'm sure they can be useful, that's not what I'm saying. I'm saying that everything Grondilu does is in bash, or at least everything he has proposed is in bash. I am sure that he's a bash wizard at this point though.
sr. member
Activity: 252
Merit: 250
What is it with you and bash scripts?  Roll Eyes
Can you do nothing else?


I think the scripts are rather useful. They are far more portable than having to mess with wxwidgets or whatever the hell else just to get what should be a simple console application to work. They are also easy to understand.

I would love to see many perl, python, and shell implementations of bitcoin.
hero member
Activity: 602
Merit: 513
GLBSE Support [email protected]
What is it with you and bash scripts?  Roll Eyes
Can you do nothing else?
legendary
Activity: 1288
Merit: 1080

I know a bit about this software and I think it's pretty cool.  I really would like to see an implementation of bitcoin using this as a database handler.


One of the reason why I think it would fit bitcoin nicely is the fact that mongodb uses JSON directly to represent data.   An other reason is that it is very easy to connect to an other mongodb on the net.  Thus, the network handling would be easy.

Also, it's very easy to handle from a bash script.


www.mongodb.org
legendary
Activity: 1288
Merit: 1080
I have modified dirtyfilthy's program so that it can export the whole wallet in an ascii format.

http://github.com/grondilu/bc_key


Just use "ALL" instead of a particular bitcoin address.

Be careful with this command, for it shows all your private keys in clear !  In particular, you should never redirect the output of this program to a file.  Unless you use an encrypted file system.

Anyway, I'll add a few bash functions that can be used to create a new address, sign a transaction, and so on...

Here is a function to create a new address already :

Code:
#!/bin/bash

. base58.sh

wallet="$HOME/.bitcoin-bash/wallet.dat"

generateNewAddress() {

    privkey="$(openssl ecparam -name secp256k1 -genkey)"

    openssl ec -pubout <<<"$privkey" 2>&- |
    publicKeyToAddress 2>&- |
    if [[ -f "$wallet" ]]
    then
        tee -a "$wallet"  # storing and showing the address
        printf "%s" "$privkey" >> "$wallet"  # storing the private key
    else
        # showing address and private key
        cat
        printf "%s" "$privkey"
    fi

}
legendary
Activity: 1288
Merit: 1080
I've added two functions : decodeBase68 and checkBitcoinAddress.

I think it might be usefull to check the validity of a bitcoin address in pure bash.

Requires "dc", the unix desk calculator.  Few people use this reverse polish notation calcultor but it's much easier to handle in scripts.


Code:
#!/bin/bash
#
# Requires bc, dc, openssl, xxd
#

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

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

encodeBase58() {
    # 58 =0x3A
    bc <<<"ibase=16; n=${1^^}; while(n>0) { n%3A ; n/=3A }" |
    tac |
    while read n
    do echo -n ${base58[n]}
    done
}

checksum() {
    xxd -p -r <<<"$1" |
    openssl dgst -sha256 -binary |
    openssl dgst -sha256 -hex |
    sed 's/^.* //' |
    head -c 8
}

checkBitcoinAddress() {
    if [[ "$1" =~ $bitcoinregex ]]
    then
        h=$(decodeBase58 "$1")
        checksum "00${h::${#h}-8}" |
        grep -qi "^${h: -8}$"
    else return 2
    fi
}

hash160() {
    openssl dgst -sha256 -binary |
    openssl dgst -rmd160 -hex |
    sed 's/^.* //'
}

hash160ToAddress() {
    printf %34s "$(encodeBase58 "00$1$(checksum "00$1")")" |
    sed "y/ /1/"
}

publicKeyToAddress() {
    hash160ToAddress $(
    openssl ec -pubin -pubout -outform DER 2>/dev/null |
    tail -c 65 |
    hash160
    )
}
sr. member
Activity: 360
Merit: 250
I'd start off with strict sh compatibility, though, not bash, unless there's really a big advantage of requiring bash over lighter posix-compliant sh implementations (e.g. dash).

Not that I've got any skin in this game, but it would be worth considering targeting the more limited toolset offered by Busybox:

http://busybox.net/

The profusion of embedded linux devices these days means Busybox is everywhere.
legendary
Activity: 1288
Merit: 1080
I'd start off with strict sh compatibility, though, not bash, unless there's really a big advantage of requiring bash over lighter posix-compliant sh implementations (e.g. dash).

Writing in POSIX is much less fun.  To me GNU is a better standard de facto.

Also, what's the point of those excellent GNU tools if we can never use them ?
sr. member
Activity: 288
Merit: 263
Firstbits.com/1davux
I like the idea: having a series of small tools that do one task, do it well, and can work together through stdin/stdout, the filesystem, sockets, etc.

I'd start off with strict sh compatibility, though, not bash, unless there's really a big advantage of requiring bash over lighter posix-compliant sh implementations (e.g. dash).
legendary
Activity: 1288
Merit: 1080
Yes !  It works  Cheesy

Code:
#!/bin/bash
#
# Requires bc, openssl, xxd
#

base58=({1..9} {A..H} {J..N} {P..Z} {a..k} {m..z})

EncodeBase58() {
    # 58 =0x3A
    bc <<<"ibase=16; n=${1^^}; while(n>0) { n%3A ; n/=3A }" |
    tac |
    while read n
    do echo -n ${base58[n]}
    done
}

Hash160ToAddress() {
    printf %34s $(EncodeBase58 "00$1$(checksum "00$1")")|
    sed "s/ /1/g"
}

checksum() {
    xxd -p -r <<<"$1" |
    openssl dgst -sha256 -binary |
    openssl dgst -sha256 -hex |
    cut -d\  -f2 |
    sed -r "s/^((..){4}).*/\1/"
}

Hash160() {
    openssl dgst -sha256 -binary |
    openssl dgst -rmd160 -hex |
    cut -d\  -f2
}

PubKeyToAdress() { Hash160ToAddress $(tail -c 65 |Hash160) ; }
legendary
Activity: 1288
Merit: 1080

I'm trying to implement the base58 functions.  I'm almost there but I have difficulties with the checksum.


Code:
#!/bin/bash

base58=({1..9} {A..H} {J..N} {P..Z} {a..k} {m..z})

EncodeBase58() {
    # 58 =0x3A
    bc <<<"ibase=16; n=${1^^}; while(n>0) { n%3A ; n/=3A }" |
    tac |
    while read n
    do echo -n ${base58[n]}
    done
}

Hash160ToAddress() {
    ADDRESSVERSION=00
    EncodeBase58 "${ADDRESSVERSION}$1$(Checksum "$1")"
}

Checksum() {
    xxd -p -r <<<"$1" |
    openssl dgst -sha256 -binary |
    openssl dgst -sha256 -hex |
    cut -d\  -f2 |
    sed -r "s/^.*((..){4})/\1/"
}

Hash160() {
    echo -n "$1" |
    openssl dgst -sha256 -binary |
    openssl dgst -rmd160 -hex |
    cut -d\  -f2
}

H=0057b0dc5aac7c215a9a458d6c3c85cd21089af8
Hash160ToAddress $H
# I should get     112p3sLidyEptFEfx3C2RCvFoRPK89HyBT
# I actually get     2p3sLidyEptFEfx3C2RCvFoRPK7JQWdq
pj
newbie
Activity: 24
Merit: 0
Could anyone educate me about the interest of coding a bitcoin client in shell script ? (protip : "just for fun" is a valid answer:) )

Someone else asked the question, so I can just guess from what they said.

My guess is that the interest is not so much in coding the guts of the client in shell script (not exactly a high performance engine for computationally intensive tasks), but rather in exposing the data flows and stores to shell script manipulation.

In other words, as I have often done myself in other tasks, write several tools that each have specific capabilities, and which have interfaces that work well when combined in shell scripts with each other and other *nix utilities.  One shot commands are handled in that environment by forking/execing a command that is passed command line arguments, environment variables and files or file descriptors to read or write.  Higher performance for repetitive tasks is obtained by using commands in a series of filters, operating on a stream of line oriented text.  The new, individual tools would each be written in C or Python or some other such language that provided adequate performance and library support for their particular purpose.
legendary
Activity: 1372
Merit: 1008
1davout
Could anyone educate me about the interest of coding a bitcoin client in shell script ? (protip : "just for fun" is a valid answer:) )
pj
newbie
Activity: 24
Merit: 0
Shell script would be fine for a connect-work-disconnect method of working.

But it is grossly ineffective for maintaining a long-running P2P network node, where long-lasting TCP connections are preferred.
One could work around that inefficiency in at least a couple of ways:
 1) Background a task that has a file descriptor open back to the active shell, that can manipulate and communicate with sockets, or
 2) Use a shell that provides this builtin, such as the net/socket module in zsh as described at  http://www.cims.nyu.edu/cgi-systems/info2html?%28zsh%29The%2520zsh%2Fnet%2Fsocket%2520Module
legendary
Activity: 1708
Merit: 1011
Shell script would be fine for a connect-work-disconnect method of working.


There is a growing demand for a client that can function disconnected from the Internet.  This might be a step in this direction.
legendary
Activity: 1596
Merit: 1100
also, Kademlia network works fine without kickstarters and other things like this

Do you mean bootstrapping?  Kademlia network needs bootstrapping, just like other P2P networks.
sr. member
Activity: 350
Merit: 252
probiwon.com
also, Kademlia network works fine without kickstarters and other things like this
legendary
Activity: 1596
Merit: 1100
Shell script would be fine for a connect-work-disconnect method of working.

But it is grossly ineffective for maintaining a long-running P2P network node, where long-lasting TCP connections are preferred.
legendary
Activity: 1288
Merit: 1080
At least it would be trivial to have small CL tools to perform bitcoin operations in this system, such as tools to import and export transactions, blocks and keypairs to/from normal files.  *nix CL shells, such as Bash, are centered around the manipulation of data streams as files, and it's an incredibly powerful model.

Exactly.

I also wonder if all communications could not be done using HTTP.  Blocks would be published via http GET method (giving the hash of the preceding block), and transactions could be sent via POST method.

One advantage of using  http would be that it would be very hard for governments to forbid.
legendary
Activity: 1708
Merit: 1011
At least it would be trivial to have small CL tools to perform bitcoin operations in this system, such as tools to import and export transactions, blocks and keypairs to/from normal files.  *nix CL shells, such as Bash, are centered around the manipulation of data streams as files, and it's an incredibly powerful model.
legendary
Activity: 1658
Merit: 1001
That would be one big dependency hell...
legendary
Activity: 1288
Merit: 1080
The thread
https://bitcointalksearch.org/topic/http-bootstrapping-2459

make me feel like suggesting a full shell implementation of bitcoin.  I've actually been thinking about this for some time but I'd like to see if other people would be interested in such a crazy project.

Here is the kind of architecture I'd like to see :

- nodes communicate transactions via IRC, XMPP or similar (a shell script communicating with such a protocol should be easy to implement) ;
- each node publishes its blocks via its own http server (possibly via a TOR hidden service to avoid NAT traversal problems) ;
- each node also publishes the list of nodes it is currently connected to ;
- nodes store their blocks using GnuNet or maybe a NoSQL database such as MongoDB  (easily scripted) ;
- cryptographic functions are performed via the openssl command line ;
- blocks and wallets are stored in an human readable ASCII format ;
Jump to: