Cryptos-ruby
The Why - the vision and goals
- I believe there are none of very few Ruby implementations and support for different crypto technologies
- I like to craft my own wallets, transactions, block explorers in all shapes and forms
- I dream to execute atomic swaps in 3 lines of Ruby code
The How - the actions
- Implementing basic cryptography from scratch - elliptic curves math, digital signature schemes, etc
- Building a simple and easy to use Ruby API
- Lean and continuous improvement along the way while I understand more advanced cryptography: pairing, lattices
The What - the features
- Generate private and public keys
- Generate addresses for Bitcoin, Litecoin, Ethereum and much more
- Create transaction to spend standard inputs or more complex multisig, hashed timelock contracts, swaps
Installation
Add this line to your application's Gemfile:
gem 'cryptos'
And then execute:
$ bundle
Or install it yourself as:
$ gem install cryptos
Usage
Bitcoin and friends
Generate keys and address
Alright, let's begin, first thing first, lets generate private and public keys:
2.5.3 > private_key = Cryptos::PrivateKey.generate
=> #<Cryptos::PrivateKey:0x00007f8cc10c0ad0 @value=1991485315816438798044329630916774278846523543844864946402119577704095054145, @order=115792089237316195423570985008687907852837564279074904382605163141518161494337>
2.5.3 > public_key = Cryptos::PublicKey.new private_key
=> #<Cryptos::PublicKey:0x00007f8cc105ed58 @private_key=#<Cryptos::PrivateKey:0x00007f8cc10c0ad0 @value=1991485315816438798044329630916774278846523543844864946402119577704095054145, @order=115792089237316195423570985008687907852837564279074904382605163141518161494337>, @x=107779388491921327681974754398507503201871466663959093103394577491037829153768, @y=78060352001932916201234328232450653863791592111885208305671830584742527863131>
Based on public key above lets create a Bitcoin address:
2.5.3 > from_address = Cryptos::Bitcoin::Address.new public_key
=> #<Cryptos::Bitcoin::Address:0x00007f8cc12fc560 @public_key=#<Cryptos::PublicKey:0x00007f8cc105ed58 @private_key=#<Cryptos::PrivateKey:0x00007f8cc10c0ad0 @value=1991485315816438798044329630916774278846523543844864946402119577704095054145, @order=115792089237316195423570985008687907852837564279074904382605163141518161494337>, @x=107779388491921327681974754398507503201871466663959093103394577491037829153768, @y=78060352001932916201234328232450653863791592111885208305671830584742527863131>, @testnet=true>
Scenario 1: Spend coinbase transaction
Before going any further we need to install bitcoin-core daemon and start node in regtest mode:
# in MacOS
brew install bitcoin
# in Linux (Debian based)
apt-get install bitcoin
# start Bitcoin daemon in regtest mode
bitcoind -regtest -printtoconsole
Now we create a simple Cli connector that will communicate to underlying bitcoin daemon.
2.5.3 :004 > cli = Cryptos::Connectors::Cli.new
=> #<Cryptos::Connectors::Cli:0x00007f8cc12ece30 @program="bitcoin-cli", @network="regtest", @verbose=false>
Import address into node and generate 101 blocks. If you ask why 101 then it is because coinbase transactions are spendable after 100 confirmatinos.
2.5.3 :005 > from_address.import cli
=> true
2.5.3 :006 > cli.generate_to_address from_address, blocks: 101
=> true
Generate and import destination address to send BTC to then check that it has no money in it.
2.5.3 :007 > to_address = Cryptos::Bitcoin::Address.new Cryptos::PublicKey.new Cryptos::PrivateKey.generate
=> #<Cryptos::Bitcoin::Address:0x00007f8cc134f2b0 @public_key=#<Cryptos::PublicKey:0x00007f8cc128fa78 @private_key=#<Cryptos::PrivateKey:0x00007f8cc128faa0 @value=104555233989943463494354097619221894829574308702717051161491781222000198727347, @order=115792089237316195423570985008687907852837564279074904382605163141518161494337>, @x=1402024405898287938501468401055931693243587868828983898835308320263377717122, @y=89146164815925753866667564550747587615674131412309491381641677989226156891240>, @testnet=true>
2.5.3 :008 > to_address.import cli
=> true
2.5.3 :009 > to_address.get_balance cli
=> "0.00000000"
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
.
2.5.3 :010 > input = Cryptos::Input.from_utxo cli, from_address
=> #<struct Cryptos::Input value=2500000000.0, tx_hash="33fc8506d7a5880cfddca3c950f95fa461398fb764da4527169d5574a7c00c7b", index=0, script_sig=nil, sequence=68719476735>
2.5.3 :011 > output = Cryptos::Output.p2pkh to_address, 123_456_789
=> #<struct Cryptos::Output value=123456789, script_pubkey=#<Cryptos::Script:0x00007f8cc12ed8a8 @script="OP_DUP OP_HASH160 9aae79929e4364ab3aabe1f83a875304d1b67a3a OP_EQUALVERIFY OP_CHECKSIG">>
2.5.3 :012 > change = Cryptos::Output.p2pkh_change from_address, input, output
=> #<struct Cryptos::Output value=2376533211.0, script_pubkey=#<Cryptos::Script:0x00007f8cc12cfdd0 @script="OP_DUP OP_HASH160 57a58e05aedfbb6bd97b373baf65ce7cc318351b OP_EQUALVERIFY OP_CHECKSIG">>
2.5.3 :013 > transaction = Cryptos::Transaction.from_ioc input, output, change
=> #<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>
Sign and broadcast the transaction:
2.5.3 :014 > transaction.sign_single_input from_address
=> "01000000017b0cc0a774559d162745da64b78f3961a45ff950c9a3dcfd0c88a5d70685fc33000000006a473044022020b53986c2ef08d54137e57f1c231a0c2fe1b6dc88c7208ecef6f7474bae985002203027db653202da53ce081da46431ef1f88f3e1bf47254940a58740a86506cbc3012103ee48f8db1d9a5dfc1b620dbe9566b77d995e0325b91d3b661a697272920f43e8ffffffff0215cd5b07000000001976a9149aae79929e4364ab3aabe1f83a875304d1b67a3a88acdb04a78d000000001976a91457a58e05aedfbb6bd97b373baf65ce7cc318351b88ac00000000"
2.5.3 :015 > transaction.broadcast cli
=> true
Mine new block that will contain our hand crafted transaction and VOILA! output amount was transafered to new address.
2.5.3 :016 > cli.generate blocks: 1
=> true
2.5.3 :017 > cli.get_received_by_address to_address
=> "1.23456789"
Scenario 2: Spend multisig transaction
Scenario 3: Atomic swaps between BTC and LTC
Monero
Generate keys and address:
2.5.3 :015 > seed = "vinegar talent sorry hybrid ultimate template nimbly jukebox axes inactive veered toenail pride plotting chrome victim agnostic science bailed paddles wounded peaches king laptop king"
=> "vinegar talent sorry hybrid ultimate template nimbly jukebox axes inactive veered toenail pride plotting chrome victim agnostic science bailed paddles wounded peaches king laptop king"
2.5.3 :016 > wallet = Cryptos::Monero::Wallet.from_mnemonic seed
=> #<Cryptos::Monero::Wallet:0x00007faa600bfad8 @seed="6ee02ef8647856f4080882a1ec4fabee19ec047ca24d3abb13c0ce589a46f702">
2.5.3 :017 > private_spend_key = wallet.private_spend_key
=> #<Cryptos::Monero::PrivateSpendKey:0x00007faa600aac50 @value=1341524205595389594312687854960107116555340486708078533906470082005332582510, @order=7237005577332262213973186563042994240857116359379907606001950938285454250989, @little=true>
Development
After checking out the repo, run bin/setup
to install dependencies. Then, run rake spec
to run the tests. You can also run bin/console
for an interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run bundle exec rake install
. To release a new version, update the version number in version.rb
, and then run bundle exec rake release
, which will create a git tag for the version, push git commits and tags, and push the .gem
file to rubygems.org.
Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/icostan/cryptos. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.
Code of Conduct
Everyone interacting in the CryptoCrafts project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.