Skip to content
This repository has been archived by the owner on Jul 21, 2023. It is now read-only.

Commit

Permalink
feat(keys): implement generateKeyPairFromSeed for ed25519
Browse files Browse the repository at this point in the history
Implement generateKeyPairFromSeed for ed25519 - this will produce the same keypair for the same seed (or first 32 bytes of reader) as given to GenerateKeyPairWithReader in go-libp2p.
  • Loading branch information
jackkleeman authored and dignifiedquire committed Mar 3, 2017
1 parent 2032619 commit e5b7c1f
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 1 deletion.
16 changes: 16 additions & 0 deletions src/crypto/ed25519.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,22 @@ exports.generateKey = function (callback) {
done(null, keys)
}

// seed should be a 32 byte uint8array
exports.generateKeyFromSeed = function (seed, callback) {
const done = (err, res) => setImmediate(() => {
callback(err, res)
})

let keys
try {
keys = nacl.sign.keyPair.fromSeed(seed)
} catch (err) {
done(err)
return
}
done(null, keys)
}

exports.hashAndSign = function (key, msg, callback) {
setImmediate(() => {
callback(null, Buffer.from(nacl.sign.detached(msg, key)))
Expand Down
13 changes: 13 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,19 @@ exports.generateKeyPair = (type, bits, cb) => {
key.generateKeyPair(bits, cb)
}

// Generates a keypair of the given type and bitsize
// seed is a 32 byte uint8array
exports.generateKeyPairFromSeed = (type, seed, bits, cb) => {
let key = keys[type.toLowerCase()]
if (!key) {
return cb(new Error('invalid or unsupported key type'))
}
if (type.toLowerCase() !== 'ed25519') {
return cb(new Error('Seed key derivation is unimplemented for RSA or secp256k1'))
}
key.generateKeyPairFromSeed(seed, bits, cb)
}

// Converts a protobuf serialized public key into its
// representative object
exports.unmarshalPublicKey = (buf) => {
Expand Down
24 changes: 23 additions & 1 deletion src/keys/ed25519.js
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,27 @@ function generateKeyPair (_bits, cb) {
})
}

function generateKeyPairFromSeed (seed, _bits, cb) {
if (cb === undefined && typeof _bits === 'function') {
cb = _bits
}

crypto.generateKeyFromSeed(seed, (err, keys) => {
if (err) {
return cb(err)
}
let privkey
try {
privkey = new Ed25519PrivateKey(keys.secretKey, keys.publicKey)
} catch (err) {
cb(err)
return
}

cb(null, privkey)
})
}

function ensure (cb) {
if (typeof cb !== 'function') {
throw new Error('callback is required')
Expand All @@ -138,5 +159,6 @@ module.exports = {
Ed25519PrivateKey,
unmarshalEd25519PrivateKey,
unmarshalEd25519PublicKey,
generateKeyPair
generateKeyPair,
generateKeyPairFromSeed
}
64 changes: 64 additions & 0 deletions test/ed25519.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,70 @@ describe('ed25519', () => {
})
})

it('generates a valid key from seed', (done) => {
var seed = crypto.randomBytes(32)
crypto.generateKeyPairFromSeed('Ed25519', seed, 512, (err, seededkey) => {
if (err) return done(err)
expect(
seededkey
).to.be.an.instanceof(
ed25519.Ed25519PrivateKey
)

seededkey.hash((err, digest) => {
if (err) {
return done(err)
}

expect(digest).to.have.length(34)
done()
})
})
})

it('generates the same key from the same seed', (done) => {
var seed = crypto.randomBytes(32)
crypto.generateKeyPairFromSeed('Ed25519', seed, 512, (err, seededkey1) => {
if (err) return done(err)
crypto.generateKeyPairFromSeed('Ed25519', seed, 512, (err, seededkey2) => {
if (err) return done(err)
expect(
seededkey1.equals(seededkey2)
).to.be.eql(
true
)
expect(
seededkey1.public.equals(seededkey2.public)
).to.be.eql(
true
)
done()
})
})
})

it('generates different keys for different seeds', (done) => {
var seed1 = crypto.randomBytes(32)
crypto.generateKeyPairFromSeed('Ed25519', seed1, 512, (err, seededkey1) => {
if (err) return done(err)
var seed2 = crypto.randomBytes(32)
crypto.generateKeyPairFromSeed('Ed25519', seed2, 512, (err, seededkey2) => {
if (err) return done(err)
expect(
seededkey1.equals(seededkey2)
).to.be.eql(
false
)
expect(
seededkey1.public.equals(seededkey2.public)
).to.be.eql(
false
)
done()
})
})
})

it('signs', (done) => {
const text = crypto.randomBytes(512)

Expand Down

0 comments on commit e5b7c1f

Please sign in to comment.