Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
80621 views
1
'use strict';
2
3
var bn = require('bn.js');
4
var elliptic = require('../../elliptic');
5
var utils = elliptic.utils;
6
var assert = utils.assert;
7
8
var KeyPair = require('./key');
9
var Signature = require('./signature');
10
11
function EC(options) {
12
if (!(this instanceof EC))
13
return new EC(options);
14
15
// Shortcut `elliptic.ec(curve-name)`
16
if (typeof options === 'string') {
17
assert(elliptic.curves.hasOwnProperty(options), 'Unknown curve ' + options);
18
19
options = elliptic.curves[options];
20
}
21
22
// Shortcut for `elliptic.ec(elliptic.curves.curveName)`
23
if (options instanceof elliptic.curves.PresetCurve)
24
options = { curve: options };
25
26
this.curve = options.curve.curve;
27
this.n = this.curve.n;
28
this.nh = this.n.shrn(1);
29
this.g = this.curve.g;
30
31
// Point on curve
32
this.g = options.curve.g;
33
this.g.precompute(options.curve.n.bitLength() + 1);
34
35
// Hash for function for DRBG
36
this.hash = options.hash || options.curve.hash;
37
}
38
module.exports = EC;
39
40
EC.prototype.keyPair = function keyPair(options) {
41
return new KeyPair(this, options);
42
};
43
44
EC.prototype.keyFromPrivate = function keyFromPrivate(priv, enc) {
45
return KeyPair.fromPrivate(this, priv, enc);
46
};
47
48
EC.prototype.keyFromPublic = function keyFromPublic(pub, enc) {
49
return KeyPair.fromPublic(this, pub, enc);
50
};
51
52
EC.prototype.genKeyPair = function genKeyPair(options) {
53
if (!options)
54
options = {};
55
56
// Instantiate Hmac_DRBG
57
var drbg = new elliptic.hmacDRBG({
58
hash: this.hash,
59
pers: options.pers,
60
entropy: options.entropy || elliptic.rand(this.hash.hmacStrength),
61
nonce: this.n.toArray()
62
});
63
64
var bytes = this.n.byteLength();
65
var ns2 = this.n.sub(new bn(2));
66
do {
67
var priv = new bn(drbg.generate(bytes));
68
if (priv.cmp(ns2) > 0)
69
continue;
70
71
priv.iaddn(1);
72
return this.keyFromPrivate(priv);
73
} while (true);
74
};
75
76
EC.prototype._truncateToN = function truncateToN(msg, truncOnly) {
77
var delta = msg.byteLength() * 8 - this.n.bitLength();
78
if (delta > 0)
79
msg = msg.shrn(delta);
80
if (!truncOnly && msg.cmp(this.n) >= 0)
81
return msg.sub(this.n);
82
else
83
return msg;
84
};
85
86
EC.prototype.sign = function sign(msg, key, enc, options) {
87
if (typeof enc === 'object') {
88
options = enc;
89
enc = null;
90
}
91
if (!options)
92
options = {};
93
94
key = this.keyFromPrivate(key, enc);
95
msg = this._truncateToN(new bn(msg, 16));
96
97
// Zero-extend key to provide enough entropy
98
var bytes = this.n.byteLength();
99
var bkey = key.getPrivate().toArray();
100
for (var i = bkey.length; i < 21; i++)
101
bkey.unshift(0);
102
103
// Zero-extend nonce to have the same byte size as N
104
var nonce = msg.toArray();
105
for (var i = nonce.length; i < bytes; i++)
106
nonce.unshift(0);
107
108
// Instantiate Hmac_DRBG
109
var drbg = new elliptic.hmacDRBG({
110
hash: this.hash,
111
entropy: bkey,
112
nonce: nonce
113
});
114
115
// Number of bytes to generate
116
var ns1 = this.n.sub(new bn(1));
117
do {
118
var k = new bn(drbg.generate(this.n.byteLength()));
119
k = this._truncateToN(k, true);
120
if (k.cmpn(1) <= 0 || k.cmp(ns1) >= 0)
121
continue;
122
123
var kp = this.g.mul(k);
124
if (kp.isInfinity())
125
continue;
126
127
var r = kp.getX().mod(this.n);
128
if (r.cmpn(0) === 0)
129
continue;
130
131
var s = k.invm(this.n).mul(r.mul(key.getPrivate()).iadd(msg)).mod(this.n);
132
if (s.cmpn(0) === 0)
133
continue;
134
135
// Use complement of `s`, if it is > `n / 2`
136
if (options.canonical && s.cmp(this.nh) > 0)
137
s = this.n.sub(s);
138
139
return new Signature({ r: r, s: s });
140
} while (true);
141
};
142
143
EC.prototype.verify = function verify(msg, signature, key, enc) {
144
msg = this._truncateToN(new bn(msg, 16));
145
key = this.keyFromPublic(key, enc);
146
signature = new Signature(signature, 'hex');
147
148
// Perform primitive values validation
149
var r = signature.r;
150
var s = signature.s;
151
if (r.cmpn(1) < 0 || r.cmp(this.n) >= 0)
152
return false;
153
if (s.cmpn(1) < 0 || s.cmp(this.n) >= 0)
154
return false;
155
156
// Validate signature
157
var sinv = s.invm(this.n);
158
var u1 = sinv.mul(msg).mod(this.n);
159
var u2 = sinv.mul(r).mod(this.n);
160
161
var p = this.g.mulAdd(u1, key.getPublic(), u2);
162
if (p.isInfinity())
163
return false;
164
165
return p.getX().mod(this.n).cmp(r) === 0;
166
};
167
168