cryptos 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7eab144e238bbc87fd1a9d71dab7c57d590a294b30a489b1cd85e87f9a2e60db
4
- data.tar.gz: 19ecae744e1f98ebc17ebfcde4ec4673183085455b62641f0d684d569aa2c50b
3
+ metadata.gz: 821b977f9586beced716c6274e4c4de1b2bd59eacb2ca2d1f00ba7555cda7a46
4
+ data.tar.gz: aef2d8dcd9b5ef0155925df43d89fb8738fe09cfa1e99d9d78065a82ee3bcf6c
5
5
  SHA512:
6
- metadata.gz: 373c5b5c1775ce8c485aa7f93706c7619ce78a09b42e499b3ff5d22256385c33767cfa681fc3c76d2ce55016fe6456861da5bfe7ca4c5866db7dfecd70af750f
7
- data.tar.gz: 42851acdf1e22ee3c6537be65c3537c6dc9c7dea69e556bc676f1cd322bdca0782467f2092850adbe5026a32c8b378803fc95eb0d3696df098e66451e60a7f12
6
+ metadata.gz: cc3b5bc76776036438e1bb65efa1988f7fd0c8c12adcd57feab46bf94103086a024b5e92b7774891e27eaa9ed330b48ea7e841ddd87bbe5e816d2762f2cee353
7
+ data.tar.gz: 51fb82e5739d2a160f7968dcc8fa37f72b805614e85407051789b3b060c08a49a8153e9cba83f212a8aa236c5325f3a2f7ff05ca91cc2b42c650924a2e8c22f6
@@ -5,6 +5,13 @@ cache: bundler
5
5
  rvm:
6
6
  - 2.5.3
7
7
 
8
+ env:
9
+ global:
10
+ - CC_TEST_REPORTER_ID=38c8686e073a8123e72d8f7c580edbfae244922662e6202e9a964152b6b234a0
11
+
12
+ apt_packages:
13
+ - bitcoind
14
+
8
15
  before_install:
9
16
  - gem install bundler -v 1.16.6
10
17
  - sudo apt-add-repository ppa:bitcoin/bitcoin -y
@@ -13,13 +20,14 @@ before_install:
13
20
  - wget https://download.litecoin.org/litecoin-0.16.3/linux/litecoin-0.16.3-x86_64-linux-gnu.tar.gz
14
21
  - tar -xvf litecoin-0.16.3-x86_64-linux-gnu.tar.gz
15
22
  - export PATH=./litecoin-0.16.3/bin:$PATH
16
- - echo $PATH
17
-
18
- apt_packages:
19
- - bitcoind
23
+ - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
24
+ - chmod +x ./cc-test-reporter
20
25
 
21
26
  before_script:
22
- # - mkdir -p /home/travis/.bitcoin && cp bitcoin.conf /home/travis/.bitcoin/bitcoin.conf
23
27
  - bitcoind -regtest -daemon
24
28
  - litecoind -regtest -daemon
25
29
  - sleep 15
30
+ - ./cc-test-reporter before-build
31
+
32
+ after_script:
33
+ - ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT
@@ -1,20 +1,23 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cryptos (0.0.1)
4
+ cryptos (0.0.2)
5
5
  hashie
6
6
  httparty
7
7
 
8
8
  GEM
9
9
  remote: https://rubygems.org/
10
10
  specs:
11
+ bump (0.7.0)
11
12
  coderay (1.1.2)
12
13
  diff-lcs (1.3)
14
+ docile (1.3.1)
13
15
  ecdsa (1.2.0)
14
16
  hashie (3.6.0)
15
17
  httparty (0.16.3)
16
18
  mime-types (~> 3.0)
17
19
  multi_xml (>= 0.5.2)
20
+ json (2.1.0)
18
21
  method_source (0.9.2)
19
22
  mime-types (3.2.2)
20
23
  mime-types-data (~> 3.2015)
@@ -37,17 +40,24 @@ GEM
37
40
  diff-lcs (>= 1.2.0, < 2.0)
38
41
  rspec-support (~> 3.8.0)
39
42
  rspec-support (3.8.0)
43
+ simplecov (0.16.1)
44
+ docile (~> 1.1)
45
+ json (>= 1.8, < 3)
46
+ simplecov-html (~> 0.10.0)
47
+ simplecov-html (0.10.2)
40
48
 
41
49
  PLATFORMS
42
50
  ruby
43
51
 
44
52
  DEPENDENCIES
53
+ bump
45
54
  bundler
46
55
  cryptos!
47
56
  ecdsa
48
57
  pry
49
58
  rake
50
59
  rspec
60
+ simplecov
51
61
 
52
62
  BUNDLED WITH
53
63
  1.17.1
data/README.md CHANGED
@@ -1,10 +1,11 @@
1
1
  # Cryptos
2
2
  [![Build Status](https://travis-ci.org/icostan/cryptos.svg?branch=master)](https://travis-ci.org/icostan/cryptos)
3
- [![Test Coverage](https://api.codeclimate.com/v1/badges/50a2b33cfb10cd5293dc/test_coverage)](https://codeclimate.com/github/icostan/cryptos/test_coverage)
3
+ [![Maintainability](https://api.codeclimate.com/v1/badges/d929c152bff4fe5be78f/maintainability)](https://codeclimate.com/github/icostan/cryptos/maintainability)
4
+ [![Test Coverage](https://api.codeclimate.com/v1/badges/d929c152bff4fe5be78f/test_coverage)](https://codeclimate.com/github/icostan/cryptos/test_coverage)
5
+ [![Gem Version](https://badge.fury.io/rb/cryptos.svg)](https://badge.fury.io/rb/cryptos)
4
6
 
5
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/cryptos`. To experiment with that code, run `bin/console` for an interactive prompt.
7
+ Cryptos project is meant to provide an unified Ruby API to work with different crypto-currencies but the ultimate goal is to support atomic-swaps between any two coins.
6
8
 
7
- TODO: Delete this and the text above, and describe your gem
8
9
 
9
10
  ## Installation
10
11
 
@@ -24,7 +25,102 @@ Or install it yourself as:
24
25
 
25
26
  ## Usage
26
27
 
27
- TODO: Write usage instructions here
28
+ ### Scenario 1: Spend coinbase transaction
29
+
30
+ Alright, let's begin, first thing first, lets generate private and public keys:
31
+
32
+ ```ruby
33
+ 2.5.3 :001 > private_key = Cryptos::PrivateKey.generate
34
+ => #<Cryptos::PrivateKey:0x00007f8cc10c0ad0 @value=1991485315816438798044329630916774278846523543844864946402119577704095054145, @order=115792089237316195423570985008687907852837564279074904382605163141518161494337>
35
+ 2.5.3 :002 > public_key = Cryptos::PublicKey.new private_key
36
+ => #<Cryptos::PublicKey:0x00007f8cc105ed58 @private_key=#<Cryptos::PrivateKey:0x00007f8cc10c0ad0 @value=1991485315816438798044329630916774278846523543844864946402119577704095054145, @order=115792089237316195423570985008687907852837564279074904382605163141518161494337>, @x=107779388491921327681974754398507503201871466663959093103394577491037829153768, @y=78060352001932916201234328232450653863791592111885208305671830584742527863131>
37
+ ```
38
+
39
+ Based in publik key above lets create a Bitcoin address:
40
+
41
+ ```ruby
42
+ 2.5.3 :003 > from_address = Cryptos::Bitcoin::Address.new public_key
43
+ => #<Cryptos::Bitcoin::Address:0x00007f8cc12fc560 @public_key=#<Cryptos::PublicKey:0x00007f8cc105ed58 @private_key=#<Cryptos::PrivateKey:0x00007f8cc10c0ad0 @value=1991485315816438798044329630916774278846523543844864946402119577704095054145, @order=115792089237316195423570985008687907852837564279074904382605163141518161494337>, @x=107779388491921327681974754398507503201871466663959093103394577491037829153768, @y=78060352001932916201234328232450653863791592111885208305671830584742527863131>, @testnet=true>
44
+ ```
45
+
46
+ Before going any further we need to install bitcoin-core daemon and start node in regtest mode:
47
+
48
+ ```shell
49
+ # in MacOS
50
+ brew install bitcoin
51
+
52
+ # in Linux (Debian based)
53
+ apt-get install bitcoin
54
+
55
+ # start Bitcoin daemon in regtest mode
56
+ bitcoin-cli -regtest -printtoconsole
57
+ ```
58
+
59
+ Now we create a simple Cli connector that will communicate to underlying bitcoin daemon.
60
+
61
+ ```ruby
62
+ 2.5.3 :004 > cli = Cryptos::Connectors::Cli.new
63
+ => #<Cryptos::Connectors::Cli:0x00007f8cc12ece30 @program="bitcoin-cli", @network="regtest", @verbose=false>
64
+ ```
65
+
66
+ Import address into node and generate 101 blocks. If you ask why 101 then it is because coinbase transactions are spendable after 100 confirmatinos.
67
+
68
+ ```ruby
69
+ 2.5.3 :005 > from_address.import cli
70
+ => true
71
+ 2.5.3 :006 > cli.generate_to_address from_address, blocks: 101
72
+ => true
73
+ ```
74
+
75
+ Generate and import destination address to send BTC to then check that it has no money in it.
76
+
77
+ ```ruby
78
+ 2.5.3 :007 > to_address = Cryptos::Bitcoin::Address.new Cryptos::PublicKey.new Cryptos::PrivateKey.generate
79
+ => #<Cryptos::Bitcoin::Address:0x00007f8cc134f2b0 @public_key=#<Cryptos::PublicKey:0x00007f8cc128fa78 @private_key=#<Cryptos::PrivateKey:0x00007f8cc128faa0 @value=104555233989943463494354097619221894829574308702717051161491781222000198727347, @order=115792089237316195423570985008687907852837564279074904382605163141518161494337>, @x=1402024405898287938501468401055931693243587868828983898835308320263377717122, @y=89146164815925753866667564550747587615674131412309491381641677989226156891240>, @testnet=true>
80
+ 2.5.3 :008 > to_address.import cli
81
+ => true
82
+ 2.5.3 :009 > cli.get_received_by_address to_address
83
+ => "0.00000000"
84
+ ```
85
+
86
+ Alright, now we get to real stuff, transactions: create input from our ```from_address```, send 123_456_789 Satoshis (1.23456789 BTC) to our ```to_address``` and change amount back to ```from_address```.
87
+
88
+ ```ruby
89
+ 2.5.3 :010 > input = Cryptos::Input.from_utxo cli, from_address
90
+ => #<struct Cryptos::Input value=2500000000.0, tx_hash="33fc8506d7a5880cfddca3c950f95fa461398fb764da4527169d5574a7c00c7b", index=0, script_sig=nil, sequence=68719476735>
91
+ 2.5.3 :011 > output = Cryptos::Output.p2pkh to_address, 123_456_789
92
+ => #<struct Cryptos::Output value=123456789, script_pubkey=#<Cryptos::Script:0x00007f8cc12ed8a8 @script="OP_DUP OP_HASH160 9aae79929e4364ab3aabe1f83a875304d1b67a3a OP_EQUALVERIFY OP_CHECKSIG">>
93
+ 2.5.3 :012 > change = Cryptos::Output.p2pkh_change from_address, input, output
94
+ => #<struct Cryptos::Output value=2376533211.0, script_pubkey=#<Cryptos::Script:0x00007f8cc12cfdd0 @script="OP_DUP OP_HASH160 57a58e05aedfbb6bd97b373baf65ce7cc318351b OP_EQUALVERIFY OP_CHECKSIG">>
95
+ 2.5.3 :013 > transaction = Cryptos::Transaction.from_ioc input, output, change
96
+ => #<struct Cryptos::Transaction version=1, inputs=[#<struct Cryptos::Input value=2500000000.0, tx_hash="33fc8506d7a5880cfddca3c950f95fa461398fb764da4527169d5574a7c00c7b", index=0, script_sig=nil, sequence=68719476735>], outputs=[#<struct Cryptos::Output value=123456789, script_pubkey=#<Cryptos::Script:0x00007f8cc12ed8a8 @script="OP_DUP OP_HASH160 9aae79929e4364ab3aabe1f83a875304d1b67a3a OP_EQUALVERIFY OP_CHECKSIG">>, #<struct Cryptos::Output value=2376533211.0, script_pubkey=#<Cryptos::Script:0x00007f8cc12cfdd0 @script="OP_DUP OP_HASH160 57a58e05aedfbb6bd97b373baf65ce7cc318351b OP_EQUALVERIFY OP_CHECKSIG">>], locktime=0>
97
+ ```
98
+
99
+ Sign and broadcast the transaction:
100
+
101
+ ```ruby
102
+ 2.5.3 :014 > transaction.sign_single_input from_address
103
+ => "01000000017b0cc0a774559d162745da64b78f3961a45ff950c9a3dcfd0c88a5d70685fc33000000006a473044022020b53986c2ef08d54137e57f1c231a0c2fe1b6dc88c7208ecef6f7474bae985002203027db653202da53ce081da46431ef1f88f3e1bf47254940a58740a86506cbc3012103ee48f8db1d9a5dfc1b620dbe9566b77d995e0325b91d3b661a697272920f43e8ffffffff0215cd5b07000000001976a9149aae79929e4364ab3aabe1f83a875304d1b67a3a88acdb04a78d000000001976a91457a58e05aedfbb6bd97b373baf65ce7cc318351b88ac00000000"
104
+ 2.5.3 :015 > transaction.broadcast cli
105
+ => true
106
+ ```
107
+
108
+ Mine new block that will contain our hand crafted transaction and VOILA! output amount was transafered to new address.
109
+
110
+ ```ruby
111
+ 2.5.3 :016 > cli.generate blocks: 1
112
+ => true
113
+ 2.5.3 :017 > cli.get_received_by_address to_address
114
+ => "1.23456789"
115
+ ```
116
+
117
+ ### Scenario 2: Spend multisig transaction
118
+
119
+ TBD
120
+
121
+ ### Scenario 3: Atomic swaps between BTC and LTC
122
+
123
+ TBD
28
124
 
29
125
  ## Development
30
126
 
data/TODOs.org CHANGED
@@ -7,3 +7,4 @@
7
7
  * autoload modules
8
8
  * deterministic signature (https://tools.ietf.org/html/rfc6979)
9
9
  * refactor elliptic curve module, extract to classes
10
+ * implement #to_s method for all classes, right now they are too verbose
data/bin/run ADDED
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ private_key = Cryptos::PrivateKey.generate
4
+ public_key = Cryptos::PublicKey.new private_key
5
+ from_address = Cryptos::Bitcoin::Address.new public_key
6
+ cli = Cryptos::Connectors::Cli.new
7
+ from_address.import cli
8
+ cli.generate_to_address from_address, blocks: 101
9
+ to_address = Cryptos::Bitcoin::Address.new Cryptos::PublicKey.new Cryptos::PrivateKey.generate
10
+ to_address.import cli
11
+ cli.get_received_by_address to_address
12
+ input = Cryptos::Input.from_utxo cli, from_address
13
+ output = Cryptos::Output.p2pkh to_address, 123_456_789
14
+ change = Cryptos::Output.p2pkh_change from_address, input, output
15
+ transaction = Cryptos::Transaction.from_ioc input, output, change
16
+ transaction.sign_single_input from_address
17
+ transaction.broadcast cli
18
+ cli.generate blocks: 1
19
+ cli.get_received_by_address to_address
@@ -42,4 +42,6 @@ Gem::Specification.new do |spec|
42
42
  spec.add_development_dependency 'rake'
43
43
  spec.add_development_dependency 'rspec'
44
44
  spec.add_development_dependency 'pry'
45
+ spec.add_development_dependency 'simplecov'
46
+ spec.add_development_dependency 'bump'
45
47
  end
@@ -3,9 +3,11 @@ require 'hashie'
3
3
 
4
4
  require 'cryptos/version'
5
5
 
6
- require 'cryptos/base'
6
+ require 'cryptos/utils/bytes'
7
+ require 'cryptos/utils/hexas'
8
+ require 'cryptos/utils/hashes'
9
+
7
10
  require 'cryptos/base58'
8
- require 'cryptos/hashing'
9
11
  require 'cryptos/elliptic_curve'
10
12
  require 'cryptos/connectors/cli'
11
13
 
@@ -1,7 +1,7 @@
1
1
  module Cryptos
2
2
  class Address
3
- include Base58, Hashing
4
- extend Base58, Hashing
3
+ include Base58, Utils::Hashes
4
+ extend Base58, Utils::Hashes
5
5
 
6
6
  attr_reader :public_key
7
7
  attr_reader :testnet
@@ -16,7 +16,7 @@ module Cryptos
16
16
  #
17
17
  def generate(network)
18
18
  prefix = network.to_s(16).rjust 2, '0'
19
- ripemd160 = hash160 public_key.compressed
19
+ ripemd160 = hash160 public_key.to_sec
20
20
  with_version = "#{prefix}#{ripemd160}"
21
21
  checksum = hash256(with_version)[0, 8]
22
22
  wrap_encode = "#{with_version}#{checksum}"
@@ -28,7 +28,7 @@ module Cryptos
28
28
  end
29
29
 
30
30
  def to_hash160
31
- hash160(public_key.compressed)
31
+ hash160(public_key.to_sec)
32
32
  end
33
33
 
34
34
  def p2pkh
@@ -39,6 +39,10 @@ module Cryptos
39
39
  generate p2sh_prefix
40
40
  end
41
41
 
42
+ def import(cli)
43
+ cli.import_address self
44
+ end
45
+
42
46
  def to_s
43
47
  p2pkh
44
48
  end
@@ -1,24 +1,29 @@
1
- module Base58
2
- def base58_encode(ripe160_hash)
3
- alphabet = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
4
- value = ripe160_hash.to_i 16
5
- output = ''
6
- while value > 0
7
- remainder = value % 58
8
- value /= 58
9
- output += alphabet[remainder]
1
+ module Cryptos
2
+ module Base58
3
+ include Utils::Bytes
4
+
5
+ def base58_encode(ripe160_hash)
6
+ alphabet = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
7
+ value = ripe160_hash.to_i 16
8
+ output = ''
9
+ while value > 0
10
+ remainder = value % 58
11
+ value /= 58
12
+ output += alphabet[remainder]
13
+ end
14
+ output += alphabet[0] * [ripe160_hash].pack('H*').bytes.find_index{|b| b != 0}
15
+ output.reverse
10
16
  end
11
- output += alphabet[0] * [ripe160_hash].pack('H*').bytes.find_index{|b| b != 0}
12
- output.reverse
13
- end
14
- def base58_decode(address)
15
- alphabet = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
16
- int_val = 0
17
- address.reverse.chars.each_with_index do |char, index|
18
- char_index = alphabet.index(char)
19
- int_val += char_index * 58**index
17
+
18
+ def base58_decode(address)
19
+ alphabet = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
20
+ int_val = 0
21
+ address.reverse.chars.each_with_index do |char, index|
22
+ char_index = alphabet.index(char)
23
+ int_val += char_index * 58**index
24
+ end
25
+ # TODO: hard coded 25 bytes?
26
+ bignum_to_bytes(int_val, 25).unpack('H*').first
20
27
  end
21
- # TODO: hard coded 25 bytes?
22
- bignum_to_bytes(int_val, 25).unpack('H*').first
23
28
  end
24
29
  end
@@ -1,4 +1,6 @@
1
- module Bitcoin
2
- class Script
1
+ module Cryptos
2
+ module Bitcoin
3
+ class Script
4
+ end
3
5
  end
4
6
  end
@@ -1,30 +1,68 @@
1
- module Connectors
2
- class Cli
3
- attr_reader :program, :network
1
+ module Cryptos
2
+ module Connectors
3
+ class Cli
4
+ attr_reader :program, :network, :verbose
4
5
 
5
- def initialize(program = 'bitcoin-cli', network = 'regtest')
6
- @program = program
7
- @network = network
8
- end
6
+ def initialize(program: 'bitcoin-cli', network: 'regtest', verbose: false)
7
+ @program = program
8
+ @network = network
9
+ @verbose = verbose
10
+ end
11
+
12
+ def import_address(address, run_mode: :system)
13
+ run "importaddress #{address} '' false", run_mode: run_mode
14
+ end
15
+
16
+ def generate_to_address(address, blocks: 101, run_mode: :system, verbose: false)
17
+ run "generatetoaddress #{blocks} #{address}"
18
+ end
19
+
20
+ def generate(blocks: 1, run_mode: :system)
21
+ run "generate #{blocks}"
22
+ end
23
+
24
+ def list_unspent(address, run_mode: :inline)
25
+ run "listunspent 1 9999 \"[\\\"#{address}\\\"]\"", run_mode: run_mode
26
+ end
27
+
28
+ def send_raw_transaction(rawtx, run_mode: :system)
29
+ run "sendrawtransaction #{rawtx}", run_mode: run_mode
30
+ end
31
+
32
+ def test_raw_transaction(rawtx, run_mode: :inline)
33
+ run "testmempoolaccept '[\"#{rawtx}\"]'", run_mode: run_mode
34
+ end
35
+
36
+ def get_block_count
37
+ run("getblockcount", run_mode: :inline).to_i
38
+ end
39
+
40
+ def get_received_by_address(address)
41
+ result = run "getreceivedbyaddress #{address}", run_mode: :inline
42
+ result.strip
43
+ end
44
+
45
+ # private
9
46
 
10
- def run(args, run_mode: :inline, v: false)
11
- cmd = "#{program} -#{network} #{args}"
12
- puts "==> #{cmd}"
13
- case run_mode
14
- when :inline
15
- output = `#{cmd}`
16
- puts output if v
17
- output
18
- when :system
19
- success = system cmd
20
- fail "failed command: #{args}" unless success
21
- success
22
- when :daemon
23
- pid = spawn cmd
24
- sleep (ENV['BOOTSTRAP'] || 10).to_i
25
- pid
26
- else
27
- raise "dont know how to run #{run_mode}"
47
+ def run(args, run_mode: :system, debug: false)
48
+ cmd = "#{program} -#{network} #{args}"
49
+ puts "==> #{cmd} run_mode=#{run_mode} verbose=#{debug}" if debug || verbose
50
+ case run_mode
51
+ when :inline
52
+ output = `#{cmd}`
53
+ puts output if debug || verbose
54
+ output
55
+ when :system
56
+ success = system cmd, out: '/dev/null'
57
+ fail "failed command: #{args}" unless success
58
+ success
59
+ when :daemon
60
+ pid = spawn cmd
61
+ sleep (ENV['BOOTSTRAP'] || 10).to_i
62
+ pid
63
+ else
64
+ raise "dont know how to run #{run_mode}"
65
+ end
28
66
  end
29
67
  end
30
68
  end
@@ -1,23 +1,27 @@
1
- Der = Struct.new :der, :length, :ri, :rl, :r, :si, :sl, :s, :sighash_type do
2
- def initialize(der: 0x30, length: 0x44, ri: 0x02, rl: 0x20, r: nil, si: 0x02, sl: 0x20, s: nil, sighash_type: 0x01)
3
- super der, length, ri, rl, r, si, sl, s, sighash_type
4
- end
1
+ module Cryptos
2
+ Der = Struct.new :der, :length, :ri, :rl, :r, :si, :sl, :s, :sighash_type do
3
+ include Utils::Hashes, Utils::Hexas
5
4
 
6
- def serialize
7
- r_bytes = bignum_to_bytes(r, 32, false)
8
- if r_bytes.first & 0x80 == 128
9
- r_bytes = [0x00] + r_bytes
10
- self.length += 1
11
- self.rl += 1
5
+ def initialize(der: 0x30, length: 0x44, ri: 0x02, rl: 0x20, r: nil, si: 0x02, sl: 0x20, s: nil, sighash_type: 0x01)
6
+ super der, length, ri, rl, r, si, sl, s, sighash_type
12
7
  end
13
- byte_to_hex(der) + byte_to_hex(length) +
14
- byte_to_hex(ri) + byte_to_hex(rl) + bytes_to_hex(r_bytes) +
15
- byte_to_hex(si) + byte_to_hex(sl) + to_hex(bignum_to_bytes(s, 32)) +
16
- byte_to_hex(sighash_type)
17
- end
18
8
 
19
- def self.parse(signature)
20
- fields = *[signature].pack('H*').unpack('CCCCH66CCH64C')
21
- Der.new r: fields[4], s: fields[7], sighash_type: fields[8]
9
+ def serialize
10
+ r_bytes = bignum_to_bytes(r, 32, false)
11
+ if r_bytes.first & 0x80 == 128
12
+ r_bytes = [0x00] + r_bytes
13
+ self.length += 1
14
+ self.rl += 1
15
+ end
16
+ byte_to_hex(der) + byte_to_hex(length) +
17
+ byte_to_hex(ri) + byte_to_hex(rl) + bytes_to_hex(r_bytes) +
18
+ byte_to_hex(si) + byte_to_hex(sl) + bignum_to_hex(s) +
19
+ byte_to_hex(sighash_type)
20
+ end
21
+
22
+ def self.parse(signature)
23
+ fields = *[signature].pack('H*').unpack('CCCCH66CCH64C')
24
+ Der.new r: fields[4], s: fields[7], sighash_type: fields[8]
25
+ end
22
26
  end
23
27
  end
@@ -1,10 +1,12 @@
1
- module EllipticCurve
2
- Group = Struct.new :gx, :gy, :prime, :order, :cofactor
3
- Secp256k1 = Group.new 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798,
4
- 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8,
5
- 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F,
6
- 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141,
7
- 1
1
+ module Cryptos
2
+ module EllipticCurve
3
+ Group = Struct.new :gx, :gy, :prime, :order, :cofactor
4
+ Secp256k1 = Group.new 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798,
5
+ 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8,
6
+ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F,
7
+ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141,
8
+ 1
9
+ end
8
10
  end
9
11
 
10
12
  EC_Gx = 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798
@@ -17,6 +19,8 @@ LOW_S = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0
17
19
  #
18
20
  # Elliptic Curve
19
21
  #
22
+ include Cryptos::Utils::Bytes
23
+
20
24
  def extended_euclidean_algorithm(a, b)
21
25
  s, old_s = 0, 1
22
26
  t, old_t = 1, 0
@@ -1,7 +1,10 @@
1
1
  module Cryptos
2
- Input = Struct.new :value, :tx_hash, :index, :unlock_script, :sequence do
3
- def self.from_utxo(data, index = 0, options = {debug: false})
4
- utxo = JSON.parse(data)[index]
2
+ Input = Struct.new :value, :tx_hash, :index, :script_sig, :sequence do
3
+ include Utils::Hexas, Utils::Hashes
4
+
5
+ def self.from_utxo(cli, address, index = 0, options = {debug: false})
6
+ utxos = cli.list_unspent address
7
+ utxo = JSON.parse(utxos)[index]
5
8
  puts utxo if options[:debug]
6
9
  txid = utxo['txid']
7
10
  vout = utxo['vout']
@@ -9,12 +12,20 @@ module Cryptos
9
12
  sequence = options[:sequence] || 0xfffffffff
10
13
  Input.new amount * 10**8, txid, vout, sequence: sequence
11
14
  end
12
- def initialize(value, tx_hash, index, unlock_script: '', sequence: 0xfffffffff)
13
- super value, tx_hash, index, unlock_script, sequence
15
+
16
+ def self.from_tx(transaction, index = 0, options = {})
17
+ amount = transaction.outputs[index].value
18
+ sequence = options[:sequence] || 0xfffffffff
19
+ Input.new amount, transaction.hash, index, sequence: sequence
20
+ end
21
+
22
+ def initialize(value, tx_hash, index, script_sig: nil, sequence: 0xfffffffff)
23
+ super value, tx_hash, index, script_sig, sequence
14
24
  end
25
+
15
26
  def serialize
16
- script_hex = script_to_hex(unlock_script)
17
- hash_to_hex(tx_hash) + int_to_hex(index) +
27
+ script_hex = script_sig ? script_sig.to_hex : ''
28
+ hex_to_little(tx_hash) + int_to_hex(index) +
18
29
  byte_to_hex(hex_size(script_hex)) + script_hex + int_to_hex(sequence)
19
30
  end
20
31
  end
@@ -1,15 +1,24 @@
1
1
  module Cryptos
2
- Output = Struct.new :value, :lock_script do
2
+ Output = Struct.new :value, :script_pubkey do
3
+ include Utils::Hexas
4
+
3
5
  def self.p2pkh(address, amount)
4
- output_script = Cryptos::Script.for_address address
6
+ output_script = Cryptos::Script.p2pkh address
5
7
  Output.new amount, output_script
6
8
  end
9
+
10
+ def self.multisig(a1, a2, amount)
11
+ redeem_script = Cryptos::Script.multisig a1, a2
12
+ Output.new amount, Cryptos::Script.p2sh(redeem_script)
13
+ end
14
+
7
15
  def self.p2pkh_change(address, input, output, fee = 10_000)
8
16
  change_value = input.value - output.value - fee
9
17
  Output.p2pkh address, change_value
10
18
  end
19
+
11
20
  def serialize
12
- script_hex = script_to_hex(lock_script)
21
+ script_hex = script_pubkey.to_hex
13
22
  long_to_hex(value) + byte_to_hex(hex_size(script_hex)) + script_hex
14
23
  end
15
24
  end
@@ -4,6 +4,9 @@ module Cryptos
4
4
  class PrivateKey
5
5
  attr_reader :value, :order
6
6
 
7
+ # Generates new private key
8
+ # @param group [EllipticCurve::Group] EC group this
9
+ # @return the private key
7
10
  def self.generate(group = EllipticCurve::Secp256k1)
8
11
  value = 1 + SecureRandom.random_number(group.order - 1)
9
12
  new value, group.order
@@ -1,27 +1,27 @@
1
1
  module Cryptos
2
2
  class PublicKey
3
- attr_reader :x, :y, :private_key
3
+ include Utils::Bytes, Utils::Hexas
4
4
 
5
- def self.from_pk(private_key)
6
- new *ec_multiply(private_key.value, EC_Gx, EC_Gy, EC_p), private_key
7
- end
5
+ attr_reader :x, :y, :private_key
8
6
 
9
- def initialize(x, y, private_key)
10
- @x = x
11
- @y = y
7
+ def initialize(private_key)
12
8
  @private_key = private_key
9
+ @x, @y = *ec_multiply(private_key.value, EC_Gx, EC_Gy, EC_p)
13
10
  end
14
11
 
15
12
  def check!
16
13
  (x**3 + 7 - y**2) % EC_p == 0 || raise('public key point is not on the curve')
17
14
  end
18
15
 
19
- def compressed
20
- "#{y > 0 ? '02' : '03'}#{x.to_s(16)}"
21
- end
22
-
23
- def uncompressed
24
- "04#{x.to_s(16)}#{y.to_s(16)}"
16
+ # Serialize public key as SEC (Standards for Efficient Cryptography) format
17
+ # @param compressed [true, false] the format to return, either compressed or uncompressed
18
+ # @return address in SEC format
19
+ def to_sec(compressed = true)
20
+ if compressed
21
+ "#{y.even? ? '02' : '03'}#{x_to_sec}"
22
+ else
23
+ "04#{x_to_sec}#{y_to_sec}"
24
+ end
25
25
  end
26
26
 
27
27
  def coordinates
@@ -31,5 +31,15 @@ module Cryptos
31
31
  def to_s
32
32
  coordinates.to_s
33
33
  end
34
+
35
+ private
36
+
37
+ def x_to_sec
38
+ bin_to_hex bignum_to_bytes(x, 32)
39
+ end
40
+
41
+ def y_to_sec
42
+ bin_to_hex bignum_to_bytes(y, 32)
43
+ end
34
44
  end
35
45
  end
@@ -1,20 +1,96 @@
1
1
  module Cryptos
2
2
  class Script
3
- def self.for_address(address)
4
- hash160 = address.to_hash160
5
- if address.to_s.start_with? '2'
6
- "OP_HASH160 #{hash160} OP_EQUAL"
7
- else
8
- p2pkh hash160
9
- end
3
+ include Utils::Hexas, Utils::Hashes
4
+
5
+ OPCODES = {
6
+ 'OP_0' => 0x00,
7
+ 'OP_1' => 0x51,
8
+ 'OP_2' => 0x52,
9
+ 'OP_DUP' => 0x76,
10
+ 'OP_HASH160' => 0xA9,
11
+ 'OP_EQUAL' => 0x87,
12
+ 'OP_EQUALVERIFY' => 0x88,
13
+ 'OP_CHECKSIG' => 0xAC,
14
+ 'OP_CHECKMULTISIG' => 0xAE
15
+ }.freeze
16
+
17
+ attr_reader :script
18
+
19
+ # scriptSig for pay-to-pubkey-hash outputs
20
+ # @param der - signature in der format
21
+ # @param public_key - the public key
22
+ # @return script - a Script object holding scriptSig
23
+ def self.sig_pubkey(der, public_key)
24
+ new "#{der.serialize} #{public_key.to_sec}"
25
+ end
26
+
27
+ # scriptSig for pay-to-multisig-hash outputs
28
+ def self.sig_multisig(der1, der2, redeem_script)
29
+ new "OP_0 #{der1.serialize} #{der2.serialize} #{redeem_script.serialize}"
30
+ end
31
+
32
+ def self.p2pkh(address_or_hex)
33
+ hash160 = if address_or_hex.is_a? String
34
+ Address.to_hash160 address_or_hex
35
+ else
36
+ address_or_hex.to_hash160
37
+ end
38
+ new "OP_DUP OP_HASH160 #{hash160} OP_EQUALVERIFY OP_CHECKSIG"
39
+ end
40
+
41
+ def self.p2sh(script)
42
+ new "OP_HASH160 #{script.to_hash160} OP_EQUAL"
43
+ end
44
+
45
+ # multisign redeem script
46
+ def self.multisig(address1, address2)
47
+ new "OP_2 #{address1.public_key.to_sec} #{address2.public_key.to_sec} OP_2 OP_CHECKMULTISIG"
48
+ end
49
+
50
+ def self.bare(script)
51
+ new script
52
+ end
53
+
54
+ def initialize(script)
55
+ @script = script
56
+ end
57
+
58
+ def to_hash160
59
+ hash160 to_hex
60
+ end
61
+
62
+ def to_hex
63
+ @hex ||= to_asm.split.map { |token| token.start_with?('OP') ? opcode(token) : data(token) }.join
64
+ end
65
+ alias :serialize :to_hex
66
+
67
+ def to_asm
68
+ script.to_s
69
+ end
70
+
71
+ def to_s
72
+ to_asm
73
+ end
74
+
75
+ def size
76
+ [to_hex].pack('H*').size
77
+ end
78
+
79
+ private
80
+
81
+ def opcode(token)
82
+ raise "opcode #{token} not found" unless OPCODES.include?(token)
83
+ byte_to_hex OPCODES[token]
10
84
  end
11
85
 
12
- def self.for_public(pa)
13
- p2pkh Address.to_hash160 pa
86
+ def data(token)
87
+ bin_size = data_size token
88
+ # TODO: data size is defined as 1-9 bytes
89
+ byte_to_hex(bin_size) + token
14
90
  end
15
91
 
16
- def self.p2pkh(hash160)
17
- "OP_DUP OP_HASH160 #{hash160} OP_EQUALVERIFY OP_CHECKSIG"
92
+ def data_size(token)
93
+ [token].pack('H*').size
18
94
  end
19
95
  end
20
96
  end
@@ -1,8 +1,11 @@
1
1
  module Cryptos
2
2
  Transaction = Struct.new :version, :inputs, :outputs, :locktime do
3
+ include Utils::Hexas, Utils::Hashes
4
+
3
5
  def self.from_ioc(input, output, change, version: 1, locktime: 0)
4
6
  new version, [input], [output, change], locktime
5
7
  end
8
+
6
9
  def serialize
7
10
  inputs_hex = inputs.map(&:serialize).join
8
11
  outputs_hex = outputs.map(&:serialize).join
@@ -11,33 +14,58 @@ module Cryptos
11
14
  end
12
15
 
13
16
  def hash
14
- hash_to_hex sha256(sha256(serialize))
17
+ hex_to_little sha256(sha256(serialize))
15
18
  end
16
19
 
17
- def signature_hash(lock_script = nil, sighash_type = 0x01)
18
- inputs.first.unlock_script = lock_script if lock_script
20
+ def signature_hash(script_pubkey = nil, sighash_type = 0x01)
21
+ inputs.first.script_sig = script_pubkey if script_pubkey
19
22
  hash = sha256(sha256(serialize + int_to_hex(sighash_type)))
20
23
  [hash].pack('H*')
21
24
  end
22
25
 
23
- def sign(private_key, public_key, lock_script, sighash_type = 0x01)
24
- bytes_string = signature_hash lock_script, sighash_type
26
+ def sign(private_key, public_key, script_pubkey, sighash_type = 0x01)
27
+ bytes_string = signature_hash script_pubkey, sighash_type
25
28
  r, s = ecdsa_sign private_key.value, bytes_string
26
- der = Der.new r: r, s: s
27
- inputs.first.unlock_script = "#{der.serialize} #{public_key.compressed}"
29
+ der = Cryptos::Der.new r: r, s: s
30
+ inputs.first.script_sig = Script.sig_pubkey(der, public_key)
28
31
  serialize
29
32
  end
33
+
30
34
  def sign_input(index, address, sighash_type = 0x01)
31
- # TODO: get lock_script from input?
32
- lock_script = Cryptos::Script.for_address address
33
- bytes_string = signature_hash lock_script, sighash_type
35
+ # TODO: get script_pubkey from input?
36
+ script_pubkey = Cryptos::Script.p2pkh address
37
+ bytes_string = signature_hash script_pubkey, sighash_type
38
+
34
39
  r, s = ecdsa_sign address.public_key.private_key.value, bytes_string
35
- der = Der.new r: r, s: s
36
- inputs[index].unlock_script = "#{der.serialize} #{address.public_key.compressed}"
40
+ der = Cryptos::Der.new r: r, s: s
41
+ inputs[index].script_sig = Script.sig_pubkey der, address.public_key
42
+
37
43
  serialize
38
44
  end
45
+
46
+ def sign_single_input(address)
47
+ sign_input 0, address
48
+ end
49
+
50
+ def multi_sign_input(index, address1, address2, sighash_type = 0x01)
51
+ redeem_script = Cryptos::Script.multisig address1, address2
52
+ bytes_string = signature_hash redeem_script, sighash_type
53
+
54
+ r, s = ecdsa_sign address1.public_key.private_key.value, bytes_string
55
+ der1 = Cryptos::Der.new r: r, s: s
56
+ r, s = ecdsa_sign address2.public_key.private_key.value, bytes_string
57
+ der2 = Cryptos::Der.new r: r, s: s
58
+ inputs[index].script_sig = Script.sig_multisig der1, der2, redeem_script
59
+
60
+ serialize
61
+ end
62
+
63
+ def broadcast(cli)
64
+ cli.send_raw_transaction serialize
65
+ end
66
+
39
67
  def to_s
40
- "Transaction[inputs:#{inputs.map &:value}, outputs:#{outputs.map &:value}"
68
+ inputs.to_s + outputs.to_s
41
69
  end
42
70
  end
43
71
  end
@@ -0,0 +1,20 @@
1
+ module Cryptos
2
+ module Utils
3
+ module Bytes
4
+ def bytes_to_bignum(bytes_string)
5
+ bytes_string.bytes.reduce { |n, b| (n << 8) + b }
6
+ end
7
+
8
+ def bignum_to_bytes(n, length=nil, stringify=true)
9
+ a = []
10
+ while n > 0
11
+ a << (n & 0xFF)
12
+ n >>= 8
13
+ end
14
+ a.fill 0x00, a.length, length - a.length if length
15
+ bytes = a.reverse
16
+ stringify ? bytes.pack('C*') : bytes
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,21 @@
1
+ require 'digest'
2
+
3
+ module Cryptos
4
+ module Utils
5
+ module Hashes
6
+ def sha256(data)
7
+ Digest::SHA256.hexdigest([data].pack('H*'))
8
+ end
9
+
10
+ def hash160(data)
11
+ sha256 = Digest::SHA256.digest([data].pack('H*'))
12
+ Digest::RMD160.hexdigest sha256
13
+ end
14
+
15
+ def hash256(data)
16
+ sha256 = Digest::SHA256.digest([data].pack('H*'))
17
+ Digest::SHA256.hexdigest sha256
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,39 @@
1
+ module Cryptos
2
+ module Utils
3
+ module Hexas
4
+ include Bytes
5
+
6
+ def bin_to_hex(binary_bytes)
7
+ binary_bytes.unpack('H*').first
8
+ end
9
+
10
+ def byte_to_hex(value)
11
+ bin_to_hex [value].pack('C')
12
+ end
13
+
14
+ def bytes_to_hex(value)
15
+ bin_to_hex value.pack('C*')
16
+ end
17
+
18
+ def int_to_hex(value)
19
+ bin_to_hex [value].pack('V')
20
+ end
21
+
22
+ def long_to_hex(value)
23
+ bin_to_hex [value].pack('Q<')
24
+ end
25
+
26
+ def bignum_to_hex(value, size = 32)
27
+ bin_to_hex bignum_to_bytes(value, size)
28
+ end
29
+
30
+ def hex_to_little(value)
31
+ bin_to_hex [value].pack('H*').reverse
32
+ end
33
+
34
+ def hex_size(hex)
35
+ [hex].pack('H*').size
36
+ end
37
+ end
38
+ end
39
+ end
@@ -1,3 +1,3 @@
1
1
  module Cryptos
2
- VERSION = '0.0.1'
2
+ VERSION = '0.0.2'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cryptos
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Iulian Costan
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-11-26 00:00:00.000000000 Z
11
+ date: 2018-12-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: httparty
@@ -108,6 +108,34 @@ dependencies:
108
108
  - - ">="
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: simplecov
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: bump
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
111
139
  description: The easiest way to craft your own transactions for multiple crypto currencies
112
140
  email:
113
141
  - iulian.costan@gmail.com
@@ -127,11 +155,11 @@ files:
127
155
  - Rakefile
128
156
  - TODOs.org
129
157
  - bin/console
158
+ - bin/run
130
159
  - bin/setup
131
160
  - cryptos.gemspec
132
161
  - lib/cryptos.rb
133
162
  - lib/cryptos/address.rb
134
- - lib/cryptos/base.rb
135
163
  - lib/cryptos/base58.rb
136
164
  - lib/cryptos/bitcoin.rb
137
165
  - lib/cryptos/bitcoin/address.rb
@@ -141,7 +169,6 @@ files:
141
169
  - lib/cryptos/der.rb
142
170
  - lib/cryptos/deribit/client.rb
143
171
  - lib/cryptos/elliptic_curve.rb
144
- - lib/cryptos/hashing.rb
145
172
  - lib/cryptos/input.rb
146
173
  - lib/cryptos/litecoin.rb
147
174
  - lib/cryptos/litecoin/address.rb
@@ -150,6 +177,9 @@ files:
150
177
  - lib/cryptos/public_key.rb
151
178
  - lib/cryptos/script.rb
152
179
  - lib/cryptos/transaction.rb
180
+ - lib/cryptos/utils/bytes.rb
181
+ - lib/cryptos/utils/hashes.rb
182
+ - lib/cryptos/utils/hexas.rb
153
183
  - lib/cryptos/version.rb
154
184
  homepage: https://github.com/icostan/cryptos
155
185
  licenses: []
@@ -1,74 +0,0 @@
1
- require 'json'
2
- require 'digest'
3
-
4
- class Struct
5
- OPCODES = {
6
- 'OP_DUP' => 0x76,
7
- 'OP_HASH160' => 0xA9,
8
- 'OP_EQUAL' => 0x87,
9
- 'OP_EQUALVERIFY' => 0x88,
10
- 'OP_CHECKSIG' => 0xAC
11
- }.freeze
12
-
13
- def opcode(token)
14
- raise "opcode #{token} not found" unless OPCODES.include?(token)
15
- OPCODES[token].to_s 16
16
- end
17
-
18
- def data(token)
19
- bin_size = hex_size token
20
- # TODO: data size is defined as 1-9 bytes
21
- byte_to_hex(bin_size) + token
22
- end
23
-
24
- def hex_size(hex)
25
- [hex].pack('H*').size
26
- end
27
-
28
- def to_hex(binary_bytes)
29
- binary_bytes.unpack('H*').first
30
- end
31
-
32
- def hash_to_hex(value)
33
- to_hex [value].pack('H*').reverse
34
- end
35
-
36
- def int_to_hex(value)
37
- to_hex [value].pack('V')
38
- end
39
-
40
- def byte_to_hex(value)
41
- to_hex [value].pack('C')
42
- end
43
-
44
- def bytes_to_hex(bytes)
45
- to_hex bytes.pack('C*')
46
- end
47
-
48
- def long_to_hex(value)
49
- to_hex [value].pack('Q<')
50
- end
51
-
52
- def script_to_hex(script_string)
53
- script_string.split.map { |token| token.start_with?('OP') ? opcode(token) : data(token) }.join
54
- end
55
-
56
- def sha256(hex)
57
- Digest::SHA256.hexdigest([hex].pack('H*'))
58
- end
59
- end
60
-
61
- def bytes_to_bignum(bytes_string)
62
- bytes_string.bytes.reduce { |n, b| (n << 8) + b }
63
- end
64
-
65
- def bignum_to_bytes(n, length=nil, stringify=true)
66
- a = []
67
- while n > 0
68
- a << (n & 0xFF)
69
- n >>= 8
70
- end
71
- a.fill 0x00, a.length, length - a.length if length
72
- bytes = a.reverse
73
- stringify ? bytes.pack('C*') : bytes
74
- end
@@ -1,13 +0,0 @@
1
- require 'digest'
2
-
3
- module Hashing
4
- def hash160(data)
5
- sha256 = Digest::SHA256.digest([data].pack('H*'))
6
- Digest::RMD160.hexdigest sha256
7
- end
8
-
9
- def hash256(data)
10
- sha256 = Digest::SHA256.digest([data].pack('H*'))
11
- Digest::SHA256.hexdigest sha256
12
- end
13
- end