Minka Ledger Docs
How To Guides

How to generate signing keys in code


Most of our tutorials show you how to configure the Minka Ledger using our CLI tool. This is the simplest and most straightforward way, and it is our recommendation to use it when starting out. In more advanced integration scenarios it becomes necessary to dynamically create new ledger resources.

Algorithms

We are using standard elliptic curve cryptography in order to create keys and verify signatures. This allows you to create signing keys using any of the already widely available libraries and tools which support the required algorithms. We are using Ed25519 (EdDSA, Curve25519) to generate our signing keys, so this is something to keep in mind when looking for libraries to use.

Ed25519 keys are in fact just very large integers represented with 256 bits. When these keys are used in text-based transport they are encoded as text. There are different standard formats and encodings used to represent the key as text. Minka Ledger uses the raw format to represent Ed25519 public and secret keys which is produced by encoding the raw 256-bit integer key value with base64 encoding. Keys represented in this format have length 44. Example public key:

tB/gTevBYDYYYUgOOlsKV2Iq8DzmEtleeTopaY63wqs=

Raw format is smaller in size than alternatives because there are no additional headers that need to be included. Additionally, a lot of existing libraries expect Ed25519 raw keys, so this format also provides good compatibility with existing ecosystem.

Generating keys in NodeJs

In this section we will show you how to generate a key pair step by step using NodeJs. From NodeJS (≥12.0.0) we can generate these keys by using the built-in crypto module. Before we had to use a third-party library like elliptic.

This module can’t directly export Ed25519 keys in raw format which is used in ledger, but instead we have to depend on the supported der format and transform it to our raw format.

Key encoded in der binary format uses ASN.1 syntax and contains the binary data prefix with metadata about key (algorithm identifier, key length, etc…) followed by the raw binary key. This prefix is different for secret and public key as shown below.

Secret key

Screenshot 2023-02-07 at 20.14.15.png

Public key

Screenshot 2023-02-07 at 20.13.57.png

More details about der format of these keys can be found at:

There is also an useful tool for debugging the content of der formatted records which are commonly used to represent keys, certficates, signatures and other cryptographic entities:

Although this tool doesn’t send any data on server when it decodes records, be careful, it’s not recommended to paste private keys used in production or other sensitive data.

In order to get the raw key used by ledger we simply need to strip the der prefix from key exported from crypto NodeJS module. Exact prefixes represented in hex encoding are:

  • secret key hex prefix: 302e020100300506032b657004220420
  • public key hex prefix: 302a300506032b6570032100

After these prefixes are stripped from der exports we need to encode the remaining 256-bit raw keys with base64 in order to get 44 character long key required for ledger.

str

This is how to generate a new key pair using the built-in crypto package:

const crypto = require('crypto')
 
const DER_SECRET_PREFIX = '302e020100300506032b657004220420'
const DER_PUBLIC_PREFIX = '302a300506032b6570032100'
 
function generateLedgerKeyPair() {
	// Generate random ed25519 keys
	const keyPairDer = crypto.generateKeyPairSync('ed25519')
	
	// Export secret and public keys in der format
	const secretDer = keyPairDer.privateKey
		.export({ format: 'der', type: 'pkcs8' })
		.toString('hex')
	const publicDer = keyPairDer.publicKey
		.export({ format: 'der', type: 'spki' })
		.toString('hex')
	
	const secretRaw = Buffer.from(
		secretDer.slice(DER_SECRET_PREFIX.length),
		'hex',
	).toString('base64')
	const publicRaw = Buffer.from(
		publicDer.slice(DER_PUBLIC_PREFIX.length),
		'hex',
	).toString('base64')
 
	return {
		format: 'ed25519-raw',
		secret: secretRaw,
		public: publicRaw,
	}
}
 
// Generate keys
const keyPair = generateLedgerKeyPair()
 
// Print keys
console.log(JSON.stringify(keyPair, null, 2))

On this page