2121import assert from 'bsert' ;
2222import elliptic from 'elliptic' ;
2323import BN from 'bn.js' ;
24+ import hashjs from 'hash.js' ;
2425import DRBG from 'hmac-drbg' ;
25- import sha256 from 'crypto-js/sha256' ;
2626import Signature from 'elliptic/lib/elliptic/ec/signature' ;
2727
2828const curve = elliptic . ec ( 'secp256k1' ) . curve ;
29+ // Public key is a point (x, y) on the curve.
30+ // Each coordinate requires 32 bytes.
31+ // In its compressed form it suffices to store the x co-ordinate
32+ // and the sign for y.
33+ // Hence a total of 33 bytes.
34+ const PUBKEY_COMPRESSED_SIZE_BYTES = 33 ;
2935
3036/**
3137 * Hash (r | M).
@@ -36,30 +42,34 @@ const curve = elliptic.ec('secp256k1').curve;
3642 */
3743
3844export const hash = ( q : BN , pubkey : Buffer , msg : Buffer ) => {
39- const totalLength = 66 + msg . byteLength ; // 33 q + 33 pubkey + variable msgLen
45+ const sha256 = hashjs . sha256 ( ) ;
46+ const totalLength = PUBKEY_COMPRESSED_SIZE_BYTES * 2 + msg . byteLength ; // 33 q + 33 pubkey + variable msgLen
4047 const Q = q . toArrayLike ( Buffer , 'be' , 33 ) ;
4148 const B = Buffer . allocUnsafe ( totalLength ) ;
4249
4350 Q . copy ( B , 0 ) ;
4451 pubkey . copy ( B , 33 ) ;
4552 msg . copy ( B , 66 ) ;
4653
47- return new BN ( sha256 . digest ( B ) ) ;
54+ return new BN ( sha256 . update ( B ) . digest ( 'hex' ) ) ;
4855} ;
4956
5057/**
51- * Sign message.
58+ * sign
59+ *
5260 * @param {Buffer } msg
5361 * @param {Buffer } key
54- * @param {Buffer } pubNonce
62+ * @param {Buffer } pubkey
63+ * @param {Buffer } pubNonce?
64+ *
5565 * @returns {Signature }
5666 */
5767export const sign = (
5868 msg : Buffer ,
5969 key : Buffer ,
6070 pubkey : Buffer ,
6171 pubNonce ?: Buffer ,
62- ) => {
72+ ) : Signature => {
6373 const prv = new BN ( key ) ;
6474 const drbg = getDRBG ( msg , key , pubNonce ) ;
6575 const len = curve . n . byteLength ( ) ;
@@ -77,38 +87,43 @@ export const sign = (
7787} ;
7888
7989/**
80- * Sign message.
90+ * trySign
8191 *
8292 * @param {Buffer } msg
83- * @param {BN } priv
84- * @param {BN } k
85- * @param {Buffer } pn
93+ * @param {BN } prv - private key
94+ * @param {BN } k - DRBG-generated random number
95+ * @param {Buffer } pn - optional
96+ * @param {Buffer) } pubKey - public key
8697 *
87- * @returns {Signature| null }
98+ * @returns {Signature | null => }
8899 */
89- const trySign = ( msg : Buffer , prv : BN , k : BN , pn : Buffer , pubKey : Buffer ) => {
100+ const trySign = ( msg : Buffer , prv : BN , k : BN , pn : Buffer , pubKey : Buffer ) : Signature | null => {
90101 if ( prv . isZero ( ) ) throw new Error ( 'Bad private key.' ) ;
91102
92103 if ( prv . gte ( curve . n ) ) throw new Error ( 'Bad private key.' ) ;
93104
105+ // 1a. check that k is not 0
94106 if ( k . isZero ( ) ) return null ;
95-
107+ // 1b. check that k is < the order of the group
96108 if ( k . gte ( curve . n ) ) return null ;
97109
110+ // 2. Compute commitment Q = kG, where g is the base point
98111 const Q = curve . g . mul ( k ) ;
112+ // convert the commitment to octets first
99113 const compressedQ = new BN ( Q . encodeCompressed ( ) ) ;
100114
101- const Q = curve . g . mul ( k ) ;
102- const compressedQ = new BN ( Q . encodeCompressed ( ) ) ;
103-
115+ // 3. Compute the challenge r = H(Q || pubKey || msg)
104116 const r = hash ( compressedQ , pubKey , msg ) ;
105117 const h = r . clone ( ) ;
106118
107119 if ( h . isZero ( ) ) return null ;
108120
109- if ( h . gte ( curve . n ) ) return null ;
121+ if ( h . eq ( curve . n ) ) return null ;
110122
123+ // 4. Compute s = k - r * prv
124+ // 4a. Compute r * prv
111125 let s = h . imul ( prv ) ;
126+ // 4b. Compute s = k - r * prv mod n
112127 s = k . isub ( s ) ;
113128 s = s . umod ( curve . n ) ;
114129
@@ -119,13 +134,20 @@ const trySign = (msg: Buffer, prv: BN, k: BN, pn: Buffer, pubKey: Buffer) => {
119134
120135/**
121136 * Verify signature.
137+ *
122138 * @param {Buffer } msg
123139 * @param {Buffer } signature
124140 * @param {Buffer } key
125- * @returns {Buffer }
141+ *
142+ * @returns {boolean }
143+ *
144+ * 1. Check if r,s is in [1, ..., order-1]
145+ * 2. Compute Q = sG + r*kpub
146+ * 3. If Q = O (the neutral point), return 0;
147+ * 4. r' = H(Q, kpub, m)
148+ * 5. return r' == r
126149 */
127-
128- export const verify = ( msg : Buffer , signature : Buffer , key : Buffer ) => {
150+ export const verify = ( msg : Buffer , signature : Signature , key : Buffer ) => {
129151 const sig = new Signature ( signature ) ;
130152
131153 if ( sig . s . gte ( curve . n ) ) throw new Error ( 'Invalid S value.' ) ;
@@ -159,8 +181,8 @@ export const alg = Buffer.from('Schnorr+SHA256 ', 'ascii');
159181 * Instantiate an HMAC-DRBG.
160182 *
161183 * @param {Buffer } msg
162- * @param {Buffer } priv
163- * @param {Buffer } data
184+ * @param {Buffer } priv - used as entropy input
185+ * @param {Buffer } data - used as nonce
164186 *
165187 * @returns {DRBG }
166188 */
@@ -177,14 +199,22 @@ export const getDRBG = (msg: Buffer, priv: Buffer, data?: Buffer) => {
177199
178200 alg . copy ( pers , 32 ) ;
179201
180- return new DRBG ( sha256 , priv , msg , pers ) ;
202+ // return new DRBG(sha256, priv, msg, pers);
203+ return new DRBG ( {
204+ hash : hashjs . sha256 ,
205+ entropy : priv ,
206+ nonce : msg ,
207+ pers,
208+ } ) ;
181209} ;
182210
183211/**
184212 * Generate pub+priv nonce pair.
213+ *
185214 * @param {Buffer } msg
186215 * @param {Buffer } priv
187216 * @param {Buffer } data
217+ *
188218 * @returns {Buffer }
189219 */
190220
0 commit comments