Skip to content

Commit e91fe6f

Browse files
committed
Minor shufflings
1 parent c00b81b commit e91fe6f

File tree

5 files changed

+61
-58
lines changed

5 files changed

+61
-58
lines changed

index.d.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -183,9 +183,9 @@ declare const sign: (message: Bytes, secretKey: Bytes, opts?: ECDSASignOpts) =>
183183
declare const signAsync: (message: Bytes, secretKey: Bytes, opts?: ECDSASignOpts) => Promise<Bytes>;
184184
/**
185185
* Verify a signature using secp256k1. Sync: uses `hashes.sha256` and `hashes.hmacSha256`.
186-
* @param signature - signature, default is 64-byte "compact" format
187-
* @param message - message which has been signed
188-
* @param publicKey - public key
186+
* @param signature - default is 64-byte 'compact' format, also see {@link ECDSASignatureFormat}
187+
* @param message - message which was signed. Keep in mind `prehash` from opts.
188+
* @param publicKey - public key which
189189
* @param opts - see {@link ECDSAVerifyOpts} for details.
190190
* @example
191191
* ```js
@@ -199,9 +199,9 @@ declare const signAsync: (message: Bytes, secretKey: Bytes, opts?: ECDSASignOpts
199199
declare const verify: (signature: Bytes, message: Bytes, publicKey: Bytes, opts?: ECDSAVerifyOpts) => boolean;
200200
/**
201201
* Verify a signature using secp256k1. Async: uses built-in WebCrypto hashes.
202-
* @param signature - signature, default is 64-byte "compact" format
203-
* @param message - message which has been signed
204-
* @param publicKey - public key
202+
* @param signature - default is 64-byte 'compact' format, also see {@link ECDSASignatureFormat}
203+
* @param message - message which was signed. Keep in mind `prehash` from opts.
204+
* @param publicKey - public key which
205205
* @param opts - see {@link ECDSAVerifyOpts} for details.
206206
* @example
207207
* ```js

index.js

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -143,11 +143,11 @@ const apoint = (p) => (p instanceof Point ? p : err('Point expected'));
143143
// -----------------
144144
/** secp256k1 formula. Koblitz curves are subclass of weierstrass curves with a=0, making it x³+b */
145145
const koblitz = (x) => M(M(x * x) * x + _b);
146-
/** assert is field element, including 0 */
146+
/** assert is element of field mod P (incl. 0) */
147147
const FpIsValid = (n) => arange(n, 0n, P);
148-
/** assert is field element and not 0 */
148+
/** assert is element of field mod P (excl. 0) */
149149
const FpIsValidNot0 = (n) => arange(n, 1n, P);
150-
/** assert is group elem */
150+
/** assert is element of field mod N (excl. 0) */
151151
const FnIsValidNot0 = (n) => arange(n, 1n, N);
152152
const isEven = (y) => (y & 1n) === 0n;
153153
/** create Uint8Array of byte n */
@@ -514,11 +514,11 @@ const hashes = {
514514
sha256Async: async (msg) => u8n(await subtle().digest(_sha, msg)),
515515
sha256: undefined,
516516
};
517-
const callPrehash = (asynchronous, message, opts) => {
518-
abytes(message, undefined, 'message');
517+
const prepMsg = (msg, opts, async_) => {
518+
abytes(msg, undefined, 'message');
519519
if (!opts.prehash)
520-
return message;
521-
return asynchronous ? hashes.sha256Async(message) : callHash('sha256')(message);
520+
return msg;
521+
return async_ ? hashes.sha256Async(msg) : callHash('sha256')(msg);
522522
};
523523
const NULL = u8n(0);
524524
const byte0 = u8of(0x00);
@@ -560,6 +560,7 @@ const hmacDrbg = (seed, pred) => {
560560
reset();
561561
return res;
562562
};
563+
// Identical to hmacDrbg, but async: uses built-in WebCrypto
563564
const hmacDrbgAsync = async (seed, pred) => {
564565
let v = u8n(L); // Steps B, C of RFC6979 3.2: set hashLen
565566
let k = u8n(L); // In our case, it's always equal to L
@@ -695,7 +696,7 @@ const setDefaults = (opts) => {
695696
*/
696697
const sign = (message, secretKey, opts = {}) => {
697698
opts = setDefaults(opts);
698-
message = callPrehash(false, message, opts);
699+
message = prepMsg(message, opts, false);
699700
return _sign(message, secretKey, opts, hmacDrbg);
700701
};
701702
/**
@@ -713,14 +714,14 @@ const sign = (message, secretKey, opts = {}) => {
713714
*/
714715
const signAsync = async (message, secretKey, opts = {}) => {
715716
opts = setDefaults(opts);
716-
message = await callPrehash(true, message, opts);
717+
message = await prepMsg(message, opts, true);
717718
return _sign(message, secretKey, opts, hmacDrbgAsync);
718719
};
719720
/**
720721
* Verify a signature using secp256k1. Sync: uses `hashes.sha256` and `hashes.hmacSha256`.
721-
* @param signature - signature, default is 64-byte "compact" format
722-
* @param message - message which has been signed
723-
* @param publicKey - public key
722+
* @param signature - default is 64-byte 'compact' format, also see {@link ECDSASignatureFormat}
723+
* @param message - message which was signed. Keep in mind `prehash` from opts.
724+
* @param publicKey - public key which
724725
* @param opts - see {@link ECDSAVerifyOpts} for details.
725726
* @example
726727
* ```js
@@ -733,14 +734,14 @@ const signAsync = async (message, secretKey, opts = {}) => {
733734
*/
734735
const verify = (signature, message, publicKey, opts = {}) => {
735736
opts = setDefaults(opts);
736-
message = callPrehash(false, message, opts);
737+
message = prepMsg(message, opts, false);
737738
return _verify(signature, message, publicKey, opts);
738739
};
739740
/**
740741
* Verify a signature using secp256k1. Async: uses built-in WebCrypto hashes.
741-
* @param signature - signature, default is 64-byte "compact" format
742-
* @param message - message which has been signed
743-
* @param publicKey - public key
742+
* @param signature - default is 64-byte 'compact' format, also see {@link ECDSASignatureFormat}
743+
* @param message - message which was signed. Keep in mind `prehash` from opts.
744+
* @param publicKey - public key which
744745
* @param opts - see {@link ECDSAVerifyOpts} for details.
745746
* @example
746747
* ```js
@@ -753,7 +754,7 @@ const verify = (signature, message, publicKey, opts = {}) => {
753754
*/
754755
const verifyAsync = async (sig, message, publicKey, opts = {}) => {
755756
opts = setDefaults(opts);
756-
message = await callPrehash(true, message, opts);
757+
message = await prepMsg(message, opts, true);
757758
return _verify(sig, message, publicKey, opts);
758759
};
759760
const _recover = (signature, messageHash) => {
@@ -779,11 +780,11 @@ const _recover = (signature, messageHash) => {
779780
* Follows [SEC1](https://secg.org/sec1-v2.pdf) 4.1.6.
780781
*/
781782
const recoverPublicKey = (signature, message, opts = {}) => {
782-
message = callPrehash(false, message, setDefaults(opts));
783+
message = prepMsg(message, setDefaults(opts), false);
783784
return _recover(signature, message);
784785
};
785786
const recoverPublicKeyAsync = async (signature, message, opts = {}) => {
786-
message = await callPrehash(true, message, setDefaults(opts));
787+
message = await prepMsg(message, setDefaults(opts), true);
787788
return _recover(signature, message);
788789
};
789790
/**

index.ts

Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ const abytes = (value: Bytes, length?: number, title: string = ''): Bytes => {
7979
return value;
8080
};
8181
/** create Uint8Array */
82-
const u8n = (len: number): Uint8Array => new Uint8Array(len);
82+
const u8n = (len: number): Bytes => new Uint8Array(len);
8383
const padh = (n: number | bigint, pad: number) => n.toString(16).padStart(pad, '0');
8484
const bytesToHex = (b: Bytes): string =>
8585
Array.from(abytes(b))
@@ -162,15 +162,15 @@ export type AffinePoint = {
162162

163163
/** secp256k1 formula. Koblitz curves are subclass of weierstrass curves with a=0, making it x³+b */
164164
const koblitz = (x: bigint) => M(M(x * x) * x + _b);
165-
/** assert is field element, including 0 */
165+
/** assert is element of field mod P (incl. 0) */
166166
const FpIsValid = (n: bigint) => arange(n, 0n, P);
167-
/** assert is field element and not 0 */
167+
/** assert is element of field mod P (excl. 0) */
168168
const FpIsValidNot0 = (n: bigint) => arange(n, 1n, P);
169-
/** assert is group elem */
169+
/** assert is element of field mod N (excl. 0) */
170170
const FnIsValidNot0 = (n: bigint) => arange(n, 1n, N);
171171
const isEven = (y: bigint) => (y & 1n) === 0n;
172172
/** create Uint8Array of byte n */
173-
const u8of = (n: number) => Uint8Array.of(n);
173+
const u8of = (n: number): Bytes => Uint8Array.of(n);
174174
const getPrefix = (y: bigint) => u8of(isEven(y) ? 0x02 : 0x03);
175175
/** lift_x from BIP340 calculates square root. Validates x, then validates root*root. */
176176
const lift_x = (x: bigint) => {
@@ -559,10 +559,10 @@ const hashes = {
559559
sha256: undefined as undefined | ((message: Bytes) => Bytes),
560560
};
561561

562-
const callPrehash = (asynchronous: boolean, message: Bytes, opts: { prehash?: boolean }) => {
563-
abytes(message, undefined, 'message');
564-
if (!opts.prehash) return message;
565-
return asynchronous ? hashes.sha256Async(message) : callHash('sha256')(message);
562+
const prepMsg = (msg: Bytes, opts: ECDSARecoverOpts, async_: boolean): Bytes | Promise<Bytes> => {
563+
abytes(msg, undefined, 'message');
564+
if (!opts.prehash) return msg;
565+
return async_ ? hashes.sha256Async(msg) : callHash('sha256')(msg);
566566
};
567567

568568
type Pred<T> = (v: Bytes) => T | undefined;
@@ -572,7 +572,7 @@ const byte1 = u8of(0x01);
572572
const _maxDrbgIters = 1000;
573573
const _drbgErr = 'drbg: tried max amount of iterations';
574574
// HMAC-DRBG from NIST 800-90. Minimal, non-full-spec - used for RFC6979 signatures.
575-
const hmacDrbg = <T>(seed: Bytes, pred: Pred<T>): T => {
575+
const hmacDrbg = (seed: Bytes, pred: Pred<Bytes>): Bytes => {
576576
let v = u8n(L); // Steps B, C of RFC6979 3.2: set hashLen
577577
let k = u8n(L); // In our case, it's always equal to L
578578
let i = 0; // Iterations counter, will throw when over max
@@ -598,13 +598,14 @@ const hmacDrbg = <T>(seed: Bytes, pred: Pred<T>): T => {
598598
};
599599
reset();
600600
reseed(seed); // Steps D-G
601-
let res: T | undefined = undefined; // Step H: grind until k is in [1..n-1]
601+
let res: Bytes | undefined = undefined; // Step H: grind until k is in [1..n-1]
602602
while (!(res = pred(gen()))) reseed(); // test predicate until it returns ok
603603
reset();
604604
return res!;
605605
};
606606

607-
const hmacDrbgAsync = async <T>(seed: Bytes, pred: Pred<T>): Promise<T> => {
607+
// Identical to hmacDrbg, but async: uses built-in WebCrypto
608+
const hmacDrbgAsync = async (seed: Bytes, pred: Pred<Bytes>): Promise<Bytes> => {
608609
let v = u8n(L); // Steps B, C of RFC6979 3.2: set hashLen
609610
let k = u8n(L); // In our case, it's always equal to L
610611
let i = 0; // Iterations counter, will throw when over max
@@ -630,7 +631,7 @@ const hmacDrbgAsync = async <T>(seed: Bytes, pred: Pred<T>): Promise<T> => {
630631
};
631632
reset();
632633
await reseed(seed); // Steps D-G
633-
let res: T | undefined = undefined; // Step H: grind until k is in [1..n-1]
634+
let res: Bytes | undefined = undefined; // Step H: grind until k is in [1..n-1]
634635
while (!(res = pred(await gen()))) await reseed(); // test predicate until it returns ok
635636
reset();
636637
return res!;
@@ -739,7 +740,7 @@ const setDefaults = (opts: ECDSASignOpts): Required<ECDSASignOpts> => {
739740
*/
740741
const sign = (message: Bytes, secretKey: Bytes, opts: ECDSASignOpts = {}): Bytes => {
741742
opts = setDefaults(opts);
742-
message = callPrehash(false, message, opts);
743+
message = prepMsg(message, opts, false) as Bytes;
743744
return _sign(message, secretKey, opts, hmacDrbg);
744745
};
745746

@@ -762,15 +763,15 @@ const signAsync = async (
762763
opts: ECDSASignOpts = {}
763764
): Promise<Bytes> => {
764765
opts = setDefaults(opts);
765-
message = await callPrehash(true, message, opts);
766+
message = await prepMsg(message, opts, true);
766767
return _sign(message, secretKey, opts, hmacDrbgAsync);
767768
};
768769

769770
/**
770771
* Verify a signature using secp256k1. Sync: uses `hashes.sha256` and `hashes.hmacSha256`.
771-
* @param signature - signature, default is 64-byte "compact" format
772-
* @param message - message which has been signed
773-
* @param publicKey - public key
772+
* @param signature - default is 64-byte 'compact' format, also see {@link ECDSASignatureFormat}
773+
* @param message - message which was signed. Keep in mind `prehash` from opts.
774+
* @param publicKey - public key which
774775
* @param opts - see {@link ECDSAVerifyOpts} for details.
775776
* @example
776777
* ```js
@@ -788,15 +789,15 @@ const verify = (
788789
opts: ECDSAVerifyOpts = {}
789790
): boolean => {
790791
opts = setDefaults(opts);
791-
message = callPrehash(false, message, opts);
792+
message = prepMsg(message, opts, false) as Bytes;
792793
return _verify(signature, message, publicKey, opts);
793794
};
794795

795796
/**
796797
* Verify a signature using secp256k1. Async: uses built-in WebCrypto hashes.
797-
* @param signature - signature, default is 64-byte "compact" format
798-
* @param message - message which has been signed
799-
* @param publicKey - public key
798+
* @param signature - default is 64-byte 'compact' format, also see {@link ECDSASignatureFormat}
799+
* @param message - message which was signed. Keep in mind `prehash` from opts.
800+
* @param publicKey - public key which
800801
* @param opts - see {@link ECDSAVerifyOpts} for details.
801802
* @example
802803
* ```js
@@ -814,7 +815,7 @@ const verifyAsync = async (
814815
opts: ECDSAVerifyOpts = {}
815816
): Promise<boolean> => {
816817
opts = setDefaults(opts);
817-
message = await callPrehash(true, message, opts);
818+
message = await prepMsg(message, opts, true);
818819
return _verify(sig, message, publicKey, opts);
819820
};
820821

@@ -842,7 +843,7 @@ const _recover = (signature: Bytes, messageHash: Bytes) => {
842843
* Follows [SEC1](https://secg.org/sec1-v2.pdf) 4.1.6.
843844
*/
844845
const recoverPublicKey = (signature: Bytes, message: Bytes, opts: ECDSARecoverOpts = {}): Bytes => {
845-
message = callPrehash(false, message, setDefaults(opts));
846+
message = prepMsg(message, setDefaults(opts), false) as Bytes;
846847
return _recover(signature, message);
847848
};
848849

@@ -851,7 +852,7 @@ const recoverPublicKeyAsync = async (
851852
message: Bytes,
852853
opts: ECDSARecoverOpts = {}
853854
): Promise<Bytes> => {
854-
message = await callPrehash(true, message, setDefaults(opts));
855+
message = await prepMsg(message, setDefaults(opts), true);
855856
return _recover(signature, message);
856857
};
857858

@@ -1166,5 +1167,6 @@ export {
11661167
Signature,
11671168
utils,
11681169
verify,
1169-
verifyAsync,
1170+
verifyAsync
11701171
};
1172+

test/point.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,7 @@ describe('basic curve tests', () => {
341341
}
342342
throws(() => C.getPublicKey('key'), "'key'");
343343
throws(() => C.getPublicKey({}));
344-
throws(() => C.getPublicKey(new Uint8Array([])));
344+
throws(() => C.getPublicKey(Uint8Array.of()));
345345
throws(() => C.getPublicKey(Array(32).fill(1)));
346346
});
347347

@@ -374,7 +374,7 @@ describe('basic curve tests', () => {
374374
// )
375375
// );
376376
should('.verify() should verify empty signatures', () => {
377-
const msg = new Uint8Array([]);
377+
const msg = Uint8Array.of();
378378
const k = C.keygen();
379379
const sig = C.sign(msg, k.secretKey);
380380
eql(
@@ -385,7 +385,7 @@ describe('basic curve tests', () => {
385385
});
386386

387387
should('.sign() type tests', () => {
388-
const msg = new Uint8Array([]);
388+
const msg = Uint8Array.of();
389389
const k = C.keygen();
390390
C.sign(msg, k.secretKey);
391391
for (let [item, repr_] of getTypeTests()) {
@@ -493,7 +493,7 @@ describe('basic curve tests', () => {
493493
}
494494

495495
// NOTE: fails for ed, because of empty message. Since we convert it to scalar,
496-
// need to check what other implementations do. Empty message != new Uint8Array([0]), but what scalar should be in that case?
496+
// need to check what other implementations do. Empty message != Uint8Array.of(0), but what scalar should be in that case?
497497
// should('should not verify signature with wrong message', () => {
498498
// fc.assert(
499499
// fc.property(

test/utils.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,9 @@ export const getTypeTests = () => [
6666
['0xbe', '"0xbe"'],
6767
['keys', '"keys"'],
6868
[new String('1234'), 'String(1234)'],
69-
[new Uint8Array([]), 'ui8a([])'],
70-
[new Uint8Array([0]), 'ui8a([0])'],
71-
[new Uint8Array([1]), 'ui8a([1])'],
69+
[Uint8Array.of(), 'ui8a([])'],
70+
[Uint8Array.of(0), 'ui8a([0])'],
71+
[Uint8Array.of(1), 'ui8a([1])'],
7272
// [new Uint8Array(32).fill(1), 'ui8a(32*[1])'],
7373
[new Uint8Array(4096).fill(1), 'ui8a(4096*[1])'],
7474
[new Uint16Array(32).fill(1), 'ui16a(32*[1])'],

0 commit comments

Comments
 (0)