In Need of a Private Key?

We’re proud to inform you that Bearmint comes with a whole bunch of great cryptography algorithms straight out the box friends! But maybe you already knew that - anyway, it takes a lot of different movin’ parts to make an application work, and in the world of blockchain, there’s a whole heap of different things you gotta take into consideration so that you can build and maintain yer operation as you see fit.

We already discussed buildin’ and implementin’ key pairs in our last blog post, and this brings us to today’s post - one of the keys in a key pair is a private key (with the other bein’ a public key, but more on that in a future blog post). A private key is sometimes called a secret key, and fer good reason - because you need to keep it a secret, Pilgrim!

If you ever lose yer private key or have it compromised in any way, then yer in fer a world of hurt! Without yer private key, you can’t access or do much of anythin’ with the funds you have saved in that particular wallet address. What’s more, if someone else gets their hands on the private key, they can do virtually anythin’ they like with yer digital assets!

So now that you have a better appreciation as to why it’s important to keep yer private keys private, it’s time to learn how to build and implement BLS12-381 private keys. Of course, before you get to doin’ that, take a little time to review a couple of important terms and definitions so that you know what we’re referrin’ to when it gets mentioned in the code.

Now let’s get to that guide and find out how to implement them private keys!

What Are You Tryin’ to Say, Amigo?

  • @bearmint/bep9 is an NPM package that offers an implementation of BEP-009 which contains a set of utilities to deal with particularly tedious tasks that do not fall within a single domain
  • @bearmint/bep13 is an NPM package that offers an implementation of BEP-013 which allows for the sharing of a set of types between all the modules that exist within Bearmint
  • @bearmint/bep16 is an NPM package that offers an implementation of BEP-016 which contains a standardized method of bootstrapping the plugins and application via service providers
  • @bearmint/bep19 is an NPM package that offers an implementation of BEP-019 which explains how protocol buffers will apply in order to provide a standard method of serialization and deserialization, and
  • bls-eth-wasm is an NPM package that offers an implementation of BLS12-381 cryptography
bls-eth-wasm is an absolutely stellar package by herumi. We recommend you take a gander if you need to work with BLS12-381 and care about performance and a small dependency footprint.

Creating the Private Key Entity

You’ll first need to create a function that generates a private key. This particular function will accept a bytes argument, which is a buffer.

function makePrivateKey(bytes: Buffer): PrivateKey {
// This is where we'll put all of our functions!
}

Converting to a Buffer

When carrying out tasks like signing, you’ll need to use a buffer. This function converts the private key to said format.

function toBytes() {
return bytes;
}

Converting to a Public Key

The following function converts the private key to a public key.

function toPublicKey() {
return makePublicKey(arrayBufferToBytes(makeSecretKey(bytes).getPublicKey().serialize()));
}

Converting to a String

Clients (like Wallets for instance) may need to display the private keys of end-users. This particular function handles this by returning a human-readable value.

function toString() {
return bytes.toString('hex');
}

Combining the Entity Functions

After combining all of the above, the following function, which returns a private key, is the result. Note that it’s this entity that you’ll use in the private key factory (which we’ll build in just a moment).

function makePrivateKey(bytes: Buffer): PrivateKey {
return {
toBytes() {
return bytes;
},
toPublicKey() {
return makePublicKey(arrayBufferToBytes(makeSecretKey(bytes).getPublicKey().serialize()));
},
toString() {
return bytes.toString('hex');
},
};
}

Creating a Private Key From a Buffer

Bearmint may use private keys internally, and it already has the ability to access the buffer that represents the private key. To this end, the following function allows it to create a private key instance for further processing with consistent behaviors.

async function fromBytes(privateKey: Buffer) {
return makePrivateKey(privateKey);
}

Creating a Private Key From a String

Clients (like Wallets for example) may allow end-users to authorize transactions using their private keys. The following function gives them the ability to take a private key string and convert it into a private instance that they may use to sign transactions.

async function fromString(privateKey: string) {
return makePrivateKey(hexToBytes(privateKey));
}

Combining the Factory Functions

After combining all of the above, the following function, which returns a private key entity based on different inputs, is the result. The next step will combine all of our work and finally register it.

function makePrivateKeyFactory(): PrivateKeyFactory {
return {
async fromBytes(privateKey: Buffer) {
return makePrivateKey(privateKey);
},
async fromString(privateKey: string) {
return makePrivateKey(hexToBytes(privateKey));
},
};
}

Combining the Entity and Factory

In the penultimate step, having created a way of generating a private key entity and factory that allows you to create that entity from various sources, the following code illustrates how all of this works together.

function makePrivateKey(bytes: Buffer): PrivateKey {
return {
toBytes() {
return bytes;
},
toPublicKey() {
return makePublicKey(arrayBufferToBytes(makeSecretKey(bytes).getPublicKey().serialize()));
},
toString() {
return bytes.toString('hex');
},
};
}
function makePrivateKeyFactory(): PrivateKeyFactory {
return {
async fromBytes(privateKey: Buffer) {
return makePrivateKey(privateKey);
},
async fromString(privateKey: string) {
return makePrivateKey(hexToBytes(privateKey));
},
};
}

Registering With the Application

Finally, bind the newly-created factory function to the container as ContainerType.PrivateKeyFactory. And that’s it! Bearmint will now use the created private key factory whenever it needs to interact with a private key.

import { ContainerType, Cradle, ServiceProvider } from '@bearmint/bep13';
import { makeServiceProviderSkeleton } from '@bearmint/bep16';
import BLS from 'bls-eth-wasm';
import { makePrivateKeyFactory } from './keypair';
function makeServiceProvider(cradle: Cradle): ServiceProvider {
return {
...makeServiceProviderSkeleton(__dirname),
async register() {
cradle.Container.bind(ContainerType.PrivateKeyFactory).toFunctionSingleton(
makePrivateKeyFactory,
);
},
};
}

Yer All Good to Go!

That concludes today’s guide, partners! You should now have a firm grasp as to how to set up private keys usin’ Bearmint. As always, should you require any help with private keys or anythin’ else regardin’ yer own project, give us a holler on GitHub or any other appropriate channel, and ol’ Buck’ll make sure that either he or one of the members of the Bearmint Gang gets back to you lickety split!