mirror of
https://github.com/fluencelabs/js-libp2p-crypto
synced 2025-03-15 17:20:58 +00:00
* Fix Ed25519 PeerID generation This commit pushes further fixes to the generation of Ed25519 peer IDs, building upon the discussion in ipfs/js-ipfs#3591 and the subsequent pull request libp2p/js-libp2p-crypto#185. The purpose of this new pull request is to harmonize the encoding of PeerIDs for Ed25519 keys such that the same new format is used everywhere: peer IDs when assigned upon key generation, peer IDs when shown via key listing, as well as the peer IDs displayed as IPNS names when the key is used as the basis for an IPNS record. Concretely, this changes the peer ID representation of Ed25519 keys from the `Qm...` format to the newer `1...` format. The accompanying test has been modified accordingly. * Satisfy linter
186 lines
6.4 KiB
JavaScript
186 lines
6.4 KiB
JavaScript
/* eslint-env mocha */
|
|
'use strict'
|
|
|
|
const chai = require('chai')
|
|
const dirtyChai = require('dirty-chai')
|
|
const expect = chai.expect
|
|
chai.use(dirtyChai)
|
|
const uint8ArrayFromString = require('uint8arrays/from-string')
|
|
|
|
const crypto = require('../../src')
|
|
const ed25519 = crypto.keys.supportedKeys.ed25519
|
|
const fixtures = require('../fixtures/go-key-ed25519')
|
|
|
|
const testGarbage = require('../helpers/test-garbage-error-handling')
|
|
|
|
/** @typedef {import("libp2p-crypto").PrivateKey} PrivateKey */
|
|
|
|
describe('ed25519', function () {
|
|
this.timeout(20 * 1000)
|
|
// @ts-check
|
|
/**
|
|
* @type {PrivateKey}
|
|
*/
|
|
let key
|
|
before(async () => {
|
|
key = await crypto.keys.generateKeyPair('Ed25519', 512)
|
|
})
|
|
|
|
it('generates a valid key', async () => {
|
|
expect(key).to.be.an.instanceof(ed25519.Ed25519PrivateKey)
|
|
const digest = await key.hash()
|
|
expect(digest).to.have.length(34)
|
|
})
|
|
|
|
it('generates a valid key from seed', async () => {
|
|
var seed = crypto.randomBytes(32)
|
|
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)
|
|
})
|
|
|
|
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)
|
|
})
|
|
|
|
it('generates different keys for different seeds', async () => {
|
|
const seed1 = crypto.randomBytes(32)
|
|
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)
|
|
})
|
|
|
|
it('signs', async () => {
|
|
const text = crypto.randomBytes(512)
|
|
const sig = await key.sign(text)
|
|
const res = await key.public.verify(text, sig)
|
|
expect(res).to.be.eql(true)
|
|
})
|
|
|
|
it('encoding', async () => {
|
|
const keyMarshal = key.marshal()
|
|
const key2 = await ed25519.unmarshalEd25519PrivateKey(keyMarshal)
|
|
const keyMarshal2 = key2.marshal()
|
|
|
|
expect(keyMarshal).to.eql(keyMarshal2)
|
|
|
|
const pk = key.public
|
|
const pkMarshal = pk.marshal()
|
|
const pk2 = ed25519.unmarshalEd25519PublicKey(pkMarshal)
|
|
const pkMarshal2 = pk2.marshal()
|
|
|
|
expect(pkMarshal).to.eql(pkMarshal2)
|
|
})
|
|
|
|
it('key id', async () => {
|
|
const key = await crypto.keys.unmarshalPrivateKey(fixtures.verify.privateKey)
|
|
const id = await key.id()
|
|
expect(id).to.eql('12D3KooWLqLxEfJ9nDdEe8Kh8PFvNPQRYDQBwyL7CMM7HhVd5LsX')
|
|
})
|
|
|
|
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')
|
|
})
|
|
|
|
describe('key equals', () => {
|
|
it('equals itself', () => {
|
|
expect(
|
|
key.equals(key)
|
|
).to.eql(
|
|
true
|
|
)
|
|
|
|
expect(
|
|
key.public.equals(key.public)
|
|
).to.eql(
|
|
true
|
|
)
|
|
})
|
|
|
|
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)
|
|
})
|
|
})
|
|
|
|
it('sign and verify', async () => {
|
|
const data = uint8ArrayFromString('hello world')
|
|
const sig = await key.sign(data)
|
|
const valid = await key.public.verify(data, sig)
|
|
expect(valid).to.eql(true)
|
|
})
|
|
|
|
it('fails to verify for different data', async () => {
|
|
const data = uint8ArrayFromString('hello world')
|
|
const sig = await key.sign(data)
|
|
const valid = await key.public.verify(uint8ArrayFromString('hello'), sig)
|
|
expect(valid).to.be.eql(false)
|
|
})
|
|
|
|
describe('throws error instead of crashing', () => {
|
|
const key = crypto.keys.unmarshalPublicKey(fixtures.verify.publicKey)
|
|
testGarbage.doTests('key.verify', key.verify.bind(key), 2, null)
|
|
testGarbage.doTests('crypto.keys.unmarshalPrivateKey', crypto.keys.unmarshalPrivateKey.bind(crypto.keys), null, null)
|
|
})
|
|
|
|
describe('go interop', () => {
|
|
// @ts-check
|
|
it('verifies with data from go', async () => {
|
|
const key = crypto.keys.unmarshalPublicKey(fixtures.verify.publicKey)
|
|
const ok = await key.verify(fixtures.verify.data, fixtures.verify.signature)
|
|
expect(ok).to.eql(true)
|
|
})
|
|
|
|
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())
|
|
})
|
|
|
|
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)
|
|
})
|
|
|
|
it('generates the same signature as go', async () => {
|
|
const key = await crypto.keys.unmarshalPrivateKey(fixtures.verify.privateKey)
|
|
const sig = await key.sign(fixtures.verify.data)
|
|
expect(sig).to.eql(fixtures.verify.signature)
|
|
})
|
|
|
|
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)
|
|
})
|
|
})
|
|
})
|