Skip to content

crypto.ecdsa #

ecdsa

ecdsa module for V language. Its a wrapper on top of openssl ecdsa functionality. Its currently (expanded) to support the following curves:

  • NIST P-256 curve, commonly referred as prime256v1 or secp256r1
  • NIST P-384 curve, commonly referred as secp384r1
  • NIST P-521 curve, commonly referred as secp521r1
  • A famous Bitcoin curve, commonly referred as secp256k1

[!CAUTION] > This module using low level OpenSSL opaque methods that mostly has been deprecated > in OpenSSL 3.0. > Please be aware, likely it would not compile with -cstrict options until > its migrated into supported higher level API.

Example

import crypto.ecdsa

fn main() {
    // create default NIST P-256 secp256r1 curve key pair. If you wish to generate another curve,
    // use: `pbkey, pvkey := ecdsa.generate_key(nid: .secp521r1)!` instead.
    pbkey, pvkey := ecdsa.generate_key()!

    message_tobe_signed := 'Hello ecdsa'.bytes()
    // create a signature with the recommended hash
    signature := pvkey.sign(message_tobe_signed)!

    // verify the message with the signature
    verified := pbkey.verify(message_tobe_signed, signature)!
    dump(verified) // should be true

    // free allocated keys when you have done with your work.
    pbkey.free()
    pvkey.free()
}

fn generate_key #

fn generate_key(opt CurveOptions) !(PublicKey, PrivateKey)

generate_key generates a new key pair. If opt was not provided, its default to prime256v1 curve. If you want another curve, use in the following manner: pubkey, pivkey := ecdsa.generate_key(nid: .secp384r1)!

fn new_key_from_seed #

fn new_key_from_seed(seed []u8, opt CurveOptions) !PrivateKey

new_key_from_seed creates a new private key from the seed bytes. If opt was not provided, its default to prime256v1 curve.

Notes on the seed: You should make sure, the seed bytes come from a cryptographically secure random generator, likes the crypto.rand or other trusted sources. Internally, the seed size's would be checked to not exceed the key size of underlying curve, ie, 32 bytes length for p-256 and secp256k1, 48 bytes length for p-384 and 64 bytes length for p-521. Its recommended to use seed with bytes length matching with underlying curve key size.

fn privkey_from_string #

fn privkey_from_string(s string) !PrivateKey

privkey_from_string loads a PrivateKey from valid PEM-formatted string in s. Underlying wrapper support for old secg and pkcs8 private key format, but this was not heavily tested. This routine does not support for the pkcs8 EncryptedPrivateKeyInfo format. See usage_test.v file for example of usage.

fn pubkey_from_bytes #

fn pubkey_from_bytes(bytes []u8) !PublicKey

pubkey_from_bytes loads ECDSA Public Key from bytes array. The bytes of data should be a valid of ASN.1 DER serialized SubjectPublicKeyInfo structrue of RFC 5480. Otherwise, its should an error. Typically, you can load the bytes from pem formatted of ecdsa public key.

Examples:

import crypto.pem
import crypto.ecdsa

const pubkey_sample = '-----BEGIN PUBLIC KEY-----
MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE+P3rhFkT1fXHYbY3CpcBdh6xTC74MQFx
cftNVD3zEPVzo//OalIVatY162ksg8uRWBdvFFuHZ9OMVXkbjwWwhcXP7qmI9rOS
LR3AGUldy+bBpV2nT306qCIwgUAMeOJP
-----END PUBLIC KEY-----'

block, _ := pem.decode(pubkey_sample) or { panic(err) }
pubkey := ecdsa.pubkey_from_bytes(block.data)!

fn pubkey_from_string #

fn pubkey_from_string(s string) !PublicKey

pubkey_from_string loads a PublicKey from valid PEM-formatted string in s.

fn PrivateKey.new #

fn PrivateKey.new(opt CurveOptions) !PrivateKey

PrivateKey.new creates a new key pair. By default, it would create a prime256v1 based key.

enum HashConfig #

enum HashConfig {
	with_recommended_hash
	with_no_hash
	with_custom_hash
}

enum Nid #

enum Nid {
	prime256v1
	secp384r1
	secp521r1
	secp256k1
}

The list of supported curve(s)

struct C.BIO #

@[typedef]
struct C.BIO {}

struct CurveOptions #

@[params]
struct CurveOptions {
pub mut:
	// default to NIST P-256 curve
	nid Nid = .prime256v1
	// by default, allow arbitrary size of seed bytes as key.
	// Set it to `true` when you need fixed size, using the curve key size.
	// Its main purposes is to support the `.new_key_from_seed` call.
	fixed_size bool
}

struct PrivateKey #

struct PrivateKey {
	key &C.EC_KEY
mut:
	// ks_flag with .flexible value allowing
	// flexible-size seed bytes as key.
	// When it is `.fixed`, it will use the underlying key size.
	ks_flag KeyFlag = .flexible
	// ks_size stores size of the seed bytes when ks_flag was .flexible.
	// You should set it to a non zero value
	ks_size int
}

PrivateKey represents ECDSA private key. Actually its a key pair, contains private key and public key parts.

fn (PrivateKey) sign #

fn (pv PrivateKey) sign(message []u8, opt SignerOpts) ![]u8

sign performs signing the message with the options. By default options, it will perform hashing before signing the message.

fn (PrivateKey) sign_with_options #

deprecated: use PrivateKey.sign() instead
fn (pv PrivateKey) sign_with_options(message []u8, opt SignerOpts) ![]u8

sign_with_options signs message with the options. It will be deprecated, Use PrivateKey.sign() instead.

fn (PrivateKey) bytes #

fn (priv_key PrivateKey) bytes() ![]u8

bytes represent private key as bytes.

fn (PrivateKey) seed #

deprecated: use PrivateKey.bytes() instead
fn (priv_key PrivateKey) seed() ![]u8

seed gets the seed (private key bytes). It will be deprecated. Use PrivateKey.bytes() instead.

fn (PrivateKey) public_key #

fn (priv_key PrivateKey) public_key() !PublicKey

Get the public key from private key.

fn (PrivateKey) equal #

fn (priv_key PrivateKey) equal(other PrivateKey) bool

equal compares two private keys was equal. Its checks for two things, ie:

  • whether both of private keys lives under the same group (curve),
  • compares if two private key bytes was equal.

fn (PrivateKey) free #

fn (pv &PrivateKey) free()

free clears out allocated memory for PrivateKey Dont use PrivateKey after calling .free()

struct PublicKey #

struct PublicKey {
	key &C.EC_KEY
}

PublicKey represents ECDSA public key for verifying message.

fn (PublicKey) bytes #

fn (pbk PublicKey) bytes() ![]u8

bytes gets the bytes of public key.

fn (PublicKey) equal #

fn (pub_key PublicKey) equal(other PublicKey) bool

Compare two public keys

fn (PublicKey) free #

fn (pb &PublicKey) free()

free clears out allocated memory for PublicKey. Dont use PublicKey after calling .free()

fn (PublicKey) verify #

fn (pub_key PublicKey) verify(message []u8, sig []u8, opt SignerOpts) !bool

verify verifies a message with the signature are valid with public key provided . You should provide it with the same SignerOpts used with the .sign() call. or verify would fail (false).

struct SignerOpts #

@[params]
struct SignerOpts {
pub mut:
	// default to .with_recommended_hash
	hash_config HashConfig = .with_recommended_hash
	// make sense when HashConfig != with_recommended_hash
	allow_smaller_size bool
	allow_custom_hash  bool
	// set to non-nil if allow_custom_hash was true
	custom_hash &hash.Hash = unsafe { nil }
}