diff --git a/.github/workflows/ci-casper-client-sdk.yml b/.github/workflows/ci-casper-client-sdk.yml index bcd6b519a..61c2f3f5a 100644 --- a/.github/workflows/ci-casper-client-sdk.yml +++ b/.github/workflows/ci-casper-client-sdk.yml @@ -40,7 +40,7 @@ jobs: run: npm install - name: Audits - run: npm audit + run: npm audit --omit=dev - name: Lints run: npm run lint:ci diff --git a/CHANGELOG.md b/CHANGELOG.md index a0b7f4c12..589e040e6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,12 @@ All notable changes to casper-js-sdk. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## 2.13.3 + +### Fixed + +- Fixed to support 64 bytes Ed25519 private key generated using v2.10 + ## 2.13.2 ### Fixed diff --git a/package-lock.json b/package-lock.json index 26ca73996..68782f3f3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "casper-js-sdk", - "version": "2.13.2", + "version": "2.13.3", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "casper-js-sdk", - "version": "2.13.2", + "version": "2.13.3", "license": "Apache 2.0", "dependencies": { "@ethersproject/bignumber": "^5.0.8", diff --git a/package.json b/package.json index 5cf998254..80b4a21d7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "casper-js-sdk", - "version": "2.13.2", + "version": "2.13.3", "license": "Apache 2.0", "description": "SDK to interact with the Casper blockchain", "homepage": "https://github.com/casper-ecosystem/casper-js-sdk#README.md", diff --git a/src/lib/Keys.test.ts b/src/lib/Keys.test.ts index 543873aa4..177fa4679 100644 --- a/src/lib/Keys.test.ts +++ b/src/lib/Keys.test.ts @@ -1,4 +1,5 @@ import { expect } from 'chai'; +import sinon from 'sinon'; import { decodeBase16, decodeBase64 } from './Conversions'; import { Ed25519, Secp256K1 } from './Keys'; @@ -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', () => { diff --git a/src/lib/Keys.ts b/src/lib/Keys.ts index 0c24453b8..2539953de 100644 --- a/src/lib/Keys.ts +++ b/src/lib/Keys.ts @@ -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 = ( @@ -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(); @@ -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)