This repository has been archived by the owner on Jul 21, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 52
/
ed25519-class.js
155 lines (130 loc) · 4.28 KB
/
ed25519-class.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
'use strict'
const errcode = require('err-code')
const { equals: uint8ArrayEquals } = require('uint8arrays/equals')
const { sha256 } = require('multiformats/hashes/sha2')
const { base58btc } = require('multiformats/bases/base58')
const { identity } = require('multiformats/hashes/identity')
const crypto = require('./ed25519')
const pbm = require('./keys')
const exporter = require('./exporter')
class Ed25519PublicKey {
constructor (key) {
this._key = ensureKey(key, crypto.publicKeyLength)
}
async verify (data, sig) { // eslint-disable-line require-await
return crypto.hashAndVerify(this._key, sig, data)
}
marshal () {
return this._key
}
get bytes () {
return pbm.PublicKey.encode({
Type: pbm.KeyType.Ed25519,
Data: this.marshal()
}).finish()
}
equals (key) {
return uint8ArrayEquals(this.bytes, key.bytes)
}
async hash () {
const { bytes } = await sha256.digest(this.bytes)
return bytes
}
}
class Ed25519PrivateKey {
// key - 64 byte Uint8Array containing private key
// publicKey - 32 byte Uint8Array containing public key
constructor (key, publicKey) {
this._key = ensureKey(key, crypto.privateKeyLength)
this._publicKey = ensureKey(publicKey, crypto.publicKeyLength)
}
async sign (message) { // eslint-disable-line require-await
return crypto.hashAndSign(this._key, message)
}
get public () {
return new Ed25519PublicKey(this._publicKey)
}
marshal () {
return this._key
}
get bytes () {
return pbm.PrivateKey.encode({
Type: pbm.KeyType.Ed25519,
Data: this.marshal()
}).finish()
}
equals (key) {
return uint8ArrayEquals(this.bytes, key.bytes)
}
async hash () {
const { bytes } = await sha256.digest(this.bytes)
return bytes
}
/**
* Gets the ID of the key.
*
* The key id is the base58 encoding of the identity multihash containing its public key.
* The public key is a protobuf encoding containing a type and the DER encoding
* of the PKCS SubjectPublicKeyInfo.
*
* @returns {Promise<string>}
*/
async id () {
const encoding = await identity.digest(this.public.bytes)
return base58btc.encode(encoding.bytes).substring(1)
}
/**
* Exports the key into a password protected `format`
*
* @param {string} password - The password to encrypt the key
* @param {string} [format=libp2p-key] - The format in which to export as
* @returns {Promise<Uint8Array>} The encrypted private key
*/
async export (password, format = 'libp2p-key') { // eslint-disable-line require-await
if (format === 'libp2p-key') {
return exporter.export(this.bytes, password)
} else {
throw errcode(new Error(`export format '${format}' is not supported`), 'ERR_INVALID_EXPORT_FORMAT')
}
}
}
function unmarshalEd25519PrivateKey (bytes) {
// Try the old, redundant public key version
if (bytes.length > crypto.privateKeyLength) {
bytes = ensureKey(bytes, crypto.privateKeyLength + crypto.publicKeyLength)
const privateKeyBytes = bytes.slice(0, crypto.privateKeyLength)
const publicKeyBytes = bytes.slice(crypto.privateKeyLength, bytes.length)
return new Ed25519PrivateKey(privateKeyBytes, publicKeyBytes)
}
bytes = ensureKey(bytes, crypto.privateKeyLength)
const privateKeyBytes = bytes.slice(0, crypto.privateKeyLength)
const publicKeyBytes = bytes.slice(crypto.publicKeyLength)
return new Ed25519PrivateKey(privateKeyBytes, publicKeyBytes)
}
function unmarshalEd25519PublicKey (bytes) {
bytes = ensureKey(bytes, crypto.publicKeyLength)
return new Ed25519PublicKey(bytes)
}
async function generateKeyPair () {
const { privateKey, publicKey } = await crypto.generateKey()
return new Ed25519PrivateKey(privateKey, publicKey)
}
async function generateKeyPairFromSeed (seed) {
const { privateKey, publicKey } = await crypto.generateKeyFromSeed(seed)
return new Ed25519PrivateKey(privateKey, publicKey)
}
function ensureKey (key, length) {
key = Uint8Array.from(key || [])
if (key.length !== length) {
throw errcode(new Error(`Key must be a Uint8Array of length ${length}, got ${key.length}`), 'ERR_INVALID_KEY_TYPE')
}
return key
}
module.exports = {
Ed25519PublicKey,
Ed25519PrivateKey,
unmarshalEd25519PrivateKey,
unmarshalEd25519PublicKey,
generateKeyPair,
generateKeyPairFromSeed
}