├── bc ├── config.bc ├── bc.sh ├── activate.bc ├── hash │ ├── hmac.bc │ ├── hmac_conf.bc │ ├── sha256.bc │ └── .tests │ │ └── test_hmac.bc ├── math │ ├── math_mod.bc │ ├── root_mod.bc │ ├── extended_euclidean.bc │ └── tonelli_shanks.bc ├── schnorr │ └── ec_schnorr.bc ├── logic │ ├── shift_rot.bc │ ├── .tests │ │ └── test_bitwise_logic.bc │ └── bitwise_logic.bc ├── base │ ├── conversion.bc │ ├── helpers.bc │ └── .tests │ │ └── test_conversion.bc ├── ecdsa │ ├── contract_hash.bc │ └── ecdsa.bc ├── bitcoin │ └── bitcoin_funcs.bc ├── ec_math │ ├── curves │ │ └── koblitz.bc │ ├── endomorphism.bc │ ├── jacobian.bc │ ├── ec_math.bc │ └── ec_point.bc └── bc_env.sh ├── config ├── bc-1.07.1.tar.gz.sha256 ├── bc-1.07.1.tar.gz.sig.sha256 ├── bin │ ├── regtest-cli.example │ ├── regtest-tx.example │ └── regtestd.example ├── paths.sh.example ├── regtest.conf ├── bc_build.patch ├── build_bc.sh └── bc_baseconvert.patch ├── .gitignore ├── base ├── number.sh ├── pattern.sh ├── .tests │ ├── test_number.sh │ ├── test_binary.sh │ ├── test_string.sh │ └── test_int_convert.sh ├── binary.sh ├── int_convert.sh └── string.sh ├── .travis.yml ├── test.sh ├── hash ├── merkle_tree.sh ├── hmac.sh ├── logic.sh ├── hexhash.sh └── .tests │ ├── test_hexhash.sh │ └── test_hmac.sh ├── activate.sh ├── bitcoin ├── script │ ├── globals │ │ ├── scripts.sh │ │ └── opcodes.sh │ ├── keys.sh │ ├── script_num.sh │ ├── core_ifc.sh │ └── scriptpubkey.sh ├── jsonrpc │ ├── json.sh │ └── sign_message.sh ├── activate_bitcoin.sh ├── bips │ ├── .tests │ │ ├── test_bip173.sh │ │ └── test_bip32.sh │ ├── bip173.sh │ └── bip32.sh ├── parse.sh └── transaction.sh ├── encode ├── bech32_segwit.sh └── base58check.sh ├── License.txt ├── ecdsa ├── rfc6979.sh ├── contract_hash.sh ├── .tests │ ├── test_rfc6979.sh │ └── test_ecdsa.sh ├── curves │ └── koblitz.sh └── ecdsa_ifc.sh ├── schnorr └── schnorr_ifc.sh └── README.md /bc/config.bc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bc 2 | 3 | scale=0; 4 | obase=16; 5 | ibase=16; 6 | -------------------------------------------------------------------------------- /config/bc-1.07.1.tar.gz.sha256: -------------------------------------------------------------------------------- 1 | 62adfca89b0a1c0164c2cdca59ca210c1d44c3ffc46daf9931cf4942664cb02a bc-1.07.1.tar.gz 2 | -------------------------------------------------------------------------------- /config/bc-1.07.1.tar.gz.sig.sha256: -------------------------------------------------------------------------------- 1 | 1746ec25209f1b3f6b680390c6f563002f1d4eb1435f93d2206eaaffaa8e6c02 bc-1.07.1.tar.gz.sig 2 | -------------------------------------------------------------------------------- /config/bin/regtest-cli.example: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | bindir="$HOME/software/install/bitcoin/bin" 3 | set -f 4 | ${bindir}/bitcoin-cli $@ 5 | set +f 6 | -------------------------------------------------------------------------------- /config/bin/regtest-tx.example: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | bindir="$HOME/software/install/bitcoin/bin" 3 | set -f 4 | ${bindir}/bitcoin-tx -regtest "$@" 5 | set +f 6 | -------------------------------------------------------------------------------- /config/bin/regtestd.example: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | mkdir -p /dev/shm/regchain 4 | if [[ ! -d /dev/shm/regchain ]]; then 5 | echo "directory /dev/shm/regchain does not exist" 1>&2 6 | exit 7 | fi 8 | bindir="$HOME/software/install/bitcoin/bin" 9 | set -f 10 | ${bindir}/bitcoind $@ 11 | set +f 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # swap 2 | [._]*.s[a-v][a-z] 3 | [._]*.sw[a-p] 4 | [._]s[a-v][a-z] 5 | [._]sw[a-p] 6 | # session 7 | Session.vim 8 | # temporary 9 | .netrwhist 10 | *~ 11 | # auto-generated tag files 12 | tags 13 | # paths.sh file 14 | config/paths.sh 15 | # bc install 16 | config/deps 17 | config/bin/bc 18 | # regtest .sh 19 | config/bin/regtest-cli 20 | config/bin/regtest-tx 21 | config/bin/regtestd 22 | # test logs 23 | tests.log 24 | -------------------------------------------------------------------------------- /base/number.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # [x] = x - {x} , 4 | # r < 0 ? : --[x] 5 | int_floor() 6 | { 7 | local int 8 | read int < <( bc_clean <<<"x=$1; scale=0; r=(x-(x/1)); x-r-(r < 0);" ) 9 | 10 | printf '%s\n' "${int%\.*}" 11 | } 12 | 13 | # [x] = x + (1 -{x}) , 14 | # r <= 0 ? : --[x] 15 | int_ceil() 16 | { 17 | local int 18 | read int < <( bc_clean <<<"x=$1; scale=0; r=(x-(x/1)); x+(1-r)-(r <= 0);" ) 19 | 20 | printf '%s\n' "${int%\.*}" 21 | } 22 | -------------------------------------------------------------------------------- /bc/bc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | alias bc="${BC_PROG}" 4 | export BC_LINE_LENGTH=0 5 | 6 | export BC_ENV_ARGS=( \ 7 | -q -l \ 8 | ./config.bc \ 9 | ./base/conversion.bc ./base/helpers.bc \ 10 | ./logic/bitwise_logic.bc ./logic/shift_rot.bc \ 11 | ./hash/hmac_conf.bc ./hash/hmac.bc ./hash/.tests/test_hmac.bc \ 12 | ./math/math_mod.bc ./math/extended_euclidean.bc ./math/tonelli_shanks.bc ./math/root_mod.bc \ 13 | ./ec_math/endomorphism.bc ./ec_math/ec_point.bc ./ec_math/ec_math.bc ./ec_math/jacobian.bc \ 14 | ./ecdsa/ecdsa.bc \ 15 | ./ec_math/curves/koblitz.bc ./activate.bc) 16 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: required 2 | dist: stretch 3 | language: bash 4 | cache: 5 | directories: 6 | - $HOME/cache/bc 7 | addons: 8 | apt: 9 | packages: 10 | - libreadline-dev 11 | notifications: 12 | irc: "ircs://chat.freenode.net:7070/#p534" 13 | before_script: 14 | - mkdir -pv $HOME/cache/bc 15 | - mkdir -pv ./config/deps 16 | - if [[ -r $HOME/cache/bc/bc-1.07.1.tar.gz ]]; then cp -v $HOME/cache/bc/bc-1.07.1.tar.gz{,.sig} ./config/deps; fi; 17 | - pushd ./config 18 | - ./build_bc.sh --no-check-signature 19 | - cp -v ./deps/bc-1.07.1.tar.gz* $HOME/cache/bc/ 20 | - popd 21 | script: 22 | - time source ./test.sh 23 | -------------------------------------------------------------------------------- /bc/activate.bc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bc 2 | 3 | secp256k1(); 4 | define void set_curve_params(*curve[]){ 5 | 6 | curve_p = curve[0]; 7 | curve_a = curve[1]; 8 | curve_b = curve[2]; 9 | curve_g = curve[3]; 10 | curve_gx = curve[4]; 11 | curve_gy = curve[5]; 12 | curve_n = curve[6]; 13 | curve_h = curve[7]; 14 | curve_words = curve[8]; 15 | } 16 | 17 | set_curve_params(secp256k1[]); 18 | set_endomorphism_vals(); 19 | # rootmod(11,3,curve_p); 20 | # balanced_length_mod((curve_n/2) + (curve_n/4), curve_p); 21 | # balanced_length_mod(curve_p-((curve_n/2) + (curve_n/4)), curve_p); 22 | # ecmul(curve_n/2); 23 | # ecadd(curve_g, curve_g); 24 | -------------------------------------------------------------------------------- /config/paths.sh.example: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | conf_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && echo $PWD )" 3 | 4 | # path to the patched bc binary 5 | # see https://github.com/fivepiece/bc_segfault 6 | # and 'patch.bc' in this directory. 7 | # run `./build_bc.sh` to install locally 8 | 9 | bc_prog="${conf_dir}/bin/bc" 10 | 11 | # path to bitcoin core \ knots executables 12 | # examples in the './config/bin' directory 13 | # remember to place 'regtest.conf' in the proper directory 14 | # for regtestd to find 15 | 16 | export PATH="${PATH//:${conf_dir}\/bin/}:${conf_dir}/bin" 17 | # alias regtestd="regtestd -conf=${btcb_home}/config/regtest.conf" 18 | # alias regtest-cli="regtest-cli -conf=${btcb_home}/config/regtest.conf" 19 | -------------------------------------------------------------------------------- /test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -x 2 | 3 | echo "" > tests.log 4 | set -x 5 | shopt -s expand_aliases 6 | source ./activate.sh 7 | set_network_versions bitcoin 8 | set +x 9 | b=0 10 | readarray tests < <(find . -type f -name test_*.sh -printf "${btcb_home}/%P\n") 11 | for testsh in ${tests[@]}; do 12 | set -x 13 | source ${testsh} 2>&1 | grep -v "read -N2 byte\|printf %b '\\\x[0-F][0-F]\|read -N2 hexchunk" >> tests.log 14 | # this used to check "$?". the best solution for this uglyness is something like a 100mb output limit on travis-ci :) 15 | if (( ${PIPESTATUS[0]} != 0 )); then 16 | set +x 17 | echo "${testsh} failed" 1>&2 18 | tail -1000 tests.log 19 | return 1 20 | fi 21 | set +x 22 | done 23 | 24 | set +x 25 | b="$?" 26 | return "$b" 27 | -------------------------------------------------------------------------------- /hash/merkle_tree.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | revbytes_list () 4 | { 5 | local -a listrev=( $@ ) 6 | for (( i=0; i<${#listrev[@]}; i++ )); do 7 | revchunks "${listrev[$i]}" 8 | done 9 | } 10 | 11 | merkle_root () 12 | { 13 | local -au list=( $@ ) 14 | local tlist=( ${list[@]} ) nlist=() 15 | 16 | while (( ${#tlist[@]} != 1 )); do 17 | if (( ${#tlist[@]} % 2 == 1 )); then 18 | tlist+=( ${tlist[-1]} ) 19 | fi 20 | nlist=() 21 | for (( i=0, j=0; i<${#tlist[@]}; i+=2, j++ )); do 22 | read nlist[$j] < <( hash256 "${tlist[$i]}${tlist[$((i+1))]}" ) 23 | done 24 | tlist=( ${nlist[@]} ) 25 | done 26 | echo ${tlist[@]} 27 | } 28 | 29 | core_merkle_root () 30 | { 31 | local -au revlist 32 | readarray -t revlist < <( revbytes_list $@ ) 33 | merkle_root ${revlist[@]} | revchunks 34 | } 35 | -------------------------------------------------------------------------------- /bc/hash/hmac.bc: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # knw : number of 0x0 words before the key 4 | # hash_size : key size in words 5 | 6 | define void hmac_api(knw, key, hash_size, *pads[], *hret[]){ 7 | 8 | auto keylen; 9 | 10 | keylen = (knw + wordlen(key)); 11 | 12 | if ( keylen > hash_size ){ 13 | 14 | key = hash(knw, key); # hash() does not exist yet. done in advance. 15 | } 16 | if ( keylen < hash_size ){ 17 | 18 | key = right_pad(key, hash_size - knw); 19 | } 20 | 21 | hret[0] = bwxor(key, pads[0]); 22 | hret[1] = bwxor(key, pads[1]); 23 | 24 | # pad(key,hash_size); 25 | # pad(o_key_pad,hash_size); 26 | # pad(i_key_pad,hash_size); 27 | } 28 | 29 | define void hmac(knw, key, hash_size){ 30 | 31 | auto hkey[]; 32 | 33 | hmac_api(knw, key, hash_size, hmac_pads[], hkey[]); 34 | left_pad(hkey[0], hash_size); 35 | left_pad(hkey[1], hash_size); 36 | } 37 | -------------------------------------------------------------------------------- /config/regtest.conf: -------------------------------------------------------------------------------- 1 | ## Common 2 | 3 | server=1 4 | daemon=1 5 | txindex=1 6 | dbcache=1000 7 | # maxsigcachesize=400 8 | mempoolexpiry=1 9 | # minimizetotray=1 10 | # sendfreetransactions=1 11 | 12 | ## Network 13 | 14 | regtest=1 15 | # onlynet=ipv4 16 | 17 | ## Auth 18 | 19 | rpcauth=btc_regtest:17492752ec78fa837dde48ac26f191$3e197a5fdeba653483313b8c93c55a86110fb3845b6019c44b26186b68652c07 20 | # 4RVTkCJGnxDErjXC8nYRm38OsjTopWSOXIlS_6l60uI= 21 | 22 | ## Policy 23 | 24 | paytxfee=0.0001 25 | # bytespersigop=1 26 | spendzeroconfchange=0 27 | blockmaxweight=4000000 28 | 29 | ## API 30 | 31 | # walletnotify="curl -sI --connect-timeout 1 http://localhost:62602/walletnotify?%s" 32 | # alertnotify="curl -sI --connect-timeout 1 http://localhost:62602/alertnotify?%s" 33 | 34 | ## Config 35 | 36 | uacomment=Reg0 37 | datadir=/dev/shm/regchain 38 | rpcallowip=127.3.0.0/16 39 | rpcbind=127.3.0.1 40 | rpcconnect=127.3.0.1 41 | whitelistrelay=1 42 | -------------------------------------------------------------------------------- /activate.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | decho () 4 | { 5 | if [[ ${__debug_btcbash} == 1 ]]; then 6 | echo -e "$@" 1>&2; 7 | fi 8 | } 9 | 10 | btcb_home="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && echo $PWD )" 11 | 12 | if [[ -r "${btcb_home}/config/paths.sh" ]]; then 13 | source "${btcb_home}/config/paths.sh" 14 | else 15 | source "${btcb_home}/config/paths.sh.example" 16 | fi 17 | 18 | source "${btcb_home}/bc/bc_env.sh" 19 | 20 | btcb_env=( \ 21 | base/binary.sh base/string.sh base/number.sh base/int_convert.sh base/pattern.sh \ 22 | ecdsa/curves/koblitz.sh \ 23 | hash/logic.sh hash/hexhash.sh hash/hmac.sh hash/merkle_tree.sh \ 24 | encode/base58check.sh encode/bech32_segwit.sh \ 25 | ecdsa/rfc6979.sh ecdsa/ecdsa_ifc.sh ecdsa/contract_hash.sh \ 26 | schnorr/schnorr_ifc.sh ) 27 | 28 | for shenv in ${btcb_env[@]}; do 29 | source "${btcb_home}/${shenv}" 30 | done 31 | 32 | source "${btcb_home}/bitcoin/activate_bitcoin.sh" 33 | secp256k1 34 | -------------------------------------------------------------------------------- /bitcoin/script/globals/scripts.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # abstract scripts and opcodes 4 | 5 | # normal scripts 6 | 7 | script_p2pkey=( "push_pubkey" "CHECKSIG" ) 8 | script_p2pkh=( "DUP" "HASH160" "0x14" "pubkeyhash" "EQUALVERIFY" "CHECKSIG" ) 9 | script_mofn=( "m" "push_pubkeys" "n" "CHECKMULTISIG" ) 10 | script_p2sh=( "HASH160" "0x14" "scripthash" "EQUAL" ) 11 | 12 | # segwit scripts 13 | 14 | script_p2wpkh=( "0x00" "0x14" "pubkeyhash" ) 15 | script_p2wsh=( "0x00" "0x20" "scripthash" ) 16 | script_p2wv1=( "0x51" "0x20" "witv1" ) # TODO port MAST 17 | 18 | # bip112 scripts 19 | 20 | script_ced=( "IF" "escrow_script" "ELSE" "countdown" "CHECKSEQUENCEVERIFY" "DROP" "timeout_script" "ENDIF" ) 21 | script_revc=( "HASH160" "revokehash" "EQUAL" "IF" "pubkey" "ELSE" "countdown" "CHECKSEQUENCEVERIFY" "DROP" "pubkey" "ENDIF" "CHECKSIG" ) 22 | script_htlc=( "HASH160" "DUP" "rhash" "EQUAL" "IF" "countdown" "CHECKSEQUENCEVERIFY" "2DROP" "pubkey" "ELSE" "crhash" "EQUAL" "NOTIF" "deadline" "CHECKLOCKTIMEVERIFY" "DROP" "ENDIF" "pubkey" "ENDIF" "CHECKSIG" ) 23 | -------------------------------------------------------------------------------- /bitcoin/jsonrpc/json.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | mkjson_credit() 4 | { 5 | local txid="$1" vout="$2" spk=( $3 ) amount="$4" rdm=( $5 ) nestrdm=( $6 ) 6 | 7 | printf '{"txid":"%s",\n"vout":%d,\n"scriptPubKey":"%s",\n' \ 8 | "${txid}" \ 9 | "${vout}" \ 10 | "$( script_serialize "${spk[*]}" )" 11 | 12 | if [[ ! -z ${rdm} ]]; then 13 | printf '"redeemScript":"%s",\n"amount":%s}\n' \ 14 | "$( script_serialize "${rdm[*]}" )" \ 15 | "${amount}" 16 | else 17 | printf '"amount":%s}\n' "${amount}" 18 | fi 19 | } 20 | 21 | core_listunspent () 22 | { 23 | local count="${1:-1}" min_sum="${2:-0.01}" minconf=1 24 | local -a in_addr=( ${3} ) 25 | if [[ -n ${in_addr} ]]; then 26 | printf -v in_addr '"%s",' ${in_addr[@]} 27 | in_addr="${in_addr%,}" 28 | fi 29 | 30 | ${4:-${clientname}}-cli -named listunspent \ 31 | minconf=${minconf} \ 32 | ${in_addr+addresses="[${in_addr}]"} \ 33 | query_options="{\"maximumCount\":${count},\"minimumSumAmount\":${min_sum}}" 34 | } 35 | -------------------------------------------------------------------------------- /encode/bech32_segwit.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | segwit_encode () 3 | { 4 | local spk="$1" ver push prog swhrp="${2:-${swHrp}}" 5 | local -a progarr 6 | ver="${spk:0:2}" 7 | push="${spk:2:2}" 8 | prog="${spk:4}" 9 | if (( ( $((16#${push} * 2)) ) != ${#prog} )); then 10 | echo "bad segwit program push" 1>&2 11 | return 1 12 | fi 13 | for ((i=0; i<${#prog}; i+=2)); do 14 | progarr+=( $((16#${prog:${i}:2})) ) 15 | done 16 | bech32_swprog_encode "${swhrp}" "$((16#${ver}))" "${progarr[@]}" 17 | } 18 | 19 | segwit_decode () 20 | { 21 | local -l ver prog hrp="${1%1*}" 22 | local -a decarr 23 | if [[ "${hrp}" != bc ]] && [[ "${hrp}" != tb ]] && [[ "${hrp}" != bcrt ]]; then 24 | echo "invalid hrp" 1>&2 25 | return 1 26 | fi 27 | readarray -t decarr < <( bech32_swprog_decode "${hrp}" "${1}" ) 28 | ver="${decarr[0]}" 29 | printf -v prog '%02X' ${decarr[1]} 30 | if [[ ! "${ver} ${prog}" =~ _ ]]; then 31 | script_serialize "${ver} @${prog}" 32 | else 33 | return 1 34 | fi 35 | } 36 | -------------------------------------------------------------------------------- /base/pattern.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # prints "SAMPLESAMPLESAM..." of specified length 4 | # $1 : sample to output, will become uppercase (for use with hex) 5 | # $2 : length 6 | input_mkbitmap() 7 | { 8 | local -u sample="$1" smp bmp 9 | local -i len="$2" 10 | 11 | printf -v bmp "%0${len}d" '0' 12 | printf -v smp "%0${#sample}d" '0' 13 | 14 | bmp="${bmp//${smp}/${sample}}" 15 | 16 | local -i rem="$((len % ${#sample}))" 17 | if (( rem != 0 )); then 18 | local -u brem srem 19 | printf -v brem "%0${rem}d" '0' 20 | srem="${sample:0:${#brem}}" 21 | bmp="${bmp:0:$((len-rem))}${srem}" 22 | fi 23 | 24 | printf '%s\n' "${bmp}" 25 | } 26 | 27 | # "walks" a pattern across a range 28 | # $1 : pattern 29 | # $2 : range, will become bitmap of specified length 30 | # $3 : length 31 | input_walk_pattern() 32 | { 33 | local -u patt="$1" range 34 | read range < <( input_mkbitmap "$2" "$3" ) 35 | 36 | for ((i=0; i<=$((${#range}-${#patt})); i++)); do 37 | 38 | printf "${range:0:$i}${patt}${range:$((${#patt}+i))}\n" 39 | done 40 | } 41 | -------------------------------------------------------------------------------- /License.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright © 2018 arubi 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the “Software”), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /bc/math/math_mod.bc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bc 2 | 3 | # functions for simple modular arithmetic 4 | 5 | # simple mod 6 | define mod(a, n){ 7 | 8 | if (a < 0){ 9 | 10 | return ((a % n) + n); 11 | } 12 | return (a % n); 13 | } 14 | 15 | # returns the inverse of a in n 16 | # (stripped down egcd) 17 | # https://en.wikipedia.org/wiki/Modular_multiplicative_inverse#Extended_Euclidean_algorithm 18 | # Guide to ECC Algorithm 2.20 19 | define invmod(a, p){ 20 | 21 | auto u, v, x, x1, x2, q, r; 22 | 23 | u = mod(a, p); 24 | v = p; 25 | x1 = 1; 26 | x2 = 0; 27 | while (u != 1){ 28 | 29 | q = v / u; 30 | r = v - q*u; 31 | x = x2 - q*x1; 32 | v = u; 33 | u = r; 34 | x2 = x1; 35 | x1 = x; 36 | } 37 | return mod(x1, p); 38 | } 39 | 40 | # returns base to the power exp mod n 41 | define powmod(base, exp, n){ 42 | 43 | auto res, b, e; 44 | 45 | b = mod(base, n); 46 | e = mod(exp, n); 47 | res = 1; 48 | 49 | while (e > 0){ 50 | 51 | if (e % 2){ 52 | res = mod((res * b), n); 53 | } 54 | b = mod((b * b), n); 55 | e = (e / 2); 56 | } 57 | return res; 58 | } 59 | -------------------------------------------------------------------------------- /bc/schnorr/ec_schnorr.bc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bc 2 | 3 | define ec_schnorr_sign_api(h, d, k, n){ 4 | 5 | return mod(k - (h * d), n); 6 | } 7 | 8 | define ec_schnorr_sign(h, d, k){ 9 | 10 | return ec_schnorr_sign_api(h, d, k, curve_n); 11 | } 12 | 13 | define ec_schnorr_verify_api(x, y, gx, gy, h, s, n, p, *r[]){ #TODO less input 14 | 15 | auto sg[], hp[], rk[]; 16 | 17 | if ( !( (0 <= h) && (h < 2^(curve_words*4)) ) && ( (1 <= s) && (s < n) )){ 18 | return 0; 19 | } 20 | ecmul_api(s, gx, gy, n, p, sg[]); 21 | ecmul_api(h, x, y, n, p, hp[]); 22 | ecadd_api(sg[0], sg[1], hp[0], hp[1], p, rk[]); 23 | 24 | if ( ispoint_api(rk[0], rk[1], curve_a, curve_b, p) ){ 25 | r[0] = rk[0]; 26 | r[1] = rk[1]; 27 | return 1; 28 | } else { 29 | r[0] = 0; 30 | r[1] = 0; 31 | return 0; 32 | } 33 | } 34 | 35 | define void ec_schnorr_verify(p, h, s){ 36 | 37 | auto p1[], valid, rk[]; 38 | 39 | uncompresspoint_api(p, p1[]); 40 | valid = ec_schnorr_verify_api(p1[0], p1[1], curve_gx, curve_gy, h, s, curve_n, curve_p, rk[]); 41 | if (valid){ 42 | left_pad(rk[0], curve_words); 43 | } else { 44 | 0; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /base/.tests/test_number.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | test_int_floor() 4 | { 5 | local -A vectors=( [2]=2 [2.4]=2 [2.9]=2 [-2.7]=-3 [-2]=-2 ) 6 | 7 | for int in ${!vectors[@]}; do 8 | if [[ "$(int_floor ${int})" != "${vectors[${int}]}" ]]; then 9 | printf '%s != %s\n%s != %s\n' "\$(int_floor ${int})" "\${vectors[${int}]}" \ 10 | "$(int_floor ${int})" "${vectors[${int}]}" 11 | return 1 12 | fi 13 | done 14 | } 15 | 16 | test_int_ceil() 17 | { 18 | local -A vectors=( [2]=2 [2.4]=3 [2.9]=3 [-2.7]=-2 [-2]=-2 ) 19 | 20 | for int in ${!vectors[@]}; do 21 | if [[ "$(int_ceil ${int})" != "${vectors[${int}]}" ]]; then 22 | printf '%s != %s\n%s != %s\n' "\$(int_ceil ${int})" "\${vectors[${int}]}" \ 23 | "$(int_ceil ${int})" "${vectors[${int}]}" 24 | return 1 25 | fi 26 | done 27 | } 28 | 29 | test_number() 30 | { 31 | local -a tests=( "test_int_floor" "test_int_ceil" ) 32 | for testi in ${tests[@]}; do 33 | if ! ${testi}; then 34 | printf '%s\n' "error: ${testi//test_/}" 35 | return 1 36 | fi 37 | done 38 | } 39 | test_number || return 1 40 | -------------------------------------------------------------------------------- /config/bc_build.patch: -------------------------------------------------------------------------------- 1 | diff -cr bc-1.07.1/bc/fix-libmath_h bc-1.07.1-build.patch/bc/fix-libmath_h 2 | *** bc-1.07.1/bc/fix-libmath_h 2017-04-08 01:20:02.000000000 +0300 3 | --- bc-1.07.1-build.patch/bc/fix-libmath_h 2018-02-23 22:32:35.570536958 +0200 4 | *************** 5 | *** 1,9 **** 6 | ! ed libmath.h < ${blocklen} )) 29 | then 30 | read key < <( "${hashfunc}" "${key}" ) 31 | fi 32 | 33 | # (1) 34 | key="$( right_pad "${key}" "${blocklen}" )" 35 | # (2) 36 | ipad="$( bwxor "${key}" "${ipad}" )" 37 | # steps (3) (4) 38 | read text < <( "${hashfunc}" "${ipad}${text}" ) 39 | # (5) 40 | opad="$( bwxor "${key}" "${opad}" )" 41 | # steps (6) (7) 42 | ${hashfunc} "${opad}${text}" 43 | } 44 | 45 | hmac_sha256() 46 | { 47 | hmac "$1" "$2" 'sha256' 48 | } 49 | 50 | hmac_sha512() 51 | { 52 | hmac "$1" "$2" 'sha512' 53 | } 54 | -------------------------------------------------------------------------------- /bc/hash/hmac_conf.bc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bc 2 | 3 | define void hmac_pads(blocklen, *pads[]){ 4 | 5 | if (blocklen == 80){ 6 | pads[0] = 5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C; 7 | pads[1] = 36363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636; 8 | } 9 | if (blocklen == 100){ 10 | pads[0] = 5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C; 11 | pads[1] = 3636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636; 12 | } 13 | } 14 | 15 | define set_hmac_sha256(){ 16 | 17 | hmac_pads(80, hmac_pads[]); 18 | return 80; 19 | } 20 | 21 | define set_hmac_sha224(){ 22 | 23 | return set_hmac_sha256(); 24 | } 25 | 26 | define set_hmac_sha384(){ 27 | 28 | hmac_pads(100, hmac_pads[]); 29 | return 100; 30 | } 31 | 32 | define set_hmac_sha512(){ 33 | 34 | return set_hmac_sha384(); 35 | } 36 | -------------------------------------------------------------------------------- /bitcoin/activate_bitcoin.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | btcb_bit_home="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && echo $PWD )" 4 | 5 | btcb_bit_env=( \ 6 | script/globals/opcodes.sh script/globals/scripts.sh \ 7 | script/script_num.sh script/keys.sh script/scriptpubkey.sh \ 8 | transaction.sh parse.sh \ 9 | bips/bip32.sh bips/bip173.sh \ 10 | jsonrpc/json.sh jsonrpc/sign_message.sh ) 11 | 12 | set_network_versions() { 13 | 14 | case "$1" in 15 | 16 | bitcoin) 17 | privkeyVer="80" 18 | p2pkhVer="00" 19 | p2shVer="05" 20 | xpubVer="0488B21E" 21 | xprvVer="0488ADE4" 22 | swHrp="bc" 23 | clientname="mainnet" 24 | ;; 25 | 26 | testnet|regtest|mastcoin) 27 | privkeyVer="EF" 28 | p2pkhVer="6F" 29 | p2shVer="C4" 30 | xpubVer="043587CF" 31 | xprvVer="04358394" 32 | clientname="$1" 33 | case "$1" in 34 | testnet) 35 | swHrp="tb" 36 | ;; 37 | regtest) 38 | swHrp="bcrt" 39 | ;; 40 | esac 41 | esac 42 | p2wpkhVer="0014" 43 | p2wshVer="0020" 44 | } 45 | 46 | for shenv in ${btcb_bit_env[@]}; do 47 | . "${btcb_bit_home}/${shenv}" 48 | done 49 | 50 | __debug_btcbash=1 51 | set_network_versions 'regtest' 52 | -------------------------------------------------------------------------------- /base/binary.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # outputs any input as bytes separated by newlines 4 | # useful for setting arrays 5 | # printf '%s' STR | bin2bytes : " byte byte..." 6 | # bin2bytes <<<"STR" : " byte byte... 0a" 7 | # bin2bytes FILE : " byte byte..." 8 | alias bin2bytes='od -t x1 -An -v -w1' 9 | 10 | # outputs any input in hex 11 | # prtinf '%s' STR | bin2hexstr : "HEX..." 12 | # bin2hex <<<"STR" : "HEX...0x0A" 13 | # bin2hex FILE : "HEX..." 14 | alias bin2hex="hexdump -v -e '\"\" 1/1 \"%02X\" \"\"'" 15 | 16 | # removed newlines and tabs from hex input and turns to upper case 17 | # a newline is redirected to stderr so it's not added to the output 18 | alias cleanhex="tr -d ' \n\t' | tr [:lower:] [:upper:]; echo 1>&2" 19 | 20 | # print the raw value of hexstr 21 | # echo HEX | hex2bin : BIN 22 | # hex2bin HEX : BIN 23 | hex2bin() 24 | { 25 | # if $1 is empty, read from stdin 26 | # TODONE find a way to expand '<<<"$1"' somehow to re-use the loop 27 | # bash only, it's ' <<<"${1:-$(< /dev/stdin)}" ', but it's slower 28 | # tl;dr this one seems pretty fast when "small" (say 64 bytes) values 29 | # are hex2bin'd repeatedly 30 | if [[ -z "$1" ]]; then 31 | while read -r -N2 byte; do 32 | printf '%b' "\\x${byte}" 33 | done 34 | else 35 | while read -r -N2 byte; do 36 | printf '%b' "\\x${byte}" 37 | done <<<"$1" 38 | fi 39 | } 40 | 41 | # get n bytes from urandom 42 | randhex() 43 | { 44 | bin2hex -n"$1" /dev/urandom 45 | echo 46 | } 47 | -------------------------------------------------------------------------------- /bitcoin/script/keys.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | key_addr2hash160 () 4 | { 5 | local -u pubhash 6 | read pubhash < <( base58dec "${1}" ) 7 | echo "${pubhash:2:40}" 8 | } 9 | 10 | key_hash1602addr () 11 | { 12 | local -u checksum 13 | read checksum < <( hash256 "${p2pkhVer}${1}" ) 14 | base58enc "${p2pkhVer}${1}${checksum:0:8}" 15 | } 16 | 17 | key_hash1602p2sh () 18 | { 19 | local -u checksum 20 | read checksum < <( hash256 "${p2shVer}${1}" ) 21 | base58enc "${p2shVer}${1}${checksum:0:8}" 22 | } 23 | 24 | key_priv2pub () 25 | { 26 | bc_ecdsa <<< "ecmul("${1^^}");" 27 | } 28 | 29 | key_priv2wif() 30 | { 31 | local -u privkey="${1^^}" keyhash 32 | 33 | if (( ${#1} < 64 )); then 34 | read privkey < <( left_pad "${privkey}" 64 ) 35 | fi 36 | read keyhash < <( hash256 "${privkeyVer}${privkey}" ) 37 | keyhash="${keyhash:0:8}" 38 | 39 | base58enc "${privkeyVer}${privkey}${keyhash}" 40 | } 41 | 42 | key_pub2addr () 43 | { 44 | local addr; 45 | local -u pubhash; 46 | read pubhash < <( hash160 "${1}" ); 47 | read checksum < <( hash256 "${p2pkhVer}${pubhash}" ) 48 | base58enc "${p2pkhVer}${pubhash}${checksum:0:8}" 49 | } 50 | 51 | key_wif2priv () 52 | { 53 | local -u privhex; 54 | read privhex < <( base58dec "${1}" ) 55 | echo "${privhex:2:64}" 56 | } 57 | 58 | key_wif2pub () 59 | { 60 | local -u prihex pubkey; 61 | read privhex < <( base58dec "${1}" ) 62 | if (( ${#privhex} == 74 )); then 63 | #uncompresspoint "$( key_priv2pub "${privhex:2:64}" )" 64 | uncompresspubkey "$( key_priv2pub "${privhex:2:64}" )" 65 | else 66 | key_priv2pub "${privhex:2:64}" 67 | fi 68 | } 69 | -------------------------------------------------------------------------------- /bc/math/root_mod.bc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bc 2 | 3 | # functions for calculating roots 4 | 5 | # accepts a number (x), square or cubic root (r) and mod (p) 6 | # returns roots of x in array the passed array 7 | # *roots[0] will hold the number of roots returned 8 | define void rootmod_api(x, r, p, *roots[]){ 9 | 10 | # auto rm_s, rm_q, rm_z, rm_c, ts_ret, rootvals[]; 11 | auto ts_ret, rootvals[]; 12 | 13 | roots[0] = 0; 14 | rootvals[0] = 0; 15 | 16 | if (! is_residue(x, r, p)){ 17 | print "\n# *** Not a residue of pow ", r, "\n"; 18 | roots[1] = 0; 19 | return; 20 | } 21 | set_root_values(r, p, rootvals[]); 22 | # rm_s = rootvals[1]; 23 | # rm_q = rootvals[2]; 24 | # rm_z = rootvals[0]; 25 | # rm_c = rootvals[3]; 26 | 27 | # print "s : ", rootvals[1], " q : ", rootvals[2], " z : ", rootvals[0], " c : ", rootvals[3], "\n"; 28 | ts_ret = tonelli_shanks_api(x, r, rootvals[1], rootvals[2], rootvals[3], p); 29 | 30 | if ( r % 2 == 0 ){ 31 | 32 | roots[0] = 2; 33 | roots[1] = ts_ret 34 | roots[2] = mod( -ts_ret, p); 35 | } else { 36 | 37 | roots[0] = 3; 38 | roots[1] = ts_ret; 39 | roots[2] = mod(ts_ret * rootvals[3], p); 40 | roots[3] = mod(ts_ret * invmod(rootvals[3], p), p); 41 | } 42 | } 43 | 44 | # computes square or cube roots from a number (n) 45 | # prints the results and returns the first root returned by the api 46 | define rootmod(n, r, p){ 47 | 48 | auto i, roots[]; 49 | 50 | rootmod_api(n, r, p, roots[]); 51 | print "\n# rootmod()\n#\n"; 52 | for ( i=1; i <= roots[0]; i++){ 53 | print "# r", i, " = ", roots[i], "\n"; 54 | } 55 | return roots[1]; 56 | } 57 | -------------------------------------------------------------------------------- /hash/logic.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | _bitwise_binary () 4 | { 5 | local num1="$1" num2="$2" max_len i rem 6 | 7 | if (( ${#num1} > ${#num2} )); then 8 | max_len="${#num1}" 9 | printf -v num2 "%0${max_len}s" "${num2}" 10 | num2="${num2// /0}" 11 | else 12 | max_len="${#num2}" 13 | printf -v num1 "%0${max_len}s" "${num1}"; 14 | num1="${num1// /0}" 15 | fi 16 | 17 | rem=$(( ${max_len} % 16 )) 18 | for ((i=0; i<${max_len}-${rem}; i+=16 )) 19 | do 20 | printf "%016X" "$(( 0x${num1:${i}:16} ${3} 0x${num2:${i}:16} ))" 21 | done 22 | if (( ${rem} )); then 23 | printf "%0${rem}X" "$(( 0x${num1:${i}} ${3} 0x${num2:${i}} ))" 24 | fi 25 | echo 26 | } 27 | 28 | _bitwise_unary () 29 | { 30 | local num="$1" i rem ret 31 | 32 | if (( ${#num} <= 16 )); then 33 | printf -v ret "%0${#num}X" "$(( ${2} 0x${num} ))" 34 | echo "${ret:$((16-${#num}))}" 35 | return 36 | fi 37 | rem=$(( ${#num} % 16 )) 38 | for ((i=0; i<${#num}-${rem}; i+=16 )) 39 | do 40 | printf "%X" "$(( ${2} 0x${num:${i}:16} ))" 41 | done 42 | if (( ${rem} )); then 43 | printf -v ret "%X" "$(( ${2} 0x${num:${i}} ))" 44 | echo "${ret:$((16-${rem}))}" 45 | return 46 | fi 47 | echo 48 | } 49 | 50 | bwor () 51 | { 52 | _bitwise_binary "$1" "$2" '|' 53 | } 54 | 55 | bwand () 56 | { 57 | _bitwise_binary "$1" "$2" '&' 58 | } 59 | 60 | bwxor () 61 | { 62 | _bitwise_binary "$1" "$2" '^' 63 | } 64 | 65 | bwnot () 66 | { 67 | _bitwise_unary "$1" '~' 68 | } 69 | 70 | bwnor () 71 | { 72 | bwnot "$(bwor "$1" "$2" )" 73 | } 74 | 75 | bwnand () 76 | { 77 | bwnot "$(bwand "$1" "$2")" 78 | } 79 | 80 | bwxnor () 81 | { 82 | bwnot "$(bwxor "$1" "$2" )" 83 | } 84 | -------------------------------------------------------------------------------- /bc/math/extended_euclidean.bc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bc 2 | 3 | # https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm#Pseudocode 4 | define void extended_gcd_api(a, b, n, *ret[]){ 5 | 6 | auto s, olds, t, oldt, r, oldr, quotient, prov; 7 | s = 0; olds = 1; 8 | t = 1; oldt = 0; 9 | r = b; oldr = a; 10 | 11 | # TODO check if mod() is required here 12 | while (r != 0){ 13 | quotient = oldr / r; 14 | prov = r; 15 | r = mod(oldr - quotient*prov, n); 16 | #r = (oldr - (quotient*prov)); 17 | oldr = prov; 18 | prov = s; 19 | s = mod(olds - quotient*prov, n); 20 | #s = (olds - (quotient*prov)); 21 | olds = prov; 22 | prov = t; 23 | t = mod(oldt - quotient*prov, n); 24 | #t = (oldt - (quotient*prov)); 25 | oldt = prov; 26 | } 27 | #ret[0] = olds; ret[1] = oldt; 28 | #ret[2] = oldr; 29 | #ret[3] = t; ret[4] = s; 30 | ret[0] = mod(olds,n); ret[1] = mod(oldt,n); # Bezout coefficients 31 | ret[2] = mod(oldr,n); # greatest common divisor 32 | ret[3] = mod(t,n); ret[4] = mod(s,n); # quotients by the gcd 33 | } 34 | 35 | # prints the results returned by the api 36 | define void egcd(a, b, n){ 37 | 38 | auto ret[]; 39 | extended_gcd_api(a,b,n,ret[]); 40 | 41 | print "Bézout coefficients :\n", ret[0], "\n", ret[1], "\n"; 42 | print "greatest common divisor :\n", ret[2], "\n"; 43 | print "quotients by the gcd : \n", ret[3], "\n", ret[4], "\n"; 44 | } 45 | 46 | # simple gcd 47 | # https://en.wikipedia.org/wiki/Euclidean_algorithm 48 | define euclidean_algorithm(a, b, n){ 49 | 50 | auto t; 51 | while (b > 1){ 52 | t = b; 53 | b = mod(a, b); 54 | a = t; 55 | } 56 | return a; 57 | } 58 | 59 | define gcd(a, b){ 60 | 61 | return euclidean_algorithm(mod(a, curve_n), mod(b,curve_n), curve_n); 62 | } 63 | -------------------------------------------------------------------------------- /bc/math/tonelli_shanks.bc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bc 2 | 3 | # factors out powers of r from p 4 | define factor_pow(p, r){ 5 | 6 | auto i; 7 | i = 0; 8 | 9 | while (( p > 1 ) && ( mod(p, r) == 0 )){ 10 | i += 1; 11 | p /= r; 12 | } 13 | 14 | return i; 15 | } 16 | 17 | # returns a non r residue in p 18 | define get_non_residue(p,r){ 19 | 20 | auto nonres, pow; 21 | pow = mod((p-1) * invmod(r ,p), p); 22 | nonres = 1; 23 | 24 | while ( is_residue(nonres, r, p) ){ 25 | nonres += 1; 26 | } 27 | 28 | return nonres; 29 | } 30 | 31 | # returns 1 if res is r residue in p, 0 if not 32 | define is_residue(res, r, p){ 33 | 34 | auto test; 35 | test = powmod(res, (p-1)/r ,p); 36 | return ( test == mod(p, test) + 1 ); 37 | } 38 | 39 | # sets an array of values required for root computation 40 | define void set_root_values(r, p, *rootvals[]){ 41 | 42 | rootvals[0] = get_non_residue(p, r); 43 | rootvals[1] = factor_pow((p-1) * rootvals[0], r); 44 | rootvals[2] = (p / r^rootvals[1]); 45 | 46 | rootvals[3] = powmod(rootvals[0], rootvals[2], p); 47 | } 48 | 49 | # https://en.wikipedia.org/wiki/Tonelli%E2%80%93Shanks_algorithm#The_algorithm 50 | # "A remark on the computation of cube roots in finite fields" 51 | # https://eprint.iacr.org/2009/457.pdf (3.1, table 3) 52 | # s, q and c are computed by set_root_values() 53 | define tonelli_shanks_api(n, l, s, q, c, p){ 54 | 55 | auto r, t, m, i, b; 56 | 57 | r = powmod(n, (q+1) / l, p); 58 | t = powmod(n, q, p); 59 | m = s; 60 | 61 | while ( t != 1 ){ 62 | 63 | i=1; 64 | while ( (powmod(t, powmod(l, i, p), p) != 1) && (i < m) ){ 65 | i += 1; 66 | } 67 | 68 | b = powmod(c, powmod(l, (m - i - 1), p), p); 69 | r = mod(r * b, p); 70 | t = mod(t * (b ^ l), p); 71 | c = mod(b ^ l, p); 72 | m = i; 73 | } 74 | 75 | return r; 76 | } 77 | -------------------------------------------------------------------------------- /hash/hexhash.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # simple functions to convert hex to binary then hash it. 4 | # openssl currently a dependency for ripemd160 5 | # TODO faster 6 | 7 | sha224() 8 | { 9 | local -u digest 10 | if [[ -z "$1" ]]; then 11 | read -r -N56 digest < <( sha224sum -b <(hex2bin = 0; i--, j++ )) 57 | do 58 | b58arr_bc[${j}]="c[${j}]=${_b58Dec[${b58str:${i}:1}]}; " 59 | done 60 | 61 | oneprefix="${b58str%%[^1]*}" 62 | oneprefix="${oneprefix//1/00}" 63 | printf "%s" "${oneprefix}" 64 | 65 | local -u hexstr 66 | bc_encode <<<" \ 67 | ibase=A; 68 | ${b58arr_bc[@]} \ 69 | hex = base_restore(58, c[]); \ 70 | ibase=16; \ 71 | if (wordlen(hex) % 2) { print 0; }; \ 72 | print hex, \"\n\";" 73 | } 74 | -------------------------------------------------------------------------------- /base/int_convert.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # functions from 4 | # https://tools.ietf.org/html/rfc6979#section-2.3 5 | 6 | # 2.3.2 7 | # convert a string of bits {1,0} to a positive integer of qlen/8 bytes 8 | # or a simple base 2->16 conversion if $2 is not provided 9 | # $1 : bit string 10 | # $2 : length of q in bits 11 | bits2int() 12 | { 13 | local iseq="$1" 14 | local -i blen="${#iseq}" 15 | local -i qlen="${2:-${blen}}" 16 | local -u oint 17 | 18 | # do the first part of step (1) first 19 | if (( qlen < blen )); then 20 | iseq="${iseq:0:${qlen}}" 21 | fi 22 | 23 | # step (2) 24 | read oint < <( bc_clean <<<"obase=16; ibase=2; ${iseq};" ) 25 | 26 | # second part of step (1) 27 | # use qlen/4 as oint is now made of words 28 | if (( ${#oint} < (qlen/4) )); then 29 | lpadhexstr "${oint}" "$(( (qlen/4)-${#oint} ))" 30 | else 31 | printf '%s\n' "${oint}" 32 | fi 33 | } 34 | 35 | # 2.3.3 36 | # converts an integer to an word\octet string of some length of bits 37 | # $1 : integer 38 | # $2 : length of q in bits 39 | int2octets() 40 | { 41 | local -u iseq="$1" oseq 42 | local -i qlen="$2" rlen 43 | [[ -z "$2" ]] && return 1 44 | 45 | # TODO maybe better to lose the multipliers 46 | (( qlen*8 < ${#iseq}*4 )) && return 1 47 | 48 | read rlen < <( int_ceil "${qlen}/8" ) 49 | (( rlen *= 8 )) 50 | 51 | # echo "rlen : ${rlen}" 52 | lpadhexstr "${iseq}" "$(( (rlen/4)-${#iseq} ))" 53 | } 54 | 55 | # 2.3.4 56 | # converts a string of bits to an octet string 57 | # $1 : bit string 58 | # $2 : q in hex ( q is a large prime ) 59 | bits2octets() 60 | { 61 | local b="$1" q="$2" 62 | local -i blen="${#b}" qlen="$(( ${#q}*4 ))" 63 | local -u z1 z2 64 | 65 | # 2.3.4.1 66 | read z1 < <( bits2int "$b" "${qlen}" ) 67 | # 2.3.4.2 68 | read z2 < <( bc_clean <<<" 69 | obase=16; 70 | ibase=16; 71 | if ( (${z1}-${q})<0 ){ 72 | ${z1}; 73 | } else { 74 | ${z1}-${q}; 75 | };" 76 | ) 77 | 78 | # 2.3.4.3 79 | int2octets "${z2}" "${qlen}" 80 | } 81 | -------------------------------------------------------------------------------- /base/string.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # we sometimes change IFS to fit our export format 4 | # this alias sets IFS back to a sane value 5 | alias set_ifs='printf -v IFS "%b%b%b" "\\x20" "\\x09" "\\x0a"' 6 | 7 | # pad hexstr with n zero words on the right 8 | # $1 : hexstr 9 | # $2 : n 10 | rpadhexstr() 11 | { 12 | local -i n="$2" 13 | (( $n < 0 )) && return 1 14 | (( ${n:-0} == 0 )) && printf '%s\n' "$1" && return 15 | printf "%s%0${n}d\n" "$1" 16 | } 17 | 18 | # pad hexstr with n zero words on the left 19 | # $1 : hexstr 20 | # $2 : n 21 | lpadhexstr() 22 | { 23 | local -i n="$2" 24 | (( $n < 0 )) && return 1 25 | (( ${n:-0} == 0 )) && printf '%s\n' "$1" && return 26 | printf "%0${n}d%s\n" '0' "$1" 27 | } 28 | 29 | right_pad() 30 | { 31 | rpadhexstr "$1" "$((${2} - ${#1}))" 32 | } 33 | 34 | left_pad() 35 | { 36 | lpadhexstr "$1" "$((${2} - ${#1}))" 37 | } 38 | 39 | # reverse chunks of n words in hexstr 40 | # the length of hexstr must be a multiple of the chunk 41 | # setting a chunk size is only possible with $2 42 | # $1 : hexstr 43 | # $2 : n 44 | revchunks() 45 | { 46 | local -u hexstr 47 | local -i chunk 48 | 49 | # read either from stdin or from $1 50 | # set a default value of 2 to chunk if none is given 51 | if [[ -z $1 ]]; then 52 | read hexstr 53 | chunk=2 54 | else 55 | hexstr="$1" 56 | chunk="${2:-2}" 57 | (( ! chunk )) && return 1 58 | fi 59 | 60 | # check for nonsese values in chunk 61 | if (( chunk > ${#hexstr} )) || \ 62 | (( chunk <= 0 )) || \ 63 | (( ${#hexstr} % chunk != 0 )); then 64 | return 1 65 | fi 66 | 67 | # read chunks from hexstr and assign 68 | # them to revstr in descending order 69 | local -a revstr 70 | local -i k="$(( ${#hexstr}/chunk ))" 71 | while read -N${chunk} hexchunk; do 72 | revstr[$((k--))]="${hexchunk}" 73 | done <<<"${hexstr}" 74 | 75 | # expand revstr to a string that looks like '00 11 22...' 76 | # with IFS unset, removal of ' ' is possible 77 | # set_ifs resets IFS back to a sane value 78 | IFS="" 79 | printf '%s%b' "${revstr[*]// /}" '\n' 80 | set_ifs 81 | } 82 | -------------------------------------------------------------------------------- /bc/hash/sha256.bc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bc 2 | 3 | define void set_init_vals(*ret[]){ 4 | 5 | ret[0] = 6A09E667; 6 | ret[1] = BB67AE85; 7 | ret[2] = 3C6EF372; 8 | ret[3] = A54FF53A; 9 | ret[4] = 510E527F; 10 | ret[5] = 9B05688C; 11 | ret[6] = 1F83D9AB; 12 | ret[7] = 5BE0CD19; 13 | } 14 | 15 | define void set_round_const(*ret[]){ 16 | 17 | ret[0] = 428A2F98; 18 | ret[1] = 71374491; 19 | ret[2] = B5C0FBCF; 20 | ret[3] = E9B5DBA5; 21 | ret[4] = 3956C25B; 22 | ret[5] = 59F111F1; 23 | ret[6] = 923F82A4; 24 | ret[7] = AB1C5ED5; 25 | ret[8] = D807AA98; 26 | ret[9] = 12835B01; 27 | ret[A] = 243185BE; 28 | ret[B] = 550C7DC3; 29 | ret[C] = 72BE5D74; 30 | ret[D] = 80DEB1FE; 31 | ret[E] = 9BDC06A7; 32 | ret[F] = C19BF174; 33 | ret[10] = E49B69C1; 34 | ret[11] = EFBE4786; 35 | ret[12] = 0FC19DC6; 36 | ret[13] = 240CA1CC; 37 | ret[14] = 2DE92C6F; 38 | ret[15] = 4A7484AA; 39 | ret[16] = 5CB0A9DC; 40 | ret[17] = 76F988DA; 41 | ret[18] = 983E5152; 42 | ret[19] = A831C66D; 43 | ret[1A] = B00327C8; 44 | ret[1B] = BF597FC7; 45 | ret[1C] = C6E00BF3; 46 | ret[1D] = D5A79147; 47 | ret[1E] = 06CA6351; 48 | ret[1F] = 14292967; 49 | ret[20] = 27B70A85; 50 | ret[21] = 2E1B2138; 51 | ret[22] = 4D2C6DFC; 52 | ret[23] = 53380D13; 53 | ret[24] = 650A7354; 54 | ret[25] = 766A0ABB; 55 | ret[26] = 81C2C92E; 56 | ret[27] = 92722C85; 57 | ret[28] = A2BFE8A1; 58 | ret[29] = A81A664B; 59 | ret[2A] = C24B8B70; 60 | ret[2B] = C76C51A3; 61 | ret[2C] = D192E819; 62 | ret[2D] = D6990624; 63 | ret[2E] = F40E3585; 64 | ret[2F] = 106AA070; 65 | ret[30] = 19A4C116; 66 | ret[31] = 1E376C08; 67 | ret[32] = 2748774C; 68 | ret[33] = 34B0BCB5; 69 | ret[34] = 391C0CB3; 70 | ret[35] = 4ED8AA4A; 71 | ret[36] = 5B9CCA4F; 72 | ret[37] = 682E6FF3; 73 | ret[38] = 748F82EE; 74 | ret[39] = 78A5636F; 75 | ret[3A] = 84C87814; 76 | ret[3B] = 8CC70208; 77 | ret[3C] = 90BEFFFA; 78 | ret[3D] = A4506CEB; 79 | ret[3E] = BEF9A3F7; 80 | ret[3F] = C67178F2; 81 | } 82 | 83 | # delaying development for now. 84 | # https://github.com/fivepiece/bc_segfault 85 | -------------------------------------------------------------------------------- /config/build_bc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | get_bc () 4 | { 5 | if ! sha256sum -c "${build_dir}/bc-1.07.1.tar.gz.sha256"; then 6 | wget --tries=5 -O bc-1.07.1.tar.gz https://ftp.gnu.org/gnu/bc/bc-1.07.1.tar.gz 7 | fi 8 | if ! sha256sum -c "${build_dir}/bc-1.07.1.tar.gz.sig.sha256"; then 9 | wget --tries=5 -O bc-1.07.1.tar.gz.sig https://ftp.gnu.org/gnu/bc/bc-1.07.1.tar.gz.sig 10 | fi 11 | } 12 | 13 | verify_bc () 14 | { 15 | wget --tries=5 -O 81C24FF12FB7B14B.pub 'https://pgp.mit.edu/pks/lookup?op=get&search=0x81C24FF12FB7B14B' 16 | gpg --dearmor <81C24FF12FB7B14B.pub >81C24FF12FB7B14B.pub.bin 17 | gpg --no-default-keyring --keyring ./81C24FF12FB7B14B.pub.bin --verify bc-1.07.1.tar.gz.sig 18 | return $? 19 | } 20 | 21 | build_bc () 22 | { 23 | if [[ -d "$PWD/bc-1.07.1" ]]; then 24 | read -p "overwrite $PWD/bc-1.07.1 ? [y/n] " q 1>&2 25 | if [[ "${q}" =~ [Yy] ]]; then 26 | rm -rf "$PWD/bc-1.07.1" 27 | else 28 | echo "stopping. move $PWD/bc-1.07.1 and retry." 1>&2 29 | exit 1 30 | fi 31 | fi 32 | tar -xzf bc-1.07.1.tar.gz 33 | pushd "bc-1.07.1" 34 | if ! patch --dry-run -p1 -i ${build_dir}/bc_build.patch; then 35 | echo "bc build patch failed" 1>&2 36 | exit 1 37 | fi 38 | if ! patch --dry-run -p1 -i ${build_dir}/bc_baseconvert.patch; then 39 | echo "bc baseconvert patch failed" 1>&2 40 | exit 1 41 | fi 42 | patch -p1 -i ${build_dir}/bc_build.patch 43 | patch -p1 -i ${build_dir}/bc_baseconvert.patch 44 | ./configure --with-readline 45 | make 46 | if ! make bc; then 47 | echo -e "\n\nre-run as \`./build_bc.sh 2>&1 > build_bc.log\` and tell arubi" 1>&2 48 | exit 1 49 | fi 50 | strip bc/bc 51 | popd 52 | ln -sf "${build_dir}/deps/bc-1.07.1/bc/bc" "${build_dir}/bin/bc" 53 | } 54 | 55 | unset BC_ENV_ARGS 56 | unset BC_LINE_LENGTH 57 | build_dir="$PWD" 58 | mkdir -p "${build_dir}/deps" 59 | pushd ./deps 60 | get_bc 61 | if which gpg && [[ "${1}" != "--no-check-signature" ]]; then 62 | if ! verify_bc; then 63 | echo "signature verification failed for bc-1.07.1.tar.gz" 1>&2 64 | exit 1 65 | fi 66 | else 67 | echo "skipping signature verification" 1>&2 68 | fi 69 | build_bc 70 | -------------------------------------------------------------------------------- /ecdsa/rfc6979.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # https://tools.ietf.org/html/rfc6979#section-3.2 4 | rfc6979 () 5 | { 6 | local -u key="$1" msg="$2" 7 | local hashfunc="$3" hlen="$4" 8 | local vlen="$(( 8 * $(int_ceil "${hlen}/8") ))" 9 | 10 | # keys shorter than the keysize are right padded with 0x00's 11 | if (( ${#key} < ${hlen} )); then 12 | read key < <( left_pad "${key}" "${hlen}" ) 13 | fi 14 | 15 | local -u h1 v k t foundk 16 | # 3.2.a 17 | read h1 < <( "${hashfunc}" "${msg}" ) 18 | # decho "\n# key : ${key}" 19 | # decho "# sighash : ${h1}" 20 | 21 | # 3.2.b 22 | read v < <( input_mkbitmap '01' "${vlen}" ) 23 | # decho "# 3.2.b, v : ${v}" 24 | 25 | # 3.2.c 26 | read k < <( input_mkbitmap '00' "${vlen}" ) 27 | # decho "# 3.2.c, k : ${k}" 28 | 29 | # 3.2.d 30 | read k < <( hmac "${k}" "${v}00${key}${h1}" "${hashfunc}" ) 31 | # 3.2.e 32 | read v < <( hmac "${k}" "${v}" "${hashfunc}" ) 33 | 34 | # decho "# 3.2.d, k : ${k}" 35 | # decho "# 3.2.e, v : ${v}" 36 | 37 | # 3.2.f 38 | read k < <( hmac "${k}" "${v}01${key}${h1}" "${hashfunc}" ) 39 | # 3.2.g 40 | read v < <( hmac "${k}" "${v}" "${hashfunc}" ) 41 | 42 | # decho "# 3.2.f, k : ${k}" 43 | # decho "# 3.2.g, v : ${v}" 44 | 45 | # 3.2.h 46 | while :; do 47 | # decho "start 3.2.h" 48 | # 3.2.h.1 49 | t="" 50 | 51 | # 3.2.h.2 52 | while (( ${#t} < ${hlen} )); do 53 | # decho "start 3.2.h.2" 54 | read v < <( hmac "${k}" "${v}" "${hashfunc}" ) 55 | t="${t}${v}" 56 | # decho "# 3.2.h.2, v : ${v}" 57 | # decho "# 3.2.h.2, t : ${t}" 58 | # decho "end 3.2.h.2" 59 | done 60 | 61 | # 3.2.h.3 62 | # lexicographical (avoid bc) 63 | if [[ "${curve_one}" < "${t}" ]] && [[ "${t}" < "${curve_n}" ]]; then 64 | echo "${t}" 65 | return 66 | fi 67 | 68 | read k < <( hmac "${k}" "${v}00" "${hashfunc}" ) 69 | # decho "# 3.2.h.3, k : ${k}" 70 | # decho "end 3.2.h" 71 | # read v < <( hmac "${k}" "${v}" ) # TODO is this needed? 72 | done 73 | } 74 | 75 | rfc6979_secp256k1_sha256_k() 76 | { 77 | rfc6979 "$1" "$2" 'sha256' '64' 78 | } 79 | -------------------------------------------------------------------------------- /bc/base/conversion.bc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bc 2 | 3 | # functions to handle numbers as bits or words 4 | 5 | 6 | # returns the number of words (4 bits) in a number 7 | define wordlen(n){ 8 | 9 | auto num, ans, i; 10 | ans = -1; 11 | i = -1; 12 | 13 | if ( n == 0 ){ 14 | return 1; 15 | } 16 | 17 | num = n; 18 | 19 | if ( n < 0 ){ 20 | num = (num * -1); 21 | } 22 | 23 | while (ans <= 0){ 24 | i=i+1; 25 | ans=( (10^i)-(num) ); 26 | } 27 | 28 | return i; 29 | } 30 | 31 | define bytelen(n){ 32 | 33 | return (wordlen(n)+1)/2; 34 | } 35 | 36 | # accepts a number, a base to convert to and an array to place 37 | # the converted number 38 | # cvrt[0] = array length 39 | # numbers are placed in cvrt[1..n] where LSB is at cvrt[1] and so on 40 | define void base_convert_api(n, b, *cvrt[]){ 41 | 42 | auto ibit; 43 | 44 | ibit = 0; 45 | 46 | if ( n == 0 ){ 47 | cvrt[0] = 1; 48 | cvrt[1] = 0; 49 | return; 50 | } 51 | 52 | while ( n > 0 ){ 53 | 54 | cvrt[ibit+1] = ( n % b ); 55 | ibit = ibit+1; 56 | n /= b; 57 | } 58 | 59 | cvrt[0] = ibit; 60 | } 61 | 62 | # accepts a number and a base, prints the converted number 63 | # as its factors LSB is leftmost 64 | define void base_convert(n, b){ 65 | 66 | auto newbase[], i; 67 | base_convert_api(n, b, newbase[]); 68 | 69 | for ( i=1; i<=newbase[0]; i++ ){ 70 | print newbase[i], " "; 71 | } 72 | print "\n"; 73 | } 74 | 75 | # accepts an array containing a base-converted number 76 | # returns the number in obase 77 | define base_restore(b, *arr[]){ 78 | 79 | auto res, i; 80 | for ( i=1; i<=arr[0]; i++ ){ 81 | res += b^(i-1) * arr[i]; 82 | } 83 | return res; 84 | } 85 | 86 | # accepts a number and named array 87 | # ret[0] = array length 88 | # bits are placed in ret[1..n] where LSB is at ret[1] and so on 89 | define void num2bitarr(n, *ret[]){ 90 | 91 | base_convert_api(n, 2, ret[]); 92 | } 93 | 94 | # accepts an array such as the output from num2bitarr() 95 | # returns the number converted back from it 96 | define bitarr2num(*ret[]){ 97 | 98 | return base_restore(2, ret[]); 99 | } 100 | -------------------------------------------------------------------------------- /bc/ecdsa/contract_hash.bc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bc 2 | 3 | # basic contract hash functions 4 | 5 | define void contracthash_sign_api(k0, tweak, z, d, *contract[]){ 6 | 7 | auto k1, s, nonce[], sig[]; 8 | 9 | ecmul_api(k0, curve_gx, curve_gy, curve_n, curve_p, nonce[]); 10 | k1 = mod(k0 + tweak, curve_n); 11 | ecdsa_sign(k1, z, d, sig[]); 12 | contract[0] = nonce[0]; 13 | contract[1] = nonce[1]; 14 | contract[2] = sig[0]; 15 | contract[3] = sig[1]; 16 | } 17 | 18 | define contracthash_verify_api(z, pub, nonce, dersig, tweak){ 19 | 20 | auto tw_pt[], cmt_pt[], nnc_pt[], pub_pt[], sig[], r_ver; 21 | 22 | uncompresspoint_api(nonce, nnc_pt[]); 23 | uncompresspoint_api(pub, pub_pt[]); 24 | ecdsa_der2sig(dersig, sig[]); 25 | ecmul_api(tweak, curve_gx, curve_gy, curve_n, curve_p, tw_pt[]); 26 | ecadd_api(tw_pt[0], tw_pt[1], nnc_pt[0], nnc_pt[1], curve_p, cmt_pt[]) 27 | r_ver = ecdsa_verify_api(z, pub_pt[0], pub_pt[1], sig[0], sig[1], curve_gx, curve_gy, curve_p, curve_n); 28 | return (sig[0] != 0) && (r_ver == cmt_pt[0]); 29 | } 30 | 31 | # used for recovering k and d from contracthash nonce reuse 32 | 33 | define contracthash_recover_k_api(r1, s1, tw1, r2, s2, tw2, z1, n){ 34 | 35 | auto r1i; 36 | 37 | r1i = invmod(r1, n); 38 | return mod( (z1*(1 - r1i*r2) + s2*(tw1 - tw2)) * invmod(s2 - s1*r1i*r2, n), n) 39 | } 40 | 41 | define void contracthash_recover_k(z1, dersig1, tw1, dersig2, tw2, n){ 42 | 43 | auto sig1[], sig2[], k1, k2, k3, k4; 44 | 45 | ecdsa_der2sig(dersig1, sig1[]); 46 | ecdsa_der2sig(dersig2, sig2[]); 47 | k1 = contracthash_recover_k_api(sig1[0], sig1[1], tw1, sig2[0], sig2[1], tw2, z1, n); 48 | k2 = contracthash_recover_k_api(sig1[0], -sig1[1], tw1, sig2[0], sig2[1], tw2, z1, n); 49 | k3 = contracthash_recover_k_api(sig1[0], sig1[1], tw1, sig2[0], -sig2[1], tw2, z1, n); 50 | k4 = contracthash_recover_k_api(sig1[0], -sig1[1], tw1, sig2[0], -sig2[1], tw2, z1, n); 51 | 52 | print "\npossible k values :\n\n"; 53 | k1; k2; k3; k4; 54 | 55 | print "\npossible d values :\n\n"; 56 | mod(mod((sig1[1]*k1)-z1,n) * invmod(sig1[0],n),n); 57 | mod(mod((sig1[1]*k2)-z1,n) * invmod(sig1[0],n),n); 58 | mod(mod((sig1[1]*k3)-z1,n) * invmod(sig1[0],n),n); 59 | mod(mod((sig1[1]*k4)-z1,n) * invmod(sig1[0],n),n); 60 | } 61 | -------------------------------------------------------------------------------- /bc/bitcoin/bitcoin_funcs.bc: -------------------------------------------------------------------------------- 1 | 2 | define compsize(nsize){ 3 | 4 | if (nsize < 10){ 5 | 6 | print 0; 7 | return nsize; 8 | } # leading zero 9 | if (nsize < FD){ 10 | 11 | return nsize; 12 | } 13 | if (nsize <= FFFF){ 14 | 15 | return FD0000+nsize; 16 | } 17 | if (nsize <= FFFFFFFF){ 18 | 19 | return FE00000000+nsize; 20 | } 21 | if (nsize <= FFFFFFFFFFFFFFFF){ 22 | 23 | return FF0000000000000000+nsize; 24 | } 25 | } 26 | 27 | define void wsize2pushop(wsize){ 28 | 29 | auto bsize 30 | if ( wsize % 2 != 0 ){ 31 | 32 | print "Error odd wordsize\n"; 33 | return; 34 | } 35 | bsize = wsize / 2; 36 | if ( bsize < 4C ){ 37 | 38 | print "0x\n"; 39 | left_pad(bsize,2); 40 | return; 41 | } 42 | if ( bsize < 100 ){ 43 | 44 | print "PUSHDATA1 0x\n" 45 | left_pad(bsize,2); 46 | return; 47 | } 48 | if ( bsize < 10000 ){ 49 | 50 | print "PUSHDATA2 0x\n" 51 | left_pad(bsize,4); 52 | return; 53 | } 54 | if ( bsize < 100000000 ){ 55 | 56 | print "PUSHDATA4 0x\n" 57 | left_pad(bsize,8); 58 | return; 59 | } 60 | print "Error data push too big\n"; 61 | return; 62 | } 63 | 64 | 65 | define void ser_num(n){ 66 | 67 | auto num, order, msb, lsb, sep; # lsb is all bytes after msb 68 | # sep is where msb ends and lsb starts 69 | if ( n == 0 ){ 70 | 71 | print "00\n"; 72 | return; 73 | } 74 | num = n; 75 | if ( num < 0 ){ 76 | 77 | num = ( num * -1 ); 78 | } 79 | order = wordlen(num); 80 | sep = (order - (2 - (order % 2) )); # yuck.. 81 | msb = num / (10^sep); 82 | lsb = num % (10^sep); 83 | 84 | if ( msb >= 80 ){ 85 | 86 | if ( n > 0 ){ 87 | 88 | print "00"; 89 | left_pad(num, order+(order % 2)); 90 | return; 91 | } else { 92 | 93 | print "80"; 94 | left_pad(num, order+(order % 2)); 95 | return; 96 | } 97 | } else { 98 | 99 | if ( n < 0) { 100 | 101 | left_pad( (msb+80)*(10^sep)+lsb, sep+2); 102 | return; 103 | } 104 | 105 | left_pad(num, order+(order % 2)); 106 | return; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /config/bc_baseconvert.patch: -------------------------------------------------------------------------------- 1 | diff -crB bc-1.07.1/bc/storage.c bc-1.07.1-baseconvert.patch/bc/storage.c 2 | *** bc-1.07.1/bc/storage.c 2017-04-08 01:20:02.000000000 +0300 3 | --- bc-1.07.1-baseconvert.patch/bc/storage.c 2018-02-24 20:56:16.290669480 +0200 4 | *************** 5 | *** 1018,1023 **** 6 | --- 1018,1024 ---- 7 | 8 | /* Compute source index and make sure some structure exists. */ 9 | ix = (int) bc_num2long (ex_stack->s_num); 10 | + ix = (int) array_index_base_convert_high_to_dec (ix, i_base); 11 | (void) get_array_num (ix, 0); 12 | 13 | /* Push a new array and Compute Destination index */ 14 | diff -crB bc-1.07.1/h/number.h bc-1.07.1-baseconvert.patch/h/number.h 15 | *** bc-1.07.1/h/number.h 2017-04-08 01:20:02.000000000 +0300 16 | --- bc-1.07.1-baseconvert.patch/h/number.h 2018-02-24 20:55:52.118693620 +0200 17 | *************** 18 | *** 140,143 **** 19 | --- 140,152 ---- 20 | int leading_zero); 21 | 22 | void bc_out_long (long val, int size, int space, void (*out_char)(int)); 23 | + 24 | + 25 | + /* btcbash patch begin */ 26 | + 27 | + /* functions to correctly handle array indexes when in bases higher than 10 */ 28 | + 29 | + long array_index_base_convert_high_to_dec(long num, int ibase); 30 | + 31 | + /* btcbash patch end */ 32 | #endif 33 | diff -crB bc-1.07.1/lib/number.c bc-1.07.1-baseconvert.patch/lib/number.c 34 | *** bc-1.07.1/lib/number.c 2017-04-08 01:20:02.000000000 +0300 35 | --- bc-1.07.1-baseconvert.patch/lib/number.c 2018-02-24 20:55:34.490711250 +0200 36 | *************** 37 | *** 1735,1737 **** 38 | --- 1735,1778 ---- 39 | } 40 | 41 | #endif 42 | + 43 | + 44 | + /* btcbash patch begin */ 45 | + 46 | + /* function to correctly handle array indexes when in bases higher than 10 */ 47 | + 48 | + // simple helper function for the next one 49 | + // takes base and exponent, returns the base to the power of the exponent 50 | + long 51 | + intpow(int base, int exp) 52 | + { 53 | + int ret = 1; 54 | + 55 | + while (exp > 0) 56 | + { 57 | + ret *= base; 58 | + --exp; 59 | + } 60 | + return ret; 61 | + } 62 | + 63 | + // takes an index integer in (ibase > 10), returns the index at base 10 64 | + long 65 | + array_index_base_convert_high_to_dec(long num, int ibase) 66 | + { 67 | + if (num < ibase) 68 | + return num; 69 | + 70 | + int mod = 0, ret = 0, pow = 0; 71 | + 72 | + while (num > 0) 73 | + { 74 | + mod = num % ibase; 75 | + ret += (mod * (intpow(10 ,pow))); 76 | + num /= ibase; 77 | + ++pow; 78 | + } 79 | + return ret; 80 | + } 81 | + 82 | + /* btcbash patch end */ 83 | -------------------------------------------------------------------------------- /ecdsa/contract_hash.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | contracthash_sign () 4 | { 5 | local -u d1="$1" c1="$2" z1="$3" k0 nnc1 tw1 6 | 7 | k0="$( rfc6979_secp256k1_sha256_k "${d1}" "${z1}" )" 8 | nnc1="$( key_priv2pub ${k0} )" 9 | tw1="$( sha256 "${nnc1}${c1}" )" 10 | 11 | bc_ecdsa ${bc_env[contract_hash]} <<<" \ 12 | contracthash_sign_api(${k0}, ${tw1}, ${z1}, ${d1}, contract[]); \ 13 | nnc1[0] = contract[0]; \ 14 | nnc1[1] = contract[1]; \ 15 | sig1[0] = contract[2]; \ 16 | sig1[1] = contract[3]; \ 17 | compresspoint(nnc1[]); \ 18 | ecdsa_sig2der(sig1[0], sig1[1]);" 19 | } 20 | 21 | contracthash_verify () 22 | { 23 | local -u z1="$1" pub="$2" nnc1="$3" sig1="$4" c1="$5" tw1 24 | 25 | tw1="$( sha256 "${nnc1}${c1}" )" 26 | # decho "tw1 = ${tw1}" 27 | bc_ecdsa ${bc_env[contract_hash]} <<<" \ 28 | contracthash_verify_api(${z1}, ${pub}, ${nnc1}, ${sig1}, ${tw1})" 29 | } 30 | 31 | contracthash_recoverk () 32 | { 33 | local -u z1="$1" nnc1="$2" sig1="$3" c1="$4" sig2="$5" c2="$6" tw1 tw2 34 | 35 | tw1="$( sha256 "${nnc1}${c1}" )" 36 | tw2="$( sha256 "${nnc1}${c2}" )" 37 | bc_ecdsa ${bc_env[contract_hash]} <<<" \ 38 | contracthash_recover_k(${z1}, ${sig1}, ${tw1}, ${sig2}, ${tw2}, curve_n);" 39 | } 40 | 41 | contracthash_auth_sign () 42 | { 43 | local -u d0="$1" c1="$2" z1="$3" k0 nnc1 tw1 c2 d1 p1 44 | 45 | # c2="$( sha256 "$(data_compsize ${#c1})${c1}" )" 46 | d1="$( key_wif2priv "${d0}" )" 47 | p1="$( key_wif2pub "${d0}" )" 48 | # k0="$( rfc6979_secp256k1_sha256_k "${d1}" "$( sha256 "${z1}${c2}" )" )" 49 | k0="$( rfc6979_secp256k1_sha256_k "${d1}" "$( sha256 "${z1}${c1}" )" )" 50 | nnc1="$( key_priv2pub ${k0} )" 51 | # tw1="$( sha256 "${nnc1}${c2}" )" 52 | tw1="$( sha256 "${nnc1}${c1}" )" 53 | 54 | bc_ecdsa ${bc_env[contract_hash]} <<<" \ 55 | contracthash_sign_api(${k0}, ${tw1}, ${z1}, ${d1}, contract[]); \ 56 | nnc1[0] = contract[0]; \ 57 | nnc1[1] = contract[1]; \ 58 | sig1[0] = contract[2]; \ 59 | sig1[1] = contract[3]; \ 60 | compresspoint(nnc1[]); \ 61 | ecdsa_sig2der(sig1[0], sig1[1]);" 62 | } 63 | 64 | contracthash_auth_verify () 65 | { 66 | local -u z1="$1" a1="$2" nnc1="$3" sig1="$4" s1 r1 c1 tw1 67 | local -au rec1 der1 68 | 69 | der1=$( der2sig "${sig1}" ) 70 | readarray -t < <( recover "${z1}" "${der1[0]}" "${der1[1]}" ) 71 | 72 | tw1="$( sha256 "${nnc1}${c1}" )" 73 | bc_ecdsa ${bc_env[contract_hash]} <<<" \ 74 | contracthash_verify_api(${z1}, ${pub}, ${nnc1}, ${sig1}, ${tw1})" 75 | } 76 | -------------------------------------------------------------------------------- /bc/logic/.tests/test_bitwise_logic.bc: -------------------------------------------------------------------------------- 1 | #!/use/bin/bc 2 | 3 | define testbwand(){ 4 | 5 | auto bool; 6 | bool = 1; 7 | print "Test bwnad()\n"; 8 | 9 | bool *= ( bwand(0, 0) == 0 ); 10 | bool *= ( bwand(1, 0) == 0 ); 11 | bool *= ( bwand(0, 1) == 0 ); 12 | bool *= ( bwand(1, 1) == 1 ); 13 | 14 | return bool; 15 | } 16 | 17 | define testbwor(){ 18 | 19 | auto bool; 20 | bool = 1; 21 | print "Test bwor()\n"; 22 | 23 | bool *= ( bwor(0, 0) == 0 ); 24 | bool *= ( bwor(1, 0) == 1 ); 25 | bool *= ( bwor(0, 1) == 1 ); 26 | bool *= ( bwor(1, 1) == 1 ); 27 | 28 | return bool; 29 | } 30 | 31 | define testbwxor(){ 32 | 33 | auto bool; 34 | bool = 1; 35 | print "Test bwxor()\n"; 36 | 37 | bool *= ( bwxor(0, 0) == 0 ); 38 | bool *= ( bwxor(1, 0) == 1 ); 39 | bool *= ( bwxor(0, 1) == 1 ); 40 | bool *= ( bwxor(1, 1) == 0 ); 41 | 42 | return bool; 43 | } 44 | 45 | define testbwnot(){ 46 | 47 | auto bool; 48 | bool = 1; 49 | print "Test bwnot()\n"; 50 | 51 | bool *= ( bwnot(0) == 1 ); 52 | bool *= ( bwnot(1) == 0 ); 53 | 54 | return bool; 55 | } 56 | 57 | define testbwnand(){ 58 | 59 | auto bool; 60 | bool = 1; 61 | print "Test bwnand()\n"; 62 | 63 | bool *= ( bwnand(0, 0) == 1 ); 64 | bool *= ( bwnand(1, 0) == 1 ); 65 | bool *= ( bwnand(0, 1) == 1 ); 66 | bool *= ( bwnand(1, 1) == 0 ); 67 | 68 | return bool; 69 | } 70 | 71 | define testbwnor(){ 72 | 73 | auto bool; 74 | bool = 1; 75 | print "Test bwnor()\n"; 76 | 77 | bool *= ( bwnor(0, 0) == 1 ); 78 | bool *= ( bwnor(1, 0) == 0 ); 79 | bool *= ( bwnor(0, 1) == 0 ); 80 | bool *= ( bwnor(1, 1) == 0 ); 81 | 82 | return bool; 83 | } 84 | 85 | define testbwxnor(){ 86 | 87 | auto bool; 88 | bool = 1; 89 | print "Test bwxnor()\n"; 90 | 91 | bool *= ( bwxnor(0, 0) == 1 ); 92 | bool *= ( bwxnor(1, 0) == 0 ); 93 | bool *= ( bwxnor(0, 1) == 0 ); 94 | bool *= ( bwxnor(1, 1) == 1 ); 95 | 96 | return bool; 97 | } 98 | 99 | define test_bitwise_logic_bc(){ 100 | 101 | auto bool; 102 | bool = 1; 103 | 104 | bool *= testbwand(); 105 | bool; 106 | bool *= testbwor(); 107 | bool; 108 | bool *= testbwxor(); 109 | bool; 110 | bool *= testbwnot(); 111 | bool; 112 | bool *= testbwnand(); 113 | bool; 114 | bool *= testbwnor(); 115 | bool; 116 | bool *= testbwxnor(); 117 | bool; 118 | 119 | return bool; 120 | } 121 | 122 | test_bitwise_logic_bc() 123 | -------------------------------------------------------------------------------- /bc/base/helpers.bc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bc 2 | 3 | # some basic useful functions 4 | 5 | define max(a, b){ 6 | 7 | if ( a > b ){ 8 | return a 9 | } else { 10 | return b 11 | } 12 | } 13 | 14 | define min(a, b){ 15 | 16 | if ( a < b ){ 17 | return a 18 | } else { 19 | return b 20 | } 21 | } 22 | 23 | define void left_pad(n, len){ 24 | 25 | auto i; 26 | i = wordlen(n); 27 | 28 | while ( len-i >= 1F ){ 29 | 30 | print "0000000000000000000000000000000"; 31 | i += 1F; 32 | } 33 | 34 | while ( len-i >= F ){ 35 | 36 | print "000000000000000"; 37 | i += F; 38 | } 39 | 40 | while ( len-i >= 7 ){ 41 | 42 | print "0000000"; 43 | i += 7; 44 | } 45 | 46 | while ( len-i >= 3 ){ 47 | 48 | print "000"; 49 | i += 3; 50 | } 51 | 52 | while ( len-i >= 1 ){ 53 | 54 | print "0"; 55 | i += 1; 56 | } 57 | 58 | n; 59 | } 60 | 61 | define right_pad(n, len){ 62 | 63 | return n*10^(len-wordlen(n)); 64 | } 65 | 66 | define ecdsa_sig2der(r, s){ 67 | 68 | auto lenr, bigr, lens, bigs, dersig, siglen; 69 | 70 | lenr = bytelen(r); 71 | lens = bytelen(s); 72 | 73 | if ( r > 7F && (r / (100 ^ (lenr - 1)) > 7F) ){ 74 | bigr = 1; 75 | } 76 | if ( s > 7F && (s / (100 ^ (lens - 1)) > 7F) ){ 77 | bigs = 1; 78 | } 79 | siglen = 2 + bigr + lenr + 2 + bigs + lens; 80 | dersig = 3000 + siglen; 81 | dersig *= 100; 82 | dersig += 02; 83 | dersig *= 100; 84 | dersig += bigr + lenr; 85 | if (bigr == 1){ 86 | dersig *= 100; 87 | } 88 | dersig *= 10 ^ (lenr * 2); 89 | dersig += r; 90 | dersig *= 100; 91 | dersig += 02 92 | dersig *= 100; 93 | dersig += bigs + lens; 94 | if (bigs == 1){ 95 | dersig *= 100; 96 | } 97 | dersig *= 10 ^ (lens * 2); 98 | dersig += s; 99 | 100 | return dersig; 101 | } 102 | 103 | define void ecdsa_der2sig(dersig, *sig[]){ 104 | 105 | auto lensig, size_dersig_bytes, lenr, r, lens, s, tmp; 106 | 107 | size_dersig_bytes = bytelen(dersig); 108 | lensig = dersig / (100 ^ (size_dersig_bytes - 2)) % 100; 109 | if ((lensig + 2) < size_dersig_bytes){ 110 | dersig /= (100 ^ (size_dersig_bytes - lensig - 2)); 111 | } 112 | lenr = dersig / (100 ^ (lensig - 2)) % 100; 113 | lens = dersig / (100 ^ (lensig - 2 - lenr - 2)) % 100; 114 | 115 | sig[1] = dersig % (100 ^ lens); 116 | dersig /= (100 ^ (lens + 2)); 117 | sig[0] = dersig % (100 ^ lenr); 118 | } 119 | -------------------------------------------------------------------------------- /bitcoin/script/script_num.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | script_is_bignum () 4 | { 5 | if [[ ! ${1} =~ ^-?[0-9]+$ ]]; then 6 | return 1 7 | fi 8 | if (( ( ${1} > -(2**31) ) && ( ${1} < (2**31) ) )); then 9 | return 0 10 | else 11 | return 1 12 | fi 13 | } 14 | 15 | script_is_opnum () 16 | { 17 | if [[ ! ${1} =~ ^[0-9][1-6]?$ ]]; then 18 | return 1 19 | fi 20 | if (( ( ${1} >= -1 ) && ( ${1} <= 16 ) )); then 21 | return 0 22 | else 23 | return 1 24 | fi 25 | } 26 | 27 | script_ser_num () 28 | { 29 | local -u sernum 30 | 31 | if script_is_opnum "${1}"; then 32 | 33 | echo "0x${op_num[${1}]}" 34 | return 35 | fi 36 | 37 | read sernum < <( bc_bitcoin <<<" 38 | obase=A; ibase=A; 39 | n=${1}; 40 | obase=16; ibase=16; 41 | ser_num(n);" ) 42 | 43 | read sernum < <( revchunks "${sernum}" ) 44 | data_pushdata "${sernum}" 45 | } 46 | 47 | tx_ser_int () 48 | { 49 | if (( "${1}" > (2**32)-1 )); then 50 | 51 | echo "error: tx_ser_int: int > 2^32-1" >&2 52 | return 53 | fi 54 | 55 | local -u serint 56 | 57 | read serint < <( bc_encode <<<" 58 | ibase=A; 59 | num=${1}; 60 | ibase=16; 61 | left_pad(num, 8);" ) 62 | read serint < <( revchunks "${serint}" ) 63 | 64 | echo "${serint}" 65 | } 66 | 67 | tx_deser_int () 68 | { 69 | local -u int 70 | 71 | read int < <( revchunks "${1}" ) 72 | bc_clean <<<"obase=A; ibase=16; ${int}" 73 | } 74 | 75 | num2compsize() { 76 | 77 | local -u size="${1}" 78 | 79 | read size < <( bc_bitcoin <<<"x=${size}; compsize(x);" ) 80 | 81 | echo -n "${size:0:2}" 82 | revchunks <<<"${size:2}" 83 | } 84 | 85 | dec2amount() { 86 | 87 | local decimal revamount 88 | if [[ "${1}" == "" ]] 89 | then 90 | read decimal 91 | else 92 | decimal="${1}" 93 | fi 94 | 95 | read revamount < <( bc_encode <<<" 96 | ibase=A; 97 | bal=${decimal}*100000000; 98 | ibase=16; 99 | left_pad(bal/1,10);" ) 100 | 101 | revchunks "${revamount}" 102 | } 103 | 104 | amount2dec() { 105 | 106 | local hexamount revamount 107 | if [[ "${1}" == "" ]] 108 | then 109 | read hexamount 110 | else 111 | hexamount="${1}" 112 | fi 113 | 114 | read revamount < <( revchunks "${hexamount}" ) 115 | 116 | bc_clean <<<" 117 | scale=8; 118 | satoshi=100000000; 119 | ibase=16; 120 | print ${revamount}/satoshi, \"\\n\";" 121 | } 122 | -------------------------------------------------------------------------------- /ecdsa/.tests/test_rfc6979.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | testrfc6979_sign(){ 4 | 5 | local -u key="${1}" datahex msg 6 | local databin="${2}" 7 | local -au kval 8 | 9 | read datahex < <( echo -n "${databin}" | bin2hex ) 10 | sign "${key}" "${datahex}" 11 | } 12 | 13 | testrfc6979() 14 | { 15 | testrfc6979_sign "1" "Satoshi Nakamoto" 16 | # data="5361746F736869204E616B616D6F746F" 17 | testrfc6979_sign "1" "All those moments will be lost in time, like tears in rain. Time to die..." 18 | # data="416C6C2074686F7365206D6F6D656E74732077696C6C206265206C6F737420696E2074696D652C206C696B6520746561727320696E207261696E2E2054696D6520746F206469652E2E2E" 19 | testrfc6979_sign "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364140" "Satoshi Nakamoto" 20 | # data="5361746F736869204E616B616D6F746F" 21 | 22 | testrfc6979_sign "F8B8AF8CE3C7CCA5E300D33939540C10D45CE001B8F252BFBC57BA0342904181" "Alan Turing" 23 | # data="416C616E20547572696E67" 24 | 25 | testrfc6979_sign "E91671C46231F833A6406CCBEA0E3E392C76C167BAC1CB013F6F1013980455C2" "There is a computer disease that anybody who works with computers knows about. It's a very serious disease and it interferes completely with the work. The trouble with computers is that you 'play' with them!" 26 | # data="5468657265206973206120636F6D70757465722064697365617365207468617420616E79626F64792077686F20776F726B73207769746820636F6D707574657273206B6E6F77732061626F75742E20497427732061207665727920736572696F7573206469736561736520616E6420697420696E746572666572657320636F6D706C6574656C7920776974682074686520776F726B2E205468652074726F75626C65207769746820636F6D707574657273206973207468617420796F752027706C6179272077697468207468656D21" 27 | } 28 | 29 | testrfc6979_secp256k1_sha256() 30 | { 31 | local -a ret 32 | readarray -t ret < <( testrfc6979 ) 33 | 34 | [[ "${ret[0]}" == "3045022100934B1EA10A4B3C1757E2B0C017D0B6143CE3C9A7E6A4A49860D7A6AB210EE3D802202442CE9D2B916064108014783E923EC36B49743E2FFA1C4496F01A512AAFD9E5" ]] && \ 35 | [[ "${ret[1]}" == "30450221008600DBD41E348FE5C9465AB92D23E3DB8B98B873BEECD930736488696438CB6B0220547FE64427496DB33BF66019DACBF0039C04199ABB0122918601DB38A72CFC21" ]] && \ 36 | [[ "${ret[2]}" == "3045022100FD567D121DB66E382991534ADA77A6BD3106F0A1098C231E47993447CD6AF2D002206B39CD0EB1BC8603E159EF5C20A5C8AD685A45B06CE9BEBED3F153D10D93BED5" ]] && \ 37 | [[ "${ret[3]}" == "304402207063AE83E7F62BBB171798131B4A0564B956930092B33B07B395615D9EC7E15C022058DFCC1E00A35E1572F366FFE34BA0FC47DB1E7189759B9FB233C5B05AB388EA" ]] && \ 38 | [[ "${ret[4]}" == "3045022100B552EDD27580141F3B2A5463048CB7CD3E047B97C9F98076C32DBDF85A68718B0220279FA72DD19BFAE05577E06C7C0C1900C371FCD5893F7E1D56A37D30174671F6" ]] 39 | } 40 | 41 | testrfc6979_secp256k1_sha256 || return 1 42 | -------------------------------------------------------------------------------- /bitcoin/jsonrpc/sign_message.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | core_signmessage_sig2core () 4 | { 5 | hex2bin "${1^^}${2^^}${3^^}" | base64 -w0; echo 6 | } 7 | 8 | core_signmessage_core2sig () 9 | { 10 | local -u hexsig r s recovery="${2}" 11 | # decho "${1%===*}" 12 | read hexsig < <( echo -n "${1%===*}" | base64 -d -w0 | bin2hex ) 13 | # decho "hexsig : ${hexsig}" 14 | echo "${hexsig:2:64}" "${hexsig:66}" "${recovery:+${hexsig:0:2}}" 15 | } 16 | 17 | # header = "Bitcoin Signed Message:\n" 18 | # header_length = 0x18 19 | # header_hex = 0x18426974636F696E205369676E6564204D6573736167653A0A 20 | # body = text_length + text 21 | # message = header + body 22 | core_signmessage_sighash () 23 | { 24 | local -u text_hex size 25 | 26 | read text_hex < <( echo -n "$1" | bin2hex ) 27 | read size < <( data_compsize "${#text_hex}" ) 28 | # decho "z0 = 18426974636F696E205369676E6564204D6573736167653A0A${size}${text_hex}" 29 | sha256 "18426974636F696E205369676E6564204D6573736167653A0A${size}${text_hex}" 30 | } 31 | 32 | core_signmessage_hex () 33 | { 34 | local -u d="$1" sighash k z 35 | local text="$2" 36 | 37 | read sighash < <( core_signmessage_sighash "${text}" ) 38 | read k < <( rfc6979_secp256k1_sha256_k "${d}" "${sighash}" ) 39 | read z < <( sha256 "${sighash}" ) 40 | bc_ecdsa <<<"\ 41 | ecdsa_sign_recoverable(${k}, ${z}, ${d}, ${3:-1}, sig[]); \ 42 | sig[2]; left_pad(sig[0], 40); left_pad(sig[1], 40);" 43 | } 44 | 45 | core_signmessage () 46 | { 47 | local -u hexsig 48 | readarray -t hexsig < <( core_signmessage_hex "$1" "$2" "${3:-1}" ) 49 | core_signmessage_sig2core ${hexsig[@]} 50 | } 51 | 52 | core_signmessage_recover_all_pubkeys () 53 | { 54 | local -u r s msg 55 | 56 | read r s < <( core_signmessage_core2sig "$1" ) 57 | read msg < <( core_signmessage_sighash "$2" | sha256 ) 58 | bc_ecdsa <<<"ecdsa_recover(${msg}, ${r}, ${s});" 59 | } 60 | 61 | core_signmessage_recover_pubkey () 62 | { 63 | local -u r s recid z 64 | 65 | read r s recid < <( core_signmessage_core2sig "$1" 'recid' ) 66 | read z < <( core_signmessage_sighash "$2" | sha256 ) 67 | bc_ecdsa ${bc_env[bitwise_logic]} <<<"ecdsa_verify_recoverable_getpub(${z}, ${recid}${r}${s});" 68 | } 69 | 70 | core_signmessage_verify () 71 | { 72 | local addr="$1" sig="$2" msg="$3" pubkey 73 | read pubkey < <( core_signmessage_recover_pubkey "${sig}" "${msg}" ) 74 | if [[ "$(key_pub2addr ${pubkey})" != "${addr}" ]]; then 75 | echo 0 76 | return 1 77 | else 78 | # not needed since recovery and checking against the address is enough 79 | # local dersig="$( sig2der "${r}" "${s}" )" 80 | # verify "${z}" "${pubkey}" "${dersig}" 81 | ### 82 | echo 1 83 | return 0 84 | fi 85 | } 86 | -------------------------------------------------------------------------------- /bc/ec_math/curves/koblitz.bc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bc 2 | 3 | define void secp256k1(){ 4 | 5 | # secp256k1_p 6 | secp256k1[0] = FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F; 7 | # secp256k1_a 8 | secp256k1[1] = 0000000000000000000000000000000000000000000000000000000000000000; 9 | # secp256k1_b 10 | secp256k1[2] = 0000000000000000000000000000000000000000000000000000000000000007; 11 | # secp256k1_g 12 | secp256k1[3] = 0279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798; 13 | # secp256k1_gx 14 | secp256k1[4] = 79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798; 15 | # secp256k1_gy 16 | secp256k1[5] = 483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8; 17 | # secp256k1_n 18 | secp256k1[6] = FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141; 19 | # secp256k1_h 20 | secp256k1[7] = 01; 21 | # secp256k1_words 22 | secp256k1[8] = 40; 23 | 24 | # curve_words = 40; 25 | } 26 | 27 | define void secp160k1(){ 28 | 29 | secp160k1[0] = FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73; 30 | secp160k1[1] = 0000000000000000000000000000000000000000; 31 | secp160k1[2] = 0000000000000000000000000000000000000007; 32 | secp160k1[3] = 023B4C382CE37AA192A4019E763036F4F5DD4D7EBB; 33 | secp160k1[4] = 3B4C382CE37AA192A4019E763036F4F5DD4D7EBB; 34 | secp160k1[5] = 938CF935318FDCED6BC28286531733C3F03C4FEE; 35 | secp160k1[6] = 0100000000000000000001B8FA16DFAB9ACA16B6B3; 36 | secp160k1[7] = 01; 37 | secp160k1[8] = 28; 38 | } 39 | 40 | define void secp192k1(){ 41 | 42 | secp192k1[0] = FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFEE37; 43 | secp192k1[1] = 000000000000000000000000000000000000000000000000; 44 | secp192k1[2] = 000000000000000000000000000000000000000000000003; 45 | secp192k1[3] = 03DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D; 46 | secp192k1[4] = DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D; 47 | secp192k1[5] = 9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D; 48 | secp192k1[6] = FFFFFFFFFFFFFFFFFFFFFFFE26F2FC170F69466A74DEFD8D; 49 | secp192k1[7] = 01; 50 | secp192k1[8] = 30 51 | } 52 | 53 | define void secp224k1(){ 54 | 55 | secp224k1[0] = FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFE56D; 56 | secp224k1[1] = 00000000000000000000000000000000000000000000000000000000; 57 | secp224k1[2] = 00000000000000000000000000000000000000000000000000000005; 58 | secp224k1[3] = 03A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C; 59 | secp224k1[4] = A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C; 60 | secp224k1[5] = 7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5; 61 | secp224k1[6] = 010000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7; 62 | secp224k1[7] = 01; 63 | secp224k1[8] = 38; 64 | } 65 | -------------------------------------------------------------------------------- /hash/.tests/test_hexhash.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source "$( cd "$( dirname "${BASH_SOURCE[0]}" )" && echo $PWD )/input_hexhash.sh" 4 | 5 | test_sha224() 6 | { 7 | test_hashfunc sha224 "${btests_sha224[*]}" "${htests_sha224[*]}" "${ret_sha224[*]}" 8 | return $? 9 | } 10 | 11 | test_sha256() 12 | { 13 | test_hashfunc sha256 "${btests_sha256[*]}" "${htests_sha256[*]}" "${ret_sha256[*]}" 14 | return $? 15 | } 16 | 17 | test_sha384() 18 | { 19 | test_hashfunc sha384 "${btests_sha384[*]}" "${htests_sha384[*]}" "${ret_sha384[*]}" 20 | return $? 21 | } 22 | 23 | test_sha512() 24 | { 25 | test_hashfunc sha512 "${btests_sha512[*]}" "${htests_sha512[*]}" "${ret_sha512[*]}" 26 | return $? 27 | } 28 | 29 | test_ripemd160() 30 | { 31 | local tval emptyhash='9C1185A5C5E9FC54612808977EE8F548B2258D31' 32 | read tval < <( printf "" | ripemd160 ) 33 | if [[ "${tval}" != "${emptyhash}" ]]; then 34 | printf '%s != %s\n%s != %s\n' "\${tval}" "\${emptyhash}" \ 35 | "${tval}" "${emptyhash}" 36 | return 1 37 | fi 38 | test_hashfunc ripemd160 "${btests_rmd160[*]}" "${htests_rmd160[*]}" "${ret_rmd160[*]}" 39 | return $? 40 | } 41 | 42 | test_hash160() 43 | { 44 | test_hashfunc hash160 "${btests_hash160[*]}" "${htests_hash160[*]}" "${ret_hash160[*]}" 45 | return $? 46 | } 47 | 48 | test_hash256() 49 | { 50 | test_hashfunc hash256 "${btests_hash256[*]}" "${htests_hash256[*]}" "${ret_hash256[*]}" 51 | return $? 52 | } 53 | 54 | test_hashfunc() 55 | { 56 | local -i flag=0 57 | local hashfunc="$1" tval 58 | local -a bintests=( $2 ) hextests=( $3 ) retvals=( $4 ) 59 | 60 | # hash binary 61 | local -i i 62 | for (( i=0; i<${#bintests[@]}; i++)); do 63 | read tval < <( printf "${bintests[$i]//_/ }" | bin2hex | ${hashfunc} ) 64 | if [[ "${tval}" != "${retvals[$i]}" ]]; then 65 | printf '%s != %s\n%s != %s\n' "\${bintests[$i]}" "\${ret_${hashfunc}[$i]}" \ 66 | "${tval}" "${retvals[$i]}" 67 | return 1 68 | fi 69 | done 70 | 71 | # hash hex 72 | for (( k=0 ; k<${#hextests[@]}; k++, i++ )); do 73 | read tval < <( printf "${hextests[$k]}" | ${hashfunc} ) 74 | if [[ "${tval}" != "${retvals[$i]}" ]]; then 75 | printf '%s != %s\n%s != %s\n' "\${hextests[$k]}" "\${ret_${hashfunc}[$i]}" \ 76 | "${tval}" "${retvals[$i]}" 77 | return 1 78 | fi 79 | done 80 | } 81 | 82 | test_hexhash() 83 | { 84 | local -a tests=( test_sha224 test_sha256 test_sha384 test_sha512 test_ripemd160 test_hash160 test_hash256 ) 85 | for testi in ${tests[@]}; do 86 | if ! ${testi}; then 87 | printf '%s\n' "error: ${testi//test_/}" 88 | return 1 89 | fi 90 | done 91 | } 92 | test_hexhash || return 1 93 | -------------------------------------------------------------------------------- /base/.tests/test_int_convert.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | test_bits2int() 4 | { 5 | local -au vector 6 | 7 | local -u tb2i vb2i 8 | for bits in {1,10,101,1011,10101}; do 9 | 10 | readarray -t vector < <( for i in {1..64}; do input_mkbitmap ${bits} $i; done ) 11 | for vect in ${vector[@]}; do 12 | 13 | read tb2i < <( bits2int "${vect}" ) 14 | read vb2i < <( bc_clean <<<"obase=2; ibase=16; ${tb2i};" ) 15 | 16 | if [[ "${vb2i}" != "${vect}" ]]; then 17 | printf '%s != %s\n%s != %s\n' '${vb2i}' '${vect}' \ 18 | "${vb2i}" "${vect}" 19 | return 1 20 | fi 21 | done 22 | done 23 | } 24 | 25 | test_int2octets() 26 | { 27 | local -ua vectors 28 | local -u ti2o vi2o 29 | printf -v vectors[0] '%02X ' {0..255} 30 | printf -v vectors[1] '%s%02X ' '0100000000000000' {0..255} 31 | printf -v vectors[2] '%s%02X ' 'FF000000' {0..255} 32 | 33 | for i in {0..2}; do 34 | for v in ${vectors[$i]}; do 35 | read ti2o < <( int2octets ${v} 64 ) 36 | read vi2o < <( bc_clean <<<"obase=16; ibase=16; ${ti2o};" ) 37 | read vi2o < <( int2octets ${vi2o} 64 ) 38 | if [[ "${ti2o}" != "${vi2o}" ]]; then 39 | printf '%s != %s\n%s != %s\n' '${ti2o}' '${vi2o}' \ 40 | "${ti2o}" "${vi2o}" 41 | return 1 42 | fi 43 | done 44 | done 45 | } 46 | 47 | test_bits2octets() 48 | { 49 | local -u tb2o vb2o 50 | local -u q=FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 51 | 52 | for bits in {1,10,101,1011,10101}; do 53 | for i in {1..256}; do 54 | read tb2o < <( bits2octets "$(input_mkbitmap ${bits} $i)" "$q" ) 55 | read vb2o < <( bc_clean <<<"obase=2; ibase=16; ${tb2o};" ) 56 | read vb2o < <( bits2int "${vb2o}" ) 57 | if (( $( bc_clean <<<"ibase=16; (${vb2o} != ${tb2o})") )); then 58 | printf '%s != %s\n%s != %s\n' '${vb2o}' '${tb2o}' \ 59 | "${vb2o}" "${tb2o}" 60 | return 1 61 | fi 62 | if (( ${#tb2o} != ${#q} )); then 63 | printf '%s != %s\n%s != %s\n' '${#vb2o}' '${#tb2o}' \ 64 | "${#vb2o}" "${#tb2o}" 65 | return 1 66 | fi 67 | done 68 | done 69 | } 70 | 71 | test_int_convert() 72 | { 73 | local -a tests=( "test_bits2int" "test_int2octets" "test_bits2octets" ) 74 | for testi in ${tests[@]}; do 75 | if ! ${testi}; then 76 | printf '%s\n' "error: ${testi//test_/}" 77 | return 1 78 | fi 79 | done 80 | } 81 | test_int_convert || return 1 82 | -------------------------------------------------------------------------------- /bc/bc_env.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | bc_home="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && echo $PWD )" 4 | # bc_prog="$HOME/software/deps/bc-1.07.1/bc/bc" 5 | 6 | export BC_LINE_LENGTH=0 7 | bc_flags="-q" 8 | unset bc_env 9 | declare -A bc_env=( 10 | [config]="${bc_home}/config.bc" 11 | [conversion]="${bc_home}/base/conversion.bc" 12 | [helpers]="${bc_home}/base/helpers.bc" 13 | [bitcoin]="${bc_home}/bitcoin/bitcoin_funcs.bc" 14 | [bitwise_logic]="${bc_home}/logic/bitwise_logic.bc" 15 | [shift_rot]="${bc_home}/logic/shift_rot.bc" 16 | [hmac_conf]="${bc_home}/hash/hmac_conf.bc" 17 | [hmac]="${bc_home}/hash/hmac.bc" 18 | [math_mod]="${bc_home}/math/math_mod.bc" 19 | [extended_euclidean]="${bc_home}/math/extended_euclidean.bc" 20 | [tonelli_shanks]="${bc_home}/math/tonelli_shanks.bc" 21 | [root_mod]="${bc_home}/math/root_mod.bc" 22 | [endomorphism]="${bc_home}/ec_math/endomorphism.bc" 23 | [ec_point]="${bc_home}/ec_math/ec_point.bc" 24 | [ec_math]="${bc_home}/ec_math/ec_math.bc" 25 | [jacobian]="${bc_home}/ec_math/jacobian.bc" 26 | [ecdsa]="${bc_home}/ecdsa/ecdsa.bc" 27 | [contract_hash]="${bc_home}/ecdsa/contract_hash.bc" 28 | [koblitz]="${bc_home}/ec_math/curves/koblitz.bc" 29 | [ec_schnorr]="${bc_home}/schnorr/ec_schnorr.bc" 30 | [activate]="${bc_home}/activate.bc" ) 31 | 32 | unset BC_ENV_ARGS; 33 | export BC_ENV_ARGS="${bc_flags} ${bc_env[config]} ${bc_env[conversion]} ${bc_env[helpers]} ${bc_env[bitwise_logic]} ${bc_env[shift_rot]} ${bc_env[hmac_conf]} ${bc_env[hmac]} ${bc_env[math_mod]} ${bc_env[extended_euclidean]} ${bc_env[tonelli_shanks]} ${bc_env[root_mod]} ${bc_env[endomorphism]} ${bc_env[ec_point]} ${bc_env[ec_math]} ${bc_env[jacobian]} ${bc_env[ecdsa]} ${bc_env[ec_schnorr]} ${bc_env[koblitz]} ${bc_env[activate]}" 34 | 35 | alias bc="${bc_prog}" 36 | alias bc_clean="BC_ENV_ARGS='-q' bc" 37 | alias bc_encode="bc_clean ${bc_env[config]} ${bc_env[conversion]} ${bc_env[helpers]}" 38 | alias bc_bitcoin="bc_encode ${bc_env[bitcoin]}" 39 | alias bc_hmac="bc_encode ${bc_env[bitwise_logic]} ${bc_env[hmac_conf]} ${bc_env[hmac]} ${bc_env[koblitz]} ${bc_env[activate]}" 40 | 41 | # alias _bc_math="bc_encode ${bc_env[math_mod]} ${bc_env[tonelli_shanks]} ${bc_env[root_mod]}" 42 | # bc_math () 43 | # { 44 | # _bc_math "${bc_env[koblitz]}" "${bc_env[activate]}" 45 | # } 46 | 47 | alias _bc_ecpoint="bc_encode ${bc_env[math_mod]} ${bc_env[tonelli_shanks]} ${bc_env[root_mod]} ${bc_env[endomorphism]} ${bc_env[ec_point]}" 48 | bc_ecpoint () 49 | { 50 | _bc_ecpoint "${bc_env[koblitz]}" "${bc_env[activate]}" 51 | } 52 | alias _bc_ecmath="_bc_ecpoint ${bc_env[ec_math]}" 53 | 54 | bc_ecmath () 55 | { 56 | _bc_ecmath "${bc_env[koblitz]}" "${bc_env[activate]}" 57 | } 58 | 59 | alias bc_ecdsa="_bc_ecmath ${bc_env[ecdsa]} ${bc_env[koblitz]} ${bc_env[activate]}" 60 | alias bc_ecschnorr="_bc_ecmath ${bc_env[ec_schnorr]} ${bc_env[koblitz]} ${bc_env[activate]}" 61 | -------------------------------------------------------------------------------- /bitcoin/script/core_ifc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | core_gen_kchain () 4 | { 5 | local addr privkey 6 | local -u pubkey 7 | rm ./addrs.list ./pubkeys.list ./privkeys.list 8 | while read -r line; do 9 | if [[ ! "${line}" =~ "addr" ]]; then 10 | continue 11 | fi 12 | addr="${line#*addr=}" 13 | addr="${addr% *}" 14 | read pubkey < <( core_addr2pubkey "${addr}" ) 15 | read privkey < <( core_addr2privkey "${addr}" ) 16 | echo "${addr}" >> addrs.list 17 | echo "${pubkey}" >> pubkeys.list 18 | echo "${privkey}" >> privkeys.list 19 | done < "./corewallet.txt" 20 | } 21 | 22 | core_dump_wallet () 23 | { 24 | "${clientname}"-cli dumpwallet "${PWD}/corewallet.txt" 25 | } 26 | 27 | core_get_inputs () 28 | { 29 | "${clientname}"-cli listunspent > inputs.json 30 | } 31 | 32 | core_json_rhs () 33 | { 34 | local rhs 35 | rhs="${1//[ ^\",]/}" 36 | echo -n "${rhs#*:}" 37 | } 38 | 39 | inputs_get_balance () 40 | { 41 | local balance total="0" 42 | while read -r line; do 43 | if [[ ! "${line}" =~ "amount" ]]; then 44 | continue 45 | fi 46 | read balance < <( core_json_rhs "${line}" ) 47 | read total < <( bc_clean <<<" 48 | scale=8 49 | total=${total}+${balance}; \ 50 | total;" ) 51 | done < "./inputs.json" 52 | echo "${total}" 53 | } 54 | 55 | inputs_reduce_balance () 56 | { 57 | bc_clean <<< "scale=8; ${1} - ${2};" 58 | } 59 | 60 | core_addr2privkey () 61 | { 62 | "${clientname}"-cli dumpprivkey "${1}" 63 | } 64 | 65 | core_addr2pubkey () 66 | { 67 | local -a retjson 68 | readarray retjson < <( "${clientname}"-cli validateaddress "${1}" ) 69 | while read -r line; do 70 | if [[ ! "${line}" =~ "pubkey" ]]; then 71 | continue 72 | fi 73 | core_json_rhs "${line^^}" 74 | done <<< "${retjson[@]}" 75 | } 76 | 77 | declare -a kc_addrs kc_pubks kc_prvks 78 | declare -i kc_ptr 79 | 80 | kchain_populate () 81 | { 82 | mapfile -t kc_addrs <"./addrs.list" 83 | mapfile -t kc_pubks <"./pubkeys.list" 84 | mapfile -t kc_prvks <"./privkeys.list" 85 | kc_pointer=0 86 | 87 | if (( "${#kc_addrs[@]}" != "${#kc_pubks[@]}" )) || \ 88 | (( "${#kc_pubks[@]}" != "${#kc_prvks[@]}" )); then 89 | 90 | unset kc_addrs kc_pubks kc_prvks kc_pointer 91 | echo "Error in keystore: list size mismatch" 92 | fi 93 | } 94 | 95 | kchain_get_address () 96 | { 97 | echo "${kc_addrs[${kc_ptr}]}" 98 | kc_ptr="$(( ${kc_ptr} + 1 ))" 99 | } 100 | 101 | kchain_get_pubkey () 102 | { 103 | echo "${kc_pubks[${kc_ptr}]}" 104 | kc_ptr="$(( ${kc_ptr} + 1 ))" 105 | } 106 | 107 | kchain_get_privkey () 108 | { 109 | echo "${kc_prvks[${kc_ptr}]}" 110 | kc_ptr="$(( ${kc_ptr} + 1 ))" 111 | } 112 | -------------------------------------------------------------------------------- /ecdsa/curves/koblitz.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | secp256k1() 4 | { 5 | declare -a secp256k1 6 | # secp256k1_p 7 | curve_p=FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F 8 | # secp256k1_a 9 | curve_a=0000000000000000000000000000000000000000000000000000000000000000 10 | # secp256k1_b 11 | curve_b=0000000000000000000000000000000000000000000000000000000000000007 12 | # secp256k1_g 13 | curve_g=0279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798 14 | # secp256k1_gx 15 | curve_gx=79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798 16 | # secp256k1_gy 17 | curve_gy=483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8 18 | # secp256k1_n 19 | curve_n=FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 20 | # secp256k1_h 21 | curve_h=01 22 | # secp256k1_words 23 | curve_words=64 24 | curve_one=0000000000000000000000000000000000000000000000000000000000000001 25 | curve_big=FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF 26 | } 27 | 28 | secp160k1() 29 | { 30 | declare -a secp160k1 31 | curve_p=FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73 32 | curve_a=0000000000000000000000000000000000000000 33 | curve_b=0000000000000000000000000000000000000007 34 | curve_g=023B4C382CE37AA192A4019E763036F4F5DD4D7EBB 35 | curve_gx=3B4C382CE37AA192A4019E763036F4F5DD4D7EBB 36 | curve_gy=938CF935318FDCED6BC28286531733C3F03C4FEE 37 | curve_n=0100000000000000000001B8FA16DFAB9ACA16B6B3 38 | curve_h=01 39 | curve_words=40 40 | curve_one=0000000000000000000000000000000000000001 41 | curve_big=FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF 42 | } 43 | 44 | secp192k1() 45 | { 46 | declare -a secp192k1 47 | curve_p=FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFEE37 48 | curve_a=000000000000000000000000000000000000000000000000 49 | curve_b=000000000000000000000000000000000000000000000003 50 | curve_g=03DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D 51 | curve_gx=DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D 52 | curve_gy=9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D 53 | curve_n=FFFFFFFFFFFFFFFFFFFFFFFE26F2FC170F69466A74DEFD8D 54 | curve_h=01 55 | curve_words=48 56 | curve_one=000000000000000000000000000000000000000000000001 57 | curve_big=FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF 58 | } 59 | 60 | secp224k1() 61 | { 62 | declare -a secp224k1 63 | curve_p=FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFE56D 64 | curve_a=00000000000000000000000000000000000000000000000000000000 65 | curve_b=00000000000000000000000000000000000000000000000000000005 66 | curve_g=03A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C 67 | curve_gx=A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C 68 | curve_gy=7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5 69 | curve_n=010000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7 70 | curve_h=01 71 | curve_words=56 72 | curve_one=00000000000000000000000000000000000000000000000000000001 73 | curve_big=FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF 74 | } 75 | -------------------------------------------------------------------------------- /ecdsa/ecdsa_ifc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # uncompressed pubkey -> compressed pubkey 4 | compresspubkey () 5 | { 6 | local -u x="${1:2:$(((${#1}/2)-1))}" y="${1:$(((${#1}/2)+1)):${#1}}" 7 | compresspoint "${x}" "${y}" 8 | } 9 | 10 | # x and y coordinates -> compressed pubkey 11 | compresspoint () 12 | { 13 | local -u x="$1" parity="${2:$((${#2}-1)):1}" 14 | parity="$((16#${parity}))" 15 | if (( ${parity} % 2 )); then 16 | echo "03${x}" 17 | else 18 | echo "02${x}" 19 | fi 20 | } 21 | 22 | # compressed pubkey -> x and y coordinates 23 | uncompresspoint () 24 | { 25 | bc_ecdsa <<<"uncompresspoint_api(${1^^}, pt[]); pt[0]; pt[1];" 26 | } 27 | 28 | # compressed pubkey -> uncompressed pubkey 29 | uncompresspubkey () 30 | { 31 | bc_ecdsa <<<"uncompresspoint(${1^^});" 32 | } 33 | 34 | # (r, s) -> DER signature 35 | sig2der () 36 | { 37 | bc_encode <<<"ecdsa_sig2der(${1^^}, ${2^^});" 38 | } 39 | 40 | # DER signature -> (r, s) 41 | der2sig () 42 | { 43 | bc_encode <<<"ecdsa_der2sig(${1^^}, sig[]); print sig[0], \" \", sig[1], \"\\n\";" 44 | } 45 | 46 | # (d, z) -> (r, s) 47 | # d : a private key 48 | # z : a message to sign (for bitcoin, this means sha256(message) 49 | sign_api () 50 | { 51 | local k m der="${3:-0}" 52 | read k < <( rfc6979_secp256k1_sha256_k "${1^^}" "${2^^}" ) 53 | read m < <( sha256 "${2^^}" ) 54 | bc_ecdsa <<<" 55 | ecdsa_sign(${k}, ${m}, ${1^^}, sig[]); 56 | if ( ${der} ){ 57 | ecdsa_sig2der(sig[0], sig[1]); 58 | } else { 59 | print sig[0], \" \", sig[1], \"\\n\"; 60 | }" 61 | } 62 | 63 | # same as the above, but returns a DER encoded signature 64 | sign () 65 | { 66 | sign_api "$1" "$2" '1' 67 | } 68 | 69 | # (z, pubkey, [ (r,s) | DER signature ]) -> {1, 0} 70 | # returns 1 on verification success or 0 on failure 71 | # the 3rd parameter can be either a DER encoded signature 72 | # or the 'r' value of the signature, in which case 73 | # the 4th parameter should be the 's' value 74 | verify () 75 | { 76 | local -u z1="$1" pubkey="$2" sig_r="$3" sig_s="$4" 77 | 78 | if [[ ${pubkey:0:2} == "04" ]]; then 79 | read pubkey < <( compresspubkey "${pubkey}" ) 80 | fi 81 | if [[ "${sig_s}" == "" ]]; then 82 | # DER signature as the 3rd parameter 83 | bc_ecdsa <<<"ecdsa_verify_der(${z1}, ${pubkey}, ${sig_r});" 84 | else 85 | bc_ecdsa <<<"ecdsa_verify(${z1}, ${pubkey}, ${sig_r}, ${sig_s});" 86 | fi 87 | } 88 | 89 | # (z, [ (r,s) | DER signature ]) -> pubkeys 90 | # returns recovered pubkeys off a message and signature 91 | # the 2nd parameter can be either a DER encoded signature 92 | # or the 'r' value of the signature, in which case 93 | # the 3rd parameter should be the 's' value 94 | recover () 95 | { 96 | local -u z1="$1" sig_r="$2" sig_s="$3" 97 | 98 | if [[ "${sig_s}" == "" ]]; then 99 | # DER signature as the 3rd parameter 100 | bc_ecdsa <<<"ecdsa_recover_der(${z1}, ${sig_r});" 101 | else 102 | bc_ecdsa <<<"ecdsa_recover(${z1}, ${sig_r}, ${sig_s});" 103 | fi 104 | } 105 | -------------------------------------------------------------------------------- /bc/logic/bitwise_logic.bc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bc 2 | 3 | # bitwise logic functions 4 | 5 | define void bwand_api(*arra[], *arrb[], *ret[]){ 6 | 7 | auto i; 8 | 9 | ret[0] = max(arra[0], arrb[0]); 10 | 11 | for ( i=1; i<=ret[0]; i++ ){ 12 | 13 | ret[i] = ( arra[i] && arrb[i] ); 14 | } 15 | } 16 | 17 | define bwand(a, b){ 18 | 19 | auto arra[], arrb[], ret[]; 20 | 21 | num2bitarr(a, arra[]); 22 | num2bitarr(b, arrb[]); 23 | 24 | bwand_api(arra[], arrb[], ret[]); 25 | 26 | return bitarr2num(ret[]); 27 | } 28 | 29 | 30 | define void bwor_api(*arra[], *arrb[], *ret[]){ 31 | 32 | auto i; 33 | 34 | ret[0] = max(arra[0], arrb[0]); 35 | 36 | for ( i=1; i<=ret[0]; i++ ){ 37 | 38 | ret[i] = ( arra[i] || arrb[i] ); 39 | } 40 | } 41 | 42 | define bwor(a, b){ 43 | 44 | auto arra[], arrb[], ret[]; 45 | 46 | num2bitarr(a, arra[]); 47 | num2bitarr(b, arrb[]); 48 | 49 | bwor_api(arra[], arrb[], ret[]); 50 | 51 | return bitarr2num(ret[]); 52 | } 53 | 54 | define void bwxor_api(*arra[], *arrb[], *ret[]){ 55 | 56 | auto i; 57 | 58 | ret[0] = max(arra[0], arrb[0]); 59 | 60 | for ( i=1; i<=ret[0]; i++ ){ 61 | 62 | ret[i] = (( arra[i] || arrb[i] ) && !( arra[i] && arrb[i] )); 63 | } 64 | } 65 | 66 | define bwxor(a, b){ 67 | 68 | auto arra[], arrb[], ret[]; 69 | 70 | num2bitarr(a, arra[]); 71 | num2bitarr(b, arrb[]); 72 | 73 | bwxor_api(arra[], arrb[], ret[]); 74 | 75 | return bitarr2num(ret[]); 76 | } 77 | 78 | define void bwnot_api(*arr[], *ret[]){ 79 | 80 | auto i; 81 | 82 | ret[0] = arr[0]; 83 | 84 | for ( i=1; i<=ret[0]; i++ ){ 85 | 86 | ret[i] = ( ! arr[i] ); 87 | } 88 | } 89 | 90 | define bwnot(a){ 91 | 92 | auto arr[], ret[]; 93 | 94 | num2bitarr(a, arr[]); 95 | 96 | bwnot_api(arr[], ret[]); 97 | 98 | return bitarr2num(ret[]); 99 | } 100 | 101 | define void bwnand_api(*arra[], *arrb[], *ret[]){ 102 | 103 | auto tmp[]; 104 | bwand_api(arra[], arrb[], tmp[]); 105 | bwnot_api(tmp[], ret[]); 106 | } 107 | 108 | define bwnand(a, b){ 109 | 110 | auto arra[], arrb[], ret[]; 111 | 112 | num2bitarr(a, arra[]); 113 | num2bitarr(b, arrb[]); 114 | 115 | bwnand_api(arra[], arrb[], ret[]); 116 | 117 | return bitarr2num(ret[]); 118 | } 119 | 120 | define void bwnor_api(*arra[], *arrb[], *ret[]){ 121 | 122 | auto tmp[]; 123 | bwor_api(arra[], arrb[], tmp[]); 124 | bwnot_api(tmp[], ret[]); 125 | } 126 | 127 | define bwnor(a, b){ 128 | 129 | auto arra[], arrb[], ret[]; 130 | 131 | num2bitarr(a, arra[]); 132 | num2bitarr(b, arrb[]); 133 | 134 | bwnor_api(arra[], arrb[], ret[]); 135 | 136 | return bitarr2num(ret[]); 137 | } 138 | 139 | define void bwxnor_api(*arra[], *arrb[], *ret[]){ 140 | 141 | auto tmp[]; 142 | bwxor_api(arra[], arrb[], tmp[]); 143 | bwnot_api(tmp[], ret[]); 144 | } 145 | 146 | define bwxnor(a, b){ 147 | 148 | auto arra[], arrb[], ret[]; 149 | 150 | num2bitarr(a, arra[]); 151 | num2bitarr(b, arrb[]); 152 | 153 | bwxnor_api(arra[], arrb[], ret[]); 154 | 155 | return bitarr2num(ret[]); 156 | } 157 | -------------------------------------------------------------------------------- /bitcoin/script/globals/opcodes.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | declare -A opcodes 4 | 5 | opcodes=( 6 | [0]='00' 7 | [FALSE]='00' 8 | [PUSHDATA1]='4C' 9 | [PUSHDATA2]='4D' 10 | [PUSHDATA4]='4E' 11 | [1NEGATE]='4F' 12 | [RESERVED]='50' 13 | [1]='51' 14 | [2]='52' 15 | [3]='53' 16 | [4]='54' 17 | [5]='55' 18 | [6]='56' 19 | [7]='57' 20 | [8]='58' 21 | [9]='59' 22 | [10]='5A' 23 | [11]='5B' 24 | [12]='5C' 25 | [13]='5D' 26 | [14]='5E' 27 | [15]='5F' 28 | [16]='60' 29 | [NOP]='61' 30 | [VER]='62' 31 | [IF]='63' 32 | [NOTIF]='64' 33 | [VERIF]='65' 34 | [VERNOTIF]='66' 35 | [ELSE]='67' 36 | [ENDIF]='68' 37 | [VERIFY]='69' 38 | [RETURN]='6A' 39 | [TOALTSTACK]='6B' 40 | [FROMALTSTACK]='6C' 41 | [2DROP]='6D' 42 | [2DUP]='6E' 43 | [3DUP]='6F' 44 | [2OVER]='70' 45 | [2ROT]='71' 46 | [2SWAP]='72' 47 | [IFDUP]='73' 48 | [DEPTH]='74' 49 | [DROP]='75' 50 | [DUP]='76' 51 | [NIP]='77' 52 | [OVER]='78' 53 | [PICK]='79' 54 | [ROLL]='7A' 55 | [ROT]='7B' 56 | [SWAP]='7C' 57 | [TUCK]='7D' 58 | [CAT]='7E' 59 | [SUBSTR]='7F' 60 | [SPLIT]='7F' 61 | [LEFT]='80' 62 | [NUM2BIN]='80' 63 | [RIGHT]='81' 64 | [BIN2NUM]='81' 65 | [SIZE]='82' 66 | [INVERT]='83' 67 | [AND]='84' 68 | [OR]='85' 69 | [XOR]='86' 70 | [EQUAL]='87' 71 | [EQUALVERIFY]='88' 72 | [RESERVED1]='89' 73 | [RESERVED2]='8A' 74 | [1ADD]='8B' 75 | [1SUB]='8C' 76 | [2MUL]='8D' 77 | [2DIV]='8E' 78 | [NEGATE]='8F' 79 | [ABS]='90' 80 | [NOT]='91' 81 | [0NOTEQUAL]='92' 82 | [ADD]='93' 83 | [SUB]='94' 84 | [MUL]='95' 85 | [DIV]='96' 86 | [MOD]='97' 87 | [LSHIFT]='98' 88 | [RSHIFT]='99' 89 | [BOOLAND]='9A' 90 | [BOOLOR]='9B' 91 | [NUMEQUAL]='9C' 92 | [NUMEQUALVERIFY]='9D' 93 | [NUMNOTEQUAL]='9E' 94 | [LESSTHAN]='9F' 95 | [GREATERTHAN]='A0' 96 | [LESSTHANOREQUAL]='A1' 97 | [GREATERTHANOREQUAL]='A2' 98 | [MIN]='A3' 99 | [MAX]='A4' 100 | [WITHIN]='A5' 101 | [RIPEMD160]='A6' 102 | [SHA1]='A7' 103 | [SHA256]='A8' 104 | [HASH160]='A9' 105 | [HASH256]='AA' 106 | [CODESEPARATOR]='AB' 107 | [CHECKSIG]='AC' 108 | [CHECKSIGVERIFY]='AD' 109 | [CHECKMULTISIG]='AE' 110 | [CHECKMULTISIGVERIFY]='AF' 111 | [NOP1]='B0' 112 | [NOP2]='B1' 113 | [CHECKLOCKTIMEVERIFY]='B1' 114 | [CLTV]='B1' 115 | [NOP3]='B2' 116 | [CHECKSEQUENCEVERIFY]='B2' 117 | [CSV]='B2' 118 | [NOP4]='B3' 119 | [NOP5]='B4' 120 | [NOP6]='B5' 121 | [NOP7]='B6' 122 | [NOP8]='B7' 123 | [NOP9]='B8' 124 | [NOP10]='B9' 125 | [SMALLINTEGER]='FA' 126 | [PUBKEYS]='FB' 127 | [PUBKEYHASH]='FD' 128 | [PUBKEY]='FE' 129 | [INVALIDOPCODE]='FF' 130 | [CHECKSIGFROMSTACKVERIFY]='BA' 131 | [CSTF]='BA' 132 | [PUSHTXDATA]='BB' 133 | [TXDATA]='BB' 134 | [EXPAND1]='D0' 135 | [EXPAND32]='EF') 136 | 137 | declare -A op_num 138 | op_num=( 139 | [-1]='4F' 140 | [-0]='00' 141 | [0]='00' 142 | [1]='51' 143 | [2]='52' 144 | [3]='53' 145 | [4]='54' 146 | [5]='55' 147 | [6]='56' 148 | [7]='57' 149 | [8]='58' 150 | [9]='59' 151 | [10]='5A' 152 | [11]='5B' 153 | [12]='5C' 154 | [13]='5D' 155 | [14]='5E' 156 | [15]='5F' 157 | [16]='60') 158 | -------------------------------------------------------------------------------- /bc/hash/.tests/test_hmac.bc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bc 2 | 3 | define void testhmac(){ 4 | 5 | auto knw, key, msg; 6 | 7 | print "Testing hmac()\n"; 8 | # set_hmac_pads(set_hmac_sha256()); 9 | # set_hmac_sha256(); 10 | 11 | key = 0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B; 12 | knw = 1; 13 | hmac(knw,key,set_hmac_sha256()); 14 | # 0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 15 | # 57575757575757575757575757575757575757575C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C 16 | # 3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3636363636363636363636363636363636363636363636363636363636363636363636363636363636363636 17 | 18 | print "\n"; 19 | key = 4A656665; 20 | knw = 0; 21 | hmac(knw,key,set_hmac_sha256()); 22 | # 4A656665000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 23 | # 16393A395C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C 24 | # 7C535053363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636 25 | 26 | print "\n"; 27 | key = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA; 28 | knw = 0; 29 | hmac(knw,key,set_hmac_sha256()); 30 | # AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 31 | # F6F6F6F6F6F6F6F6F6F6F6F6F6F6F6F6F6F6F6F65C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C 32 | # 9C9C9C9C9C9C9C9C9C9C9C9C9C9C9C9C9C9C9C9C3636363636363636363636363636363636363636363636363636363636363636363636363636363636363636 33 | 34 | print "\n"; 35 | key = 0102030405060708090A0B0C0D0E0F10111213141516171819; 36 | knw = 1; 37 | hmac(knw,key,set_hmac_sha256()); 38 | # 0102030405060708090A0B0C0D0E0F10111213141516171819000000000000000000000000000000000000000000000000000000000000000000000000000000 39 | # 5D5E5F58595A5B54555657505152534C4D4E4F48494A4B44455C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C 40 | # 373435323330313E3F3C3D3A3B383926272425222320212E2F363636363636363636363636363636363636363636363636363636363636363636363636363636 41 | 42 | print "\n"; 43 | key = 0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C; 44 | knw = 1; 45 | hmac(knw,key,set_hmac_sha256()); 46 | # 0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 47 | # 50505050505050505050505050505050505050505C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C 48 | # 3A3A3A3A3A3A3A3A3A3A3A3A3A3A3A3A3A3A3A3A3636363636363636363636363636363636363636363636363636363636363636363636363636363636363636 49 | 50 | # hash256(AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) 51 | print "\n"; 52 | key = 45AD4B37C6E2FC0A2CFCC1B5DA524132EC707615C2CAE1DBBC43C97AA521DB81; 53 | knw = 0; 54 | hmac(knw,key,set_hmac_sha256()); 55 | # 45AD4B37C6E2FC0A2CFCC1B5DA524132EC707615C2CAE1DBBC43C97AA521DB810000000000000000000000000000000000000000000000000000000000000000 56 | # 19F1176B9ABEA05670A09DE9860E1D6EB02C2A499E96BD87E01F9526F97D87DD5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C 57 | # 739B7D01F0D4CA3C1ACAF783EC647704DA464023F4FCD7ED8A75FF4C9317EDB73636363636363636363636363636363636363636363636363636363636363636 58 | } 59 | 60 | testhmac() 61 | -------------------------------------------------------------------------------- /bitcoin/bips/.tests/test_bip173.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | test_bip173_vectors() 4 | { 5 | valid_bech32=( \ 6 | 'A12UEL5L' \ 7 | 'a12uel5l' \ 8 | 'an83characterlonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1tt5tgs' \ 9 | 'abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw' \ 10 | '11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc8247j' \ 11 | 'split1checkupstagehandshakeupstreamerranterredcaperred2y9e3w' \ 12 | '?1ezyfcl' ) 13 | 14 | invalid_bech32=( \ 15 | "$( printf '%b%s' '\x20' '1nwldj5' )" \ 16 | "$( printf '%b%s' '\x7f' '1axkwrx' )" \ 17 | "$( printf '%b%s' '\x80' '1eym55h' )" \ 18 | 'an84characterslonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1569pvx' \ 19 | 'pzry9x0s0muk' \ 20 | '1pzry9x0s0muk' \ 21 | 'x1b4n0q5v' \ 22 | 'li1dgmt3' \ 23 | "$( printf '%s%b' 'de1lg7wt' '\xff' )" \ 24 | 'A1G7SGD8' \ 25 | '10a06t8' \ 26 | '1qzzfhee' ) 27 | 28 | valid_segwit=( \ 29 | 'BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4:0014751e76e8199196d454941c45d1b3a323f1433bd6' \ 30 | 'tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7:00201863143c14c5166804bd19203356da136c985678cd4d27a1b8c6329604903262' \ 31 | 'bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7k7grplx:5128751e76e8199196d454941c45d1b3a323f1433bd6751e76e8199196d454941c45d1b3a323f1433bd6' \ 32 | 'BC1SW50QA3JX3S:6002751e' \ 33 | 'bc1zw508d6qejxtdg4y5r3zarvaryvg6kdaj:5210751e76e8199196d454941c45d1b3a323' \ 34 | 'tb1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesrxh6hy:0020000000c4a5cad46221b2a187905e5266362b99d5e91c6ce24d165dab93e86433' ) 35 | 36 | invalid_segwit=( \ 37 | 'tc1qw508d6qejxtdg4y5r3zarvary0c5xw7kg3g4ty' \ 38 | 'bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t5' \ 39 | 'BC13W508D6QEJXTDG4Y5R3ZARVARY0C5XW7KN40WF2' \ 40 | 'bc1rw5uspcuh' \ 41 | 'bc10w508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kw5rljs90' \ 42 | 'BC1QR508D6QEJXTDG4Y5R3ZARVARYV98GJ9P' \ 43 | 'tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sL5k7' \ 44 | 'bc1zw508d6qejxtdg4y5r3zarvaryvqyzf3du' \ 45 | 'tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3pjxtptv' \ 46 | 'bc1gmk9yu' ) 47 | } 48 | 49 | test_bech32_valid_bech32 () 50 | { 51 | for vbech32 in ${valid_bech32[@]}; do 52 | if ! bech32_decode "${vbech32}"; then 53 | return 1 54 | fi 55 | done 56 | } 57 | 58 | test_bech32_invalid_bech32 () 59 | { 60 | for ibech32 in ${invalid_bech32[@]}; do 61 | if bech32_decode "${ibech32}"; then 62 | return 1 63 | fi 64 | done 65 | } 66 | 67 | test_bech32_valid_segwit () 68 | { 69 | local addr script decoded 70 | for pair in ${valid_segwit[@]}; do 71 | addr="${pair%:*}" 72 | script="${pair#*:}" 73 | if ! segwit_decode "${addr}"; then 74 | return 1 75 | fi 76 | decoded="$( segwit_decode "${addr}" )" 77 | if [[ "${script}" != "${decoded,,}" ]]; then 78 | return 1 79 | fi 80 | done 81 | } 82 | 83 | test_bech32_invalid_segwit () 84 | { 85 | for isegwit in ${invalid_segwit[@]}; do 86 | if segwit_decode "${isegwit}"; then 87 | return 1 88 | fi 89 | done 90 | } 91 | 92 | test_bech32 () 93 | { 94 | test_bip173_vectors 95 | 96 | test_bech32_valid_bech32 || return 1 97 | test_bech32_invalid_bech32 || return 1 98 | test_bech32_valid_segwit || return 1 99 | test_bech32_invalid_segwit || return 1 100 | } 101 | test_bech32 || false 102 | -------------------------------------------------------------------------------- /bc/ec_math/endomorphism.bc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bc 2 | 3 | # frobenius endomorphism 4 | # https://bitcointalk.org/index.php?topic=3238.0 5 | # Guide to Elliptic Curve Cryptography - 6 | # Hankerson, Menezes, Vanstone 7 | 8 | define get_decimal_sqrt(n){ 9 | 10 | auto base; 11 | base = 2; 12 | for (i=1; base<(2 ^ (wordlen(n) * 2)); i++){ 13 | 14 | base = powmod(2, i, n); 15 | } 16 | 17 | return base-1; 18 | } 19 | 20 | # 2.19 Extended Euclidean algorithm for integers 21 | define void set_balanced_mul_vals_api(a, b, n, *ret[]){ 22 | 23 | auto s[], t[], r[], quotient, prov, sqrtn, sflag, i, l; 24 | s[1] = 0; s[0] = 1; 25 | t[1] = 1; t[0] = 0; 26 | r[1] = b; r[0] = a; 27 | sqrtn = get_decimal_sqrt(n); 28 | sflag = 1; 29 | 30 | i = 1; 31 | while (r[i] != 0){ 32 | # print "r[",i-1,"] : ", r[i-1],"\n"; 33 | # print "r[",i,"] : ", r[i],"\n"; 34 | quotient = r[i-1] / r[i]; 35 | prov = r[i]; 36 | r[i] = mod(r[i-1] - mod(quotient*prov, n), n); 37 | r[i-1] = prov; 38 | prov = s[i]; 39 | s[i] = mod(s[i-1] - mod(quotient*prov, n), n); 40 | s[i-1] = prov; 41 | prov = t[i]; 42 | t[i] = mod(t[i-1] - mod(quotient*prov, n), n); 43 | t[i-1] = prov; 44 | # print "i : ", i, "\n"; 45 | # print "r[",i-1,"] : ", r[i-1],"\n"; 46 | # print "r[",i,"] : ", r[i],"\n"; 47 | if ((r[i] < sqrtn) && sflag ){ 48 | l = i-1; 49 | sflag = 0; 50 | } 51 | r[i+2] = r[i] 52 | s[i+2] = s[i] 53 | t[i+2] = t[i] 54 | r[i+1] = r[i-1] 55 | s[i+1] = s[i-1] 56 | t[i+1] = t[i-1] 57 | i+=2; 58 | } 59 | # print "l : ", l, "\n"; 60 | # print "r[l] : ", r[l], "\n"; 61 | # print "s[l] : ", s[l], "\n"; 62 | # print "t[l] : ", t[l], "\n"; 63 | # print "r[l+1] : ", r[l+1], "\nr[l+2] : ", r[l+2], "\n"; 64 | # print "s[l+1] : ", s[l+1], "\ns[l+2] : ", s[l+2], "\n"; 65 | # print "t[l+1] : ", t[l+1], "\nt[l+2] : ", t[l+2], "\n"; 66 | #a1 = r[l+1]; 67 | #b1 = -t[l+1]; 68 | ret[0] = r[l+1]; 69 | ret[1] = -t[l+1]; 70 | if (mod((r[l]^2 + t[l]^2), n) <= mod((r[l+2]^2 + t[l+2]^2), n)) { 71 | #a2 = r[l]; 72 | #b2 = -t[l]; 73 | ret[2] = r[l]; 74 | ret[3] = mod(-t[l], n); 75 | } else { 76 | #a2 = r[l+2]; 77 | #b2 = -t[l+2]; 78 | ret[2] = r[l+2]; 79 | ret[3] = mod(-t[l+2], n); 80 | } 81 | # b2 = mod(b2,n); 82 | # ret[0] = a1; ret[1] = b1; 83 | # ret[2] = a2; ret[3] = b2; 84 | } 85 | 86 | define void set_endomorphism_vals(){ 87 | 88 | auto roots[], ret[]; 89 | rootmod_api(1, 3, curve_p, roots[]); 90 | endomorphism_beta = roots[2]; 91 | 92 | rootmod_api(1, 3, curve_n, roots[]); 93 | endomorphism_lambda = roots[3]; 94 | 95 | set_balanced_mul_vals_api(curve_n, endomorphism_lambda, curve_n, ret[]); 96 | endomorphism_a1 = ret[0]; 97 | endomorphism_b1 = ret[1]; 98 | endomorphism_a2 = ret[2]; 99 | endomorphism_b2 = ret[3]; 100 | } 101 | 102 | define void get_lambda_point_api(beta, gx, gy, pp, *ret[]){ 103 | 104 | ret[0] = mod(beta * gx, curve_p); # Q'_x 105 | ret[1] = gy; # Q'_y 106 | } 107 | 108 | # 3.74 Balanced length-two representation of a multiplier 109 | define void balanced_length_api(k, a1, b1, a2, b2, n, *ret[]){ 110 | 111 | auto c1, c2, k1, k2; 112 | 113 | c1 = (b2 * k)/n; 114 | c2 = (-b1 * k)/n; 115 | 116 | k1 = (k - c1*a1 - c2*a2); 117 | k2 = (-c1*b1 - c2*b2); 118 | 119 | ret[0] = k1; 120 | ret[1] = k2; 121 | } 122 | 123 | define void balanced_length_mod(k, n){ 124 | 125 | auto ret[]; 126 | balanced_length_api(k, endomorphism_a1, endomorphism_b1, endomorphism_a2, endomorphism_b2, n, ret[]); 127 | print "k1 : ", ret[0], "\nk2 : ", ret[1], "\n"; 128 | } 129 | -------------------------------------------------------------------------------- /bc/base/.tests/test_conversion.bc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bc 2 | 3 | define testwordlen(){ 4 | 5 | auto bool; 6 | print "Test wordlen()\n"; 7 | bool = 1; 8 | 9 | bool *= ( wordlen(0) == 1 ); 10 | bool *= ( wordlen(00) == 1 ); 11 | bool *= ( wordlen(1) == 1 ); 12 | bool *= ( wordlen(A) == 1 ); 13 | bool *= ( wordlen(10) == 2); 14 | bool *= ( wordlen(99) == 2); 15 | bool *= ( wordlen(100) == 3); 16 | bool *= ( wordlen(FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) == 40 ); 17 | bool *= ( wordlen(10000000000000000000000000000000000000000000000000000000000000000) == 41 ); 18 | 19 | return bool; 20 | } 21 | 22 | define testnum2bitarr(){ 23 | 24 | auto ret[], arr_1000[], arr_dead[], arr_beef[], arr_cafe[], bool, i, o; 25 | 26 | arr_1000[0] = D; 27 | arr_1000[1] = 1; arr_1000[2] = 0; arr_1000[3] = 0; arr_1000[4] = 0; 28 | arr_1000[5] = 0; arr_1000[6] = 0; arr_1000[7] = 0; arr_1000[8] = 0; 29 | arr_1000[9] = 0; arr_1000[A] = 0; arr_1000[B] = 0; arr_1000[C] = 0; 30 | arr_1000[D] = 0; 31 | 32 | arr_dead[0] = 10; 33 | arr_dead[1] = 1; arr_dead[2] = 1; arr_dead[3] = 0; arr_dead[4] = 1; 34 | arr_dead[5] = 1; arr_dead[6] = 1; arr_dead[7] = 1; arr_dead[8] = 0; 35 | arr_dead[9] = 1; arr_dead[A] = 0; arr_dead[B] = 1; arr_dead[C] = 0; 36 | arr_dead[D] = 1; arr_dead[E] = 1; arr_dead[F] = 0; arr_dead[10] = 1; 37 | 38 | arr_beef[0] = 10; 39 | arr_beef[1] = 1; arr_beef[2] = 0; arr_beef[3] = 1; arr_beef[4] = 1; 40 | arr_beef[5] = 1; arr_beef[6] = 1; arr_beef[7] = 1; arr_beef[8] = 0; 41 | arr_beef[9] = 1; arr_beef[A] = 1; arr_beef[B] = 1; arr_beef[C] = 0; 42 | arr_beef[D] = 1; arr_beef[E] = 1; arr_beef[F] = 1; arr_beef[10] = 1; 43 | 44 | arr_cafe[0] = 10; 45 | arr_cafe[1] = 1; arr_cafe[2] = 1; arr_cafe[3] = 0; arr_cafe[4] = 0; 46 | arr_cafe[5] = 1; arr_cafe[6] = 0; arr_cafe[7] = 1; arr_cafe[8] = 0; 47 | arr_cafe[9] = 1; arr_cafe[A] = 1; arr_cafe[B] = 1; arr_cafe[C] = 1; 48 | arr_cafe[D] = 1; arr_cafe[E] = 1; arr_cafe[F] = 1; arr_cafe[10] = 0; 49 | 50 | print "Test num2bitarr()\n"; 51 | bool = 1; 52 | 53 | num2bitarr(0, ret[]); 54 | bool *= ( ret[0] == 1 ); 55 | bool *= ( ret[1] == 0 ); 56 | 57 | num2bitarr(1, ret[]); 58 | bool *= ( ret[0] == 1 ); 59 | bool *= ( ret[1] == 1 ); 60 | 61 | o = 1; 62 | bool = 1; 63 | num2bitarr(1000, ret[]); 64 | for ( i=(ret[0]); i>0; i-- ){ 65 | #print "ret[", i, "] == ", ret[i], "\n", "arr_1000[", o, "] == ", arr_1000[o], "\n", "bool = ", bool, "\n" 66 | bool *= ( ret[i] == arr_1000[o] ); 67 | o += 1; 68 | } 69 | for (i=ret[0]; i>0; i--) { print ret[i]; }; print "\n" 70 | for (i=1; i<=arr_1000[0]; i++) { print arr_1000[i]; }; print "\n" 71 | 72 | o = 1; 73 | num2bitarr(DEAD, ret[]); 74 | for ( i=(ret[0]); i>0; i-- ){ 75 | bool *= ( ret[i] == arr_dead[o] ); 76 | o += 1; 77 | } 78 | for (i=ret[0]; i>0; i--) { print ret[i]; }; print "\n" 79 | for (i=1; i<=arr_dead[0]; i++) { print arr_dead[i]; }; print "\n" 80 | 81 | o = 1; 82 | num2bitarr(BEEF, ret[]); 83 | for ( i=(ret[0]); i>0; i-- ){ 84 | bool *= ( ret[i] == arr_beef[o] ); 85 | o += 1; 86 | } 87 | for (i=ret[0]; i>0; i--) { print ret[i]; }; print "\n" 88 | for (i=1; i<=arr_beef[0]; i++) { print arr_beef[i]; }; print "\n" 89 | 90 | o = 1; 91 | num2bitarr(CAFE, ret[]); 92 | for ( i=(ret[0]); i>0; i-- ){ 93 | bool *= ( ret[i] == arr_cafe[o] ); 94 | o += 1; 95 | } 96 | for (i=ret[0]; i>0; i--) { print ret[i]; }; print "\n" 97 | for (i=1; i<=arr_cafe[0]; i++) { print arr_cafe[i]; }; print "\n" 98 | 99 | return ( bool == 1 ); 100 | } 101 | 102 | define testbitarr2num(){ 103 | 104 | auto num, ret[], bool; 105 | 106 | print "Test bitarr2num()\n"; 107 | bool = 1; 108 | 109 | num2bitarr(0, ret[]) 110 | bool *= ( bitarr2num(ret[]) == 0 ) 111 | 112 | num2bitarr(1, ret[]) 113 | bool *= ( bitarr2num(ret[]) == 1 ) 114 | 115 | num2bitarr(55555, ret[]) 116 | bool *= ( bitarr2num(ret[]) == 55555 ) 117 | 118 | num2bitarr(AAAAAAAAAA, ret[]) 119 | bool *= ( bitarr2num(ret[]) == AAAAAAAAAA ) 120 | 121 | num2bitarr(010101, ret[]) 122 | bool *= ( bitarr2num(ret[]) == 010101 ) 123 | 124 | return bool; 125 | } 126 | 127 | define test_conversion_bc(){ 128 | 129 | auto bool; 130 | bool = 1; 131 | bool *= testwordlen(); 132 | bool; 133 | bool *= testnum2bitarr(); 134 | bool; 135 | bool *= testbitarr2num(); 136 | 137 | return bool; 138 | } 139 | 140 | test_conversion_bc() 141 | -------------------------------------------------------------------------------- /bc/ec_math/jacobian.bc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bc 2 | 3 | # jacobian coordinates on prime curves 4 | 5 | define void ecpf_aff2jac_api(x, y, *jpt[]){ 6 | 7 | jpt[0] = x; 8 | jpt[1] = y; 9 | jpt[2] = 1; 10 | } 11 | 12 | define void ecpf_aff2jac(p, *jpt[]){ 13 | 14 | auto pt[]; 15 | uncompresspoint_api(p, pt[]); 16 | ecpf_aff2jac_api(pt[0], pt[1], jpt[]); 17 | } 18 | 19 | define void ecpf_jac2aff_api(jpx, jpy, jpz, p, *pt[]){ 20 | 21 | pt[0] = mod(jpx * invmod(powmod(jpz, 2, curve_p), curve_p), curve_p); 22 | pt[1] = mod(jpy * invmod(powmod(jpz, 3, curve_p), curve_p), curve_p); 23 | } 24 | 25 | define void ecpf_jac2aff(*jpt[], *pt[]){ 26 | 27 | ecpf_jac2aff_api(jpt[0], jpt[1], jpt[2], curve_p, pt[]); 28 | } 29 | 30 | define void ecpf_jac_double_api(jpx, jpy, jpz, a, p, *jpt[]){ 31 | 32 | auto s, m; 33 | 34 | if ((jpx == 1 && jpy == 1 && jpz == 0) || jpy == 0){ 35 | jpt[0] = 1; 36 | jpt[1] = 1; 37 | jpt[2] = 0; 38 | return; 39 | } 40 | s = mod(4 * jpx * jpy^2, p); 41 | m = mod((3 * jpx^2) + (a * jpy^4), p); 42 | jpt[0] = mod(m^2 - 2*s, p); 43 | jpt[1] = mod(m * (s - jpt[0]) - 8*jpy^4, p); 44 | jpt[2] = mod(2 * jpy * jpz, p); 45 | } 46 | 47 | define void ecpf_jac_double(*jin[], *jpt[]){ 48 | 49 | ecpf_jac_double_api(jin[0], jin[1], jin[2], curve_a, curve_p, jpt[]); 50 | } 51 | 52 | define void ecpf_jac_add_api(jpx, jpy, jpz, jqx, jqy, jqz, a, p, *jpt[]){ 53 | 54 | auto u1, u2, s1, s2, h, r; 55 | 56 | if (jpx == 1 && jpy == 1 && jpz == 0){ 57 | jpt[0] = jqx; 58 | jpt[1] = jqy; 59 | jpt[2] = jqz; 60 | return; 61 | } 62 | if (jqx == 1 && jqy == 1 && jqz == 0){ 63 | jpt[0] = jpx; 64 | jpt[1] = jpy; 65 | jpt[2] = jpz; 66 | return; 67 | } 68 | u1 = mod(jpx * jqz^2, p); 69 | u2 = mod(jqx * jpz^2, p); 70 | s1 = mod(jpy * jqz^3, p); 71 | s2 = mod(jqy * jpz^3, p); 72 | if (u1 == u2){ 73 | if (s1 != s2){ 74 | jpt[0] = 1; 75 | jpt[1] = 1; 76 | jpt[2] = 0; 77 | return; 78 | } else { 79 | ecpf_jac_double_api(jpx, jpy, jpz, a, p, jpt[]); 80 | return; 81 | } 82 | } 83 | h = mod(u2 - u1, p); 84 | r = mod(s2 - s1, p); 85 | jpt[0] = mod(r^2 - h^3 - (2 * u1 * h^2), p); 86 | jpt[1] = mod(r * (u1 * h^2 - jpt[0]) - (s1 * h^3), p); 87 | jpt[2] = mod(h * jpz * jqz, p); 88 | } 89 | 90 | define void ecpf_jac_add(*jp[], *jq[], *jpt[]){ 91 | 92 | ecpf_jac_add_api(jp[0], jp[1], jp[2], jq[0], jq[1], jq[2], curve_a, curve_p, jpt[]); 93 | } 94 | 95 | define void ecpf_jac_stdmul_api(d, gx, gy, gz, a, p, n, *jpt[]){ 96 | 97 | auto jtmp[]; 98 | 99 | jtmp[0] = gx; 100 | jtmp[1] = gy; 101 | jtmp[2] = gz; 102 | jpt[0] = 1; 103 | jpt[1] = 1; 104 | jpt[2] = 0; 105 | if (d < 0){ 106 | d = mod(d, n); 107 | } 108 | if (d > n/2){ 109 | d = mod(-d, n); 110 | jtmp[1] = mod(-gy, p); 111 | } 112 | 113 | while (d > 0){ 114 | 115 | if (d % 2){ 116 | ecpf_jac_add_api(jtmp[0], jtmp[1], jtmp[2], jpt[0], jpt[1], jpt[2], a, p, jpt[]); 117 | } 118 | ecpf_jac_double_api(jtmp[0], jtmp[1], jtmp[2], a, p, jtmp[]); 119 | d /= 2; 120 | } 121 | } 122 | 123 | define void ecpf_jac_stdmul(d, *jpt[]){ 124 | 125 | ecpf_jac_stdmul_api(d, curve_gx, curve_gy, 1, curve_a, curve_p, curve_n, jpt[]); 126 | } 127 | 128 | define void jac_ecmul_std(d){ 129 | 130 | auto jpt[], pt[]; 131 | 132 | ecpf_jac_stdmul(d, jpt[]); 133 | ecpf_jac2aff(jpt[], pt[]); 134 | compresspoint(pt[]); 135 | } 136 | 137 | define void ecpf_jac_ecmul_api(d, gx, gy, gz, a, n, p, *jpt[]){ 138 | 139 | auto jlq[], k[], jp1[], jp2[]; 140 | 141 | if (d < 0){ 142 | d = mod(d, n); 143 | } 144 | if (d > n/2){ 145 | d = mod(-d, n); 146 | gy = mod(-gy, p); 147 | } 148 | get_lambda_point_api(endomorphism_beta, gx, gy, p, jlq[]); 149 | jlq[2] = 1; 150 | 151 | balanced_length_api(d, endomorphism_a1, endomorphism_b1, endomorphism_a2, endomorphism_b2, n, k[]); 152 | ecpf_jac_stdmul_api(k[0], gx, gy, gz, curve_a, curve_p, curve_n, jp1[]); 153 | ecpf_jac_stdmul_api(-k[1], jlq[0], -jlq[1], jlq[2], curve_a, curve_p, curve_n, jp2[]); 154 | ecpf_jac_add(jp1[], jp2[], jpt[]); 155 | } 156 | 157 | define void ecpf_jac_ecmul(d, *jpt[]){ 158 | 159 | ecpf_jac_ecmul_api(d, curve_gx, curve_gy, 1, curve_a, curve_n, curve_p, jpt[]); 160 | } 161 | 162 | define void jac_ecmul(d){ 163 | 164 | auto ret[], pt[]; 165 | 166 | ecpf_jac_ecmul(d, ret[]); 167 | ecpf_jac2aff(ret[], pt[]); 168 | compresspoint(pt[]); 169 | } 170 | -------------------------------------------------------------------------------- /bc/ec_math/ec_math.bc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bc 2 | 3 | # functions for operations on an elliptic curve 4 | 5 | define slope_api(px, py, qx, qy, p) 6 | { 7 | auto num, den; 8 | 9 | if (qy - py != 0){ 10 | 11 | num = mod((qy - py),p); 12 | den = invmod((qx - px),p); 13 | 14 | } else { 15 | 16 | num = mod((3 * px^2 + curve_a),p); 17 | den = invmod((2 * py),p); 18 | } 19 | 20 | return (mod((num * den),p)); 21 | } 22 | 23 | define slope(p, q) 24 | { 25 | auto parr[], qarr[]; 26 | 27 | uncompresspoint_api(p, parr[]); 28 | uncompresspoint_api(q, qarr[]); 29 | return slope_api(parr[0], parr[1], qarr[0], qarr[1], curve_p); 30 | } 31 | 32 | define void ecdouble_api(x, y, p, *ret[]) 33 | { 34 | auto tangent; 35 | 36 | #tangent = mod((3 * x^2 + curve_a) * invmod(2 * y, p), curve_p); #TODO COMON!! curve_p -> p 37 | tangent = mod((3 * x^2 + curve_a) * invmod(2 * y, p), p); #TODO COMON!! curve_p -> p 38 | ret[0] = mod(tangent^2 - 2*x, p); 39 | ret[1] = mod((tangent * (x - ret[0]) - y),p); 40 | } 41 | 42 | define void ecdouble(p) 43 | { 44 | auto pt[], ret[]; 45 | 46 | uncompresspoint_api(p, pt[]); 47 | if ( !ispoint(pt[]) ){ 48 | print "\n ### Not a point\n"; 49 | return; 50 | } 51 | ecdouble_api(pt[0], pt[1], curve_p, ret[]); 52 | compresspoint(ret[]); 53 | } 54 | 55 | define void ecadd_api(px, py, qx, qy, p, *ret[]) 56 | { 57 | auto slp; 58 | 59 | if (px == 0){ 60 | 61 | ret[0] = qx; 62 | ret[1] = qy; 63 | return; 64 | } 65 | if (qx == 0){ 66 | 67 | ret[0] = px; 68 | ret[1] = py; 69 | return; 70 | } 71 | 72 | # if (py != mod(-qy, p)){ 73 | 74 | slp = mod((qy - py) * invmod((qx - px), p), p); 75 | ret[0] = mod((slp^2 - px - qx),p); 76 | ret[1] = mod((slp * (px - ret[0]) - py),p); 77 | return; 78 | /* } else { 79 | 80 | print "else 1\n"; 81 | if (px == qx){ 82 | print "else 2\n"; 83 | ecdouble_api(px, py, curve_p, ret[]); 84 | return; 85 | } 86 | } 87 | # infinity 88 | ret[0] = 0; 89 | ret[1] = 0; 90 | */ 91 | } 92 | 93 | define ecadd(p, q) 94 | { 95 | auto ptp[], ptq[], pt[]; 96 | 97 | uncompresspoint_api(p, ptp[]); 98 | uncompresspoint_api(q, ptq[]); 99 | if (ptp[0] == 0 && ptp[1] == 0){ 100 | compresspoint(ptq[]); 101 | return; 102 | } 103 | if (ptq[0] == 0 && ptq[1] == 0){ 104 | compresspoint(ptp[]); 105 | return 106 | } 107 | if ( !ispoint(ptp[]) || !ispoint(ptq[]) ){ 108 | print "\n ### Not a point ?\n"; 109 | return; 110 | } 111 | if (ptp[0] == ptq[0] && ptp[1] == ptq[1]){ 112 | ecdouble(p); 113 | return; 114 | } 115 | ecadd_api(ptp[0], ptp[1], ptq[0], ptq[1], curve_p, pt[]); 116 | return compresspoint(pt[]); 117 | } 118 | 119 | define void ecmul_std_api(d, gx, gy, n, p, *ret[]) 120 | { 121 | auto parr[]; 122 | 123 | parr[0] = gx; 124 | parr[1] = gy; 125 | ret[0] = 0; 126 | ret[1] = 0; 127 | if (d < 0){ 128 | d = mod(d, n); 129 | } 130 | if (d > n/2){ 131 | d = mod(-d, n); 132 | parr[1] = mod(-gy, p); 133 | } 134 | 135 | while (d > 0){ 136 | 137 | if (d % 2){ 138 | 139 | ecadd_api(parr[0], parr[1], ret[0], ret[1], curve_p, ret[]); 140 | } 141 | ecdouble_api(parr[0], parr[1], curve_p, parr[]); 142 | d /= 2; 143 | } 144 | } 145 | 146 | define void ecmul_std(d) 147 | { 148 | auto ret[]; 149 | 150 | ecmul_std_api(d, curve_gx, curve_gy, curve_n, curve_p, ret[]); 151 | compresspoint(ret[]); 152 | } 153 | 154 | define void ecmul_api(d, qx, qy, n, p, *ret[]) 155 | { 156 | auto lambda_q[], k[], p1[], p2[]; 157 | 158 | if (d < 0){ 159 | d = mod(d, n); 160 | } 161 | if (d > n/2){ 162 | d = mod(-d, n); 163 | qy = mod(-qy, p); 164 | } 165 | get_lambda_point_api(endomorphism_beta, qx, qy, p, lambda_q[]); 166 | 167 | balanced_length_api(d, endomorphism_a1, endomorphism_b1, endomorphism_a2, endomorphism_b2, n, k[]); 168 | ecmul_std_api(k[0] ,qx, qy, n, p, p1[]); 169 | ecmul_std_api(-k[1], lambda_q[0], -lambda_q[1], n, p, p2[]); 170 | ecadd_api(p1[0], p1[1], p2[0], p2[1], p, ret[]); 171 | } 172 | 173 | define ecmul(d) 174 | { 175 | auto ret[]; 176 | ecmul_api(d, curve_gx, curve_gy, curve_n, curve_p, ret[]); 177 | return compresspoint(ret[]); 178 | } 179 | 180 | define ecmul_pt(d, pt) 181 | { 182 | auto uncompr_pt[], mul_ret[]; 183 | 184 | uncompresspoint_api(pt, uncompr_pt[]); 185 | ecmul_api(d, uncompr_pt[0], uncompr_pt[1], curve_n, curve_p, mul_ret[]); 186 | print "0"; 187 | return compresspoint_api(mul_ret[0], mul_ret[1]); 188 | } 189 | 190 | # NOT a secure random number 191 | define rand() 192 | { 193 | auto rnd; 194 | 195 | rnd = 1; 196 | for (i=0; i<(curve_words + 1); i++) { 197 | rnd = rnd * random(); 198 | } 199 | return mod(rnd, curve_n) 200 | } 201 | -------------------------------------------------------------------------------- /ecdsa/.tests/test_ecdsa.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | test_ecdsa_res () 4 | { 5 | # random key 6 | privkey=5A90F5357E326FC0A657BA4E620DDAFA4DC5508C39FC204BF952B1F667E62C16 7 | point_x=FB859A0B232B6F2CB1BD302E134F338A2378D67EEABB010B43A93177EF9605C3 8 | point_y=BCAF85BD92C1107BB2B27D5826A75099B7B43810D56FE46E964EE3F6BAD6B54E 9 | pubkey_c=02FB859A0B232B6F2CB1BD302E134F338A2378D67EEABB010B43A93177EF9605C3 10 | pubkey_u=04FB859A0B232B6F2CB1BD302E134F338A2378D67EEABB010B43A93177EF9605C3BCAF85BD92C1107BB2B27D5826A75099B7B43810D56FE46E964EE3F6BAD6B54E 11 | # bitcoin signed message format, "test message" 12 | test_msg=18426974636F696E205369676E6564204D6573736167653A0A0C74657374206D657373616765 13 | test_z=E4CD07AA6F940179E7CFF9EA7FA6C6C73AE15E523CEB51C7145589641A78403E 14 | test_z_hash=1226179DDF6383FBCF5102C9492538B7206C739AE79EB064408C2ABD67D39BED 15 | test_sig=3045022100E13708D5A664231302098BD99A363E66CA07752F6741191FBC47449CABE758B202201B0AD260DDD5205D4DDDB6DBA980C1D14621F0BA58D043785871822FBD4130B9 16 | test_sig_r=E13708D5A664231302098BD99A363E66CA07752F6741191FBC47449CABE758B2 17 | test_sig_s=1B0AD260DDD5205D4DDDB6DBA980C1D14621F0BA58D043785871822FBD4130B9 18 | 19 | # bitcoin signed message format, "wrap case" 20 | wrap_msg=18426974636F696E205369676E6564204D6573736167653A0A09777261702063617365 21 | wrap_z=2DF2A5BEE61D12C95A36A1F06D7BCAF488F7E3A3D65A634878F7A7D0CDCE7D78 22 | wrap_z_hash=91C4A9180B083F4AD073AD6CDFFDE562CCA995AB05CD07C73EA11A2EE93DC3B5 23 | wrap_sig_r=4 24 | wrap_sig_s=4 25 | wrap_sig=3006020104020104 26 | pubkeys_c=( \ 27 | 03C8C4EF223F205353341CD26A1751235224A76816D11D4C99C85E5E18EF04A125 \ 28 | 02C242044819C628E1DD9D4ACACF0A06EB493CE18A1F0C678173512C5C82096AB9 \ 29 | 02302600BECC7AC78E2AE9D175F930796288A0A1CDCA02C71604C253B3EF14B30A \ 30 | 03D1B0D67A892F0EA31B59491E4A7BD25191A2F413C5211D2EF6FA3CBBB5339214 ) 31 | pubkeys_u=( \ 32 | 04C8C4EF223F205353341CD26A1751235224A76816D11D4C99C85E5E18EF04A1259C59CFA6D5B2E606DD6B93790003144B31A99B1FCD764675E2DA84E17692DCFB \ 33 | 04C242044819C628E1DD9D4ACACF0A06EB493CE18A1F0C678173512C5C82096AB9966340E278AC67244658827C25E5D93952BC35412B4E9252B661C198F66DB1A6 \ 34 | 04302600BECC7AC78E2AE9D175F930796288A0A1CDCA02C71604C253B3EF14B30A4B85479D08D530D348EEEC322F028779E5F04368CEDE44A8E3C20EB86925E954 \ 35 | 04D1B0D67A892F0EA31B59491E4A7BD25191A2F413C5211D2EF6FA3CBBB53392148717B73673801C6AAE84F057BC5CDE72FE838E6EA431A3EA0A2BD62405B99E4B ) 36 | } 37 | 38 | test_ecdsa_compresspubkey () 39 | { 40 | [[ "${pubkey_c}" == "$(compresspubkey ${pubkey_u})" ]] || (return 1) 41 | for ((i=0; i<${#pubkeys_u[@]}; i++)); do 42 | [[ "${pubkeys_c[$i]}" == "$(compresspubkey ${pubkeys_u[$i]})" ]] || (return 1) 43 | done 44 | } 45 | 46 | test_ecdsa_uncompresspubkey () 47 | { 48 | [[ "${pubkey_u}" == "$(uncompresspubkey ${pubkey_c})" ]] || (return 1) 49 | for ((i=0; i<${#pubkeys_u[@]}; i++)); do 50 | [[ "${pubkeys_u[$i]}" == $(uncompresspubkey "${pubkeys_c[$i]}") ]] || (return 1) 51 | done 52 | } 53 | 54 | test_sig2der () 55 | { 56 | [[ "${test_sig}" == "$( sig2der "${test_sig_r}" "${test_sig_s}")" ]] && \ 57 | [[ "${wrap_sig}" == "$( sig2der "${wrap_sig_r}" "${wrap_sig_s}")" ]] 58 | } 59 | 60 | test_der2sig () 61 | { 62 | [[ "${test_sig_r} ${test_sig_s}" == "$( der2sig "${test_sig}" )" ]] && \ 63 | [[ "${wrap_sig_r} ${wrap_sig_s}" == "$( der2sig "${wrap_sig}" )" ]] 64 | } 65 | 66 | test_ecdsa_sign () 67 | { 68 | local -u sig="$(sign "${privkey}" "${test_z}")" z_hash="$( sha256 "${test_z}" )" 69 | [[ "${sig}" == "${test_sig}" ]] && \ 70 | [[ "${z_hash}" == "${test_z_hash}" ]] && \ 71 | (( "$( verify "${z_hash}" "${pubkey_c}" "${sig}")" == 1 )) && \ 72 | (( "$( verify "${z_hash}" "${pubkey_u}" "${sig}")" == 1 )) 73 | } 74 | 75 | test_ecdsa_verify () 76 | { 77 | local -u z1_hash="$( sha256 "${test_z}" )" z2_hash="$( sha256 "${wrap_z}" )" 78 | (( $(verify "${z1_hash}" "${pubkey_c}" "${test_sig}") == 1 )) && \ 79 | (( $(verify "${z1_hash}" "${pubkey_u}" "${test_sig}") == 1 )) && \ 80 | (( $(verify "${z1_hash}" "${pubkey_c}" "${test_sig_r}" "${test_sig_s}") == 1 )) && \ 81 | (( $(verify "${z1_hash}" "${pubkey_u}" "${test_sig_r}" "${test_sig_s}") == 1 )) || (return 1) 82 | for ((i=0; i<${#pubkeys_c[@]}; i++)); do 83 | (( $(verify "${z2_hash}" "${pubkeys_c[$i]}" "${wrap_sig}") == 1 )) || (return 1) 84 | done 85 | } 86 | 87 | test_ecdsa_recover () 88 | { 89 | local -au rec1 rec2 90 | readarray -t rec1 < <( recover "${test_z_hash}" "${test_sig}" ) 91 | [[ "${rec1[1]}" == "${pubkey_c}" ]] || (return 1) 92 | readarray -t rec2 < <( recover "${wrap_z_hash}" "${wrap_sig_r}" "${wrap_sig_s}" ) 93 | for ((i=0; i<${#pubkeys_c[@]}; i++)); do 94 | [[ "${rec2[$i]}" == "${pubkeys_c[$i]}" ]] || (return 1) 95 | done 96 | } 97 | 98 | test_ecdsa () 99 | { 100 | test_ecdsa_res 101 | 102 | test_ecdsa_compresspubkey && \ 103 | test_ecdsa_uncompresspubkey && \ 104 | test_sig2der && \ 105 | test_der2sig && \ 106 | test_ecdsa_sign && \ 107 | test_ecdsa_verify && \ 108 | test_ecdsa_recover 109 | } 110 | test_ecdsa || return 1 111 | -------------------------------------------------------------------------------- /bitcoin/bips/.tests/test_bip32.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | test_bip32_vectors () 4 | { 5 | declare -A vec1 vec2 vec3 6 | 7 | seed1='000102030405060708090a0b0c0d0e0f' 8 | path1='0h/1/2h/2/1000000000' 9 | vec1_priv=( \ 10 | 'xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi' \ 11 | 'xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7' \ 12 | 'xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs' \ 13 | 'xprv9z4pot5VBttmtdRTWfWQmoH1taj2axGVzFqSb8C9xaxKymcFzXBDptWmT7FwuEzG3ryjH4ktypQSAewRiNMjANTtpgP4mLTj34bhnZX7UiM' \ 14 | 'xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334' \ 15 | 'xprvA41z7zogVVwxVSgdKUHDy1SKmdb533PjDz7J6N6mV6uS3ze1ai8FHa8kmHScGpWmj4WggLyQjgPie1rFSruoUihUZREPSL39UNdE3BBDu76' ) 16 | vec1_pub=( \ 17 | 'xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8' \ 18 | 'xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw' \ 19 | 'xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ' \ 20 | 'xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5' \ 21 | 'xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV' \ 22 | 'xpub6H1LXWLaKsWFhvm6RVpEL9P4KfRZSW7abD2ttkWP3SSQvnyA8FSVqNTEcYFgJS2UaFcxupHiYkro49S8yGasTvXEYBVPamhGW6cFJodrTHy' ) 23 | 24 | seed2='fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542' 25 | path2='0/2147483647h/1/2147483646h/2' 26 | vec2_priv=( \ 27 | 'xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U' \ 28 | 'xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt' \ 29 | 'xprv9wSp6B7kry3Vj9m1zSnLvN3xH8RdsPP1Mh7fAaR7aRLcQMKTR2vidYEeEg2mUCTAwCd6vnxVrcjfy2kRgVsFawNzmjuHc2YmYRmagcEPdU9' \ 30 | 'xprv9zFnWC6h2cLgpmSA46vutJzBcfJ8yaJGg8cX1e5StJh45BBciYTRXSd25UEPVuesF9yog62tGAQtHjXajPPdbRCHuWS6T8XA2ECKADdw4Ef' \ 31 | 'xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc' \ 32 | 'xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw7nadnHM8Dq38EGfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j' ) 33 | vec2_pub=( \ 34 | 'xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB' \ 35 | 'xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH' \ 36 | 'xpub6ASAVgeehLbnwdqV6UKMHVzgqAG8Gr6riv3Fxxpj8ksbH9ebxaEyBLZ85ySDhKiLDBrQSARLq1uNRts8RuJiHjaDMBU4Zn9h8LZNnBC5y4a' \ 37 | 'xpub6DF8uhdarytz3FWdA8TvFSvvAh8dP3283MY7p2V4SeE2wyWmG5mg5EwVvmdMVCQcoNJxGoWaU9DCWh89LojfZ537wTfunKau47EL2dhHKon' \ 38 | 'xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL' \ 39 | 'xpub6FnCn6nSzZAw5Tw7cgR9bi15UV96gLZhjDstkXXxvCLsUXBGXPdSnLFbdpq8p9HmGsApME5hQTZ3emM2rnY5agb9rXpVGyy3bdW6EEgAtqt' ) 40 | 41 | seed3='4b381541583be4423346c643850da4b320e46a87ae3d2a4e6da11eba819cd4acba45d239319ac14f863b8d5ab5a0d0c64d2e8a1e7d1457df2e5a3c51c73235be' 42 | path3='0h' 43 | vec3_priv=( \ 44 | 'xprv9s21ZrQH143K25QhxbucbDDuQ4naNntJRi4KUfWT7xo4EKsHt2QJDu7KXp1A3u7Bi1j8ph3EGsZ9Xvz9dGuVrtHHs7pXeTzjuxBrCmmhgC6' \ 45 | 'xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L' ) 46 | vec3_pub=( \ 47 | 'xpub661MyMwAqRbcEZVB4dScxMAdx6d4nFc9nvyvH3v4gJL378CSRZiYmhRoP7mBy6gSPSCYk6SzXPTf3ND1cZAceL7SfJ1Z3GC8vBgp2epUt13' \ 48 | 'xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y' ) 49 | } 50 | 51 | test_bip32 () 52 | { 53 | test_bip32_vectors 54 | local -a xprivs xpubs 55 | 56 | readarray -t xprivs < <( bip32_master "${seed1}" | bip32_encode_master | bip32_encode | bip32_derive_path "${path1}" ) 57 | for (( i=0; i<${#vec1_priv[@]}; i++ )); do 58 | xpubs[$i]="$( base58dec "${xprivs[$i]}" | bip32_neuter | bip32_encode )" 59 | [[ "${vec1_priv[$i]}" == "${xprivs[$i]}" ]] || return 1 60 | [[ "${vec1_pub[$i]}" == "${xpubs[$i]}" ]] || return 1 61 | done 62 | xprivs=(); xpubs=() 63 | readarray -t xprivs < <( bip32_master "${seed2}" | bip32_encode_master | bip32_encode | bip32_derive_path "${path2}" ) 64 | for (( i=0; i<${#vec2_priv[@]}; i++ )); do 65 | xpubs[$i]="$( base58dec "${xprivs[$i]}" | bip32_neuter | bip32_encode )" 66 | [[ "${vec2_priv[$i]}" == "${xprivs[$i]}" ]] || return 1 67 | [[ "${vec2_pub[$i]}" == "${xpubs[$i]}" ]] || return 1 68 | done 69 | xprivs=(); xpubs=() 70 | readarray -t xprivs < <( bip32_master "${seed3}" | bip32_encode_master | bip32_encode | bip32_derive_path "${path3}" ) 71 | for (( i=0; i<${#vec3_priv[@]}; i++ )); do 72 | xpubs[$i]="$( base58dec "${xprivs[$i]}" | bip32_neuter | bip32_encode )" 73 | [[ "${vec3_priv[$i]}" == "${xprivs[$i]}" ]] || return 1 74 | [[ "${vec3_pub[$i]}" == "${xpubs[$i]}" ]] || return 1 75 | done 76 | } 77 | test_bip32_vectors 78 | test_bip32 || return 1 79 | -------------------------------------------------------------------------------- /schnorr/schnorr_ifc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | schnorr_hs_sign () 4 | { 5 | local -u m="$1" d="$2" a="$3" k r h 6 | 7 | read k < <( rfc6979_secp256k1_sha256_k "$d" "$m" ) 8 | r="$( bc_ecmath <<<" \ 9 | ecmul_api(${k}, curve_gx, curve_gy, curve_n, curve_p, r[]); \ 10 | left_pad(r[0], curve_words);")" 11 | read h < <( sha256 "${m}${r}${a}" ) 12 | printf '%s ' "$h" 13 | bc_ecschnorr <<<"ec_schnorr_sign(${h}, ${d}, ${k});" 14 | } 15 | 16 | schnorr_hs_verify () 17 | { 18 | local -u m="$1" p="$2" h="$3" s="$4" a="$5" q v 19 | 20 | q="$( bc_ecschnorr <<<"ec_schnorr_verify(${p}, ${h}, ${s});")" 21 | if [[ -z ${q/0//} ]]; then 22 | decho "false (q == 0)" 23 | return 1 24 | fi 25 | read v < <( sha256 "${m}${q}${a}" ) 26 | if [[ "$v" == "$h" ]]; then 27 | decho "true" 28 | else 29 | decho "false (v != h)" 30 | fi 31 | } 32 | 33 | schnorr_rs_sign () 34 | { 35 | local -u m="$1" d="$2" k="$4" q h recoverable="${3:-0}" 36 | 37 | if [[ -z "$k" ]]; then 38 | read k < <( rfc6979_secp256k1_sha256_k "$d" "$m" ) 39 | fi 40 | read k r < <( bc_ecschnorr <<<" \ 41 | ecmul_api(${k}, curve_gx, curve_gy, curve_n, curve_p, r[]); \ 42 | if ( ! is_residue( r[1], 2, curve_p )){ \ 43 | print mod(-${k}, curve_n), \" \"; \ 44 | } else { \ 45 | print ${k}, \" \"; \ 46 | }; \ 47 | left_pad(r[0], curve_words);") 48 | read h < <( sha256 "${r}${m}" ) 49 | printf '%s ' "${r}" 50 | bc_ecschnorr <<<"ec_schnorr_sign(${h}, ${d}, ${k});" 51 | } 52 | 53 | schnorr_rs_sign_recoverable () 54 | { 55 | schnorr_rs_sign "$1" "$2" "1" "$4" 56 | } 57 | 58 | schnorr_rs_verify () 59 | { 60 | local -u m="$1" q="$2" r="$3" s="$4" h 61 | 62 | read h < <( sha256 "${r}${m}" ) 63 | v="$(bc_ecschnorr <<<" \ 64 | if ( (${s} >= curve_n) || \ 65 | (${r} >= curve_p) || \ 66 | ((${h} > 0) && (${h} >= curve_n))){ \ 67 | print \"invalid (r,s,h)\\n\"; \ 68 | halt; \ 69 | }; \ 70 | uncompresspoint_api(${q}, q[]); \ 71 | valid = ec_schnorr_verify_api(q[0], q[1], curve_gx, curve_gy, ${h}, ${s}, curve_n, curve_p, v[]); \ 72 | if ( valid && is_residue(v[1], 2, curve_p) ){ \ 73 | left_pad(v[0], curve_words); \ 74 | } else { 0; };")" 75 | if [[ "${v}" == "${r}" ]]; then 76 | decho "true" 77 | else 78 | decho "false (v != r)" 79 | fi 80 | } 81 | 82 | schnorr_rs_recover () 83 | { 84 | local -u m="$1" r="$2" s="$3" h 85 | 86 | read h < <( sha256 "${r}${m}" ) 87 | bc_ecschnorr <<<" \ 88 | if ( (${s} >= curve_n) || \ 89 | (${h} >= curve_n)){ \ 90 | print \"invalid (r,s)\\n\"; \ 91 | halt; \ 92 | }; \ 93 | r[0] = ${r}; 94 | gety_api(${r}, r_yvals[]); \ 95 | if ( ! is_residue(r_yvals[0], 2, curve_p) ){ \ 96 | r[1] = r_yvals[0]; \ 97 | } else { \ 98 | r[1] = r_yvals[1]; \ 99 | }; \ 100 | # if ( ! ispoint(r[0], r[1]) ){ \ 101 | if ( ! ispoint(r[]) ){ \ 102 | print \"invalid R\"; \ 103 | halt; \ 104 | }; \ 105 | ecmul_api(${s}, curve_gx, curve_gy, curve_n, curve_p, sg[]); \ 106 | ecadd_api(r[0], r[1], sg[0], sg[1], curve_p, rs[]); \ 107 | ecmul_api(-invmod(${h}, curve_n), rs[0], rs[1], curve_n, curve_p, q[]); \ 108 | compresspoint(q[]);" 109 | } 110 | 111 | schnorr_swap_sign () 112 | { 113 | local -u m="$1" d="$2" t="$3" c r r_t k q h 114 | 115 | read k < <( rfc6979_secp256k1_sha256_k "$d" "$m" ) 116 | read k q c r r_t < <( bc_ecschnorr <<<" \ 117 | ecmul_api(${k}, curve_gx, curve_gy, curve_n, curve_p, r[]); \ 118 | ecmul_api(${t}, curve_gx, curve_gy, curve_n, curve_p, c[]); \ 119 | if ( ! is_residue( r[1], 2, curve_p )){ \ 120 | print mod(-${k}, curve_n), \" \"; \ 121 | r[1] = mod(-r[1], curve_p); \ 122 | tweak = mod(-${k}+${t}, curve_n); \ 123 | } else { \ 124 | print ${k}, \" \"; \ 125 | tweak = mod(${k}+${t}, curve_n); \ 126 | }; \ 127 | ecmul_api(tweak, curve_gx, curve_gy, curve_n, curve_p, r_t[]); \ 128 | ecmul_api(${d}, curve_gx, curve_gy, curve_n, curve_p, q[]); \ 129 | compresspoint_api(q[]); \ 130 | compresspoint_api(c[]); \ 131 | compresspoint_api(r[]); \ 132 | compresspoint_api(r_t[]);") 133 | read h < <( sha256 "${q}${r_t}${m}" ) 134 | decho "h : ${h}" 135 | printf '%s ' "${c}" "${r}" 136 | bc_ecschnorr <<<"\ 137 | mod(ec_schnorr_sign(${h}, ${d}, ${k}+${t}) - ${t}, curve_n); \ 138 | print \"s : \", ec_schnorr_sign(${h}, ${d}, ${k}+${t}), \"\n\";" 139 | } 140 | 141 | schnorr_swap_verify () 142 | { 143 | local -u m="$1" q="$2" c="$3" r="$4" s="$5" r_c h 144 | 145 | read r_t < <( bc_ecschnorr <<<"ecadd(${c}, ${r});" ) 146 | read h < <( sha256 "${q}${r_t}${m}" ) 147 | decho "h : ${h}" 148 | v="$(bc_ecschnorr <<<" \ 149 | if ( (${s} >= curve_n) || \ 150 | ((${h} > 0) && (${h} >= curve_n))){ \ 151 | print \"invalid (r,s,h)\\n\"; \ 152 | halt; \ 153 | }; \ 154 | uncompresspoint_api(${q}, q[]); \ 155 | valid = ec_schnorr_verify_api(q[0], q[1], curve_gx, curve_gy, ${h}, ${s}, curve_n, curve_p, v[]); \ 156 | compresspoint(v[]);")" 157 | decho "r : ${r}" 158 | decho "v : ${v}" 159 | if [[ "${v}" == "${r}" ]]; then 160 | decho "true" 161 | else 162 | decho "false (v != r)" 163 | fi 164 | } 165 | 166 | schnorr_swap_deny () 167 | { 168 | local -u m="$1" q="$2" r1="$4" s1="$5" s2="$6" r2="$7" t c r_t h 169 | } 170 | -------------------------------------------------------------------------------- /bc/ec_math/ec_point.bc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bc 2 | 3 | # functions for points on elliptic curves 4 | 5 | define void gety_fast_api(x, *yarr[]) 6 | { 7 | auto q, z, ysq, tmp; 8 | 9 | q = (curve_p - 1) / 2; 10 | z = invmod(2, q); 11 | ysq = mod((powmod(x, 3, curve_p) + curve_b), curve_p); 12 | # would've been this next line, but our curve_a is zero. 13 | # ysq = mod((powmod(x, 3, curve_p) + (curve_a * x) + curve_b), curve_p); 14 | 15 | tmp = powmod(ysq, z, curve_p); 16 | #if (! ispoint(x, tmp)) { 17 | if ( !ispoint_api(x, tmp, curve_a, curve_b, curve_p) ) { 18 | yarr[0] = 0; 19 | yarr[0] = 0; 20 | return; 21 | } 22 | if (tmp % 2 == 0) { 23 | yarr[0] = tmp; 24 | yarr[1] = mod(-tmp, curve_p); 25 | } else { 26 | yarr[0] = mod(-tmp, curve_p); 27 | yarr[1] = tmp; 28 | } 29 | } 30 | 31 | define gety_fast(x) 32 | { 33 | auto ret[]; 34 | 35 | gety_fast_api(x, ret[]) 36 | return ret[0]; 37 | } 38 | 39 | define is_parsable_point(p) 40 | { 41 | auto size_p; 42 | size_p = wordlen(p); 43 | 44 | if ( (size_p == (curve_words * 2) + 1) || (size_p == curve_words + 1) ) { 45 | return 1; 46 | } else { 47 | return 0; 48 | } 49 | } 50 | 51 | define is_point_compressed(p) 52 | { 53 | if ( is_point_compressed_or_uncompressed(p) && (wordlen(p) == curve_words + 1) ) { 54 | return 1; 55 | } else { 56 | return 0; 57 | } 58 | } 59 | 60 | define void getyfromx_api(x, *yvals[]) 61 | { 62 | auto roots[]; 63 | if (is_residue(powmod(x, 3, curve_p) + curve_b, 2, curve_p)) { 64 | rootmod_api(powmod(x, 3, curve_p) + curve_b, 2, curve_p, roots[]); 65 | yvals[0] = roots[1]; 66 | yvals[1] = roots[2]; 67 | } else { 68 | yvals[0] = 0; 69 | yvals[1] = 0; 70 | } 71 | } 72 | 73 | define void getxfromy_api(y, *ret[]) 74 | { 75 | auto roots[]; 76 | 77 | if (is_residue(powmod(y, 2, curve_p) - curve_b, 3, curve_p)) { 78 | rootmod_api(powmod(y, 2, curve_p) - curve_b, 3, curve_p, roots[]); 79 | ret[0] = roots[1]; 80 | ret[1] = roots[2]; 81 | ret[2] = roots[3]; 82 | } else { 83 | ret[0] = 0; 84 | ret[1] = 0; 85 | ret[2] = 0; 86 | } 87 | } 88 | 89 | define getyfromx(x) 90 | { 91 | auto ret[]; 92 | 93 | getyfromx_api(x, ret[]); 94 | if (ret[0] == 0) 95 | print "\n# *** Not a residue of pow 2\n"; 96 | return ret[0]; 97 | } 98 | 99 | define getxfromy(y) 100 | { 101 | auto ret[]; 102 | 103 | getxfromy_api(y, ret[]); 104 | if (ret[0] == 0) 105 | print "\n# *** Not a residue of pow 3\n"; 106 | return ret[0]; 107 | } 108 | 109 | define void gety_api(x, *yvals[]) 110 | { 111 | auto ret[]; 112 | if (curve_p % 4 == 3) { 113 | gety_fast_api(x, ret[]); 114 | } else { 115 | getyfromx_api(x, ret[]); 116 | } 117 | 118 | yvals[0] = ret[0]; 119 | yvals[1] = ret[1]; 120 | } 121 | 122 | define void gety(x) 123 | { 124 | auto ret[]; 125 | gety_api(x, ret[]); 126 | if (ret[0] == 0) { 127 | print "\n# not an x coordinate\n"; 128 | return; 129 | } 130 | print "\n# y1 = ", ret[0]; 131 | print "\n# y2 = ", ret[1], "\n"; 132 | } 133 | 134 | define void getx(y) 135 | { 136 | auto ret[]; 137 | 138 | getyfromx(y, ret[]); 139 | if (ret[0] == 0) { 140 | print "\n# not a y coordinate\n"; 141 | return; 142 | } 143 | print "\n# x1 = ", ret[0]; 144 | print "\n# x2 = ", ret[1]; 145 | print "\n# x3 = ", ret[2], "\n"; 146 | } 147 | 148 | define ispoint_api(x, y, a, b, p) 149 | { 150 | auto ysq, xcb, ax, ans; 151 | 152 | ysq = powmod(y, 2, p); 153 | xcb = powmod(x, 3, p); 154 | ax = mod(a * x, p); 155 | ans = mod( mod((ysq - xcb - ax - b), p), p); 156 | return (ans == 0); 157 | } 158 | 159 | define ispoint(*pt[]) 160 | { 161 | return ispoint_api(pt[0], pt[1], curve_a, curve_b, curve_p); 162 | } 163 | 164 | define void coords2ptarr(x, y, *ret[]) 165 | { 166 | ret[0] = x; 167 | ret[1] = y; 168 | } 169 | 170 | define compresspoint_api(x, y) 171 | { 172 | if ( ispoint_api(x, y, curve_a, curve_b, curve_p) ) { 173 | if (y % 2 == 1) { 174 | return (x + 3*(10 ^ curve_words)); 175 | } else { 176 | return (x + 2*(10 ^ curve_words)); 177 | } 178 | } else { 179 | return 0; 180 | } 181 | } 182 | 183 | define compresspoint(pt[]) 184 | { 185 | auto res; 186 | 187 | res = compresspoint_api(pt[0], pt[1]); 188 | if (res == 0) { 189 | print "\n ### Not a point\n"; 190 | } else { 191 | print "0"; 192 | } 193 | return res; 194 | } 195 | 196 | define void uncompresspoint_api(x, *point[]) 197 | { 198 | auto tmp[]; 199 | 200 | if ( x < 0 ) { 201 | if ( x < (10 ^ curve_words)*3 ) { 202 | x = (-x) - (10 ^ curve_words); 203 | } else if ( x < (10 ^ curve_words)*2 ) { 204 | x = (-x) + (10 ^ curve_words); 205 | } 206 | } 207 | 208 | gety_api(( mod(x, 10 ^ curve_words) ), tmp[]); 209 | 210 | if ( x > ( 3*(10 ^ curve_words) ) ) { 211 | point[0] = ( x - 3*(10 ^ curve_words) ); 212 | point[1] = tmp[1]; 213 | } else if ( x > ( 2*(10 ^ curve_words) ) ) { 214 | point[0] = ( x - 2*(10 ^ curve_words) ); 215 | point[1] = tmp[0]; 216 | } else { 217 | point[0] = 0; 218 | point[1] = 0; 219 | } 220 | } 221 | 222 | define uncompresspoint(x) 223 | { 224 | auto ret[], pt; 225 | 226 | uncompresspoint_api(x, ret[]); 227 | pt = 4 * (10 ^ (curve_words*2)); 228 | pt += (ret[0] * (10 ^ curve_words)); 229 | pt += ret[1]; 230 | print "0"; 231 | return pt; 232 | } 233 | 234 | define compresspubkey(pub) 235 | { 236 | auto cpub, tmp; 237 | 238 | cpub = pub / (10 ^ curve_words); 239 | if (pub % 2) { 240 | cpub -= 10^curve_words; 241 | } else { 242 | cpub -= 2*10^curve_words; 243 | } 244 | print "0" 245 | return cpub; 246 | } 247 | -------------------------------------------------------------------------------- /hash/.tests/test_hmac.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | testhmac() { 4 | 5 | local -u key data 6 | 7 | key="0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B" 8 | read data < <( echo -n "Hi There" | bin2hex ) 9 | # data="4869205468657265" 10 | hmac "${key}" "${data}" "$1" 11 | 12 | read key < <( echo -n "Jefe" | bin2hex ) 13 | # key="4A656665" 14 | read data < <( echo -n "what do ya want for nothing?" | bin2hex ) 15 | # data="7768617420646F2079612077616E7420666F72206E6F7468696E673F" 16 | hmac "${key}" "${data}" "$1" 17 | 18 | key="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" 19 | data="DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD" 20 | hmac "${key}" "${data}" "$1" 21 | 22 | key="0102030405060708090A0B0C0D0E0F10111213141516171819" 23 | data="CDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCD" 24 | hmac "${key}" "${data}" "$1" 25 | 26 | key="0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C" 27 | read data < <( echo -n "Test With Truncation" | bin2hex ) 28 | # data="546573742057697468205472756E636174696F6E" 29 | hmac "${key}" "${data}" "$1" 30 | 31 | key="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" 32 | read data < <( echo -n "Test Using Larger Than Block-Size Key - Hash Key First" | bin2hex ) 33 | # data="54657374205573696E67204C6172676572205468616E20426C6F636B2D53697A65204B6579202D2048617368204B6579204669727374" 34 | hmac "${key}" "${data}" "$1" 35 | 36 | key="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" 37 | read data < <( echo -n "This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm." | bin2hex ) 38 | # data="5468697320697320612074657374207573696E672061206C6172676572207468616E20626C6F636B2D73697A65206B657920616E642061206C6172676572207468616E20626C6F636B2D73697A6520646174612E20546865206B6579206E6565647320746F20626520686173686564206265666F7265206265696E6720757365642062792074686520484D414320616C676F726974686D2E" 39 | hmac "${key}" "${data}" "$1" 40 | } 41 | 42 | testhmac_sha256() { 43 | 44 | local -a ret 45 | readarray -t ret < <( testhmac 'sha256' ) 46 | 47 | # printf "%s\n" ${ret[@]} 48 | [[ "${ret[0]}" == "B0344C61D8DB38535CA8AFCEAF0BF12B881DC200C9833DA726E9376C2E32CFF7" ]] && \ 49 | [[ "${ret[1]}" == "5BDCC146BF60754E6A042426089575C75A003F089D2739839DEC58B964EC3843" ]] && \ 50 | [[ "${ret[2]}" == "773EA91E36800E46854DB8EBD09181A72959098B3EF8C122D9635514CED565FE" ]] && \ 51 | [[ "${ret[3]}" == "82558A389A443C0EA4CC819899F2083A85F0FAA3E578F8077A2E3FF46729665B" ]] && \ 52 | [[ "${ret[4]:0:32}" == "A3B6167473100EE06E0C796C2955552B" ]] && \ 53 | [[ "${ret[5]}" == "60E431591EE0B67F0D8A26AACBF5B77F8E0BC6213728C5140546040F0EE37F54" ]] && \ 54 | [[ "${ret[6]}" == "9B09FFA71B942FCB27635FBCD5B0E944BFDC63644F0713938A7F51535C3A35E2" ]] # && \ 55 | # echo "testhmac_sha256() passed" 56 | } 57 | 58 | testhmac_sha224() { 59 | 60 | local -a ret 61 | readarray -t ret < <( testhmac 'sha224' ) 62 | 63 | # printf "%s\n" ${ret[@]} 64 | [[ "${ret[0]}" == "896FB1128ABBDF196832107CD49DF33F47B4B1169912BA4F53684B22" ]] && \ 65 | [[ "${ret[1]}" == "A30E01098BC6DBBF45690F3A7E9E6D0F8BBEA2A39E6148008FD05E44" ]] && \ 66 | [[ "${ret[2]}" == "7FB3CB3588C6C1F6FFA9694D7D6AD2649365B0C1F65D69D1EC8333EA" ]] && \ 67 | [[ "${ret[3]}" == "6C11506874013CAC6A2ABC1BB382627CEC6A90D86EFC012DE7AFEC5A" ]] && \ 68 | [[ "${ret[4]:0:32}" == "0E2AEA68A90C8D37C988BCDB9FCA6FA8" ]] && \ 69 | [[ "${ret[5]}" == "95E9A0DB962095ADAEBE9B2D6F0DBCE2D499F112F2D2B7273FA6870E" ]] && \ 70 | [[ "${ret[6]}" == "3A854166AC5D9F023F54D517D0B39DBD946770DB9C2B95C9F6F565D1" ]] # && \ 71 | # echo "testhmac_sha224() passed" 72 | } 73 | 74 | testhmac_sha384() { 75 | 76 | local -a ret 77 | readarray -t ret < <( testhmac 'sha384' ) 78 | 79 | # printf "%s\n" ${ret[@]} 80 | [[ "${ret[0]}" == "AFD03944D84895626B0825F4AB46907F15F9DADBE4101EC682AA034C7CEBC59CFAEA9EA9076EDE7F4AF152E8B2FA9CB6" ]] && \ 81 | [[ "${ret[1]}" == "AF45D2E376484031617F78D2B58A6B1B9C7EF464F5A01B47E42EC3736322445E8E2240CA5E69E2C78B3239ECFAB21649" ]] && \ 82 | [[ "${ret[2]}" == "88062608D3E6AD8A0AA2ACE014C8A86F0AA635D947AC9FEBE83EF4E55966144B2A5AB39DC13814B94E3AB6E101A34F27" ]] && \ 83 | [[ "${ret[3]}" == "3E8A69B7783C25851933AB6290AF6CA77A9981480850009CC5577C6E1F573B4E6801DD23C4A7D679CCF8A386C674CFFB" ]] && \ 84 | [[ "${ret[4]:0:32}" == "3ABF34C3503B2A23A46EFC619BAEF897" ]] && \ 85 | [[ "${ret[5]}" == "4ECE084485813E9088D2C63A041BC5B44F9EF1012A2B588F3CD11F05033AC4C60C2EF6AB4030FE8296248DF163F44952" ]] && \ 86 | [[ "${ret[6]}" == "6617178E941F020D351E2F254E8FD32C602420FEB0B8FB9ADCCEBB82461E99C5A678CC31E799176D3860E6110C46523E" ]] # && \ 87 | # echo "testhmac_sha384() passed" 88 | } 89 | 90 | testhmac_sha512() { 91 | 92 | local -a ret 93 | readarray -t ret < <( testhmac 'sha512' ) 94 | 95 | # printf "%s\n" ${ret[@]} 96 | [[ "${ret[0]}" == "87AA7CDEA5EF619D4FF0B4241A1D6CB02379F4E2CE4EC2787AD0B30545E17CDEDAA833B7D6B8A702038B274EAEA3F4E4BE9D914EEB61F1702E696C203A126854" ]] && \ 97 | [[ "${ret[1]}" == "164B7A7BFCF819E2E395FBE73B56E0A387BD64222E831FD610270CD7EA2505549758BF75C05A994A6D034F65F8F0E6FDCAEAB1A34D4A6B4B636E070A38BCE737" ]] && \ 98 | [[ "${ret[2]}" == "FA73B0089D56A284EFB0F0756C890BE9B1B5DBDD8EE81A3655F83E33B2279D39BF3E848279A722C806B485A47E67C807B946A337BEE8942674278859E13292FB" ]] && \ 99 | [[ "${ret[3]}" == "B0BA465637458C6990E5A8C5F61D4AF7E576D97FF94B872DE76F8050361EE3DBA91CA5C11AA25EB4D679275CC5788063A5F19741120C4F2DE2ADEBEB10A298DD" ]] && \ 100 | [[ "${ret[4]:0:32}" == "415FAD6271580A531D4179BC891D87A6" ]] && \ 101 | [[ "${ret[5]}" == "80B24263C7C1A3EBB71493C1DD7BE8B49B46D1F41B4AEEC1121B013783F8F3526B56D037E05F2598BD0FD2215D6A1E5295E64F73F63F0AEC8B915A985D786598" ]] && \ 102 | [[ "${ret[6]}" == "E37B6A775DC87DBAA4DFA9F96E5E3FFDDEBD71F8867289865DF5A32D20CDC944B6022CAC3C4982B10D5EEB55C3E4DE15134676FB6DE0446065C97440FA8C6A58" ]] # && \ 103 | # echo "testhmac_sha512() passed" 104 | } 105 | testhmac_sha256 && \ 106 | testhmac_sha224 && \ 107 | testhmac_sha384 && \ 108 | testhmac_sha512 109 | -------------------------------------------------------------------------------- /bitcoin/parse.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | tx_deser_version () 4 | { 5 | if (( ${#1} != 8 )); then 6 | 7 | echo -1 # bad version 8 | return 9 | fi 10 | tx_deser_int "${1}" 11 | } 12 | 13 | tx_compsize_len () 14 | { 15 | local -u byte="$1" 16 | if [[ ${byte} < FD ]]; then echo 2 && return; fi 17 | if [[ ${byte} < FE ]]; then echo "$(( 4+2 ))" && return; fi 18 | if [[ ${byte} < FF ]]; then echo "$(( 8+2 ))" && return; fi 19 | 20 | echo "$(( 16+2 ))" && return 21 | } 22 | 23 | tx_deser_compsize () 24 | { 25 | local -u revcsize 26 | if [[ "${1:0:2}" < FD ]]; then 27 | 28 | echo "$(( 2*$((16#${1})) ))" 29 | return 30 | fi 31 | read revcsize < <( revchunks "${1:2}" ) 32 | 33 | bc_clean <<<"ibase=16; ${revcsize}*2" 34 | } 35 | 36 | tx_parse () 37 | { 38 | if [[ "${1}" == "" ]] 39 | then 40 | local -u tx 41 | read tx 42 | tx_parse "${tx}" 43 | return 44 | fi 45 | 46 | local -u version tmpbytes tmpval swmarker swflag wit_size 47 | local -i ptr=0 segwit_tx=0 num_inputs num_outputs 48 | local -au txid_index in_script_size in_script in_seq 49 | local -au out_amount out_script_size out_script 50 | local -au num_wits tmpwits in_wits 51 | 52 | version="${1:0:8}" 53 | ptr=8 54 | tmpbytes="${1:${ptr}:2}" 55 | 56 | decho "version : ${version}\nptr : ${ptr}" 57 | if [[ "${tmpbytes}" == "00" ]]; then 58 | 59 | swmarker="00" 60 | swflag="${1:10:2}" 61 | 62 | if [[ "${swflag}" == "01" ]]; then 63 | 64 | ptr="$(( ${ptr}+4 ))" 65 | tmpbytes="${1:${ptr}:2}" 66 | 67 | if [[ "${tmpbytes}" == "00" ]] || [[ "$2" == 'fnosw' ]]; then 68 | 69 | ptr="$(( ${ptr}-4 ))" 70 | segwit_tx=0 71 | swmarker= 72 | swflag= 73 | fi 74 | segwit_tx=1 75 | else 76 | segwit_tx=0 77 | swmarker= 78 | swflag= 79 | fi 80 | fi 81 | decho "segwit_tx : ${segwit_tx}\nswmarker : ${swmarker}\nswflag : ${swflag}\nptr : ${ptr}" 82 | 83 | read tmpval < <( tx_compsize_len "${1:${ptr}:2}" ) 84 | read num_inputs < <( tx_deser_compsize "${1:${ptr}:${tmpval}}" ) 85 | ptr="$(( ${ptr}+${tmpval} ))" 86 | decho "num_inputs : $(( ${num_inputs}/2 ))\nptr : ${ptr}" 87 | 88 | for (( i=0; i<$(( ${num_inputs}/2 )); i++ )); do 89 | 90 | if [[ "${1:${ptr}:1}" == "" ]]; then 91 | 92 | if (( ${segwit_tx} == 1 )); then 93 | 94 | segwit_tx=0 95 | ptr=8 96 | read tmpval < <( tx_compsize_len "${1:${ptr}:2}" ) 97 | read num_inputs < <( tx_deser_compsize "${1:${ptr}:${tmpval}}" ) 98 | ptr="$(( ${ptr}+${tmpval} ))" 99 | i=0 100 | decho "-------------------------------------------------" 101 | decho "num_inputs : $(( ${num_inputs}/2 ))\nptr : ${ptr}" 102 | continue 103 | else 104 | decho "PARSE_TX FAILED" 105 | return 106 | fi 107 | fi 108 | 109 | txid_index[$i]="${1:${ptr}:72}" 110 | ptr="$(( ${ptr}+72 ))" 111 | decho "txid_index[$i] : ${txid_index[$i]}\nptr : ${ptr}" 112 | 113 | read tmpval < <( tx_compsize_len "${1:${ptr}:2}" ) 114 | in_script_size[$i]="${1:${ptr}:${tmpval}}" 115 | ptr="$(( ${ptr}+${tmpval} ))" 116 | decho "in_script_size[$i] : ${in_script_size[$i]}\nptr : ${ptr}" 117 | 118 | read tmpval < <( tx_deser_compsize "${in_script_size[$i]}" ) 119 | in_script[$i]="${1:${ptr}:${tmpval}}" 120 | ptr="$(( ${ptr}+${tmpval} ))" 121 | decho "in_script[$i] : ${in_script[$i]}\nptr : ${ptr}" 122 | 123 | in_seq[$i]="${1:${ptr}:8}" 124 | ptr="$(( ${ptr}+8 ))" 125 | decho "in_seq[$i] : ${in_seq[$i]}\nptr : ${ptr}" 126 | done 127 | 128 | read tmpval < <( tx_compsize_len "${1:${ptr}:2}" ) 129 | read num_outputs < <( tx_deser_compsize "${1:${ptr}:${tmpval}}" ) 130 | ptr="$(( ${ptr}+${tmpval} ))" 131 | decho "num_outputs : $(( ${num_outputs}/2 ))\nptr : ${ptr}" 132 | 133 | for (( i=0; i<$(( ${num_outputs}/2 )); i++ )); do 134 | 135 | if [[ "${1:${ptr}:1}" == "" ]]; then 136 | 137 | decho "PARSE_TX FAILED" 138 | return 139 | fi 140 | 141 | out_amount="${1:${ptr}:16}" 142 | ptr="$(( ${ptr}+16 ))" 143 | decho "out_amount : ${out_amount}\nptr : ${ptr}" 144 | 145 | read tmpval < <( tx_compsize_len "${1:${ptr}:2}" ) 146 | out_script_size[$i]="${1:${ptr}:${tmpval}}" 147 | ptr="$(( ${ptr}+${tmpval} ))" 148 | decho "out_script_size[$i] : ${out_script_size[$i]}\nptr : ${ptr}" 149 | 150 | read tmpval < <( tx_deser_compsize "${out_script_size[$i]}" ) 151 | out_script[$i]="${1:${ptr}:${tmpval}}" 152 | ptr="$(( ${ptr}+${tmpval} ))" 153 | decho "out_script[$i] : ${out_script[$i]}\nptr : ${ptr}" 154 | done 155 | 156 | if (( ${segwit_tx} == 1 )); then 157 | 158 | if [[ "${1:${ptr}:1}" == "" ]]; then 159 | 160 | decho "PARSE_TX FAILED" 161 | return 162 | fi 163 | 164 | for (( i=0; i<$(( ${num_inputs}/2 )); i++ )); do 165 | 166 | read tmpval < <( tx_compsize_len "${1:${ptr}:2}" ) 167 | read num_wits[$i] < <( tx_deser_compsize "${1:${ptr}:${tmpval}}" ) 168 | ptr="$(( ${ptr}+${tmpval} ))" 169 | decho "num_wits[$i] : $(( ${num_wits[$i]}/2 ))\nptr : ${ptr}" 170 | 171 | wit_size="" 172 | tmpwits=() 173 | 174 | for (( j=0; j<$(( ${num_wits[$i]}/2 )); j++ )); do 175 | 176 | read tmpval < <( tx_compsize_len "${1:${ptr}:2}" ) 177 | wit_size="${1:${ptr}:${tmpval}}" 178 | ptr="$(( ${ptr}+${tmpval} ))" 179 | decho "wit_size : ${wit_size}\nptr : ${ptr}" 180 | 181 | read tmpval < <( tx_deser_compsize "${wit_size}" ) 182 | tmpwits[$j]="${wit_size}${1:${ptr}:${tmpval}}" 183 | ptr="$(( ${ptr}+${tmpval} ))" 184 | decho "tmpwits[$j] : ${tmpwits[$j]}\nptr : ${ptr}" 185 | done 186 | 187 | in_wits[$i]="${tmpwits[@]}" 188 | decho "in_wits[$i] : ${in_wits[$i]}" 189 | done 190 | fi 191 | 192 | nlocktime="${1:${ptr}:8}" 193 | decho "nlocktime : ${nlocktime}" 194 | ptr="$(( ${ptr}+8 ))" 195 | 196 | if [[ "${1:${ptr}:1}" != "" ]]; then 197 | 198 | decho "PARSE_TX FAILED" 199 | return 200 | fi 201 | } 202 | -------------------------------------------------------------------------------- /bitcoin/bips/bip173.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # bash implementation of https://github.com/sipa/bech32/blob/master/ref/python/segwit_addr.py 4 | # enables https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki 5 | 6 | _bech32_charset=( \ 7 | 'q' 'p' 'z' 'r' 'y' '9' 'x' '8' \ 8 | 'g' 'f' '2' 't' 'v' 'd' 'w' '0' \ 9 | 's' '3' 'j' 'n' '5' '4' 'k' 'h' \ 10 | 'c' 'e' '6' 'm' 'u' 'a' '7' 'l' ) 11 | 12 | declare -A _bech32_setchar 13 | _bech32_setchar=( \ 14 | [q]='0' [p]='1' [z]='2' [r]='3' [y]='4' [9]='5' [x]='6' [8]='7' \ 15 | [g]='8' [f]='9' [2]='10' [t]='11' [v]='12' [d]='13' [w]='14' [0]='15' \ 16 | [s]='16' [3]='17' [j]='18' [n]='19' [5]='20' [4]='21' [k]='22' [h]='23' \ 17 | [c]='24' [e]='25' [6]='26' [m]='27' [u]='28' [a]='29' [7]='30' [l]='31' ) 18 | 19 | bech32_polymod () 20 | { 21 | local -a generator values=( $@ ) 22 | local chk top i value 23 | generator=( 0x3b6a57b2 0x26508e6d 0x1ea119fa 0x3d4233dd 0x2a1462b3 ) 24 | chk=1 25 | for value in ${values[@]}; do 26 | top=$(( ${chk} >> 25 )) 27 | chk=$(( ( ${chk} & 0x1ffffff) << 5 ^ ${value} )) 28 | for i in {0..4}; do 29 | if (( ( ${top} >> ${i} ) & 1 )); then 30 | chk=$(( ${chk} ^ ${generator[$i]} )) 31 | else 32 | chk=$(( ${chk} ^ 0 )) 33 | fi 34 | done 35 | done 36 | echo ${chk} 37 | } 38 | 39 | bech32_hrp_expand () 40 | { 41 | local -a ords 42 | for ((i=0; i<${#1}; i++)); do 43 | printf -v ords[$i] '%d\n' "'${1:${i}:1}" # http://mywiki.wooledge.org/BashFAQ/071 , ord() 44 | done 45 | for ord in ${ords[@]}; do 46 | echo -n "$(( ${ord} >> 5 )) " 47 | done 48 | echo -n "0 " 49 | for ord in ${ords[@]}; do 50 | echo -n "$(( ${ord} & 31 )) " 51 | done 52 | echo 53 | } 54 | 55 | bech32_verify_checksum () 56 | { 57 | local -a hrp_vals 58 | local checksum_ret 59 | readarray -t hrp_vals < <( bech32_hrp_expand "$1" ) 60 | shift 61 | read checksum_ret < <( bech32_polymod ${hrp_vals[@]} ${@} ) 62 | (( ${checksum_ret} == 1 )) 63 | } 64 | 65 | bech32_create_checksum () 66 | { 67 | local -a hrp_vals values 68 | local polymod 69 | readarray -t hrp_vals < <( bech32_hrp_expand "$1" ) 70 | shift 71 | values=( ${hrp_vals[@]} ${@} ) 72 | read polymod < <( bech32_polymod ${values[@]} 0 0 0 0 0 0 ) 73 | polymod=$(( ${polymod} ^ 1 )) 74 | for i in {0..5}; do 75 | echo -n "$(( (${polymod} >> 5 * (5 - ${i})) & 31 )) " 76 | done 77 | echo 78 | } 79 | 80 | bech32_encode () 81 | { 82 | local val hrp="${1,,}" 83 | shift 84 | local -a checksum data=( ${@} ) 85 | readarray -t checksum < <( bech32_create_checksum "${hrp}" ${data[@]} ) 86 | echo -n "${hrp}1" 87 | for val in ${data[@]} ${checksum[@]}; do 88 | echo -n "${_bech32_charset[${val}]}" 89 | done 90 | echo 91 | } 92 | 93 | bech32_decode () 94 | { 95 | local i ord hrp="" pos enc bech="$1" 96 | local -a data 97 | for ((i=0; i<${#bech}; i++)); do 98 | printf -v ord '%d' "'${bech:${i}:1}" 99 | if (( ${ord} < 33 )) || (( ${ord} > 126 )); then 100 | echo 1 1>&2 101 | echo '_ _' 102 | return 1 103 | fi 104 | done 105 | if [[ ${bech,,} != ${bech} ]] && [[ ${bech^^} != ${bech} ]]; then 106 | echo 2 1>&2 107 | echo '_ _' 108 | return 1 109 | fi 110 | bech="${bech,,}" 111 | [[ ${bech} =~ 1 ]] && hrp="${bech%1*}" 112 | pos="${#hrp}" 113 | if (( ${pos} < 1 )) || (( (${pos} + 7) > ${#bech} )) || (( ${#bech} > 90 )); then 114 | echo 3 1>&2 115 | echo '_ _' 116 | return 1 117 | fi 118 | for ((i=(${#hrp}+1); i<${#bech}; i++)); do 119 | enc="${_bech32_setchar[${bech:${i}:1}]}" 120 | if [[ -z ${enc} ]]; then 121 | echo 4 1>&2 122 | echo '_ _' 123 | return 1 124 | else 125 | data+=( ${enc} ) 126 | fi 127 | done 128 | if ! bech32_verify_checksum "${hrp}" ${data[@]}; then 129 | echo 5 1>&2 130 | echo '_ _' 131 | return 1 132 | fi 133 | echo "${hrp,,}" 134 | echo "${data[@]:0:$((${#data[@]} - 6))}" 135 | } 136 | 137 | bech32_convertbits () 138 | { 139 | local -a data=( ${1} ) ret 140 | local frombits="$2" tobits="$3" pad="${4:-true}" 141 | local acc=0 bits=0 maxv max_acc value 142 | 143 | maxv=$(( (1 << ${tobits}) - 1 )) 144 | max_acc=$(( (1 << (${frombits} + ${tobits} - 1)) - 1 )) 145 | for value in ${data[@]}; do 146 | if (( ${value} < 0 )) || (( ${value} >> ${frombits} )); then 147 | echo '_' 148 | return 1 149 | fi 150 | acc=$(( ( ( ${acc} << ${frombits} ) | ${value} ) & ${max_acc} )) 151 | bits=$(( ${bits} + ${frombits} )) 152 | while (( ${bits} >= ${tobits} )); do 153 | bits=$(( ${bits} - ${tobits} )) 154 | ret+=( $(( (${acc} >> ${bits}) & ${maxv} )) ) 155 | done 156 | done 157 | if [[ ${pad} == true ]]; then 158 | if (( ${bits} > 0 )); then 159 | ret+=( $(( (${acc} << (${tobits} - ${bits})) & ${maxv} )) ) 160 | fi 161 | elif (( ${bits} >= ${frombits} )) || (( ( (${acc} << (${tobits} - ${bits}) ) & ${maxv}) )); then 162 | echo '_' 163 | return 1 164 | fi 165 | echo ${ret[@]} 166 | } 167 | 168 | bech32_swprog_decode () 169 | { 170 | local hrp="${1,,}" addr="$2" hrpgot 171 | local -a data decoded tmp 172 | readarray -t tmp < <( bech32_decode "${addr}" ) 173 | hrpgot=${tmp[0]} 174 | data=( ${tmp[1]} ) 175 | if [[ ${hrpgot} != ${hrp} ]]; then 176 | echo '_ _' 177 | return 1 178 | fi 179 | read -r decoded < <( bech32_convertbits "${data[*]:1}" 5 8 false ) 180 | decoded=( ${decoded[@]} ) 181 | if [[ ${decoded} == _ ]] || (( ${#decoded[@]} < 2 )) || (( ${#decoded[@]} > 40 )); then 182 | echo 1 1>&2 183 | echo '_ _' 184 | return 1 185 | fi 186 | if (( ${data[0]} > 16 )); then 187 | echo 2 1>&2 188 | echo '_ _' 189 | return 1 190 | fi 191 | if (( ${data[0]} == 0 )) && (( ${#decoded[@]} != 20 )) && (( ${#decoded[@]} != 32 )); then 192 | echo 3 1>&2 193 | echo '_ _' 194 | return 1 195 | fi 196 | echo "${data[0]}" 197 | echo "${decoded[@]}" 198 | } 199 | 200 | bech32_swprog_encode () 201 | { 202 | local hrp="${1,,}" witver="$2" ret 203 | shift; shift 204 | local -a witprog=( ${@} ) ver_prog converted 205 | read -r converted < <( bech32_convertbits "${witprog[*]}" 8 5 ) 206 | read -r ret < <( bech32_encode ${hrp} "${witver} ${converted[@]}" ) 207 | if ! bech32_swprog_decode "${hrp}" "${ret}" 1>/dev/null; then 208 | return 1 209 | fi 210 | echo "${ret}" 211 | } 212 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Bitcoin tools for bash and bc 2 | [![Build Status](https://travis-ci.org/fivepiece/btc-bash-ng.svg?branch=master)](https://travis-ci.org/fivepiece/btc-bash-ng) 3 | 4 | ## Setup 5 | 6 | ### Build BC 7 | 8 | You will need to install `libreadline` , for example `sudo apt-get install libreadline-dev` on Ubuntu. 9 | 10 | 1. `cd ./config` 11 | 2. run `./build_bc.sh` 12 | 13 | A symlink to BC will be created in `./config/bin` 14 | 15 | ### Set up paths 16 | 17 | 3. While still in `./config`, run: 18 | ``` 19 | for rtsh in $(echo bin/*.example); do \ 20 | cp $PWD/${rtsh} $PWD/${rtsh%.example}; \ 21 | chmod +x $PWD/${rtsh%.example}; \ 22 | done 23 | ``` 24 | 4. `cd ..` 25 | 5. `source activate.sh` 26 | 27 | ## math stuff 28 | 29 | 30 | See `./bc/` for some ec math and ecdsa tools. 31 | Fun things to try: 32 | 33 | rootmod(11, 3, curve_p) 34 | 35 | Returns the cube roots of 11 mod the curve's p 36 | 37 | balanced_length_mod((curve_n/2) + (curve_n/4), curve_p) 38 | balanced_length_mod(curve_p-((curve_n/2) + (curve_n/4)), curve_n) 39 | 40 | Returns balanced length multipliers for these two numbers 41 | 42 | ecmul(12EF) 43 | 44 | Multiplies `12EF` by the curve's generator and returns the point 45 | 46 | ecadd(curve_g, 038282263212C609D9EA2A6E3E172DE238D8C39CABD5AC1CA10646E23FD5F51508) 47 | ecmul(101) 48 | 49 | Examples of `1 * G + 100 * G` and `(1 + 100) * G` 50 | 51 | ```bc 52 | satoshi_pubkey = 0311DB93E1DCDB8A016B49840F8C53BC1EB68A382E97B1482ECAD7B148A6909A5C 53 | block170_sighash = 7A05C6145F10101E9D6325494245ADF1297D80F8F38D4D576D57CDBA220BCB19 54 | satoshi_sig = 304402204E45E16932B8AF514961A1D3A1A25FDF3F4F7732E9D624C6C61548AB5FB8CD410220181522EC8ECA07DE4860A4ACDD12909D831CC56CBBAC4622082221A8768D1D09 55 | 56 | ecdsa_verify_der( block170_sighash, satoshi_pubkey, satoshi_sig ) 57 | ``` 58 | * note that `bc` expects numbers in upper case base 16 59 | 60 | 61 | ## Bitcoin stuff 62 | 63 | See `./bitcoin/` for the main effort behind this project. 64 | Lots of the supporting infrastructure is whatever you'll find in the 65 | different directories, which might also be interesting. 66 | 67 | The assumption is that regtest is used, and some global values are set 68 | to hold versions and such. 69 | 70 | Functions of specific scope tend to have a common prefix, and more general 71 | functions have a non scoped name. 72 | The interface tries to keep to a sane interpretation of numbers (decimal or hexadecimal). 73 | 74 | Some examples... 75 | 76 | randhex 32 77 | 78 | Returns a random 32 byte value 79 | 80 | key_priv2wif "$(randhex 32)" 81 | key_priv2wif "$(randhex 32)01" 82 | 83 | Returns a random wif encoded private key 84 | Appending `01` will return the compressed wif key 85 | 86 | key_priv2pub 101 87 | key_wif2pub cMahea7zqjxrtgAbB7LSGbcQUr1uX1ojuat9jZodMN89W6SfaiTA 88 | key_wif2pub 91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbhSh2hjwa 89 | 90 | Returns the public point 91 | 92 | spk_pay2mofn 2 "0237ACF3D1FBC3D8EB3F23367B12EEAA8AFB081EB21B579A95882F0C36B8C20E7F 03D2920160CCDB8D885B31AFAD20DAA806A6ADEE603A700D0005D223AE435124D4 033CBB01DAECB89937BF82DE986446E8BC0BBF11A89F41E0BABD3068DAFCBC8F5E" 93 | spk_pay2wpkh "$(pub2addr 0290A80DB6EB294B9EAB0B4E8DDFA3EFE7263458CE2D07566DF4E6C58868FEEF23)" 94 | 95 | Return the scripts 96 | 97 | script_serialize "DUP HASH160 @FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF EQUALVERIFY CHECKSIG" 98 | 99 | Serializes a script - `@` means minimal push 100 | 101 | ``` 102 | secret="22A40F35E3ACF36C644C287A619749527B27009B3178E5C4DE6C78CA4E20E97A" 103 | 104 | h_secret="$(hash160 ${secret})" 105 | echo ${h_secret} 106 | # 337CD7EEF868D5E8E1CC76CA0C2CC156276F9F85 107 | 108 | alice_pub="02174D35691F461D141A10BD0B6BF13D26769EC062FCB5E8D4AAD923207E07F0F2" 109 | carol_priv="F00DE6A284DE9CAD522615EC30D9C36879825022568695E8CB826257F6AEE993" 110 | carol_pub="$(key_priv2pub ${carol_priv})" 111 | 112 | spk_pay2shash "IF HASH160 @${h_secret} EQUALVERIFY @${carol_pub} CHECKSIG ELSE 100 CLTV DROP @${alice_pub} CHECKSIG ENDIF" 113 | # HASH160 0x14 0x133DA6A707DFA29298AFF738064D370D6B1D936E EQUAL 114 | 115 | rdm_script="$(script_serialize "IF HASH160 @${h_secret} EQUALVERIFY @${carol_pub} CHECKSIG ELSE 100 CLTV DROP @${alice_pub} CHECKSIG ENDIF")" 116 | p2sh_script="$(script_serialize "HASH160 0x14 0x133DA6A707DFA29298AFF738064D370D6B1D936E EQUAL")" 117 | 118 | pay_to="$(tx_mkout_p2wpkh 10.123 mfpm1nTTppvtzzgCgozarhGu7R7w33pxoV)" 119 | 120 | txin0="$(tx_mkin_serialize 1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F 12 "$((2**32-3))" "0x${rdm_script}")" 121 | # '0x...' means the bytes are read literally (e.g. for a serialized script) 122 | 123 | echo ${txin0} 124 | # 1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F0C0000006463A914337CD7EEF868D5E8E1CC76CA0C2CC156276F9F8588210393B6CA84177971DB77AC121360CAE355C3E7B3C7BF5B54A469C3B5F0EDA99434AC670164B1752102174D35691F461D141A10BD0B6BF13D26769EC062FCB5E8D4AAD923207E07F0F2AC68FDFFFFFF 125 | 126 | unsigned="$(tx_build 2 "" "${txin0}" "${pay_to}" 0 | cleanhex)" 127 | echo ${unsigned} 128 | # 02000000011F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F0C0000006463A914337CD7EEF868D5E8E1CC76CA0C2CC156276F9F8588210393B6CA84177971DB77AC121360CAE355C3E7B3C7BF5B54A469C3B5F0EDA99434AC670164B1752102174D35691F461D141A10BD0B6BF13D26769EC062FCB5E8D4AAD923207E07F0F2AC68FDFFFFFF01E078563C00000000160014035E122123B4350416715C54F0CE5AD6E7D2B95C00000000 129 | 130 | to_sign="${unsigned}01000000" 131 | mid_hash="$(sha256 "${to_sign}")" 132 | 133 | sign "${carol_priv}" "${mid_hash}" 134 | # 3045022100FB13D6158B46F1BAD299826A14616598EB6B18F695541E26ACCBE5626FE479F50220078379EEC7FD763437F55603F6BF1913D784DDC728127C0638AE51863F4EAACC 135 | 136 | sig_carol="3045022100FB13D6158B46F1BAD299826A14616598EB6B18F695541E26ACCBE5626FE479F50220078379EEC7FD763437F55603F6BF1913D784DDC728127C0638AE51863F4EAACC" 137 | 138 | txin="$(tx_mkin_serialize 1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F 12 "$((2**32-3))" "@${sig_carol}01 @${secret} 1 @${rdm_script}")" 139 | 140 | signed="$(tx_build 2 "" "${txin}" "${pay_to}" 0 | cleanhex)" 141 | echo ${signed} 142 | # 02000000011F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F0C000000D1483045022100FB13D6158B46F1BAD299826A14616598EB6B18F695541E26ACCBE5626FE479F50220078379EEC7FD763437F55603F6BF1913D784DDC728127C0638AE51863F4EAACC012022A40F35E3ACF36C644C287A619749527B27009B3178E5C4DE6C78CA4E20E97A514C6463A914337CD7EEF868D5E8E1CC76CA0C2CC156276F9F8588210393B6CA84177971DB77AC121360CAE355C3E7B3C7BF5B54A469C3B5F0EDA99434AC670164B1752102174D35691F461D141A10BD0B6BF13D26769EC062FCB5E8D4AAD923207E07F0F2AC68FDFFFFFF01E078563C00000000160014035E122123B4350416715C54F0CE5AD6E7D2B95C00000000 143 | 144 | regtest-cli signrawtransaction ${signed} '[{"txid":"1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F","vout":12,"scriptPubKey":"A914133DA6A707DFA29298AFF738064D370D6B1D936E87","redeemScript":"63A914337CD7EEF868D5E8E1CC76CA0C2CC156276F9F8588210393B6CA84177971DB77AC121360CAE355C3E7B3C7BF5B54A469C3B5F0EDA99434AC670164B1752102174D35691F461D141A10BD0B6BF13D26769EC062FCB5E8D4AAD923207E07F0F2AC68"}]' 145 | 146 | # true 147 | 148 | ``` 149 | -------------------------------------------------------------------------------- /bitcoin/bips/bip32.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | bip32_point() 4 | { 5 | bc_ecmath <<<"ecmul(${1^^});" 6 | } 7 | 8 | bip32_parse_index() 9 | { 10 | local index="${1}" 11 | 12 | if [[ "${index}" =~ "h" ]] 13 | then 14 | index="$(( ${index//h/} + 2147483648 ))" 15 | fi 16 | 17 | echo "${index}" 18 | } 19 | 20 | bip32_ser32() 21 | { 22 | int2octets "$(bc_clean <<<"obase=16; ${1};")" 32 23 | } 24 | 25 | bip32_ser256() 26 | { 27 | int2octets "${1^^}" 256 28 | } 29 | 30 | bip32_ckdpriv() 31 | { 32 | local -u k_par="${1}" c_par="${2}" n="${3}" I_val 33 | 34 | read n < <( bip32_parse_index "${n}" ) 35 | 36 | local -u ser_k ser_i ser_p 37 | if (( ${n} >= 2147483648 )) 38 | then 39 | read ser_k < <( bip32_ser256 "${k_par}" ) 40 | read ser_i < <( bip32_ser32 "${n}" ) 41 | read I_val < <( hmac_sha512 "${c_par}" "00${ser_k}${ser_i}" ) 42 | else 43 | read ser_p < <( bip32_point "${k_par}" ) 44 | read ser_i < <( bip32_ser32 "${n}" ) 45 | read I_val < <( hmac_sha512 "${c_par}" "${ser_p}${ser_i}" ) 46 | fi 47 | 48 | local -u I_L I_R k_i c_i 49 | 50 | I_L="${I_val:0:64}" 51 | I_R="${I_val:64}" 52 | 53 | read k_i < <( bc_ecpoint <<<" \ 54 | if ( ${I_L} == 0 ){ \ 55 | 0; \ 56 | } else { \ 57 | left_pad(mod( ${I_L} + ${k_par}, curve_n),40); \ 58 | }" ) 59 | if [[ "${k_i}" == "0" ]] 60 | then 61 | bip32_ckdpriv "${k_par}" "${c_par}" "$(( ${n}+1 ))" 62 | return 63 | fi 64 | 65 | c_i="${I_R}" 66 | echo -e "${k_i}\n${c_i}" 67 | } 68 | 69 | bip32_ckdpub() 70 | { 71 | local -u p_par="${1}" c_par="${2}" n="${3}" 72 | 73 | read n < <( bip32_parse_index "${n}" ) 74 | 75 | local -u ser_i I_val 76 | if (( "${n}" >= 2147483648 )) 77 | then 78 | echo "FAILURE" 79 | return 80 | else 81 | read ser_i < <( bip32_ser32 "${n}" ) 82 | read I_val < <( hmac_sha512 "${c_par}" "${p_par}${ser_i}" ) 83 | fi 84 | 85 | local -u I_L I_R k_i c_i 86 | local -au p_upk 87 | 88 | readarray -t p_upk < <( uncompresspoint "${p_par}" ) 89 | 90 | I_L="${I_val:0:64}" 91 | # decho "offset = ${I_L}" 92 | I_R="${I_val:64}" 93 | 94 | read p_i < <( bc_ecmath <<<" \ 95 | if ( ${I_L} == 0 ){ \ 96 | 0; \ 97 | } else { \ 98 | ecmul_api(${I_L},curve_gx,curve_gy,curve_n,curve_p, pt1[]); \ 99 | ecadd_api(pt1[0], pt1[1],${p_upk[0]},${p_upk[1]},curve_p, pt2[]); \ 100 | if ( pt2[0] == 0 ){ \ 101 | 0; \ 102 | } else { 103 | compresspoint(pt2[]); 104 | } 105 | }" ) 106 | if [[ "${p_i}" == "0" ]] 107 | then 108 | bip32_ckdpub "${p_par}" "${c_par}" "$(( ${n}+1 ))" 109 | fi 110 | 111 | c_i="${I_R}" 112 | echo -e "${p_i}\n${c_i}" 113 | } 114 | 115 | bip32_master() 116 | { 117 | local -u data="${1}" bip32_key="426974636F696E2073656564" # 'Bitcoin seed' 118 | local -u I_val I_R I_L 119 | 120 | read I_val < <( hmac_sha512 "${bip32_key}" "${data}" ) 121 | I_L="${I_val:0:64}" 122 | I_R="${I_val:64}" 123 | 124 | echo -e "${I_L}\n${I_R}" 125 | } 126 | 127 | bip32_neuter() 128 | { 129 | if [[ "${1}" == "" ]] 130 | then 131 | read hex_xpriv 132 | else 133 | hex_xpriv="${1}" 134 | fi 135 | 136 | local -au data 137 | readarray -t data < <( bip32_decode "${hex_xpriv}" ) 138 | 139 | local -u k_i 140 | read k_i < <( bip32_point "${data[5]}" ) 141 | 142 | echo "${xpubVer}${data[1]}${data[2]}${data[3]}${data[4]}${k_i}" 143 | } 144 | 145 | bip32_decode() 146 | { 147 | local -u hexstr 148 | local -au xkey 149 | 150 | if [[ "${1}" == "" ]] 151 | then 152 | read hexstr 153 | else 154 | hexstr="${1}" 155 | fi 156 | 157 | xkey[0]="${hexstr:0:8}" # magic 158 | xkey[1]="${hexstr:8:2}" # depth 159 | xkey[2]="${hexstr:10:8}" # parent fingerprint 160 | xkey[3]="${hexstr:18:8}" # child number 161 | xkey[4]="${hexstr:26:64}" # chain code 162 | xkey[5]="${hexstr:90:66}" # private / public key 163 | 164 | printf "%s\n" "${xkey[@]}" 165 | } 166 | 167 | bip32_encode() 168 | { 169 | local -a hexstr xkey256 170 | if [[ "${1}" == "" ]] 171 | then 172 | read hexstr 173 | else 174 | hexstr="${1}" 175 | fi 176 | 177 | read xkey256 < <( hash256 "${hexstr}" ) 178 | 179 | base58enc "${hexstr}${xkey256:0:8}" 180 | } 181 | 182 | bip32_encode_master() 183 | { 184 | local -au data 185 | if [[ "${1}" == "" ]] 186 | then 187 | readarray -t data 188 | else 189 | data[0]="${1}" 190 | data[1]="${2}" 191 | fi 192 | if (( ${#data[0]} == 64 )); then 193 | data[3]="00" 194 | data[4]="${xprvVer}" 195 | elif (( ${#data[0]} == 66 )); then 196 | data[3]="" 197 | data[4]="${xpubVer}" 198 | fi 199 | 200 | echo "${data[4]}000000000000000000${data[1]}${data[3]}${data[0]}" 201 | } 202 | 203 | bip32_xpriv_branch() 204 | { 205 | local -u par_xpriv 206 | if [[ "${2}" == "" ]] 207 | then 208 | read par_xpriv 209 | read index < <( bip32_parse_index "${1}" ) 210 | else 211 | par_xpriv="${1}" 212 | read index < <( bip32_parse_index "${2}" ) 213 | fi 214 | 215 | local -au data next_ckey 216 | readarray -t data < <( bip32_decode "${par_xpriv}" ) 217 | 218 | if [[ "${data[5]:0:2}" != "00" ]] 219 | then 220 | echo "FAILURE xpub -> xpriv" 221 | return 222 | fi 223 | 224 | local -u par_fp next_depth next_i 225 | read par_fp < <( bip32_point "${data[5]}" | hash160 ) 226 | 227 | read next_depth < <( bc_encode <<<"left_pad(${data[1]} + 1,2)" ) 228 | 229 | read next_i < <( bip32_ser32 "${index}" ) 230 | 231 | readarray -t next_ckey < <( bip32_ckdpriv "${data[5]:2}" "${data[4]}" "${index}" ) 232 | 233 | echo "${xprvVer}${next_depth}${par_fp:0:8}${next_i}${next_ckey[1]}00${next_ckey[0]}" 234 | } 235 | 236 | bip32_xpub_branch() 237 | { 238 | local -u par_xpub 239 | if [[ "${2}" == "" ]] 240 | then 241 | read par_xpub 242 | read index < <( bip32_parse_index "${1}" ) 243 | else 244 | par_xpub="${1}" 245 | read index < <( bip32_parse_index "${2}" ) 246 | fi 247 | 248 | local -au data next_ckey 249 | readarray -t data < <( bip32_decode "${par_xpub}" ) 250 | 251 | if [[ "${data[5]:0:2}" != "02" ]] && [[ "${data[5]:0:2}" != "03" ]] 252 | then 253 | echo "FAILURE not an xpub" 254 | return 255 | fi 256 | 257 | local -au par_point 258 | local -u par_fp next_depth next_i 259 | 260 | read par_fp < <( hash160 "${data[5]}" ) 261 | 262 | read next_depth < <( bc_encode <<<"left_pad(${data[1]} + 1,2)" ) 263 | 264 | read next_i < <( bip32_ser32 "${index}" ) 265 | 266 | readarray -t next_ckey < <( bip32_ckdpub "${data[5]}" "${data[4]}" "${index}" ) 267 | 268 | echo "${xpubVer}${next_depth}${par_fp:0:8}${next_i}${next_ckey[1]}${next_ckey[0]}" 269 | } 270 | 271 | bip32_derive_path () 272 | { 273 | local par_xkey path 274 | local -u xkey_hex 275 | if [[ "${2}" == "" ]] 276 | then 277 | read par_xkey 278 | path="$1" 279 | else 280 | par_xkey="$1" 281 | path="$2" 282 | fi 283 | 284 | read xkey_hex < <( base58dec "${par_xkey}" ) 285 | local -au data 286 | readarray -t data < <( bip32_decode "${xkey_hex}" ) 287 | 288 | local tmpk="${xkey_hex}" 289 | echo "${par_xkey}" 290 | for p in ${path//\// }; do 291 | case "${data[5]:0:2}" in 292 | 00) 293 | tmpk="$(bip32_xpriv_branch ${tmpk} ${p})" 294 | ;; 295 | 02|03) 296 | tmpk="$(bip32_xpub_branch ${tmpk} ${p})" 297 | ;; 298 | esac 299 | bip32_encode "${tmpk}" 300 | done 301 | # bip32_encode "${tmpk}" 302 | } 303 | 304 | bip32_nonce () 305 | { 306 | local -u x1="$1" c1="$2" z1="$3" 307 | local xkey="$(bip32_encode_master ${x1} ${c1} | bip32_encode)" 308 | read z1 < <( 309 | for (( i=0; i<${#z1}; i+=6 )); do 310 | printf '%s/' "$(( 16#${z1:$i:6} ))" 311 | done ) 312 | # decho "${xkey} ${z1}\n" 313 | decho "\nderiving ${xkey:0:4} ..." 314 | decho "path = ${z1}\n" 315 | while read branch; do 316 | k0="$( base58dec ${branch} )" 317 | k0="${k0:90:66}" 318 | decho "... ${k0}" 319 | done < <(bip32_derive_path "${xkey}" "${z1}") 320 | decho 321 | echo "${k0}" 322 | } 323 | -------------------------------------------------------------------------------- /bc/ecdsa/ecdsa.bc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bc 2 | 3 | # basic ecdsa functions 4 | 5 | define ecdsa_sign_api(r, k, z, d, n){ 6 | 7 | auto rval, sval; 8 | rval = mod(r, n); 9 | 10 | sval = mod((invmod(k, n) * mod((z + (rval * d)), n)), n); 11 | if ( sval > (n / 2) ){ 12 | return curve_n - sval; 13 | } 14 | return sval; 15 | } 16 | 17 | define void ecdsa_sign(k, z, d, *sig[]){ 18 | 19 | auto r_pt[], s; 20 | ecmul_api(k, curve_gx, curve_gy, curve_n, curve_p, r_pt[]); 21 | sig[0] = mod(r_pt[0], curve_n); 22 | sig[1] = ecdsa_sign_api(r_pt[0], k, z, d, curve_n); 23 | } 24 | 25 | define void ecdsa_sign_recoverable(k, z, d, compr, *sig[]){ 26 | 27 | auto recid, r_pt[], s, fflip; 28 | recid = 1B; 29 | fflip = 1; 30 | ecmul_api(k, curve_gx, curve_gy, curve_n, curve_p, r_pt[]); 31 | sig[0] = mod(r_pt[0], curve_n); 32 | sig[1] = mod((invmod(k, curve_n) * mod((z + (sig[0] * d)), curve_n)), curve_n); 33 | if ( sig[1] > (curve_n / 2) ){ 34 | sig[1] = curve_n - sig[1]; 35 | r_pt[1] = mod( -r_pt[1], curve_p ); 36 | } 37 | if ( (r_pt[1] % 2) == 1 ){ 38 | recid += 1; 39 | } 40 | if ( r_pt[0] > curve_n ){ 41 | recid += 2; 42 | } 43 | if ( compr == 1 ){ 44 | recid += 4; 45 | } 46 | sig[2] = recid; 47 | sig[3] = compresspoint_api(r_pt[0], r_pt[1]); 48 | } 49 | 50 | define ecdsa_sign_der(k, z, d){ 51 | 52 | auto raw_sig[], lenr, bigr, lens, dersig, siglen; 53 | 54 | ecdsa_sign(k, z, d, raw_sig[]); 55 | return ecdsa_sig2der(raw_sig[0], raw_sig[1]); 56 | } 57 | 58 | define ecdsa_verify_api(z, x, y, r, s, gx, gy, p, n){ 59 | 60 | auto w, u1, u2, u1_pt[], u2_pt[], r_pt[]; 61 | 62 | w = invmod(s, n); 63 | u1 = mod(z * w, n); 64 | u2 = mod(r * w, n); 65 | 66 | ecmul_api(u1, gx, gy, n, p, u1_pt[]); 67 | ecmul_api(u2, x, y, n, p, u2_pt[]); 68 | ecadd_api(u1_pt[0], u1_pt[1], u2_pt[0], u2_pt[1], p, r_pt[]); 69 | 70 | # left_pad(r_pt[0], 40); 71 | # left_pad(r_pt[1], 40); 72 | if (( r_pt[0] != 0) && (mod(r_pt[0], n) == r )){ 73 | return r; 74 | } 75 | if ( r + n < p ){ 76 | if ( ispoint_api(r+n, gety_fast(r+n), curve_a, curve_b, curve_p) ){ 77 | return ecdsa_verify_api(z, x, y, (r + n), s, gx, gy, p, n); 78 | } 79 | } 80 | return 0; 81 | } 82 | 83 | define ecdsa_verify(z, pubkey, r, s){ 84 | 85 | auto pubpt[]; 86 | uncompresspoint_api(pubkey, pubpt[]); 87 | return (ecdsa_verify_api(z, pubpt[0], pubpt[1], r, s, curve_gx, curve_gy, curve_p, curve_n) == r); 88 | } 89 | 90 | define ecdsa_verify_der(z, pubkey, dersig){ 91 | 92 | auto sig[]; 93 | 94 | ecdsa_der2sig(dersig, sig[]); 95 | if ( ispoint_api(sig[0], gety_fast(sig[0]), curve_a, curve_b, curve_p) ){ 96 | return ecdsa_verify(z, pubkey, sig[0], sig[1]); 97 | } 98 | if ( ispoint_api(sig[0]+curve_n, gety_fast(sig[0]+curve_n), curve_a, curve_b, curve_p) ){ 99 | return ecdsa_verify(z, pubkey, sig[0], sig[1]); 100 | } 101 | } 102 | 103 | define void ecdsa_recover_raw(z, r, s, g, *ret[]) # TODO take two arrays instead of one 104 | { 105 | auto g_pt[], ry_arr[], invr, r1_pt[], r2_pt[], sr1_pt[], sr2_pt[], zg_pt[], mul1_pt[], mul2_pt[], rmul1_pt[], rmul2_pt[]; 106 | 107 | uncompresspoint_api(g, g_pt[]); 108 | z = mod(-z, curve_n); 109 | gety_api(r, ry_arr[]); 110 | invr = invmod(r, curve_n); 111 | 112 | ecmul_api(s, r, ry_arr[0], curve_n, curve_p, r1_pt[]); 113 | 114 | ecmul_api(s, r, ry_arr[1], curve_n, curve_p, r2_pt[]); 115 | 116 | ecmul_api(z, g_pt[0], g_pt[1], curve_n, curve_p, zg_pt[]); 117 | 118 | ecadd_api(r1_pt[0], r1_pt[1], zg_pt[0], zg_pt[1], curve_p, mul1_pt[]); 119 | 120 | ecadd_api(r2_pt[0], r2_pt[1], zg_pt[0], zg_pt[1], curve_p, mul2_pt[]); 121 | 122 | ecmul_api(invr, mul1_pt[0], mul1_pt[1], curve_n, curve_p, rmul1_pt[]); 123 | 124 | ecmul_api(invr, mul2_pt[0], mul2_pt[1], curve_n, curve_p, rmul2_pt[]); 125 | 126 | if ( (ry_arr[0] % 2) == 0 ){ 127 | ret[0] = rmul1_pt[0]; 128 | ret[1] = rmul1_pt[1]; 129 | ret[2] = rmul2_pt[0]; 130 | ret[3] = rmul2_pt[1]; 131 | } else { 132 | ret[0] = rmul2_pt[0]; 133 | ret[1] = rmul2_pt[1]; 134 | ret[2] = rmul1_pt[0]; 135 | ret[3] = rmul1_pt[1]; 136 | } 137 | } 138 | 139 | define void ecdsa_recover_api(z, r, s, *ret[]) 140 | { 141 | ecdsa_recover_raw(z, r, s, curve_g, ret[]); 142 | } 143 | 144 | define void ecdsa_recover(z, r, s){ 145 | 146 | auto ret[], pt1[], pt2[]; 147 | 148 | if ( ispoint_api(r, gety_fast(r), curve_a, curve_b, curve_p) ){ 149 | ecdsa_recover_api(z, r, s, ret[]); 150 | pt1[0] = ret[0]; 151 | pt1[1] = ret[1]; 152 | pt2[0] = ret[2]; 153 | pt2[1] = ret[3]; 154 | compresspoint(pt1[]); 155 | compresspoint(pt2[]); 156 | } 157 | 158 | if ( r + curve_n < curve_p ){ 159 | if ( ispoint_api(r + curve_n, gety_fast(r + curve_n), curve_a, curve_b, curve_p) ){ 160 | ecdsa_recover(z, r + curve_n, s); 161 | } 162 | } 163 | } 164 | 165 | define void ecdsa_recover_der(z, dersig){ 166 | 167 | auto sig[]; 168 | ecdsa_der2sig(dersig, sig[]); 169 | ecdsa_recover(z, sig[0], sig[1]); 170 | } 171 | 172 | define ecdsa_verify_recoverable_getpub(z, recsig){ 173 | 174 | auto recid, r, s, fcomp, pubkey_pt[], pubkey, rec_pubkeys[]; 175 | 176 | recid = recsig / (100^40); 177 | r = (recsig % 100^40) / (100 ^ 20); 178 | s = recsig % (100^20); 179 | fcomp = (bwand(recid - 1B, 4) != 0); 180 | recid = bwand(recid - 1B, 3); 181 | 182 | if ( recid < 2 ){ 183 | ecdsa_recover_api(z, r, s, rec_pubkeys[]); 184 | } else { 185 | ecdsa_recover_api(z, r+curve_n, s, rec_pubkeys[]); 186 | } 187 | if ( (recid % 2) == 0 ){ 188 | pubkey_pt[0] = rec_pubkeys[0]; 189 | pubkey_pt[1] = rec_pubkeys[1]; 190 | } else { 191 | pubkey_pt[0] = rec_pubkeys[2]; 192 | pubkey_pt[1] = rec_pubkeys[3]; 193 | } 194 | pubkey = compresspoint_api(pubkey_pt[0], pubkey_pt[1]); 195 | if ( fcomp == 0 ){ 196 | pubkey = uncompresspoint(pubkey); 197 | } else { 198 | print "0"; 199 | } 200 | return pubkey; 201 | } 202 | 203 | 204 | # some useful algebra 205 | 206 | define ecdsa_getk(r, s, z, d, n){ 207 | 208 | return mod((invmod(s,n) * mod((z+(r*d)),n)),n); 209 | } 210 | 211 | define ecdsa_getz_api(r, s, k, d, n){ 212 | 213 | return mod((mod(k*s,n) - mod(r*d,n)),n); 214 | } 215 | 216 | define ecdsa_getz(s, k, d){ 217 | 218 | auto r_pt[]; 219 | ecmul_api(k, curve_gx, curve_gy, curve_n, curve_p, r_pt[]); 220 | return ecdsa_getz_api(mod(r_pt[0], curve_n), s, k, d, curve_n); 221 | } 222 | 223 | define ecdsa_getd_api(r, s, k, z, n){ 224 | 225 | return mod(mod((s*k)-z,n) * invmod(r,n),n); 226 | } 227 | 228 | define ecdsa_getd(s, k, z){ 229 | 230 | auto r_pt[]; 231 | ecmul_api(k, curve_gx, curve_gy, curve_n, curve_p, r_pt[]); 232 | return ecdsa_getd_api(mod(r_pt[0], curve_n), s, k, z, curve_n); 233 | } 234 | 235 | define ecdsa_getr(k, s, z, d, n){ 236 | 237 | return mod(invmod(d,n) * mod((k*s) - z,n),n); 238 | } 239 | 240 | define void ecdsa_recover_k_api(z1, dersig1, z2, dersig2, n, *kvals[], *dvals[]){ 241 | 242 | auto sig1[], sig2[]; 243 | 244 | ecdsa_der2sig(dersig1, sig1[]); 245 | ecdsa_der2sig(dersig2, sig2[]); 246 | kvals[0] = mod(((z1 - z2) * invmod(sig1[1] - sig2[1], n)), n); 247 | kvals[1] = mod(((z1 - z2) * invmod(sig1[1] + sig2[1], n)), n); 248 | kvals[2] = mod(((z1 - z2) * invmod(-sig1[1] - sig2[1], n)), n); 249 | kvals[3] = mod(((z1 - z2) * invmod(-sig1[1] + sig2[1], n)), n); 250 | 251 | # dvals[0] = mod(mod((sig1[1] * kvals[0]) - z1, n) * invmod(sig1[0], n), n); 252 | # dvals[1] = mod(mod((sig1[1] * kvals[1]) - z1, n) * invmod(sig1[0], n), n); 253 | # dvals[2] = mod(mod((sig1[1] * kvals[2]) - z1, n) * invmod(sig1[0], n), n); 254 | # dvals[3] = mod(mod((sig1[1] * kvals[3]) - z1, n) * invmod(sig1[0], n), n); 255 | dvals[0] = ecdsa_getd_api(sig1[0], sig1[1], kvals[0], z1, n); 256 | dvals[1] = ecdsa_getd_api(sig1[0], sig1[1], kvals[1], z1, n); 257 | dvals[2] = ecdsa_getd_api(sig1[0], sig1[1], kvals[2], z1, n); 258 | dvals[3] = ecdsa_getd_api(sig1[0], sig1[1], kvals[3], z1, n); 259 | } 260 | 261 | define void ecdsa_recover_k(z1, dersig1, z2, dersig2){ 262 | 263 | auto kvals[], dvals[]; 264 | 265 | ecdsa_recover_k_api(z1, dersig1, z2, dersig2, curve_n, kvals[], dvals[]); 266 | print "possible k values :\n"; 267 | kvals[0]; kvals[1]; kvals[2]; kvals[3]; 268 | print "possible d values :\n"; 269 | dvals[0]; dvals[1]; dvals[2]; dvals[3]; 270 | } 271 | -------------------------------------------------------------------------------- /bitcoin/transaction.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | tx_mkout_serialize () 4 | { 5 | local amount="${1}" asmscript="${2}" nest="${3}" 6 | local -a meta=( $4 ) 7 | local -u seramt serscript 8 | local scriptsize 9 | 10 | if [[ "${nest}" =~ "mshash" ]]; then 11 | 12 | tx_mkout_p2mshash "${amount}" "${asmscript}" "${nest//msash/}" # "${meta[0]}" "${meta[1]}" 13 | return 14 | fi 15 | 16 | if [[ "${nest}" =~ "p2wsh" ]]; then 17 | 18 | tx_mkout_p2wsh "${amount}" "${asmscript}" "${nest//p2wsh/}" 19 | return 20 | fi 21 | 22 | if [[ "${nest}" =~ "p2sh" ]]; then 23 | 24 | tx_mkout_p2sh "${amount}" "${asmscript}" "" 25 | return 26 | fi 27 | 28 | read seramt < <( dec2amount "${amount}" ) 29 | read serscript < <( script_serialize "${asmscript}" ) 30 | read scriptsize < <( data_compsize "${#serscript}" ) 31 | echo "${seramt}${scriptsize}${serscript}" 32 | } 33 | 34 | tx_mkout_p2pkey () 35 | { 36 | local amount="${1}" pubkey="${2}" 37 | local nest="${3}" script 38 | 39 | read script < <( spk_pay2pubkey "${pubkey}" ) 40 | tx_mkout_serialize "${amount}" "${script}" "${nest}" 41 | } 42 | 43 | tx_mkout_p2pkh () 44 | { 45 | local amount="${1}" addr="${2}" 46 | local nest="${3}" script 47 | 48 | read script < <( spk_pay2pkhash "${addr}" ) 49 | tx_mkout_serialize "${amount}" "${script}" "${nest}" 50 | } 51 | 52 | tx_mkout_mofn () 53 | { 54 | local amount="${1}" pubkeys="${3}" 55 | local -i m="${2}" 56 | local nest="${3}" script 57 | 58 | read script < <( spk_pay2mofn "${m}" "${pubkeys}" ) 59 | tx_mkout_serialize "${amount}" "${script}" "${nest}" 60 | } 61 | 62 | tx_mkout_p2wpkh () 63 | { 64 | local amount="${1}" addr="${2}" 65 | local nest="${3//p2wsh/}" script 66 | 67 | read script < <( spk_pay2wpkhash "${addr}" ) 68 | tx_mkout_serialize "${amount}" "${script}" "${nest}" 69 | } 70 | 71 | tx_mkout_p2wsh () 72 | { 73 | local amount="${1}" asmscript="${2}" 74 | local nest="${3//p2wsh/}" script 75 | 76 | read script < <( spk_pay2wshash "${asmscript}" ) 77 | tx_mkout_serialize "${amount}" "${script}" "${nest}" 78 | } 79 | 80 | tx_mkout_p2mshash () 81 | { 82 | local amount="${1}" asmscript="${2}" 83 | local nest="${3//mshash/}" script path="$4" position="$5" 84 | 85 | read script < <( spk_pay2mshash "${asmscript}" "${path:-0}" "${position:-0}" ) 86 | tx_mkout_serialize "${amount}" "${script}" "${nest}" 87 | } 88 | 89 | tx_mkout_p2wpkv0 () 90 | { 91 | local amount="${1}" pubkey="${2}" 92 | local nest="${3}" script 93 | 94 | read script < <( spk_pay2wpkv0 "${pubkey}" ) 95 | tx_mkout_serialize "${amount}" "${script}" "${nest}" 96 | } 97 | 98 | tx_mkout_p2sh () 99 | { 100 | local amount="${1}" asmscript="${2}" 101 | local script 102 | 103 | read script < <( spk_pay2shash "${asmscript}" ) 104 | tx_mkout_serialize "${amount}" "${script}" "" 105 | } 106 | 107 | # in : previous txid, previous output index, sequence number to apply, script to use 108 | tx_mkin_serialize () 109 | { 110 | local -u prevtx="${1}" serpidx serseq serscript 111 | local -i previdx="${2}" sequence="${3}" 112 | local asmscript="${4}" scriptsize 113 | 114 | read prevtx < <( revchunks "${prevtx}" ) 115 | 116 | read serpidx < <( tx_ser_int "${previdx}" ) 117 | 118 | read serseq < <( tx_ser_int "${sequence}" ) 119 | 120 | read serscript < <( script_serialize "${asmscript}" ) 121 | read scriptsize < <( data_compsize "${#serscript}" ) 122 | 123 | echo -e "${prevtx}${serpidx}${scriptsize}${serscript}${serseq}" 124 | } 125 | 126 | tx_input_script () 127 | { 128 | local -u script 129 | 130 | script="${1:72}" 131 | script="${script::-8}" 132 | 133 | echo "${script}" 134 | } 135 | 136 | tx_bip141_iswitprog () 137 | { 138 | local -u scriptpk 139 | local pushcode pushop 140 | 141 | read scriptpk < <( tx_input_script "${1}" ) 142 | 143 | case ${#scriptpk} in 144 | 145 | 46|70) 146 | pushcode="${scriptpk:2:2}" 147 | pushop="${scriptpk:4:2}" 148 | ;; 149 | 48|72) 150 | pushcode="${scriptpk:4:2}" 151 | pushop="${scriptpk:6:2}" 152 | ;; 153 | 2) 154 | if [[ ${scriptpk} == "00" ]]; then 155 | echo 1 156 | return 157 | fi 158 | ;;& 159 | *) 160 | echo 0 161 | return 162 | ;; 163 | esac 164 | # spklen="${#scriptpk}" 165 | 166 | # if (( "${spklen}" != 46 )) && (( "${spklen}" != 70 )) && (( "${spklen}" != 2 )); then 167 | #if [[ ! ${spklen} =~ 46|48|70|72|2 ]]; then 168 | # 169 | # echo "0" 170 | # return 171 | #fi 172 | 173 | if [[ ! ${pushop} =~ 14|20 ]]; then 174 | echo 0 175 | return 176 | fi 177 | 178 | # if [[ ${scriptpk:2:2} =~ 00|51|52|53|54|55|56|57|58|59|5A|5B|5C|5D|5E|5F|60 ]] || [[ ${scriptpk} == "00" ]]; then 179 | if [[ ! ${pushcode} =~ 00|51|52|53|54|55|56|57|58|59|5A|5B|5C|5D|5E|5F|60 ]]; then 180 | 181 | echo "0" 182 | return 183 | fi 184 | 185 | echo 1 186 | # read pushcode < <( BC_ENV_ARGS='-q' bc <<<"${scriptpk:2:2}" ) 187 | # 188 | # if (( "${pushcode}" < 0 )) || (( "${pushcode}" > 16 )); then 189 | # 190 | # echo "0" 191 | # fi 192 | # 193 | # echo "1" 194 | } 195 | 196 | tx_bip141_serwitness() 197 | { 198 | local -a stack=( $1 ) 199 | local -au serstack 200 | local -u sersize bn elem stacksize 201 | 202 | for (( i=0; i<${#stack[@]}; i++ )); do 203 | if script_is_opnum "${stack[$i]}"; then 204 | if [[ ${stack[$i]} == "0" ]]; then 205 | serstack[$i]="00" 206 | else 207 | printf -v serstack[$i] '01%02X' ${stack[$i]} 208 | continue 209 | fi 210 | fi 211 | if script_is_bignum "${stack[$i]}"; then 212 | read serstack[$i] < <( script_serialize "${stack[$i]}" ) 213 | else 214 | read elem < <( script_serialize "${stack[$i]}" ) 215 | read sersize < <( data_compsize ${#elem} ) 216 | serstack[$i]="${sersize}${elem}" 217 | fi 218 | done 219 | 220 | read stacksize < <( data_compsize $((${#serstack[@]}*2)) ) 221 | printf '%s' ${stacksize} ${serstack[@]} 222 | echo 223 | } 224 | 225 | _tx_bip141_serwitness () 226 | { 227 | local -au stack serstack 228 | local -u sersize 229 | stack=( ${1} ) 230 | 231 | read sersize < <( data_compsize "$(( ${#stack[@]}*2 ))" ) 232 | 233 | for (( i=0; i<"${#stack[@]}"; i++ )); do 234 | 235 | if [[ ${stack[$i]} == "0" ]]; then 236 | serstack[$i]="00" 237 | continue 238 | fi 239 | read itemlen < <( data_compsize "${#stack[${i}]}" ) 240 | serstack[${i}]="${itemlen}${stack[${i}]}" 241 | done 242 | 243 | # printf "%s\n" "${sersize}" ${serstack[@]} 244 | echo -n "${sersize}" 245 | for (( i=0; i<"${#serstack[@]}"; i++ )); do 246 | 247 | echo -n "${serstack[${i}]}" 248 | done 249 | } 250 | 251 | tx_build () 252 | { 253 | local -u version swmarker swflag vins vouts nlocktime 254 | local -au inputs outputs witness witsigs 255 | 256 | read version < <( tx_ser_int "${1}" ) 257 | 258 | if [[ "${2,,}" != "" ]]; then 259 | 260 | swmarker="00" 261 | swflag="01" 262 | fi 263 | 264 | inputs=( ${3} ) 265 | outputs=( ${4} ) 266 | witsigs=( ${6} ) 267 | 268 | read vins < <( data_compsize "$(( ${#inputs}*2 ))" ) 269 | read vouts < <( data_compsize "$(( ${#outputs}*2 ))" ) 270 | 271 | if [[ "${swflag}" == "01" ]]; then 272 | 273 | local -i j=0 274 | for (( i=0; i<"${#inputs[@]}"; i++ )); do 275 | 276 | read iswitness < <( tx_bip141_iswitprog "${inputs[${i}]}" ) 277 | 278 | if (( "${iswitness}" )); then 279 | 280 | # 010100 - dummy witness 281 | witness[${i}]="${witsigs[${j}]:-010100}" 282 | j="$(( ${j}+1 ))" 283 | else 284 | witness[${i}]="00" 285 | fi 286 | done 287 | fi 288 | 289 | read nlocktime < <( tx_ser_int "${5}" ) 290 | 291 | echo "${version}" 292 | if [[ "${swflag}" == "01" ]]; then 293 | 294 | echo "${swmarker}" 295 | echo "${swflag}" 296 | fi 297 | data_compsize "$(( (${#inputs[@]}*2) ))" 298 | printf "%s\n" ${inputs[@]} 299 | data_compsize "$(( ${#outputs[@]}*2 ))" 300 | printf "%s\n" ${outputs[@]} 301 | if [[ "${swflag}" == "01" ]]; then 302 | 303 | printf "%s\n" ${witness[@]} 304 | fi 305 | echo "${nlocktime}" 306 | } 307 | -------------------------------------------------------------------------------- /bitcoin/script/scriptpubkey.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # in : length of data in words 4 | # out: length in compactsize 5 | data_compsize () 6 | { 7 | local len size order 8 | 9 | if [[ "${1}" == "" ]]; then 10 | read len 11 | else 12 | len="${1}" 13 | fi 14 | 15 | read size < <( bc_bitcoin <<<" 16 | obase=A; ibase=A; 17 | size=(${len}/2); 18 | obase=16; ibase=16; 19 | compsize(size);" ) 20 | 21 | if (( $((16#${size})) > 252 )); then 22 | order="${size:0:2}" 23 | read size < <( revchunks "${size:2}" ) 24 | fi 25 | echo "${order}""${size}" 26 | } 27 | 28 | # in : length of data in words 29 | # out: " 0x" 30 | data_wsize2pushop() 31 | { 32 | bc_bitcoin <<<"wsize2pushop(${1^^});" 33 | } 34 | 35 | # in : length of data in decimal 36 | # out: length of data in words 37 | data_size2wsize() 38 | { 39 | bc_clean <<<" 40 | size=${1}; 41 | obase=16; ibase=16; 42 | size;" 43 | } 44 | 45 | # in : data to be pushed 46 | # out: serialized push 47 | data_pushdata() 48 | { 49 | local -u data size 50 | local -a pushop 51 | data="${1}" 52 | 53 | if (( "${#data}" == 2 )); then 54 | 55 | local data16="$((16#${data}))" 56 | 57 | if [[ "${op_num[${data16}]}" != "" ]]; then 58 | 59 | echo "0x${op_num[${data16}]}" 60 | return 61 | fi 62 | 63 | if [[ "${data}" == '81' ]]; then 64 | 65 | echo "0x${op_num[-1]}" 66 | return 67 | fi 68 | fi 69 | 70 | read size < <( data_size2wsize "${#data}" ) 71 | readarray -t pushop < <( data_wsize2pushop "${size}" ) 72 | read pushop[1] < <( revchunks <<<"${pushop[1]}" ) 73 | 74 | echo "${pushop[0]}${pushop[1]} 0x${data}" 75 | } 76 | 77 | # in : data separated by spaced, sorrounded by quotes 78 | # out: serialized push 79 | data_pushmany() 80 | { 81 | local -a tmparr 82 | local -a data 83 | 84 | read -r -a data <<<"${1^^}" 85 | 86 | local -i j 87 | for (( i=0; i<"${#data[@]}"; i++ )); do 88 | 89 | read tmparr[${i}] < <( data_pushdata "${data[${i}]}" ) 90 | done 91 | 92 | echo "${tmparr[@]}" 93 | } 94 | 95 | # in : bitcoin script in asm 96 | # out: the script serialized in hex 97 | script_serialize () 98 | { 99 | local -a script 100 | read -r -a script <<<"${@}" 101 | local elem pushdata serdata pushnum hextext ser="" 102 | 103 | for ((i=0; i<${#script[@]}; i++ )); do 104 | 105 | elem="${script[${i}]}" 106 | 107 | if [[ "${elem:0:2}" == "0x" ]]; then # literal element: 0x7093, 0xAABB00 ... 108 | ser+="${elem/0x/}" 109 | elif [[ "${elem:0:1}" == "@" ]]; then # hex data push: @AA10 -> 02AA10, @0A -> 5A, @81 -> 4F ... 110 | read pushdata < <( data_pushdata "${elem:1}" ) 111 | read serdata < <( script_serialize "${pushdata}" ) 112 | ser+="${serdata}" 113 | elif script_is_bignum "${elem}"; then # bignum [-2^31+1, 2^31-1]: -100, 999, 1512, 0 ... 114 | read pushnum < <( script_ser_num "${elem}" ) 115 | pushnum="${pushnum[*]// /}" 116 | ser+="${pushnum//0x/}" 117 | elif [[ "${elem:0:1}" == "%" ]]; then # text %abcd -> 0x0461626364 118 | read hextext < <( bin2hex <<<"${elem:1}" ) 119 | read pushdata < <( data_pushdata "${hextext:0:-2}" ) 120 | read serdata < <( script_serialize "${pushdata}" ) 121 | ser+="${serdata}" 122 | else # opcode element (or INVALIDOPCODE) 123 | ser+="${opcodes[${elem}]:-FF}" 124 | fi 125 | done 126 | 127 | echo "${ser^^}" 128 | } 129 | 130 | # in : pubkey 131 | # out: p2pk script in asm 132 | spk_pay2pubkey() 133 | { 134 | local -a tmpscript 135 | local pushop_pubkey 136 | 137 | tmpscript=( "${script_p2pkey[@]}" ) 138 | read pushop_pubkey < <( data_pushdata "${1}" ) 139 | 140 | tmpscript[0]="${pushop_pubkey}" 141 | 142 | echo "${tmpscript[@]}" 143 | } 144 | 145 | # in : base58 address 146 | # out: p2pkh script in asm 147 | spk_pay2pkhash() 148 | { 149 | local -a tmpscript 150 | local pkhash 151 | 152 | tmpscript=( "${script_p2pkh[@]}" ) 153 | read pkhash < <( key_addr2hash160 "${1}" ) 154 | 155 | tmpscript[3]="0x${pkhash}" 156 | 157 | echo "${tmpscript[@]}" 158 | } 159 | 160 | # in 1: 'm' value of m-of-n script 161 | # in 2: pubkeys separated by spaces, surrounded by quotes 162 | # out : m-of-n bare multisig script in asm 163 | spk_pay2mofn() 164 | { 165 | local -a pubkeys tmpscript 166 | local -i m="${1}" n 167 | pubkeys=( ${2} ) 168 | n="${#pubkeys[@]}" 169 | 170 | if (( "${m}" > "${n}" )); then 171 | # error, setting m=1 172 | m='1' 173 | fi 174 | 175 | tmpscript=( "${script_mofn[@]}" ) 176 | 177 | tmpscript[0]="${m}" 178 | read tmpscript[1] < <( data_pushmany "${pubkeys[*]}" ) 179 | tmpscript[2]="${n}" 180 | 181 | echo "${tmpscript[@]}" 182 | } 183 | 184 | # in : scriptpubkey in asm, surrounded by quotes 185 | # out: p2sh script in asm 186 | spk_pay2shash() 187 | { 188 | local -a script tmpscript 189 | local -u scripthash 190 | 191 | script=( ${1} ) 192 | read scripthash < <( script_serialize "${script[*]}" | hash160 ) 193 | tmpscript=( "${script_p2sh[@]}" ) 194 | 195 | tmpscript[2]="0x${scripthash}" 196 | 197 | echo "${tmpscript[@]}" 198 | } 199 | 200 | # in : base58 address 201 | # out: p2wpkh script in asm 202 | spk_pay2wpkhash() 203 | { 204 | local -a tmpscript 205 | local -u pkhash 206 | 207 | tmpscript=( "${script_p2wpkh[@]}" ) 208 | read pkhash < <( key_addr2hash160 "${1}" ) 209 | 210 | tmpscript[2]="0x${pkhash}" 211 | 212 | echo "${tmpscript[@]}" 213 | } 214 | 215 | # in : scriptpubkey in asm, surrounded by quotes 216 | # out: p2wsh script in asm 217 | spk_pay2wshash() 218 | { 219 | local -a script tmpscript 220 | local -u scripthash 221 | 222 | script=( ${1} ) 223 | read scripthash < <( script_serialize "${script[*]}" | sha256 ) 224 | tmpscript=( "${script_p2wsh[@]}" ) 225 | 226 | tmpscript[2]="0x${scripthash}" 227 | 228 | echo "${tmpscript[@]}" 229 | } 230 | 231 | spk_pay2ced() 232 | { 233 | local -a escrow_script="${2}" timeout_script="${3}" tmpscript 234 | local timeout="${1}" 235 | 236 | tmpscript=( "${script_ced[@]}" ) 237 | read timeout < <( script_ser_num "${timeout}" ) 238 | 239 | tmpscript[1]="${escrow_script}" 240 | tmpscript[3]="${timeout}" 241 | tmpscript[6]="${timeout_script}" 242 | 243 | echo "${tmpscript[@]}" 244 | } 245 | 246 | spk_pay2mshash() 247 | { 248 | local -a keycode=( ${1} ) tmpscript=( ${script_p2wv1[@]} ) 249 | local -u scriptroot serscript keycodehash path="$2" 250 | local -u scripthash position="$3" k leaf depth version="${4:-00000000}" 251 | 252 | decho "keycode : ${keycode[@]}" 253 | 254 | read serscript < <( script_serialize "0 ${keycode[@]}" ) 255 | decho "serscript : ${serscript}" 256 | 257 | read keycodehash < <( sha256 "${serscript}" ) 258 | decho "keycodehash : ${keycodehash}" 259 | 260 | depth="$(( ${#path}/64 ))" 261 | iter="${keycodehash}" 262 | decho "depth : ${depth}" 263 | decho "position : ${position}" 264 | read leaf < <( BC_ENV_ARGS='-q' bc_clean <<<"obase=2; ((2^${depth})+${position})" | rev ) 265 | decho "leaf : ${leaf}" 266 | for (( i=0, j=${leaf:0:1}; i<$((${#leaf}-1)); ++i, j=${leaf:$i:1} )); do 267 | decho "\${leaf:$i:1} = ${leaf:$i:1}" 268 | if (( ${leaf:$i:1} == 0 )); then 269 | decho "iter < <( sha256 "${iter}\|${path:$((i*64)):64}" )" 270 | read iter < <( sha256 "${iter}${path:$((i*64)):64}" ) 271 | else 272 | decho "iter < <( sha256 "${path:$((i*64)):64}\|${iter}" )" 273 | read iter < <( sha256 "${path:$((i*64)):64}${iter}" ) 274 | fi 275 | done 276 | 277 | #leaf="$(( position % 2 ))" 278 | #decho "${path:0:$((leaf*64))}|${scripthash}|${path:$(((leaf)*64))}" 279 | #tree="${path:0:$((leaf*64))}${scripthash}${path:$(((leaf)*64))}" 280 | #iter="${tree:0:64}" 281 | #for (( i=64; i<${#tree}; i+=64 )); do 282 | # echo "read iter < <( hash256 "${iter}\|${tree:$i:64}" )" 283 | # read iter < <( hash256 "${iter}${tree:$i:64}" ) 284 | # echo "iter : ${iter}" 285 | #done 286 | tmpscript[2]="0x${iter:-${keycodehash}}" 287 | echo "${tmpscript[@]}" 288 | } 289 | 290 | spk_pay2wpkv0 () 291 | { 292 | echo "0x5121${1}" 293 | } 294 | 295 | #spk_pay2wmast() 296 | #{ 297 | # local -a mastroot tmpscript 298 | # local -u masthash 299 | # 300 | # # script=( ${1} ) 301 | # read mastroot < <( script_serialize "$1" ) 302 | # read masthash < <( printf "${mastroot}" | hash256 ) 303 | # tmpscript=( "${script_p2wmast[@]}" ) 304 | # 305 | # tmpscript[2]="0x${masthash}" 306 | # 307 | # echo "${tmpscript[@]}" 308 | #} 309 | --------------------------------------------------------------------------------