@noble/curves 0.6.2 → 0.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -22,8 +22,7 @@ Package consists of two parts:
22
22
 
23
23
  Curves incorporate work from previous noble packages
24
24
  ([secp256k1](https://github.com/paulmillr/noble-secp256k1),
25
- [ed25519](https://github.com/paulmillr/noble-ed25519),
26
- [bls12-381](https://github.com/paulmillr/noble-bls12-381)),
25
+ [ed25519](https://github.com/paulmillr/noble-ed25519)),
27
26
  which had security audits and were developed from 2019 to 2022.
28
27
  Check out [Upgrading](#upgrading) section if you've used them before.
29
28
 
@@ -31,14 +30,14 @@ Check out [Upgrading](#upgrading) section if you've used them before.
31
30
 
32
31
  > **noble-crypto** — high-security, easily auditable set of contained cryptographic libraries and tools.
33
32
 
34
- - Minimal dependencies, small files
33
+ - Protection against supply chain attacks
35
34
  - Easily auditable TypeScript/JS code
36
35
  - Supported in all major browsers and stable node.js versions
37
36
  - All releases are signed with PGP keys
38
37
  - Check out [homepage](https://paulmillr.com/noble/) & all libraries:
39
- [curves](https://github.com/paulmillr/noble-curves) ([secp256k1](https://github.com/paulmillr/noble-secp256k1),
40
- [ed25519](https://github.com/paulmillr/noble-ed25519),
41
- [bls12-381](https://github.com/paulmillr/noble-bls12-381)),
38
+ [curves](https://github.com/paulmillr/noble-curves)
39
+ ([secp256k1](https://github.com/paulmillr/noble-secp256k1),
40
+ [ed25519](https://github.com/paulmillr/noble-ed25519)),
42
41
  [hashes](https://github.com/paulmillr/noble-hashes)
43
42
 
44
43
  ## Usage
@@ -48,23 +47,7 @@ Use NPM in node.js / browser, or include single file from
48
47
 
49
48
  > npm install @noble/curves
50
49
 
51
- The library does not have an entry point. It allows you to select specific primitives and drop everything else. If you only want to use secp256k1, just use the library with rollup or other bundlers. This is done to make your bundles tiny.
52
-
53
- ```ts
54
- // Common.js and ECMAScript Modules (ESM)
55
- import { secp256k1 } from '@noble/curves/secp256k1';
56
-
57
- const key = secp256k1.utils.randomPrivateKey();
58
- const pub = secp256k1.getPublicKey(key);
59
- const msg = new Uint8Array(32).fill(1);
60
- const sig = secp256k1.sign(msg, key);
61
- secp256k1.verify(sig, msg, pub) === true;
62
- sig.recoverPublicKey(msg) === pub;
63
- const someonesPub = secp256k1.getPublicKey(secp256k1.utils.randomPrivateKey());
64
- const shared = secp256k1.getSharedSecret(key, someonesPub);
65
- ```
66
-
67
- All curves:
50
+ The library does not have an entry point. It allows you to select specific primitives and drop everything else. If you only want to use secp256k1, just use the library with rollup or other bundlers. This is done to make your bundles tiny. All curves:
68
51
 
69
52
  ```ts
70
53
  import { secp256k1 } from '@noble/curves/secp256k1';
@@ -80,7 +63,25 @@ import { bn254 } from '@noble/curves/bn';
80
63
  import { jubjub } from '@noble/curves/jubjub';
81
64
  ```
82
65
 
83
- To define a custom curve, check out API below.
66
+ Every curve can be used in the following way:
67
+
68
+ ```ts
69
+ import { secp256k1 } from '@noble/curves/secp256k1'; // Common.js and ECMAScript Modules (ESM)
70
+
71
+ const key = secp256k1.utils.randomPrivateKey();
72
+ const pub = secp256k1.getPublicKey(key);
73
+ const msg = new Uint8Array(32).fill(1);
74
+ const sig = secp256k1.sign(msg, key);
75
+ // weierstrass curves should use extraEntropy: https://moderncrypto.org/mail-archive/curves/2017/000925.html
76
+ const sigImprovedSecurity = secp256k1.sign(msg, key, { extraEntropy: true });
77
+ secp256k1.verify(sig, msg, pub) === true;
78
+ // secp, p*, pasta curves allow pub recovery
79
+ sig.recoverPublicKey(msg) === pub;
80
+ const someonesPub = secp256k1.getPublicKey(secp256k1.utils.randomPrivateKey());
81
+ const shared = secp256k1.getSharedSecret(key, someonesPub);
82
+ ```
83
+
84
+ To define a custom curve, check out docs below.
84
85
 
85
86
  ## API
86
87
 
@@ -109,17 +110,20 @@ import * as utils from '@noble/curves/abstract/utils';
109
110
  They allow to define a new curve in a few lines of code:
110
111
 
111
112
  ```ts
112
- import { Fp } from '@noble/curves/abstract/modular';
113
+ import { Field } from '@noble/curves/abstract/modular';
113
114
  import { weierstrass } from '@noble/curves/abstract/weierstrass';
114
115
  import { hmac } from '@noble/hashes/hmac';
115
116
  import { sha256 } from '@noble/hashes/sha256';
116
117
  import { concatBytes, randomBytes } from '@noble/hashes/utils';
117
118
 
118
- const secp256k1 = weierstrass({
119
+ // secq (NOT secp) 256k1: cycle of secp256k1 with Fp/N flipped.
120
+ // https://zcash.github.io/halo2/background/curves.html#cycles-of-curves
121
+ // https://personaelabs.org/posts/spartan-ecdsa
122
+ const secq256k1 = weierstrass({
119
123
  a: 0n,
120
124
  b: 7n,
121
- Fp: Fp(2n ** 256n - 2n ** 32n - 2n ** 9n - 2n ** 8n - 2n ** 7n - 2n ** 6n - 2n ** 4n - 1n),
122
- n: 2n ** 256n - 432420386565659656852420866394968145599n,
125
+ Fp: Field(2n ** 256n - 432420386565659656852420866394968145599n),
126
+ n: 2n ** 256n - 2n ** 32n - 2n ** 9n - 2n ** 8n - 2n ** 7n - 2n ** 6n - 2n ** 4n - 1n,
123
127
  Gx: 55066263022277343669578718895168534326250603453777594175500187360389116729240n,
124
128
  Gy: 32670510020758816978083085130507043184471273380659243275938904335757337482424n,
125
129
  hash: sha256,
@@ -26,15 +26,19 @@ export declare function wNAF<T extends Group<T>>(c: GroupConstructor<T>, bits: n
26
26
  /**
27
27
  * Creates a wNAF precomputation window. Used for caching.
28
28
  * Default window size is set by `utils.precompute()` and is equal to 8.
29
- * Which means we are caching 65536 points: 256 points for every bit from 0 to 256.
30
- * @returns 65K precomputed points, depending on W
29
+ * Number of precomputed points depends on the curve size:
30
+ * 2^(𝑊−1) * (Math.ceil(𝑛 / 𝑊) + 1), where:
31
+ * - 𝑊 is the window size
32
+ * - 𝑛 is the bitlength of the curve order.
33
+ * For a 256-bit curve and window size 8, the number of precomputed points is 128 * 33 = 4224.
34
+ * @returns precomputed point tables flattened to a single array
31
35
  */
32
36
  precomputeWindow(elm: T, W: number): Group<T>[];
33
37
  /**
34
- * Implements w-ary non-adjacent form for calculating ec multiplication.
38
+ * Implements ec multiplication using precomputed tables and w-ary non-adjacent form.
35
39
  * @param W window size
36
- * @param affinePoint optional 2d point to save cached precompute windows on it.
37
- * @param n bits
40
+ * @param precomputes precomputed tables
41
+ * @param n scalar (we don't check here, but should be less than curve order)
38
42
  * @returns real and fake (for const-time) points
39
43
  */
40
44
  wNAF(W: number, precomputes: T[], n: bigint): {
@@ -7,8 +7,17 @@ const modular_js_1 = require("./modular.js");
7
7
  const utils_js_1 = require("./utils.js");
8
8
  const _0n = BigInt(0);
9
9
  const _1n = BigInt(1);
10
- // Elliptic curve multiplication of Point by scalar. Complicated and fragile. Uses wNAF method.
11
- // Windowed method is 10% faster, but takes 2x longer to generate & consumes 2x memory.
10
+ // Elliptic curve multiplication of Point by scalar. Fragile.
11
+ // Scalars should always be less than curve order: this should be checked inside of a curve itself.
12
+ // Creates precomputation tables for fast multiplication:
13
+ // - private scalar is split by fixed size windows of W bits
14
+ // - every window point is collected from window's table & added to accumulator
15
+ // - since windows are different, same point inside tables won't be accessed more than once per calc
16
+ // - each multiplication is 'Math.ceil(CURVE_ORDER / 𝑊) + 1' point additions (fixed for any scalar)
17
+ // - +1 window is neccessary for wNAF
18
+ // - wNAF reduces table size: 2x less memory + 2x faster generation, but 10% slower multiplication
19
+ // TODO: Research returning 2d JS array of windows, instead of a single window. This would allow
20
+ // windows to be in different memory locations
12
21
  function wNAF(c, bits) {
13
22
  const constTimeNegate = (condition, item) => {
14
23
  const neg = item.negate();
@@ -36,8 +45,12 @@ function wNAF(c, bits) {
36
45
  /**
37
46
  * Creates a wNAF precomputation window. Used for caching.
38
47
  * Default window size is set by `utils.precompute()` and is equal to 8.
39
- * Which means we are caching 65536 points: 256 points for every bit from 0 to 256.
40
- * @returns 65K precomputed points, depending on W
48
+ * Number of precomputed points depends on the curve size:
49
+ * 2^(𝑊−1) * (Math.ceil(𝑛 / 𝑊) + 1), where:
50
+ * - 𝑊 is the window size
51
+ * - 𝑛 is the bitlength of the curve order.
52
+ * For a 256-bit curve and window size 8, the number of precomputed points is 128 * 33 = 4224.
53
+ * @returns precomputed point tables flattened to a single array
41
54
  */
42
55
  precomputeWindow(elm, W) {
43
56
  const { windows, windowSize } = opts(W);
@@ -57,14 +70,14 @@ function wNAF(c, bits) {
57
70
  return points;
58
71
  },
59
72
  /**
60
- * Implements w-ary non-adjacent form for calculating ec multiplication.
73
+ * Implements ec multiplication using precomputed tables and w-ary non-adjacent form.
61
74
  * @param W window size
62
- * @param affinePoint optional 2d point to save cached precompute windows on it.
63
- * @param n bits
75
+ * @param precomputes precomputed tables
76
+ * @param n scalar (we don't check here, but should be less than curve order)
64
77
  * @returns real and fake (for const-time) points
65
78
  */
66
79
  wNAF(W, precomputes, n) {
67
- // TODO: maybe check that scalar is less than group order? wNAF will fail otherwise
80
+ // TODO: maybe check that scalar is less than group order? wNAF behavious is undefined otherwise
68
81
  // But need to carefully remove other checks before wNAF. ORDER == bits here
69
82
  const { windows, windowSize } = opts(W);
70
83
  let p = c.ZERO;
@@ -11,7 +11,6 @@ export declare type Opts = {
11
11
  expand?: 'xmd' | 'xof';
12
12
  hash: CHash;
13
13
  };
14
- export declare function validateOpts(opts: Opts): void;
15
14
  export declare function stringToBytes(str: string): Uint8Array;
16
15
  export declare function expand_message_xmd(msg: Uint8Array, DST: Uint8Array, lenInBytes: number, H: CHash): Uint8Array;
17
16
  export declare function expand_message_xof(msg: Uint8Array, DST: Uint8Array, lenInBytes: number, k: number, H: CHash): Uint8Array;
@@ -1,23 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.hashToCurve = exports.isogenyMap = exports.hash_to_field = exports.expand_message_xof = exports.expand_message_xmd = exports.stringToBytes = exports.validateOpts = void 0;
3
+ exports.hashToCurve = exports.isogenyMap = exports.hash_to_field = exports.expand_message_xof = exports.expand_message_xmd = exports.stringToBytes = void 0;
4
4
  const modular_js_1 = require("./modular.js");
5
5
  const utils_js_1 = require("./utils.js");
6
- function validateOpts(opts) {
7
- if (typeof opts.DST !== 'string')
8
- throw new Error('Invalid htf/DST');
9
- if (typeof opts.p !== 'bigint')
10
- throw new Error('Invalid htf/p');
11
- if (typeof opts.m !== 'number')
12
- throw new Error('Invalid htf/m');
13
- if (typeof opts.k !== 'number')
14
- throw new Error('Invalid htf/k');
15
- if (opts.expand !== 'xmd' && opts.expand !== 'xof' && opts.expand !== undefined)
16
- throw new Error('Invalid htf/expand');
17
- if (typeof opts.hash !== 'function' || !Number.isSafeInteger(opts.hash.outputLen))
18
- throw new Error('Invalid htf/hash function');
19
- }
20
- exports.validateOpts = validateOpts;
21
6
  function stringToBytes(str) {
22
7
  if (typeof str !== 'string') {
23
8
  throw new Error(`utf8ToBytes expected string, got ${typeof str}`);
@@ -143,7 +128,15 @@ function isogenyMap(field, map) {
143
128
  }
144
129
  exports.isogenyMap = isogenyMap;
145
130
  function hashToCurve(Point, mapToCurve, def) {
146
- validateOpts(def);
131
+ (0, utils_js_1.validateObject)(def, {
132
+ DST: 'string',
133
+ p: 'bigint',
134
+ m: 'isSafeInteger',
135
+ k: 'isSafeInteger',
136
+ hash: 'hash',
137
+ });
138
+ if (def.expand !== 'xmd' && def.expand !== 'xof' && def.expand !== undefined)
139
+ throw new Error('Invalid htf/expand');
147
140
  if (typeof mapToCurve !== 'function')
148
141
  throw new Error('hashToCurve: mapToCurve() has not been defined');
149
142
  return {
@@ -4,8 +4,17 @@ import { validateField, nLength } from './modular.js';
4
4
  import { validateObject } from './utils.js';
5
5
  const _0n = BigInt(0);
6
6
  const _1n = BigInt(1);
7
- // Elliptic curve multiplication of Point by scalar. Complicated and fragile. Uses wNAF method.
8
- // Windowed method is 10% faster, but takes 2x longer to generate & consumes 2x memory.
7
+ // Elliptic curve multiplication of Point by scalar. Fragile.
8
+ // Scalars should always be less than curve order: this should be checked inside of a curve itself.
9
+ // Creates precomputation tables for fast multiplication:
10
+ // - private scalar is split by fixed size windows of W bits
11
+ // - every window point is collected from window's table & added to accumulator
12
+ // - since windows are different, same point inside tables won't be accessed more than once per calc
13
+ // - each multiplication is 'Math.ceil(CURVE_ORDER / 𝑊) + 1' point additions (fixed for any scalar)
14
+ // - +1 window is neccessary for wNAF
15
+ // - wNAF reduces table size: 2x less memory + 2x faster generation, but 10% slower multiplication
16
+ // TODO: Research returning 2d JS array of windows, instead of a single window. This would allow
17
+ // windows to be in different memory locations
9
18
  export function wNAF(c, bits) {
10
19
  const constTimeNegate = (condition, item) => {
11
20
  const neg = item.negate();
@@ -33,8 +42,12 @@ export function wNAF(c, bits) {
33
42
  /**
34
43
  * Creates a wNAF precomputation window. Used for caching.
35
44
  * Default window size is set by `utils.precompute()` and is equal to 8.
36
- * Which means we are caching 65536 points: 256 points for every bit from 0 to 256.
37
- * @returns 65K precomputed points, depending on W
45
+ * Number of precomputed points depends on the curve size:
46
+ * 2^(𝑊−1) * (Math.ceil(𝑛 / 𝑊) + 1), where:
47
+ * - 𝑊 is the window size
48
+ * - 𝑛 is the bitlength of the curve order.
49
+ * For a 256-bit curve and window size 8, the number of precomputed points is 128 * 33 = 4224.
50
+ * @returns precomputed point tables flattened to a single array
38
51
  */
39
52
  precomputeWindow(elm, W) {
40
53
  const { windows, windowSize } = opts(W);
@@ -54,14 +67,14 @@ export function wNAF(c, bits) {
54
67
  return points;
55
68
  },
56
69
  /**
57
- * Implements w-ary non-adjacent form for calculating ec multiplication.
70
+ * Implements ec multiplication using precomputed tables and w-ary non-adjacent form.
58
71
  * @param W window size
59
- * @param affinePoint optional 2d point to save cached precompute windows on it.
60
- * @param n bits
72
+ * @param precomputes precomputed tables
73
+ * @param n scalar (we don't check here, but should be less than curve order)
61
74
  * @returns real and fake (for const-time) points
62
75
  */
63
76
  wNAF(W, precomputes, n) {
64
- // TODO: maybe check that scalar is less than group order? wNAF will fail otherwise
77
+ // TODO: maybe check that scalar is less than group order? wNAF behavious is undefined otherwise
65
78
  // But need to carefully remove other checks before wNAF. ORDER == bits here
66
79
  const { windows, windowSize } = opts(W);
67
80
  let p = c.ZERO;
@@ -1,19 +1,5 @@
1
1
  import { mod } from './modular.js';
2
- import { concatBytes, ensureBytes } from './utils.js';
3
- export function validateOpts(opts) {
4
- if (typeof opts.DST !== 'string')
5
- throw new Error('Invalid htf/DST');
6
- if (typeof opts.p !== 'bigint')
7
- throw new Error('Invalid htf/p');
8
- if (typeof opts.m !== 'number')
9
- throw new Error('Invalid htf/m');
10
- if (typeof opts.k !== 'number')
11
- throw new Error('Invalid htf/k');
12
- if (opts.expand !== 'xmd' && opts.expand !== 'xof' && opts.expand !== undefined)
13
- throw new Error('Invalid htf/expand');
14
- if (typeof opts.hash !== 'function' || !Number.isSafeInteger(opts.hash.outputLen))
15
- throw new Error('Invalid htf/hash function');
16
- }
2
+ import { concatBytes, ensureBytes, validateObject } from './utils.js';
17
3
  export function stringToBytes(str) {
18
4
  if (typeof str !== 'string') {
19
5
  throw new Error(`utf8ToBytes expected string, got ${typeof str}`);
@@ -134,7 +120,15 @@ export function isogenyMap(field, map) {
134
120
  };
135
121
  }
136
122
  export function hashToCurve(Point, mapToCurve, def) {
137
- validateOpts(def);
123
+ validateObject(def, {
124
+ DST: 'string',
125
+ p: 'bigint',
126
+ m: 'isSafeInteger',
127
+ k: 'isSafeInteger',
128
+ hash: 'hash',
129
+ });
130
+ if (def.expand !== 'xmd' && def.expand !== 'xof' && def.expand !== undefined)
131
+ throw new Error('Invalid htf/expand');
138
132
  if (typeof mapToCurve !== 'function')
139
133
  throw new Error('hashToCurve: mapToCurve() has not been defined');
140
134
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@noble/curves",
3
- "version": "0.6.2",
3
+ "version": "0.6.3",
4
4
  "description": "Minimal, auditable JS implementation of elliptic curve cryptography",
5
5
  "files": [
6
6
  "lib"
@@ -21,19 +21,17 @@
21
21
  },
22
22
  "license": "MIT",
23
23
  "dependencies": {
24
- "@noble/hashes": "1.1.5"
24
+ "@noble/hashes": "1.2.0"
25
25
  },
26
26
  "devDependencies": {
27
- "@rollup/plugin-node-resolve": "13.3.0",
28
27
  "@scure/base": "~1.1.1",
29
- "@scure/bip32": "~1.1.1",
30
- "@scure/bip39": "~1.1.0",
28
+ "@scure/bip32": "~1.1.5",
29
+ "@scure/bip39": "~1.1.1",
31
30
  "@types/node": "18.11.3",
32
31
  "fast-check": "3.0.0",
33
32
  "micro-bmark": "0.3.0",
34
33
  "micro-should": "0.4.0",
35
34
  "prettier": "2.8.3",
36
- "rollup": "2.75.5",
37
35
  "typescript": "4.7.3"
38
36
  },
39
37
  "main": "index.js",