Skip to content

Commit

Permalink
fix: support 64 bytes private key
Browse files Browse the repository at this point in the history
  • Loading branch information
gyroflaw committed Jul 5, 2023
1 parent 53d7d9a commit ec7f8f7
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 6 deletions.
60 changes: 60 additions & 0 deletions src/lib/Keys.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { expect } from 'chai';
import sinon from 'sinon';

import { decodeBase16, decodeBase64 } from './Conversions';
import { Ed25519, Secp256K1 } from './Keys';
Expand Down Expand Up @@ -33,6 +34,65 @@ describe('Ed25519', () => {
const key3 = Ed25519.readBase64WithPEM(keyWithCRLF);
expect(key3).to.deep.eq(key1);
});

it('should parse old 64 bytes private key', () => {
// In v2.10 we used https://www.npmjs.com/package/tweetnacl-ts#sign_keypair which private key length is 64 bytes,
// From v2.13 migrated to noble scope libraries which private key length is 32 bytes [correct implementation]
// new version should support old format

// prettier-ignore
const privateKey = new Uint8Array([
92, 85, 34, 21, 229, 142, 168,
76, 221, 116, 56, 193, 153, 129,
32, 198, 125, 90, 231, 143, 220,
220, 158, 37, 196, 198, 34, 177,
100, 221, 229, 228
]);
// prettier-ignore
const publicKey = new Uint8Array([
225, 123, 67, 141, 123, 40, 119, 138,
213, 235, 175, 59, 71, 169, 39, 235,
243, 228, 113, 203, 25, 9, 125, 64,
97, 165, 224, 86, 97, 251, 1, 91
]);

const privateKeyPEM =
'-----BEGIN PRIVATE KEY-----\n' +
'MC4CAQAwBQYDK2VwBCIEIFxVIhXljqhM3XQ4wZmBIMZ9WueP3NyeJcTGIrFk3eXk=\n' +
'-----END PRIVATE KEY-----\n';

const publicKeyPEM =
'-----BEGIN PUBLIC KEY-----\n' +
'MCowBQYDK2VwAyEA4XtDjXsod4rV6687R6kn6/PkccsZCX1AYaXgVmH7AVs=\n' +
'-----END PUBLIC KEY-----\n';

// prettier-ignore
const oldPrivateKey = new Uint8Array([
92, 85, 34, 21, 229, 142, 168, 76, 221, 116, 56,
193, 153, 129, 32, 198, 125, 90, 231, 143, 220, 220,
158, 37, 196, 198, 34, 177, 100, 221, 229, 228, 225,
123, 67, 141, 123, 40, 119, 138, 213, 235, 175, 59,
71, 169, 39, 235, 243, 228, 113, 203, 25, 9, 125,
64, 97, 165, 224, 86, 97, 251, 1, 91
])

const keyPair = Ed25519.parseKeyPair(publicKey, privateKey);
const keyPairFromPEM = Ed25519.parseKeyPair(
Ed25519.parsePublicKey(Ed25519.readBase64WithPEM(publicKeyPEM)),
Ed25519.parsePrivateKey(Ed25519.readBase64WithPEM(privateKeyPEM))
);

const spy = sinon.spy(console, 'warn');

const oldKeyPair = new Ed25519({ publicKey, secretKey: oldPrivateKey });

expect(keyPair.privateKey).deep.equal(keyPairFromPEM.privateKey);
expect(oldKeyPair.privateKey).deep.equal(keyPairFromPEM.privateKey);

expect(spy.calledOnce).true;

spy.restore();
});
});

describe('Secp256K1', () => {
Expand Down
20 changes: 14 additions & 6 deletions src/lib/Keys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const ED25519_PEM_PUBLIC_KEY_TAG = 'PUBLIC KEY';

export interface SignKeyPair {
publicKey: Uint8Array; // Array with 32-byte public key
secretKey: Uint8Array; // Array with 64-byte secret key
secretKey: Uint8Array; // Array with 32-byte secret key
}

export const getKeysFromHexPrivKey = (
Expand Down Expand Up @@ -206,16 +206,24 @@ export class Ed25519 extends AsymmetricKey {
/**
* Constructs a new Ed25519 object from a `SignKeyPair`
* @param {SignKeyPair} keyPair An object containing the keys "publicKey" and "secretKey" with corresponding `ByteArray` values
* @see [SignKeyPair](https://www.npmjs.com/package/tweetnacl-ts#sign_keypair)
*/
constructor(keyPair: SignKeyPair) {
super(keyPair.publicKey, keyPair.secretKey, SignatureAlgorithm.Ed25519);
if (keyPair.secretKey.length != 32) {
console.warn(
`You're using private key from old version, please use newly formatted key with 32 bytes length.`
);
}

super(
keyPair.publicKey,
Ed25519.parsePrivateKey(keyPair.secretKey),
SignatureAlgorithm.Ed25519
);
}

/**
* Generates a new Ed25519 key pair
* @returns A new `Ed25519` object
* @see [nacl.sign_keyPair](https://www.npmjs.com/package/tweetnacl-ts#sign_keypair)
*/
public static new() {
const privateKey = ed25519.utils.randomPrivateKey();
Expand Down Expand Up @@ -265,12 +273,12 @@ export class Ed25519 extends AsymmetricKey {
* Construct a keypair from a public key and corresponding private key
* @param {Uint8Array} publicKey The public key of an Ed25519 account
* @param {Uint8Array} privateKey The private key of the same Ed25519 account
* @returns A new `AsymmetricKey` keypair
* @returns A new `Ed25519` keypair
*/
public static parseKeyPair(
publicKey: Uint8Array,
privateKey: Uint8Array
): AsymmetricKey {
): Ed25519 {
const keyPair = new Ed25519({
publicKey: Ed25519.parsePublicKey(publicKey),
secretKey: Ed25519.parsePrivateKey(privateKey)
Expand Down

0 comments on commit ec7f8f7

Please sign in to comment.