Add ed25519 keypair, sign & verify (#71)

This commit is contained in:
Jaco Greeff
2018-01-31 14:50:20 +01:00
committed by GitHub
parent 061e3991a2
commit 3720ebc920
14 changed files with 452 additions and 2 deletions
+40 -2
View File
@@ -1,8 +1,46 @@
// @flow
declare module 'tweetnacl' {
declare type Tweetnacl$KeypairType = {
publicKey: Uint8Array,
secretKey: Uint8Array
};
declare type Tweetnacl$Hash = {
(message: Uint8Array): Uint8Array,
hashLength: number
};
declare type Tweetnacl$Sign$Detached = {
(message: Uint8Array, secretKey: Uint8Array): Uint8Array,
verify: (message: Uint8Array, signature: Uint8Array, publicKey: Uint8Array) => boolean
};
declare type Tweetnacl$Sign$Keypair = {
(): Tweetnacl$KeypairType,
fromSecretKey: (secretKey: Uint8Array) => Tweetnacl$KeypairType,
fromSeed: (seed: Uint8Array) => Tweetnacl$KeypairType,
};
declare type Tweetnacl$Sign = {
(message: Uint8Array, secretKey: Uint8Array): Uint8Array,
detached: Tweetnacl$Sign$Detached,
open: (signedMsg: Uint8Array, publicKey: Uint8Array) => Uint8Array,
keyPair: Tweetnacl$Sign$Keypair,
publicKeyLength: number,
secretKeyLength: number,
seedLength: number,
signatureLength: number,
};
declare module.exports: {
hash: (data: Uint8Array) => Uint8Array,
randomBytes: (length: number) => Uint8Array
randomBytes: (length: number) => Uint8Array,
hash: Tweetnacl$Hash,
sign: Tweetnacl$Sign
}
}
+91
View File
@@ -1,3 +1,94 @@
# nacl
Implements [NaCl](http://nacl.cr.yp.to/) secret-key authenticated encryption, public-key authenticated encryption, hashing, and public-key signatures
- [naclKeypair](#naclkeypair) Creates a new public/secret keypair.
- [naclKeypairFromSecret](#naclkeypairfromsecret) Creates a new public/secret keypair from a secret.
- [naclKeypairFromSeed](#naclkeypairfromseed) Creates a new public/secret keypair from a seed.
- [naclSign](#naclsign) Signs a message using the supplied secretKey
- [naclSign](#naclsign) Verifies the signature on the supplied message.
## naclKeypair
Creates a new public/secret keypair.
```js
naclKeypair (): { secretKey: Uint8Array, publicKey: Uint8Array }
```
Returns a new generate object containing a `publicKey` & `secretKey`.
```js
import { naclKeypair } from '@polkadot/util-crypto';
naclKeypair() // => { secretKey: [...], publicKey: [...] }
```
## naclKeypairFromSecret
Creates a new public/secret keypair from a secret.
```js
naclKeypairFromSecret (secretKey: Uint8Array): { secretKey: Uint8Array, publicKey: Uint8Array }
```
Returns a object containing a `publicKey` & `secretKey` generated from the supplied secret.
```js
import { naclKeypairFromSecret } from '@polkadot/util-crypto';
naclKeypairFromSecret(...) // => { secretKey: [...], publicKey: [...] }
```
## naclKeypairFromSeed
Creates a new public/secret keypair from a seed.
```js
naclKeypairFromSeed (seed: Uint8Array): { secretKey: Uint8Array, publicKey: Uint8Array }
```
Returns a object containing a `publicKey` & `secretKey` generated from the supplied seed.
```js
import { naclKeypairFromSeed } from '@polkadot/util-crypto';
naclKeypairFromSeed(...) // => { secretKey: [...], publicKey: [...] }
```
## naclSign
Signs a message using the supplied secretKey
```js
naclSign (message: Uint8Array, secretKey: Uint8Array): Uint8Array
```
Returns message signature of `message`, using the `secretKey`.
```js
import { naclSign } from '@polkadot/util-crypto';
naclSign([...], [...]) // => [...]
```
## naclSign
Verifies the signature on the supplied message.
```js
naclVerify (message: Uint8Array, signature: Uint8Array, publicKey: Uint8Array): boolean
```
Verifies the `signature` on `message` with the supplied `plublicKey`. Returns `true` on sucess, `false` otherwise.
```js
import { naclVerify } from '@polkadot/util-crypto';
naclVerify([...], [...], [...]) // => true/false
```
+11
View File
@@ -3,8 +3,19 @@
// of the ISC license. See the LICENSE file for details.
// @flow
const naclKeypair = require('./keypair');
const naclKeypairFromSecret = require('./keypairFromSecret');
const naclKeypairFromSeed = require('./keypairFromSeed');
const naclSign = require('./sign');
const naclVerify = require('./verify');
/**
@summary Implements [NaCl](http://nacl.cr.yp.to/) secret-key authenticated encryption, public-key authenticated encryption, hashing, and public-key signatures
*/
module.exports = {
naclKeypair,
naclKeypairFromSecret,
naclKeypairFromSeed,
naclSign,
naclVerify
};
+23
View File
@@ -0,0 +1,23 @@
// Copyright 2017-2018 Jaco Greeff
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
// @flow
import type { KeypairType } from '../types';
const nacl = require('tweetnacl');
/**
@name naclKeypair
@signature naclKeypair (): { secretKey: Uint8Array, publicKey: Uint8Array }
@summary Creates a new public/secret keypair.
@description
Returns a new generate object containing a `publicKey` & `secretKey`.
@example
import { naclKeypair } from '@polkadot/util-crypto';
naclKeypair() // => { secretKey: [...], publicKey: [...] }
*/
module.exports = function naclKeypair (): KeypairType {
return nacl.sign.keyPair();
};
@@ -0,0 +1,25 @@
// Copyright 2017-2018 Jaco Greeff
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
const { naclKeypair } = require('./index');
describe('naclKeypair', () => {
let keypair;
beforeEach(() => {
keypair = naclKeypair();
});
it('generates a valid publicKey', () => {
expect(
keypair.publicKey
).toHaveLength(32);
});
it('generates a valid secretKey', () => {
expect(
keypair.secretKey
).toHaveLength(64);
});
});
@@ -0,0 +1,23 @@
// Copyright 2017-2018 Jaco Greeff
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
// @flow
import type { KeypairType } from '../types';
const nacl = require('tweetnacl');
/**
@name naclKeypairFromSecret
@signature naclKeypairFromSecret (secretKey: Uint8Array): { secretKey: Uint8Array, publicKey: Uint8Array }
@summary Creates a new public/secret keypair from a secret.
@description
Returns a object containing a `publicKey` & `secretKey` generated from the supplied secret.
@example
import { naclKeypairFromSecret } from '@polkadot/util-crypto';
naclKeypairFromSecret(...) // => { secretKey: [...], publicKey: [...] }
*/
module.exports = function naclKeypairFromSecret (secretKey: Uint8Array): KeypairType {
return nacl.sign.keyPair.fromSecretKey(secretKey);
};
@@ -0,0 +1,32 @@
// Copyright 2017-2018 Jaco Greeff
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
const { naclKeypairFromSecret } = require('./index');
describe('naclKeypairFromSecret', () => {
const secretKey = new Uint8Array([
18, 52, 86, 120, 144, 18, 52, 86,
120, 144, 18, 52, 86, 120, 144, 18,
18, 52, 86, 120, 144, 18, 52, 86,
120, 144, 18, 52, 86, 120, 144, 18,
180, 114, 93, 155, 165, 255, 217, 82,
16, 250, 209, 11, 193, 10, 88, 218,
190, 190, 41, 193, 236, 252, 1, 152,
216, 214, 0, 41, 45, 138, 13, 53
]);
it('generates a valid publicKey/secretKey pair', () => {
expect(
naclKeypairFromSecret(secretKey)
).toEqual({
publicKey: new Uint8Array([
180, 114, 93, 155, 165, 255, 217, 82,
16, 250, 209, 11, 193, 10, 88, 218,
190, 190, 41, 193, 236, 252, 1, 152,
216, 214, 0, 41, 45, 138, 13, 53
]),
secretKey
});
});
});
@@ -0,0 +1,23 @@
// Copyright 2017-2018 Jaco Greeff
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
// @flow
import type { KeypairType } from '../types';
const nacl = require('tweetnacl');
/**
@name naclKeypairFromSeed
@signature naclKeypairFromSeed (seed: Uint8Array): { secretKey: Uint8Array, publicKey: Uint8Array }
@summary Creates a new public/secret keypair from a seed.
@description
Returns a object containing a `publicKey` & `secretKey` generated from the supplied seed.
@example
import { naclKeypairFromSeed } from '@polkadot/util-crypto';
naclKeypairFromSeed(...) // => { secretKey: [...], publicKey: [...] }
*/
module.exports = function naclKeypairFromSeed (seed: Uint8Array): KeypairType {
return nacl.sign.keyPair.fromSeed(seed);
};
@@ -0,0 +1,37 @@
// Copyright 2017-2018 Jaco Greeff
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
const { naclKeypairFromSeed } = require('./index');
describe('naclKeypairFromSeed', () => {
it('generates a valid publicKey/secretKey pair', () => {
expect(
naclKeypairFromSeed(
new Uint8Array([
0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56,
0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12,
0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56,
0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12
])
)
).toEqual({
publicKey: new Uint8Array([
180, 114, 93, 155, 165, 255, 217, 82,
16, 250, 209, 11, 193, 10, 88, 218,
190, 190, 41, 193, 236, 252, 1, 152,
216, 214, 0, 41, 45, 138, 13, 53
]),
secretKey: new Uint8Array([
18, 52, 86, 120, 144, 18, 52, 86,
120, 144, 18, 52, 86, 120, 144, 18,
18, 52, 86, 120, 144, 18, 52, 86,
120, 144, 18, 52, 86, 120, 144, 18,
180, 114, 93, 155, 165, 255, 217, 82,
16, 250, 209, 11, 193, 10, 88, 218,
190, 190, 41, 193, 236, 252, 1, 152,
216, 214, 0, 41, 45, 138, 13, 53
])
});
});
});
+22
View File
@@ -0,0 +1,22 @@
// Copyright 2017-2018 Jaco Greeff
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
// @flow
const nacl = require('tweetnacl');
/**
@name naclSign
@signature naclSign (message: Uint8Array, secretKey: Uint8Array): Uint8Array
@summary Signs a message using the supplied secretKey
@description
Returns message signature of `message`, using the `secretKey`.
@example
import { naclSign } from '@polkadot/util-crypto';
naclSign([...], [...]) // => [...]
*/
module.exports = function naclSign (message: Uint8Array, secretKey: Uint8Array): Uint8Array {
// NOTE: Original message appended to the signature, slice result only
return nacl.sign(message, secretKey).subarray(0, 64);
};
@@ -0,0 +1,33 @@
// Copyright 2017-2018 Jaco Greeff
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
const { naclSign, naclKeypairFromSeed } = require('./index');
describe('naclSign', () => {
let secretKey;
beforeEach(() => {
secretKey = naclKeypairFromSeed(
new Uint8Array([
0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56,
0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12,
0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56,
0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12
])
).secretKey;
});
it('returns a valid signature for the message', () => {
expect(
naclSign(
new Uint8Array([0x61, 0x62, 0x63, 0x64]),
secretKey
)
).toEqual(
new Uint8Array([
209, 234, 164, 44, 182, 218, 103, 16, 205, 238, 97, 222, 123, 112, 2, 240, 24, 192, 26, 134, 11, 170, 167, 153, 141, 108, 187, 171, 241, 125, 226, 179, 244, 232, 131, 61, 44, 68, 87, 41, 141, 131, 88, 36, 175, 173, 57, 29, 12, 112, 26, 200, 247, 89, 14, 64, 224, 188, 211, 198, 233, 119, 158, 6
])
);
});
});
+21
View File
@@ -0,0 +1,21 @@
// Copyright 2017-2018 Jaco Greeff
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
// @flow
const nacl = require('tweetnacl');
/**
@name naclSign
@signature naclVerify (message: Uint8Array, signature: Uint8Array, publicKey: Uint8Array): boolean
@summary Verifies the signature on the supplied message.
@description
Verifies the `signature` on `message` with the supplied `plublicKey`. Returns `true` on sucess, `false` otherwise.
@example
import { naclVerify } from '@polkadot/util-crypto';
naclVerify([...], [...], [...]) // => true/false
*/
module.exports = function naclVerify (message: Uint8Array, signature: Uint8Array, publicKey: Uint8Array): boolean {
return nacl.sign.detached.verify(message, signature, publicKey);
};
@@ -0,0 +1,63 @@
// Copyright 2017-2018 Jaco Greeff
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
const { naclVerify, naclKeypairFromSeed } = require('./index');
describe('naclSign', () => {
let publicKey;
let signature;
beforeEach(() => {
publicKey = naclKeypairFromSeed(
new Uint8Array([
0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56,
0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12,
0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56,
0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12
])
).publicKey;
signature = new Uint8Array([
209, 234, 164, 44, 182, 218, 103, 16,
205, 238, 97, 222, 123, 112, 2, 240,
24, 192, 26, 134, 11, 170, 167, 153,
141, 108, 187, 171, 241, 125, 226, 179,
244, 232, 131, 61, 44, 68, 87, 41,
141, 131, 88, 36, 175, 173, 57, 29,
12, 112, 26, 200, 247, 89, 14, 64,
224, 188, 211, 198, 233, 119, 158, 6
]);
});
it('validates a correctly signed message', () => {
expect(
naclVerify(
new Uint8Array([0x61, 0x62, 0x63, 0x64]),
signature,
publicKey
)
).toEqual(true);
});
it('fails a correctly signed message (message changed)', () => {
expect(
naclVerify(
new Uint8Array([0x61, 0x62, 0x63, 0x64, 0x65]),
signature,
publicKey
)
).toEqual(false);
});
it('fails a correctly signed message (signature changed)', () => {
signature[0] = 0xff;
expect(
naclVerify(
new Uint8Array([0x61, 0x62, 0x63, 0x64]),
signature,
publicKey
)
).toEqual(false);
});
});
+8
View File
@@ -0,0 +1,8 @@
// Copyright 2017-2018 Jaco Greeff
// This software may be modified and distributed under the terms
// of the ISC license. See the LICENSE file for details.
// @flow
import type { Tweetnacl$KeypairType } from 'tweetnacl';
export type KeypairType = Tweetnacl$KeypairType;