module Secp256k1

Overview

Implements 256-bit Secp256k1 Koblitz elliptic curve reference https://www.secg.org/sec2-v2.pdf

Defined in:

constants.cr
ec_point.cr
secp256k1.cr
signature.cr
utils.cr
version.cr

Constant Summary

EC_BASE_G = EC_Point.new(EC_BASE_G_X, EC_BASE_G_Y)
EC_BASE_G_COMPRESSED = BigInt.new((public_key_compressed_prefix(EC_BASE_G)), 16)

The base point G in compressed form is:

EC_BASE_G_UNCOMPRESSED = BigInt.new((public_key_uncompressed_prefix(EC_BASE_G)), 16)

The base point G in uncompressed form is:

EC_BASE_G_X = BigInt.new("79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", 16)

The commonly used base point G coordinates x, y; any other point that satisfies y^2 = x^3 + 7 would also do:

EC_BASE_G_Y = BigInt.new("483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8", 16)
EC_COFACTOR_H = BigInt.new("01", 16)
EC_FACTOR_A = BigInt.new("0000000000000000000000000000000000000000000000000000000000000000", 16)

The curve E: y^2 = x^3 + ax + b over F_p is defined by a, b: As the a constant is zero, the ax term in the curve equation is always zero, hence the curve equation becomes y^2 = x^3 + 7.

EC_FACTOR_B = BigInt.new("0000000000000000000000000000000000000000000000000000000000000007", 16)
EC_ORDER_N = BigInt.new("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", 16)

Finally, the order n of G and the cofactor h are:

EC_PARAM_PRIME = BigInt.new("fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", 16)

The elliptic curve domain parameters over F_p associated with a Koblitz curve Secp256k1 are specified by the sextuple T = (p, a, b, G, n, h) where the finite field F_p is defined by p = 2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1:

VERSION = "0.1.6"

the version of the module

Class Method Summary

Class Method Detail

def self.decode_compressed_public_key(pub : String, prime = EC_PARAM_PRIME) #

decodes a public key as ec point from a compressed public key string


[View source]
def self.ec_add(p : EC_Point, q : EC_Point, prime = EC_PARAM_PRIME) #

elliptic curve jive addition of point p(x, y) and q(x, y). 'draw' a line between p and q which will intersect the curve in the point r which will be mirrored over the x-axis.


[View source]
def self.ec_double(p : EC_Point, prime = EC_PARAM_PRIME) #

elliptic curve juke point doubling of p(x, y). a special case of addition where both points are the same. 'draw' a tangent line at p which will intersect the curve at point r which will be mirrored over the x-axis.


[View source]
def self.ec_mod_inv(a : BigInt, prime = EC_PARAM_PRIME) #

elliptic curve modular multiplicative inverse of a


[View source]
def self.ec_mul(p : EC_Point, s : BigInt) #

elliptic curve sequence multiplication of point p(x, y) and a skalar s, with s being a private key within the elliptic curve field size of EC_ORDER_N


[View source]
def self.new_private_key #

a helper to generate 32 pseudo-random bytes


[View source]
def self.public_key_compressed_prefix(p : EC_Point) #

exports the compressed public key from an ec point with prefix 02 or 03


[View source]
def self.public_key_from_private(priv : BigInt) #

wrapper function to perform an ec multiplication with the generator point and a provided private key


[View source]
def self.public_key_uncompressed(p : EC_Point) #

exports the uncompressed public key from an ec point without prefix


[View source]
def self.public_key_uncompressed_prefix(p : EC_Point) #

exports the uncompressed public key from an ec point with prefix 04


[View source]
def self.restore_public_key(pub : String) #

detects public key type and tries to restore the ec point from it


[View source]
def self.sign(msg : String, priv : BigInt) #

the ecdsa signing algorithm (rfc 6979) takes as input a message msg and a private key priv. It produces as output a signature, which consists of pair of integers (r, s).


[View source]
def self.to_padded_hex_01(i : Int32) #

generic tool to encode single hex bytes as strings, e.g., "07"


[View source]
def self.to_padded_hex_32(i : BigInt) #

utility tool to ensure hex keys are always 32 bytes it pads the number with leading zeros if not


[View source]
def self.verify(msg : String, sig : EC_Signature, pub : EC_Point) #

the algorithm to verify an ecdsa signature takes as input the signed message msg and the signature (r, s) produced from self.sign and the public key pub, corresponding to the signer's private key. The result is boolean.


[View source]
def self.verify_hash(hash : BigInt, sig : EC_Signature, pub : EC_Point) #

same as self.verify, just using the hashed message directly


[View source]