secp256k1.cr

Badge Language License

a native library implementing secp256k1 purely for the crystal language. secp256k1 is the elliptic curve used in the public-private-key cryptography required by bitcoin and ethereum.

this library allows for key generation of:

this library allows for address generation of:

furthermore, this library allows for:

installation

add the secp256k1 library to your shard.yml

dependencies:
  secp256k1:
    github: q9f/secp256k1.cr
    version: "~> 0.2"

usage

tl;dr, check out crystal run ./try.cr!

# import secp256k1
require "secp256k1"

this library exposes the following modules (in logical order):

basic usage:

# generate a keypair
private_key = Secp256k1::Util.new_private_key
public_key = Secp256k1::Util.public_key_from_private private_key

# display the compressed public key with prefix
puts Secp256k1::Util.public_key_compressed_prefix public_key

# > 02b3c141fba20c129806290f04cee097305fb7391abfde01b3bb3affcd935332a1

generate a compressed bitcoin mainnet address:

# generate a keypair
private_key = Secp256k1::Util.new_private_key
public_key = Secp256k1::Util.public_key_from_private private_key
compressed = Secp256k1::Util.public_key_compressed_prefix public_key

# display the bitcoin address (version "00" for bitcoin mainnet)
puts Secp256k1::Bitcoin.address_from_public_key compressed, "00"

# > "1PMycacnJaSqwwJqjawXBErnLsZ7RkXUAs"

generate a checksummed ethereum address:

# generate a keypair
private_key = Secp256k1::Util.new_private_key
public_key = Secp256k1::Util.public_key_from_private private_key
uncompressed = Secp256k1::Util.public_key_uncompressed public_key

# display the ethereum address
puts Secp256k1::Ethereum.address_from_public_key uncompressed

# > "0x2Ef1f605AF5d03874eE88773f41c1382ac71C239"

documentation

the full library documentation can be found here: q9f.github.io/secp256k1.cr

generate a local copy with:

crystal docs

testing

the library is entirely specified through tests in ./spec; run:

crystal spec --verbose

understand

private keys are just scalars and public keys are points with x and y coordinates.

bitcoin public keys can be uncompressed #{p}#{x}#{y} or compressed #{p}#{x}. both come with a prefix p which is useless for uncompressed keys but necessary for compressed keys to recover the y coordinate on the secp256k1 elliptic curve.

ethereum public keys are uncompressed #{x}#{y} without any prefix. the last 20 bytes slice of the y coordinate is actually used as address without any checksum. a checksum was later added in eip-55 using a keccak256 hash and indicating character capitalization.

neither bitcoin nor ethereum allow for recovering public keys from an address unless there exists a transaction with a valid signature on the blockchain.

known issues

note: this library should not be used in production without proper auditing.

found another issue? report it: https://github.com/q9f/secp256k1.cr/issues

contribute

create a pull request, and make sure tests and linter passes.

this pure crystal implementation is based on the python implementation wobine/blackboard101 which is also used as reference to write tests against. it's a complete rewrite of the abandoned packetzero/bitcoinutils for educational purposes.

honerable mention for the bitcoin wiki and the ethereum stackexchange for providing so many in-depth resources that supported this project in reimplementing everything.

license: apache license v2.0