|
| 1 | +# encoding: utf-8 |
| 2 | + |
| 3 | +require 'pp' |
| 4 | +require 'digest' |
| 5 | + |
| 6 | + |
| 7 | +## our own code |
| 8 | +require 'bytes/version' # note: let version always go first |
| 9 | + |
| 10 | + |
| 11 | +class Bytes |
| 12 | + def self.new( *args ) |
| 13 | + String.new( *args ).b |
| 14 | + end |
| 15 | + |
| 16 | + def self.from_hex( hexstr ) |
| 17 | + if ['0x', '0X'].include?( hexstr[0...2] ) |
| 18 | + [hexstr[2..-1]].pack('H*') ## cut-of leading 0x or 0X if present |
| 19 | + else |
| 20 | + [hexstr].pack('H*') |
| 21 | + end |
| 22 | + end |
| 23 | + |
| 24 | + def self.to_hex( str ) |
| 25 | + # note: unpack returns string with <Encoding:US-ASCII> |
| 26 | + # conver to default encoding |
| 27 | + ## todo/fix: do NOT hardcode UTF-8 - use default encoding - how? |
| 28 | + str.unpack('H*').first.encode("UTF-8") |
| 29 | + end |
| 30 | + |
| 31 | + def self.convert( *args ) |
| 32 | + ## used by Bytes() in global Kernel converter method |
| 33 | + if args.size == 1 |
| 34 | + if args[0].is_a? Array |
| 35 | + ## assume array of bytes |
| 36 | + ## to be done |
| 37 | + else ## assume String |
| 38 | + ## todo/fix: use coerce to_str if arg is NOT a string - why? why not? |
| 39 | + str = args[0] |
| 40 | + ## |
| 41 | + if str.encoding == Encoding::ASCII_8BIT |
| 42 | + ## assume it's binary data - use as is (no hexstring conversion) |
| 43 | + new( str ) ## todo/check: return str as-is (without new) - why? why not? |
| 44 | + else ## assume it's a hexstring |
| 45 | + from_hex( str ) |
| 46 | + end |
| 47 | + end |
| 48 | + else |
| 49 | + ## todo/fix: throw argument error |
| 50 | + end |
| 51 | + end |
| 52 | +end |
| 53 | + |
| 54 | + |
| 55 | +class Buffer |
| 56 | + def self.new( *args ) |
| 57 | + if args.size == 0 |
| 58 | + ## note: use "" to always use default encoding (and NOT binary) |
| 59 | + String.new( "" ) |
| 60 | + else |
| 61 | + String.new( *args ) |
| 62 | + end |
| 63 | + end |
| 64 | +end |
| 65 | + |
| 66 | + |
| 67 | +module BytesHelper |
| 68 | + def hex_to_bytes( hexstr ) Bytes.from_hex( hexstr); end |
| 69 | + alias_method :h_to_b, :hex_to_bytes |
| 70 | + alias_method :htob, :hex_to_bytes |
| 71 | + |
| 72 | + def bytes_to_hex( str ) Bytes.to_hex( str ); end |
| 73 | + alias_method :b_to_h, :bytes_to_hex |
| 74 | + alias_method :btoh, :bytes_to_hex |
| 75 | +end |
| 76 | + |
| 77 | + |
| 78 | + |
| 79 | +class String |
| 80 | + def h_to_b() Bytes.from_hex( self ); end |
| 81 | + alias_method :htob, :h_to_b |
| 82 | + |
| 83 | + def b_to_h() Bytes.to_hex( self ); end ## add .b-like shortcut |
| 84 | + alias_method :btoh, :b_to_h |
| 85 | + alias_method :h, :b_to_h |
| 86 | +end |
| 87 | + |
| 88 | + |
| 89 | +module HashHelper |
| 90 | + def sha256( bytes ) |
| 91 | + ## todo/fix: check bytes.encoding - warn if not BINARY!!!! |
| 92 | + Digest::SHA256.digest( bytes ) |
| 93 | + end |
| 94 | + |
| 95 | + def ripemd160( bytes ) |
| 96 | + ## todo/fix: check bytes.encoding - warn if not BINARY!!!! |
| 97 | + Digest::RMD160.digest( bytes ) |
| 98 | + end |
| 99 | + |
| 100 | + def hash256( bytes ) |
| 101 | + ## double - uses sha256(sha256()) |
| 102 | + sha256(sha256( bytes )) |
| 103 | + end |
| 104 | + |
| 105 | + def hash160( bytes ) |
| 106 | + ## double - uses ripemd160(sha256()) |
| 107 | + ripemd160(sha256( bytes )) |
| 108 | + end |
| 109 | + |
| 110 | + ## convenience shortcut helpers |
| 111 | + def sha256hex( bytes ) Bytes.to_hex(sha256( bytes )); end |
| 112 | + def ripemd160hex( bytes ) Bytes.to_hex(ripemd160( bytes )); end |
| 113 | + def hash256( bytes ) Bytes.to_hex(hash256( bytes )); end |
| 114 | + def hash160( bytes ) Bytes.to_hex(hash160( bytes )); end |
| 115 | +end |
| 116 | + |
| 117 | +## make "global" for now - check if there's a better way (include in Kernel) - why? why ot? |
| 118 | +include HashHelper |
| 119 | +include BytesHelper |
| 120 | + |
| 121 | + |
| 122 | + |
| 123 | +module Kernel |
| 124 | + def Bytes( *args ) Bytes.convert( *args ); end |
| 125 | +end |
| 126 | + |
| 127 | +puts Bytes.banner ## say hello |
0 commit comments