- Notifications
You must be signed in to change notification settings - Fork6
a native library implementing secp256k1 purely for the crystal language.
License
q9f/secp256k1.cr
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
A library implementing theSecp256k1
elliptic curve natively in pure Crystal.Secp256k1
is the elliptic curve used in the public-private-key cryptography required byBitcoin
,Ethereum
, andPolkadot
.
This library allows for:
- providing a
Secp256k1
cryptographic context, seeSecp256k1::Context
- managing
Secp256k1
signatures and verification, seeSecp256k1::Signature
- managing private-public keypairs, see
Secp256k1::Key
- generating public keys, see
Secp256k1::Point
- generating private keys, see
Secp256k1::Num
Add theSecp256k1
library to yourshard.yml
dependencies:secp256k1:github:q9f/secp256k1.crversion:"~> 0.5"
Import and expose theSecp256k1
module.
require"secp256k1"
This library exposes the following modules and classes (in logical order):
Secp256k1
: necessary constants and data structures, including:Secp256k1::Num
: for managing big numerics (private keys)Secp256k1::Point
: for handling of elliptic curve points (public keys)Secp256k1::Key
: for managing private-public keypairs (accounts)Secp256k1::Signature
: for handling ECDSA signatures (r, s, v)
Secp256k1::Context
: providing a cryptographic context for signing and verificationSecp256k1::Curve
: the entire core mathematics behind the elliptic curve cryptographySecp256k1::Util
: binding of various hashing algorithms for convenience
Basic usage:
# generates a new, random keypairkey=Secp256k1::Key.new# => #<Secp256k1::Key:0x7fad7235aee0# @private_key=#<Secp256k1::Num:0x7fad7235d300# @hex="3ccf84820c20d5e8c536ba84c52ba410375b29b1812b5f7e722445c969a0fb30",# @dec=27505422793993207218034260454067205887515304192802142316084292370834437241648,# @bin=Bytes[60, 207, 132, 130, 12, 32, 213, 232, 197, 54, 186, 132, 197, 43, 164, 16, 55, 91, 41, 177, 129, 43, 95, 126, 114, 36, 69, 201, 105, 160, 251, 48]>,# @public_key=#<Secp256k1::Point:0x7fad7235ad20# @x=#<Secp256k1::Num:0x7fad69294ec0# @hex="cd4a8712ee6efc15b5abe37c0dbfa979d89c427d3fe24b076008decefe94dba2",# @dec=92855812888509048668847240903552964511053624688683992093822247249407942908834,# @bin=Bytes[205, 74, 135, 18, 238, 110, 252, 21, 181, 171, 227, 124, 13, 191, 169, 121, 216, 156, 66, 125, 63, 226, 75, 7, 96, 8, 222, 206, 254, 148, 219, 162]>,# @y=#<Secp256k1::Num:0x7fad69294e80# @hex="81363d298e4a40ebcb13f1afa85a0b94b967f243ee59a59010cb5deaf0d7b66c",# @dec=58444189335609256006902338825877424261513225250255958585656342678587884156524,# @bin=Bytes[129, 54, 61, 41, 142, 74, 64, 235, 203, 19, 241, 175, 168, 90, 11, 148, 185, 103, 242, 67, 238, 89, 165, 144, 16, 203, 93, 234, 240, 215, 182, 108]>>># gets the private keykey.private_hex# => "3ccf84820c20d5e8c536ba84c52ba410375b29b1812b5f7e722445c969a0fb30"# gets the compressed public key with prefixkey.public_hex_compressed# => "02cd4a8712ee6efc15b5abe37c0dbfa979d89c427d3fe24b076008decefe94dba2"
Signature generation and verification:
# sign a message with a private keyctx=Secp256k1::Context.newpriv=Secp256k1::Num.new"1f0c122d41ff536b19bfd83537c0dfc290e45cd3c375a43237c8b8fff7ac8af7"key=Secp256k1::Key.new privhash=Secp256k1::Util.sha256"Henlo, Wordl"sig= ctx.sign key, hash# => #<Secp256k1::Signature:0x7f5332e1d9c0# @r=#<Secp256k1::Num:0x7f5332decac0# @hex="c4079db44240b7afe94985c69fc89602e33629fd9b8623d711c30ce6378b33df",# @dec=88666774685717741514025410921892109286073075687452443491001272268566542627807,# @bin=Bytes[196, 7, 157, 180, 66, 64, 183, 175, 233, 73, 133, 198, 159, 200, 150, 2, 227, 54, 41, 253, 155, 134, 35, 215, 17, 195, 12, 230, 55, 139, 51, 223]>,# @s=#<Secp256k1::Num:0x7f5332deca80# @hex="6842c1b63c94bdb8e4f5ae88fb65f7a98b77b197c8323004fb47ef57fab29053",# @dec=47158485109070227797431103290229472044663017260590156038384319099500326195283,# @bin=Bytes[104, 66, 193, 182, 60, 148, 189, 184, 228, 245, 174, 136, 251, 101, 247, 169, 139, 119, 177, 151, 200, 50, 48, 4, 251, 71, 239, 87, 250, 178, 144, 83]>,# @v=#<Secp256k1::Num:0x7f5332deca40# @hex="00",# @dec=0,# @bin=Bytes[0]>># verify a signature with a public keyr=Secp256k1::Num.new"c4079db44240b7afe94985c69fc89602e33629fd9b8623d711c30ce6378b33df"s=Secp256k1::Num.new"6842c1b63c94bdb8e4f5ae88fb65f7a98b77b197c8323004fb47ef57fab29053"v=Secp256k1::Num.new"00"sig=Secp256k1::Signature.new r, s, vhash=Secp256k1::Util.sha256"Henlo, Wordl"publ=Secp256k1::Point.new"0416008a369439f1a8a75cf974860bed5b10180518d6b1dd3ac847f423fd375d6aa29474394f0cd79d2ea543507d069e97339284f01bdbfd27392daec0ec553816"ctx.verify sig, hash, publ# => true
There are example scripts for generatingBitcoin
andEthereum
accounts insrc/bitcoin.cr
andsrc/ethereum.cr
.
The full library documentation can be found here:q9f.github.io/secp256k1.cr
Generate a local copy with:
crystal docs
The library is entirely specified through tests in./spec
; run:
crystal spec --verbose
Private keys are just scalars (Secp256k1::Num
) and public keys are points (Secp256k1::Point
) withx
andy
coordinates.
Bitcoin public keys can be uncompressedp|x|y
or compressedp|x
. both come with a prefixp
which is useless for uncompressed keys but necessary for compressed keys to recover they
coordinate on theSecp256k1
elliptic curve field.
Ethereum public keys are uncompressedx|y
without any prefix. The last 20 bytes slice of they
coordinate is actually used as address without any checksum. A checksum was later added in EIP-55 using akeccak256
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.
Note: this library should not be used in production without proper auditing. It should be considered slow and insecure.
- 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) - This library is slow in recovering signatures. Future versions should respect the recovery ID to quickly identify the correct public key from a signature.
Found any other issue? Report it:github.com/q9f/secp256k1.cr/issues
Create a pull request, and make sure tests and linter pass.
This pure crystal implementation is based on the python implementationwobine/blackboard101 which is also used as reference to write tests against. It's a complete rewrite of the abandonedpacketzero/bitcoinutils for educational purposes.
Honerable mention for thebitcoin wiki and theethereum stackexchange for providing so many in-depth resources that supported this project in reimplementing everything.
License: Apache License v2.0
About
a native library implementing secp256k1 purely for the crystal language.
Topics
Resources
License
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Uh oh!
There was an error while loading.Please reload this page.
Contributors3
Uh oh!
There was an error while loading.Please reload this page.