crypto::ec+x86_64 +linux

The crypto::ec module provides implementations for a selection of elliptic curves and their operations.

This is a low-level module which implements cryptographic primitives. Direct use of cryptographic primitives is not recommended for non-experts, as incorrect use of these primitives can easily lead to the introduction of security vulnerabilities. Non-experts are advised to use the high-level operations available in the top-level crypto:: module.

Be advised that Hare's cryptography implementations have not been audited.

Index

Types

type curve = struct {
	// Size in bytes of an encoded point.
	pointsz: size,
	// Returns the order of the subgroup generated by the conventional
	// generator. Unsigned big-endian encoding is used.
	order: *fn() const []u8,
	// Get the conventional generator as an encoded curve point.
	generator: *fn() const []u8,
	// Multiply curve point 'p' by scalar 'x'. The result is stored in 'r'.
	// Returns 1 on success.
	//
	// Point 'p' must be a valid point on the curve subgroup. If this is
	// not the case the function fails with 0 as result.
	//
	// On error the results in 'p' are indeterminate.
	mul: *fn(p: []u8, x: []u8) u32,
	// Multiply the generator by the scalar 'x' and write the result to 'r'.
	//
	// Returns the encoded point length in bytes.
	mulgen: *fn(r: []u8, x: []u8) size,
	// Multiply two curve points ('a' and 'b') by two integers ('x' and 'y')
	// and stores the sum in 'a' ('a' = 'a' * 'x' + 'b' * 'y').
	//
	// If an empty slice is given as 'b', the curve generator is used
	// instead of 'b'.
	//
	// Returns 0 in case of failure. Validates that the provided points are
	// part of the relevant curve subgroup.
	//
	// Returns 1 on success.
	muladd: *fn(a: []u8, b: []u8, x: []u8, y: []u8) u32,
	// Generate a private key from given random seed 'rand'. The function
	// may read repeatedly from 'rand' until a suitable key is found.
	//
	// Returns the size of bytes read into 'priv' on success or
	// [[io::error]], if reading from 'rand' failed.
	keygen: *fn(c: *curve, priv: []u8, rand: io::handle) (size | io::error),
};

Errors

type invalid = !void;

Constants

def MAX_COORDBITSZ = 528z;
def MAX_POINTSZ = P521_POINTSZ;
def MAX_SCALARSZ = P521_SCALARSZ;
def P256_POINTSZ = 65;
def P256_SCALARSZ = 32;
def P384_POINTSZ = 97;
def P384_SCALARSZ = 48;
def P521_POINTSZ = 133;
def P521_SCALARSZ = 66;

Globals

const p256: *curve;
const p384: *curve;
const p521: *curve;

Functions

fn keygen(c: *curve, priv: []u8, rand: io::handle) (size | io::error);
fn pointsz(c: *curve) size;
fn scalarsz(c: *curve) size;
fn validate_point(c: *curve, p: []u8) (void | invalid);
fn validate_pointformat(c: *curve, p: []u8) (void | invalid);
fn validate_scalar(c: *curve, n: []u8) (void | invalid);

Types

type curve[link]

type curve = struct {
	// Size in bytes of an encoded point.
	pointsz: size,
	// Returns the order of the subgroup generated by the conventional
	// generator. Unsigned big-endian encoding is used.
	order: *fn() const []u8,
	// Get the conventional generator as an encoded curve point.
	generator: *fn() const []u8,
	// Multiply curve point 'p' by scalar 'x'. The result is stored in 'r'.
	// Returns 1 on success.
	//
	// Point 'p' must be a valid point on the curve subgroup. If this is
	// not the case the function fails with 0 as result.
	//
	// On error the results in 'p' are indeterminate.
	mul: *fn(p: []u8, x: []u8) u32,
	// Multiply the generator by the scalar 'x' and write the result to 'r'.
	//
	// Returns the encoded point length in bytes.
	mulgen: *fn(r: []u8, x: []u8) size,
	// Multiply two curve points ('a' and 'b') by two integers ('x' and 'y')
	// and stores the sum in 'a' ('a' = 'a' * 'x' + 'b' * 'y').
	//
	// If an empty slice is given as 'b', the curve generator is used
	// instead of 'b'.
	//
	// Returns 0 in case of failure. Validates that the provided points are
	// part of the relevant curve subgroup.
	//
	// Returns 1 on success.
	muladd: *fn(a: []u8, b: []u8, x: []u8, y: []u8) u32,
	// Generate a private key from given random seed 'rand'. The function
	// may read repeatedly from 'rand' until a suitable key is found.
	//
	// Returns the size of bytes read into 'priv' on success or
	// [[io::error]], if reading from 'rand' failed.
	keygen: *fn(c: *curve, priv: []u8, rand: io::handle) (size | io::error),
};

Interface for common operations over a specific curve.

The encoding of points (e.g. public keys for dsa and dh) depends on the curve. For the NIST curves (p256, p384 and p521) the point is required to be stored according to the uncompressed format defined in RFC 8422 Chapter 5.4.1. That means with a leading byte of value 0x04 that indicates the format. Followed by the x and y coordinates, which must be of length pointsz / 2, left padded by 0.

Scalar values (e.g. private keys for dsa and dh) must be provided in big-endian encoding and left-padded to fill the indicated space. They MUST be non-zero and less than the curve order, otherwise result values will be indeterminate and an error code is not guaranteed. The function scalarsz will return the encoded scalar size of any curve implemented by this module.

Errors

type invalid[link]

type invalid = !void;

Invalid curve parameter.

Constants

def MAX_COORDBITSZ[link]

def MAX_COORDBITSZ = 528z;

Maxium coordinate size of the modules curves in bits.

def MAX_POINTSZ[link]

def MAX_POINTSZ = P521_POINTSZ;

Maximum size of a point of the modules curves in bytes.

def MAX_SCALARSZ[link]

def MAX_SCALARSZ = P521_SCALARSZ;

Maximum size of a scalar of the modules curves in bytes.

def P256_POINTSZ[link]

def P256_POINTSZ = 65;

Size of a p256 point in bytes.

def P256_SCALARSZ[link]

def P256_SCALARSZ = 32;

Size of a p256 scalar in bytes.

def P384_POINTSZ[link]

def P384_POINTSZ = 97;

Size of a p384 point in bytes.

def P384_SCALARSZ[link]

def P384_SCALARSZ = 48;

Size of a p384 scalar in bytes.

def P521_POINTSZ[link]

def P521_POINTSZ = 133;

Size of a p521 point in bytes.

def P521_SCALARSZ[link]

def P521_SCALARSZ = 66;

Size of a p521 scalar in bytes.

Globals

let p256[link]

const p256: *curve;

Can't parse docs: /home/build/hare/crypto/ec/p256.ha:1258:27: syntax error: Unterminated reference

let p384[link]

const p384: *curve;

Can't parse docs: /home/build/hare/crypto/ec/prime.ha:711:27: syntax error: Unterminated reference

let p521[link]

const p521: *curve;

Can't parse docs: /home/build/hare/crypto/ec/prime.ha:777:27: syntax error: Unterminated reference

Functions

fn keygen[link]

fn keygen(c: *curve, priv: []u8, rand: io::handle) (size | io::error);

Generates a random private key scalar suitable for given curve 'c'. 'rand' must be cryptographic random stream like the one provided by crypto::random::stream.

fn pointsz[link]

fn pointsz(c: *curve) size;

Returns the encoded size of any point of curve 'c'.

fn scalarsz[link]

fn scalarsz(c: *curve) size;

Returns the encoded size of any scalar of curve 'c'.

fn validate_point[link]

fn validate_point(c: *curve, p: []u8) (void | invalid);

Checks if given point is properly encoded and a valid point on given curve 'c'. This operation is quite expensive. Note that in any case point validation will be done on every mul and muladd operation.

fn validate_pointformat[link]

fn validate_pointformat(c: *curve, p: []u8) (void | invalid);

Checks whether the point is encoded in the curves point format. Does NOT check if it is a valid point on the curve. For such point validation use validate_point.

fn validate_scalar[link]

fn validate_scalar(c: *curve, n: []u8) (void | invalid);

Validates if given scalar is less than the curve order and greater then zero.