From 21a775c524fa77d4037e3a8eda30ea2f5c25e5ac Mon Sep 17 00:00:00 2001 From: Kyle Peacock Date: Tue, 20 Feb 2024 15:12:13 -0800 Subject: [PATCH] fix: ed25519KeyIdentity generates unique identities when no seed is provided --- docs/generated/changelog.html | 1 + package-lock.json | 56 +++++++++---------- .../identity/src/identity/ed25519.test.ts | 14 +++++ packages/identity/src/identity/ed25519.ts | 16 +++++- 4 files changed, 58 insertions(+), 29 deletions(-) diff --git a/docs/generated/changelog.html b/docs/generated/changelog.html index c309863e..22e06c18 100644 --- a/docs/generated/changelog.html +++ b/docs/generated/changelog.html @@ -12,6 +12,7 @@

Agent-JS Changelog

Version x.x.x

Version 1.0.0

diff --git a/package-lock.json b/package-lock.json index 8d60f4ee..3f4d1ce5 100755 --- a/package-lock.json +++ b/package-lock.json @@ -62,11 +62,11 @@ }, "e2e/browser": { "name": "@do-not-publish/ic-cypress-e2e-tests", - "version": "0.21.4", + "version": "1.0.0", "dependencies": { - "@dfinity/agent": "^0.21.4", - "@dfinity/identity": "^0.21.4", - "@dfinity/principal": "^0.21.4", + "@dfinity/agent": "^1.0.0", + "@dfinity/identity": "^1.0.0", + "@dfinity/principal": "^1.0.0", "idb-keyval": "^6.2.0" }, "devDependencies": { @@ -110,12 +110,12 @@ }, "e2e/node": { "name": "@do-not-publish/ic-node-e2e-tests", - "version": "0.21.4", + "version": "1.0.0", "dependencies": { - "@dfinity/agent": "^0.21.4", - "@dfinity/assets": "^0.21.4", - "@dfinity/identity": "^0.21.4", - "@dfinity/principal": "^0.21.4", + "@dfinity/agent": "^1.0.0", + "@dfinity/assets": "^1.0.0", + "@dfinity/identity": "^1.0.0", + "@dfinity/principal": "^1.0.0", "whatwg-fetch": "^3.6.2" }, "devDependencies": { @@ -18930,7 +18930,7 @@ }, "packages/agent": { "name": "@dfinity/agent", - "version": "0.21.4", + "version": "1.0.0", "license": "Apache-2.0", "dependencies": { "@noble/curves": "^1.2.0", @@ -18957,8 +18957,8 @@ "whatwg-fetch": "^3.0.0" }, "peerDependencies": { - "@dfinity/candid": "^0.21.4", - "@dfinity/principal": "^0.21.4" + "@dfinity/candid": "^1.0.0", + "@dfinity/principal": "^1.0.0" } }, "packages/agent/node_modules/@typescript-eslint/eslint-plugin": { @@ -19137,7 +19137,7 @@ }, "packages/assets": { "name": "@dfinity/assets", - "version": "0.21.4", + "version": "1.0.0", "license": "Apache-2.0", "dependencies": { "base64-arraybuffer": "^1.0.2", @@ -19157,8 +19157,8 @@ "typedoc": "^0.22.11" }, "peerDependencies": { - "@dfinity/agent": "^0.21.4", - "@dfinity/principal": "^0.21.4", + "@dfinity/agent": "^1.0.0", + "@dfinity/principal": "^1.0.0", "@noble/hashes": "^1.3.1" } }, @@ -19346,7 +19346,7 @@ }, "packages/auth-client": { "name": "@dfinity/auth-client", - "version": "0.21.4", + "version": "1.0.0", "license": "Apache-2.0", "dependencies": { "idb": "^7.0.2" @@ -19369,9 +19369,9 @@ "whatwg-fetch": "^3.0.0" }, "peerDependencies": { - "@dfinity/agent": "^0.21.4", - "@dfinity/identity": "^0.21.4", - "@dfinity/principal": "^0.21.4" + "@dfinity/agent": "^1.0.0", + "@dfinity/identity": "^1.0.0", + "@dfinity/principal": "^1.0.0" } }, "packages/auth-client/node_modules/@typescript-eslint/eslint-plugin": { @@ -19550,7 +19550,7 @@ }, "packages/bls-verify": { "name": "@dfinity/bls-verify", - "version": "0.21.4", + "version": "1.0.0", "license": "Apache-2.0", "dependencies": { "amcl-js": "file:src/vendor/amcl-js" @@ -19591,7 +19591,7 @@ }, "packages/candid": { "name": "@dfinity/candid", - "version": "0.21.4", + "version": "1.0.0", "license": "Apache-2.0", "devDependencies": { "@types/jest": "^29.5.5", @@ -19609,7 +19609,7 @@ "whatwg-fetch": "^3.0.0" }, "peerDependencies": { - "@dfinity/principal": "^0.21.4" + "@dfinity/principal": "^1.0.0" } }, "packages/candid/node_modules/@typescript-eslint/eslint-plugin": { @@ -19853,7 +19853,7 @@ }, "packages/identity": { "name": "@dfinity/identity", - "version": "0.21.4", + "version": "1.0.0", "license": "Apache-2.0", "dependencies": { "@noble/curves": "^1.2.0", @@ -19874,17 +19874,17 @@ "whatwg-fetch": "^3.0.0" }, "peerDependencies": { - "@dfinity/agent": "^0.21.4", - "@dfinity/principal": "^0.21.4", + "@dfinity/agent": "^1.0.0", + "@dfinity/principal": "^1.0.0", "@peculiar/webcrypto": "^1.4.0" } }, "packages/identity-secp256k1": { "name": "@dfinity/identity-secp256k1", - "version": "0.21.4", + "version": "1.0.0", "license": "Apache-2.0", "dependencies": { - "@dfinity/agent": "^0.21.4", + "@dfinity/agent": "^1.0.0", "@noble/curves": "^1.3.0", "@noble/hashes": "^1.3.1", "bip39": "^3.1.0", @@ -20072,7 +20072,7 @@ }, "packages/principal": { "name": "@dfinity/principal", - "version": "0.21.4", + "version": "1.0.0", "license": "Apache-2.0", "dependencies": { "@noble/hashes": "^1.3.1" diff --git a/packages/identity/src/identity/ed25519.test.ts b/packages/identity/src/identity/ed25519.test.ts index 22fd5d44..2313acb2 100644 --- a/packages/identity/src/identity/ed25519.test.ts +++ b/packages/identity/src/identity/ed25519.test.ts @@ -114,6 +114,20 @@ describe('Ed25519KeyIdentity tests', () => { expect(isValid).toBe(true); }); + + it('generates random private keys', () => { + const key1 = Ed25519KeyIdentity.generate(); + const key2 = Ed25519KeyIdentity.generate(); + expect(key1.toJSON().toString()).not.toEqual(key2.toJSON().toString()); + }); + + it('should warn if the key is an Uint8Array consisting of all zeroes', () => { + const consoleSpy = jest.spyOn(console, 'warn').mockImplementation(() => {}); + + const baseKey = new Uint8Array(new Array(32).fill(0)); + Ed25519KeyIdentity.generate(baseKey); + expect(consoleSpy).toHaveBeenCalledWith("Seed is all zeros. This is not a secure seed. Please provide a seed with sufficient entropy if this is a production environment."); + }); }); test('from JSON', async () => { diff --git a/packages/identity/src/identity/ed25519.ts b/packages/identity/src/identity/ed25519.ts index 9510fbe1..e8752d83 100644 --- a/packages/identity/src/identity/ed25519.ts +++ b/packages/identity/src/identity/ed25519.ts @@ -1,3 +1,4 @@ +import { bufEquals } from '@dfinity/agent'; import { DerEncodedPublicKey, KeyPair, @@ -105,12 +106,25 @@ export class Ed25519PublicKey implements PublicKey { } } +/** + * Ed25519KeyIdentity is an implementation of SignIdentity that uses Ed25519 keys. This class is used to sign and verify messages for an agent. + */ export class Ed25519KeyIdentity extends SignIdentity { - public static generate(seed = new Uint8Array(32)): Ed25519KeyIdentity { + /** + * Generate a new Ed25519KeyIdentity. + * @param seed a 32-byte seed for the private key. If not provided, a random seed will be generated. + * @returns Ed25519KeyIdentity + */ + public static generate(seed?: Uint8Array): Ed25519KeyIdentity { + if (seed && seed.length !== 32) { throw new Error('Ed25519 Seed needs to be 32 bytes long.'); } if (!seed) seed = ed25519.utils.randomPrivateKey(); + // Check if the seed is all zeros + if(bufEquals(seed, new Uint8Array(new Array(32).fill(0)))) { + console.warn('Seed is all zeros. This is not a secure seed. Please provide a seed with sufficient entropy if this is a production environment.'); + } const sk = new Uint8Array(32); for (let i = 0; i < 32; i++) sk[i] = new Uint8Array(seed)[i];