secp256k1

Elliptic curve used in the public-private-key cryptography native-library secp256k1 bitcoin ethereum ec ecdh ecdsa ethereum-addresses bitcoin-addresses compressed checksum byte
0.1.6 released

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:

  • private keys (from secure random within the elliptic curve field size)
  • mini private keys (short 30-char base-57 keys)
  • wallet import format (checksummed private keys)
  • public keys, prefixed, compressed (from private)
  • public keys, unprefixed and prefixed, uncompressed (from private)
  • conversion between the different public key formats

this library allows for address generation of:

  • bitcoin address, compressed and uncompressed (from private or public key)
  • any other bitcoin-based address by passing a version byte
  • ethereum address, checksummed and unchecksummed (from private or public key)
  • any other ethereum-based address

furthermore, this library allows for:

  • signing (r, s) and verification of arbitrary messages and message-hashes (with key pairs)

installation

add the secp256k1 library to your shard.yml

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

usage

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

# import secp256k1
require "secp256k1"

this library exposes the following modules:

  • Secp256k1: the entire handling of private-public key-pairs
  • Crypto: implementation of various hashing algorithms
  • Bitcoin: for the generation of bitcoin addresses
  • Ethereum: for the generation of ethereum addresses

basic usage:

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

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

# > 02b3c141fba20c129806290f04cee097305fb7391abfde01b3bb3affcd935332a1

generate a compressed bitcoin mainnet address:

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

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

# > "1PMycacnJaSqwwJqjawXBErnLsZ7RkXUAs"

generate a checksummed ethereum address:

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

# display the ethereum address
puts Ethereum.address_from_public_key uncompressed

# > "0x2Ef1f605AF5d03874eE88773f41c1382ac71C239"

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.

  • this library is not constant time and might be subject to side-channel attacks. #4
  • this library does unnecessary big-integer math and should someday rather correctly implement the secp256k1 prime field #5

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

secp256k1:
  github: q9f/secp256k1.cr
  version: ~> 0.1.6
License APLv2
Crystal 0.32.1

Authors

Dependencies 1

  • sha3 ~> 0.3
    {'github' => 'OscarBarrett/crystal-sha3', 'version' => '~> 0.3'}

Development Dependencies 0

Dependents 0

Last synced .
search fire star recently