Skip to content

Commit

Permalink
replaces tweetnacl with @noble/curves
Browse files Browse the repository at this point in the history
  • Loading branch information
krpeacock committed Oct 24, 2023
1 parent 80bef81 commit f34e122
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 25 deletions.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions packages/identity/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@
"@peculiar/webcrypto": "^1.4.0"
},
"dependencies": {
"@noble/curves": "^1.2.0",
"@noble/hashes": "^1.3.1",
"borc": "^2.1.1",
"tweetnacl": "^1.0.1"
"borc": "^2.1.1"
},
"devDependencies": {
"@types/jest": "^28.1.4",
Expand Down
2 changes: 1 addition & 1 deletion packages/identity/src/identity/ed25519.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ describe('Ed25519KeyIdentity tests', () => {
const shortArray = new Uint8Array(secretKey).subarray(1, 32);
Ed25519KeyIdentity.fromSecretKey(Uint8Array.from(shortArray).subarray(1, 32));
};
expect(shouldFail).toThrowError('bad secret key size');
expect(shouldFail).toThrowError('private key expected 32 bytes, got 30');
});

test('can encode and decode to/from JSON', async () => {
Expand Down
52 changes: 34 additions & 18 deletions packages/identity/src/identity/ed25519.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import { DerEncodedPublicKey, KeyPair, PublicKey, Signature, SignIdentity } from '@dfinity/agent';
import * as tweetnacl from 'tweetnacl';
import {
DerEncodedPublicKey,
KeyPair,
PublicKey,
Signature,
SignIdentity,
uint8ToBuf,
} from '@dfinity/agent';
import { ed25519 } from '@noble/curves/ed25519';
import { fromHexString, toHexString } from '../buffer';
import { ED25519_OID, unwrapDER, wrapDER } from './der';

Expand Down Expand Up @@ -50,14 +57,14 @@ export class Ed25519PublicKey implements PublicKey {
}

export class Ed25519KeyIdentity extends SignIdentity {
public static generate(seed?: Uint8Array): Ed25519KeyIdentity {
public static generate(seed = new Uint8Array(32)): Ed25519KeyIdentity {
if (seed && seed.length !== 32) {
throw new Error('Ed25519 Seed needs to be 32 bytes long.');
}

const { publicKey, secretKey } =
seed === undefined ? tweetnacl.sign.keyPair() : tweetnacl.sign.keyPair.fromSeed(seed);
return new this(Ed25519PublicKey.fromRaw(publicKey), secretKey);
const sk = new Uint8Array(32);
for (let i = 0; i < 32; i++) sk[i] = new Uint8Array(seed)[i];
const pk = ed25519.getPublicKey(sk);
return Ed25519KeyIdentity.fromKeyPair(pk, sk);
}

public static fromParsedJson(obj: JsonnableEd25519KeyIdentity): Ed25519KeyIdentity {
Expand Down Expand Up @@ -85,40 +92,42 @@ export class Ed25519KeyIdentity extends SignIdentity {
}

public static fromSecretKey(secretKey: ArrayBuffer): Ed25519KeyIdentity {
const keyPair = tweetnacl.sign.keyPair.fromSecretKey(new Uint8Array(secretKey));
return Ed25519KeyIdentity.fromKeyPair(keyPair.publicKey, keyPair.secretKey);
const publicKey = ed25519.getPublicKey(new Uint8Array(secretKey));
return Ed25519KeyIdentity.fromKeyPair(publicKey, secretKey);
}

protected _publicKey: Ed25519PublicKey;
#publicKey: Ed25519PublicKey;
#privateKey: Uint8Array;

// `fromRaw` and `fromDer` should be used for instantiation, not this constructor.
protected constructor(publicKey: PublicKey, protected _privateKey: ArrayBuffer) {
protected constructor(publicKey: PublicKey, privateKey: ArrayBuffer) {
super();
this._publicKey = Ed25519PublicKey.from(publicKey);
this.#publicKey = Ed25519PublicKey.from(publicKey);
this.#privateKey = new Uint8Array(privateKey);
}

/**
* Serialize this key to JSON.
*/
public toJSON(): JsonnableEd25519KeyIdentity {
return [toHexString(this._publicKey.toDer()), toHexString(this._privateKey)];
return [toHexString(this.#publicKey.toDer()), toHexString(this.#privateKey)];
}

/**
* Return a copy of the key pair.
*/
public getKeyPair(): KeyPair {
return {
secretKey: this._privateKey,
publicKey: this._publicKey,
secretKey: this.#privateKey,
publicKey: this.#publicKey,
};
}

/**
* Return the public key.
*/
public getPublicKey(): PublicKey {
return this._publicKey;
return this.#publicKey;
}

/**
Expand All @@ -127,7 +136,14 @@ export class Ed25519KeyIdentity extends SignIdentity {
*/
public async sign(challenge: ArrayBuffer): Promise<Signature> {
const blob = new Uint8Array(challenge);
const signature = tweetnacl.sign.detached(blob, new Uint8Array(this._privateKey)).buffer;
const signature = uint8ToBuf(ed25519.sign(blob, this.#privateKey));
// add { __signature__: void; } to the signature to make it compatible with the agent

Object.defineProperty(signature, '__signature__', {
enumerable: false,
value: undefined,
});

return signature as Signature;
}

Expand All @@ -152,7 +168,7 @@ export class Ed25519KeyIdentity extends SignIdentity {
}
return new Uint8Array(x);
});
return tweetnacl.sign.detached.verify(message, signature, publicKey);
return ed25519.verify(message, signature, publicKey);
}
}

Expand Down
4 changes: 2 additions & 2 deletions packages/identity/src/identity/webauthn.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { DerEncodedPublicKey, PublicKey, Signature, SignIdentity } from '@dfinity/agent';
import borc from 'borc';
import * as tweetnacl from 'tweetnacl';
import { fromHexString, toHexString } from '../buffer';
import { randomBytes } from '@noble/hashes/utils';
import { DER_COSE_OID, wrapDER } from './der';

function _coseToDerEncodedBlob(cose: ArrayBuffer): DerEncodedPublicKey {
Expand Down Expand Up @@ -93,7 +93,7 @@ async function _createCredential(
name: 'Internet Identity Service',
},
user: {
id: tweetnacl.randomBytes(16),
id: randomBytes(16),
name: 'Internet Identity',
displayName: 'Internet Identity',
},
Expand Down

0 comments on commit f34e122

Please sign in to comment.