2016-12-23 08:52:40 -05:00
|
|
|
/* eslint-env mocha */
|
|
|
|
'use strict'
|
|
|
|
|
2017-03-21 15:05:22 +00:00
|
|
|
const chai = require('chai')
|
|
|
|
const dirtyChai = require('dirty-chai')
|
|
|
|
const expect = chai.expect
|
|
|
|
chai.use(dirtyChai)
|
2020-08-07 15:23:02 +01:00
|
|
|
const uint8ArrayFromString = require('uint8arrays/from-string')
|
2016-12-23 08:52:40 -05:00
|
|
|
|
2017-07-22 10:57:27 -07:00
|
|
|
const crypto = require('../../src')
|
2017-07-22 13:25:15 -07:00
|
|
|
const ed25519 = crypto.keys.supportedKeys.ed25519
|
2017-07-22 10:57:27 -07:00
|
|
|
const fixtures = require('../fixtures/go-key-ed25519')
|
2016-12-23 08:52:40 -05:00
|
|
|
|
2017-12-01 09:36:29 +01:00
|
|
|
const testGarbage = require('../helpers/test-garbage-error-handling')
|
|
|
|
|
2020-01-17 03:04:52 -08:00
|
|
|
/** @typedef {import("libp2p-crypto").PrivateKey} PrivateKey */
|
|
|
|
|
2017-12-01 09:36:29 +01:00
|
|
|
describe('ed25519', function () {
|
|
|
|
this.timeout(20 * 1000)
|
2020-01-17 03:04:52 -08:00
|
|
|
// @ts-check
|
|
|
|
/**
|
|
|
|
* @type {PrivateKey}
|
|
|
|
*/
|
2016-12-23 08:52:40 -05:00
|
|
|
let key
|
2019-07-10 17:15:26 +01:00
|
|
|
before(async () => {
|
|
|
|
key = await crypto.keys.generateKeyPair('Ed25519', 512)
|
2016-12-23 08:52:40 -05:00
|
|
|
})
|
|
|
|
|
2019-07-10 17:15:26 +01:00
|
|
|
it('generates a valid key', async () => {
|
2017-07-22 10:57:27 -07:00
|
|
|
expect(key).to.be.an.instanceof(ed25519.Ed25519PrivateKey)
|
2019-07-10 17:15:26 +01:00
|
|
|
const digest = await key.hash()
|
|
|
|
expect(digest).to.have.length(34)
|
2016-12-23 08:52:40 -05:00
|
|
|
})
|
|
|
|
|
2019-07-10 17:15:26 +01:00
|
|
|
it('generates a valid key from seed', async () => {
|
2017-03-03 20:38:51 +00:00
|
|
|
var seed = crypto.randomBytes(32)
|
2019-07-10 17:15:26 +01:00
|
|
|
const seededkey = await crypto.keys.generateKeyPairFromSeed('Ed25519', seed, 512)
|
|
|
|
expect(seededkey).to.be.an.instanceof(ed25519.Ed25519PrivateKey)
|
|
|
|
const digest = await seededkey.hash()
|
|
|
|
expect(digest).to.have.length(34)
|
2017-03-03 20:38:51 +00:00
|
|
|
})
|
|
|
|
|
2019-07-10 17:15:26 +01:00
|
|
|
it('generates the same key from the same seed', async () => {
|
|
|
|
const seed = crypto.randomBytes(32)
|
|
|
|
const seededkey1 = await crypto.keys.generateKeyPairFromSeed('Ed25519', seed, 512)
|
|
|
|
const seededkey2 = await crypto.keys.generateKeyPairFromSeed('Ed25519', seed, 512)
|
|
|
|
expect(seededkey1.equals(seededkey2)).to.eql(true)
|
|
|
|
expect(seededkey1.public.equals(seededkey2.public)).to.eql(true)
|
2017-03-03 20:38:51 +00:00
|
|
|
})
|
|
|
|
|
2019-07-10 17:15:26 +01:00
|
|
|
it('generates different keys for different seeds', async () => {
|
2017-07-22 10:57:27 -07:00
|
|
|
const seed1 = crypto.randomBytes(32)
|
2019-07-10 17:15:26 +01:00
|
|
|
const seededkey1 = await crypto.keys.generateKeyPairFromSeed('Ed25519', seed1, 512)
|
|
|
|
const seed2 = crypto.randomBytes(32)
|
|
|
|
const seededkey2 = await crypto.keys.generateKeyPairFromSeed('Ed25519', seed2, 512)
|
|
|
|
expect(seededkey1.equals(seededkey2)).to.eql(false)
|
|
|
|
expect(seededkey1.public.equals(seededkey2.public)).to.eql(false)
|
2017-03-03 20:38:51 +00:00
|
|
|
})
|
|
|
|
|
2019-07-10 17:15:26 +01:00
|
|
|
it('signs', async () => {
|
2016-12-23 08:52:40 -05:00
|
|
|
const text = crypto.randomBytes(512)
|
2019-07-10 17:15:26 +01:00
|
|
|
const sig = await key.sign(text)
|
|
|
|
const res = await key.public.verify(text, sig)
|
|
|
|
expect(res).to.be.eql(true)
|
2016-12-23 08:52:40 -05:00
|
|
|
})
|
|
|
|
|
2019-07-10 17:15:26 +01:00
|
|
|
it('encoding', async () => {
|
2016-12-23 08:52:40 -05:00
|
|
|
const keyMarshal = key.marshal()
|
2019-07-10 17:15:26 +01:00
|
|
|
const key2 = await ed25519.unmarshalEd25519PrivateKey(keyMarshal)
|
|
|
|
const keyMarshal2 = key2.marshal()
|
2016-12-23 08:52:40 -05:00
|
|
|
|
2019-07-10 17:15:26 +01:00
|
|
|
expect(keyMarshal).to.eql(keyMarshal2)
|
2016-12-23 08:52:40 -05:00
|
|
|
|
2019-07-10 17:15:26 +01:00
|
|
|
const pk = key.public
|
|
|
|
const pkMarshal = pk.marshal()
|
|
|
|
const pk2 = ed25519.unmarshalEd25519PublicKey(pkMarshal)
|
|
|
|
const pkMarshal2 = pk2.marshal()
|
2016-12-23 08:52:40 -05:00
|
|
|
|
2019-07-10 17:15:26 +01:00
|
|
|
expect(pkMarshal).to.eql(pkMarshal2)
|
2016-12-23 08:52:40 -05:00
|
|
|
})
|
|
|
|
|
2019-07-10 17:15:26 +01:00
|
|
|
it('key id', async () => {
|
2021-03-15 18:07:13 +01:00
|
|
|
const key = await crypto.keys.unmarshalPrivateKey(fixtures.verify.privateKey)
|
2019-07-10 17:15:26 +01:00
|
|
|
const id = await key.id()
|
2021-03-17 19:01:53 +01:00
|
|
|
expect(id).to.eql('12D3KooWLqLxEfJ9nDdEe8Kh8PFvNPQRYDQBwyL7CMM7HhVd5LsX')
|
2017-12-20 21:11:47 +13:00
|
|
|
})
|
|
|
|
|
2020-08-05 17:14:12 +02:00
|
|
|
it('should export a password encrypted libp2p-key', async () => {
|
|
|
|
const key = await crypto.keys.generateKeyPair('Ed25519')
|
|
|
|
const encryptedKey = await key.export('my secret')
|
|
|
|
// Import the key
|
|
|
|
const importedKey = await crypto.keys.import(encryptedKey, 'my secret')
|
|
|
|
expect(key.equals(importedKey)).to.equal(true)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should fail to import libp2p-key with wrong password', async () => {
|
|
|
|
const key = await crypto.keys.generateKeyPair('Ed25519')
|
|
|
|
const encryptedKey = await key.export('my secret', 'libp2p-key')
|
|
|
|
try {
|
|
|
|
await crypto.keys.import(encryptedKey, 'not my secret')
|
|
|
|
} catch (err) {
|
|
|
|
expect(err).to.exist()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
expect.fail('should have thrown')
|
|
|
|
})
|
|
|
|
|
2016-12-23 08:52:40 -05:00
|
|
|
describe('key equals', () => {
|
|
|
|
it('equals itself', () => {
|
|
|
|
expect(
|
|
|
|
key.equals(key)
|
2017-07-22 10:57:27 -07:00
|
|
|
).to.eql(
|
2016-12-23 08:52:40 -05:00
|
|
|
true
|
|
|
|
)
|
|
|
|
|
|
|
|
expect(
|
|
|
|
key.public.equals(key.public)
|
2017-07-22 10:57:27 -07:00
|
|
|
).to.eql(
|
2016-12-23 08:52:40 -05:00
|
|
|
true
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
2019-07-10 17:15:26 +01:00
|
|
|
it('not equals other key', async () => {
|
|
|
|
const key2 = await crypto.keys.generateKeyPair('Ed25519', 512)
|
|
|
|
expect(key.equals(key2)).to.eql(false)
|
|
|
|
expect(key2.equals(key)).to.eql(false)
|
|
|
|
expect(key.public.equals(key2.public)).to.eql(false)
|
|
|
|
expect(key2.public.equals(key.public)).to.eql(false)
|
2016-12-23 08:52:40 -05:00
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2019-07-10 17:15:26 +01:00
|
|
|
it('sign and verify', async () => {
|
2020-08-07 15:23:02 +01:00
|
|
|
const data = uint8ArrayFromString('hello world')
|
2019-07-10 17:15:26 +01:00
|
|
|
const sig = await key.sign(data)
|
|
|
|
const valid = await key.public.verify(data, sig)
|
|
|
|
expect(valid).to.eql(true)
|
2016-12-23 08:52:40 -05:00
|
|
|
})
|
|
|
|
|
2019-07-10 17:15:26 +01:00
|
|
|
it('fails to verify for different data', async () => {
|
2020-08-07 15:23:02 +01:00
|
|
|
const data = uint8ArrayFromString('hello world')
|
2019-07-10 17:15:26 +01:00
|
|
|
const sig = await key.sign(data)
|
2020-08-07 15:23:02 +01:00
|
|
|
const valid = await key.public.verify(uint8ArrayFromString('hello'), sig)
|
2019-07-10 17:15:26 +01:00
|
|
|
expect(valid).to.be.eql(false)
|
2016-12-23 08:52:40 -05:00
|
|
|
})
|
|
|
|
|
2019-07-22 06:16:02 -04:00
|
|
|
describe('throws error instead of crashing', () => {
|
2017-12-01 09:36:29 +01:00
|
|
|
const key = crypto.keys.unmarshalPublicKey(fixtures.verify.publicKey)
|
2020-01-17 03:04:52 -08:00
|
|
|
testGarbage.doTests('key.verify', key.verify.bind(key), 2, null)
|
|
|
|
testGarbage.doTests('crypto.keys.unmarshalPrivateKey', crypto.keys.unmarshalPrivateKey.bind(crypto.keys), null, null)
|
2017-12-01 09:36:29 +01:00
|
|
|
})
|
|
|
|
|
2016-12-23 08:52:40 -05:00
|
|
|
describe('go interop', () => {
|
2020-01-17 03:04:52 -08:00
|
|
|
// @ts-check
|
2019-07-10 17:15:26 +01:00
|
|
|
it('verifies with data from go', async () => {
|
2017-07-22 10:57:27 -07:00
|
|
|
const key = crypto.keys.unmarshalPublicKey(fixtures.verify.publicKey)
|
2019-07-10 17:15:26 +01:00
|
|
|
const ok = await key.verify(fixtures.verify.data, fixtures.verify.signature)
|
|
|
|
expect(ok).to.eql(true)
|
2016-12-23 08:52:40 -05:00
|
|
|
})
|
|
|
|
|
2020-08-07 17:16:00 +02:00
|
|
|
it('does not include the redundant public key when marshalling privatekey', async () => {
|
|
|
|
const key = await crypto.keys.unmarshalPrivateKey(fixtures.redundantPubKey.privateKey)
|
|
|
|
const bytes = key.marshal()
|
|
|
|
expect(bytes.length).to.equal(64)
|
|
|
|
expect(bytes.slice(32)).to.eql(key.public.marshal())
|
|
|
|
})
|
|
|
|
|
2020-07-18 12:44:07 +02:00
|
|
|
it('verifies with data from go with redundant public key', async () => {
|
|
|
|
const key = crypto.keys.unmarshalPublicKey(fixtures.redundantPubKey.publicKey)
|
|
|
|
const ok = await key.verify(fixtures.redundantPubKey.data, fixtures.redundantPubKey.signature)
|
|
|
|
expect(ok).to.eql(true)
|
|
|
|
})
|
|
|
|
|
2019-07-10 17:15:26 +01:00
|
|
|
it('generates the same signature as go', async () => {
|
2020-07-18 12:44:07 +02:00
|
|
|
const key = await crypto.keys.unmarshalPrivateKey(fixtures.verify.privateKey)
|
|
|
|
const sig = await key.sign(fixtures.verify.data)
|
2019-07-10 17:15:26 +01:00
|
|
|
expect(sig).to.eql(fixtures.verify.signature)
|
2016-12-23 08:52:40 -05:00
|
|
|
})
|
2020-07-18 12:44:07 +02:00
|
|
|
|
|
|
|
it('generates the same signature as go with redundant public key', async () => {
|
|
|
|
const key = await crypto.keys.unmarshalPrivateKey(fixtures.redundantPubKey.privateKey)
|
|
|
|
const sig = await key.sign(fixtures.redundantPubKey.data)
|
|
|
|
expect(sig).to.eql(fixtures.redundantPubKey.signature)
|
|
|
|
})
|
2016-12-23 08:52:40 -05:00
|
|
|
})
|
|
|
|
})
|