External Key Import (EdDSA)
Importing an EdDSA key from an external key store or wallet works much like importing an external ECDSA key.
Importing from a Seed (RFC 8032)
When importing an Ed25519 or Ed448 key, as in the example below, the TSM expects you to start with the raw private key scalar. But some external wallets instead hold a seed, which is then derived into a raw Ed25519 or Ed448 key pair according to RFC 8032 Section 5.1.5. If you start out with a seed like this, you first need to convert it into a raw private key.
The following example shows how you can use a 3rd party tool like @noble/ed25519
to convert the RFC 8032 seed into a raw Ed25519 key pair. The example illustrates that the same conversion happens internally in tools such as @polkadot-util-crypto
.
const { hexToU8a, u8aToHex } = require('@polkadot/util');
const { ed25519PairFromSeed } = require('@polkadot/util-crypto');
const ed = require('@noble/ed25519'); // npm install @noble/[email protected] (2.0 doesn't support import via 'require')
const Example = async () => {
// The Ed25519 RFC 8032 seed to import
const seed = hexToU8a("b6b3dd3021cffe5fdaaccd9c2fa2543ea97584ad1da01e3bd12fe0656f1bf4b6")
// Derive the raw Ed25519 key pair from the seed according to RFC-8032 (Section 5.1.5)
const hash = await ed.utils.sha512(seed)
var left = hash.slice(0,32)
left[0] &= 248;
left[31] &= 127;
left[31] |= 64;
const privateKey = modlLE(left);
const publicKey = ed.Point.BASE.multiply(privateKey);
// We can use polkadot-js to test that we have done it correctly. It also derives according to
// RFC-8032, so we should get the same public key from the seed:
const keyPairPolkaJS = ed25519PairFromSeed(seed);
console.log("private key :", privateKey.toString(16).padStart(64, '0'));
console.log("public key :", u8aToHex(publicKey.toRawBytes()));
console.log("public key (polkadot-js) :", u8aToHex(keyPairPolkaJS.publicKey));
}
function modlLE(uint8a) {
const bytesLE = Uint8Array.from(uint8a).reverse();
const hex = Buffer.from(bytesLE).toString('hex').padStart(64, "0");
let scalar = BigInt('0x' + hex) % ed.CURVE.l;
return scalar >= BigInt(0) ? scalar : ed.CURVE.l + scalar;
}
Example().catch(console.error).finally(() => process.exit());
The raw private key output by this example can be used in the following example.
Code Example
You can find running example code showing how to import a raw Ed25519 key into a Builder Vault instance in our demo repository here: Go, node.js.
Updated 19 days ago