@oxy.so/protocol 1.5.1 → 1.6.0
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/dist/cjs/auth/registrationPow.js +2 -2
- package/dist/cjs/platform/random.native.js +4 -5
- package/dist/cjs/random.js +4 -5
- package/dist/cjs/secp256k1.js +5 -1
- package/dist/esm/auth/registrationPow.js +2 -2
- package/dist/esm/platform/random.native.js +4 -5
- package/dist/esm/random.js +4 -5
- package/dist/esm/secp256k1.js +5 -1
- package/dist/types/auth/registrationPow.d.ts +2 -2
- package/dist/types/platform/random.native.d.ts +4 -5
- package/dist/types/random.d.ts +4 -5
- package/package.json +11 -9
- package/src/__tests__/randomEntry.test.ts +4 -5
- package/src/auth/registrationPow.ts +2 -2
- package/src/platform/random.native.ts +4 -5
- package/src/random.ts +4 -5
- package/src/secp256k1.ts +5 -1
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
* platform hashing primitive and is trivially unit-testable with fixed
|
|
26
26
|
* digests. Each side hashes with whatever SHA-256 it already has — Node's
|
|
27
27
|
* `crypto` server-side (`packages/api/src/controllers/session.controller.ts`),
|
|
28
|
-
* `@noble/hashes/sha256` client-side (`packages/core/src/crypto/registrationPow.ts`,
|
|
28
|
+
* `@noble/hashes/sha2.js`'s `sha256` client-side (`packages/core/src/crypto/registrationPow.ts`,
|
|
29
29
|
* already a `@oxy.so/core` dependency — see `crypto/kdf.ts`,
|
|
30
30
|
* `crypto/identityProof.ts`) — and both produce byte-identical digests over
|
|
31
31
|
* the same message, because SHA-256 has exactly one correct output for a
|
|
@@ -101,7 +101,7 @@ function registrationPowMessage(publicKey, timestamp, nonce) {
|
|
|
101
101
|
* requires of a solved nonce's digest.
|
|
102
102
|
*
|
|
103
103
|
* 16 bits ⇒ 65,536 SHA-256 attempts on average to solve. The client grinds
|
|
104
|
-
* with `@noble/hashes/sha256` — a pure-JS, SYNCHRONOUS implementation with
|
|
104
|
+
* with `@noble/hashes/sha2.js`'s `sha256` — a pure-JS, SYNCHRONOUS implementation with
|
|
105
105
|
* "identical behaviour on web, Node, and React Native with zero WebCrypto /
|
|
106
106
|
* native-module dependency" (its own doc comment in `crypto/kdf.ts`) — so,
|
|
107
107
|
* unlike a solve loop built on a platform hashing primitive that crosses a
|
|
@@ -7,11 +7,10 @@
|
|
|
7
7
|
*
|
|
8
8
|
* This module is deliberately tiny and imports NOTHING but `expo-crypto`: it
|
|
9
9
|
* backs `@oxy.so/core`'s `globalThis.crypto.getRandomValues` polyfill, which
|
|
10
|
-
* must be fully installed before any module that
|
|
11
|
-
* at evaluation time (`@noble/hashes` 1.x's `crypto.js`
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* `crypto.getRandomValues must be defined` for the lifetime of the app.
|
|
10
|
+
* must be fully installed before any module that reads `globalThis.crypto`
|
|
11
|
+
* at evaluation time is evaluated (`@noble/hashes` 1.x's `crypto.js` did, and
|
|
12
|
+
* threw `crypto.getRandomValues must be defined` for the lifetime of the app).
|
|
13
|
+
* Reaching a crypto library from here would evaluate it before the shim.
|
|
15
14
|
*
|
|
16
15
|
* `expo-crypto` is an OPTIONAL peer, so it is resolved with a string-literal
|
|
17
16
|
* `require` inside a `try` (Metro's optional-dependency form; see
|
package/dist/cjs/random.js
CHANGED
|
@@ -3,13 +3,12 @@
|
|
|
3
3
|
* `@oxy.so/protocol/random` — the platform randomness source, and nothing else.
|
|
4
4
|
*
|
|
5
5
|
* `@oxy.so/core`'s crypto polyfill installs `globalThis.crypto.getRandomValues`
|
|
6
|
-
* on hosts that lack it (React Native / Hermes)
|
|
7
|
-
*
|
|
8
|
-
* has to be installed before any `@noble/*` module is evaluated. ES imports are
|
|
6
|
+
* on hosts that lack it (React Native / Hermes), and has to be installed before
|
|
7
|
+
* any module that reads `globalThis.crypto` is evaluated. ES imports are
|
|
9
8
|
* evaluated before the importing module's body, so whatever the polyfill
|
|
10
9
|
* imports is evaluated first: importing the ROOT entry (which reaches
|
|
11
|
-
* `@noble/curves` through the envelope signer) let noble capture
|
|
12
|
-
* and broke identity creation on Android.
|
|
10
|
+
* `@noble/curves` through the envelope signer) let `@noble/hashes` 1.x capture
|
|
11
|
+
* `undefined` at evaluation and broke identity creation on Android.
|
|
13
12
|
*
|
|
14
13
|
* This entry therefore reaches no crypto library, no `@oxy.so/*` package and no
|
|
15
14
|
* third-party module other than the optional `expo-crypto` peer (RN variant
|
package/dist/cjs/secp256k1.js
CHANGED
|
@@ -121,10 +121,13 @@ function normalizeSecp256k1PublicKey(publicKeyHex, compressed = false) {
|
|
|
121
121
|
* accepts both forms; callers that require low-S normalization opt in explicitly.
|
|
122
122
|
*/
|
|
123
123
|
function signSecp256k1Digest(privateKeyHex, digestHex, options = {}) {
|
|
124
|
+
// The input is already a digest: `prehash: false` keeps noble from hashing it again.
|
|
124
125
|
const signature = secp256k1_js_1.secp256k1.sign(parseDigest(digestHex), parsePrivateKey(privateKeyHex), {
|
|
126
|
+
prehash: false,
|
|
125
127
|
lowS: options.lowS ?? false,
|
|
128
|
+
format: 'der',
|
|
126
129
|
});
|
|
127
|
-
return signature
|
|
130
|
+
return bytesToHex(signature);
|
|
128
131
|
}
|
|
129
132
|
/** Verify a DER-encoded ECDSA signature, accepting historical high-S signatures. */
|
|
130
133
|
function verifySecp256k1Digest(publicKeyHex, digestHex, signatureDerHex) {
|
|
@@ -134,6 +137,7 @@ function verifySecp256k1Digest(publicKeyHex, digestHex, signatureDerHex) {
|
|
|
134
137
|
// Parse once up front so malformed or non-DER input is rejected explicitly.
|
|
135
138
|
secp256k1_js_1.secp256k1.Signature.fromBytes(signature, 'der');
|
|
136
139
|
return secp256k1_js_1.secp256k1.verify(signature, digest, publicKey, {
|
|
140
|
+
prehash: false,
|
|
137
141
|
format: 'der',
|
|
138
142
|
lowS: false,
|
|
139
143
|
});
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
* platform hashing primitive and is trivially unit-testable with fixed
|
|
25
25
|
* digests. Each side hashes with whatever SHA-256 it already has — Node's
|
|
26
26
|
* `crypto` server-side (`packages/api/src/controllers/session.controller.ts`),
|
|
27
|
-
* `@noble/hashes/sha256` client-side (`packages/core/src/crypto/registrationPow.ts`,
|
|
27
|
+
* `@noble/hashes/sha2.js`'s `sha256` client-side (`packages/core/src/crypto/registrationPow.ts`,
|
|
28
28
|
* already a `@oxy.so/core` dependency — see `crypto/kdf.ts`,
|
|
29
29
|
* `crypto/identityProof.ts`) — and both produce byte-identical digests over
|
|
30
30
|
* the same message, because SHA-256 has exactly one correct output for a
|
|
@@ -95,7 +95,7 @@ export function registrationPowMessage(publicKey, timestamp, nonce) {
|
|
|
95
95
|
* requires of a solved nonce's digest.
|
|
96
96
|
*
|
|
97
97
|
* 16 bits ⇒ 65,536 SHA-256 attempts on average to solve. The client grinds
|
|
98
|
-
* with `@noble/hashes/sha256` — a pure-JS, SYNCHRONOUS implementation with
|
|
98
|
+
* with `@noble/hashes/sha2.js`'s `sha256` — a pure-JS, SYNCHRONOUS implementation with
|
|
99
99
|
* "identical behaviour on web, Node, and React Native with zero WebCrypto /
|
|
100
100
|
* native-module dependency" (its own doc comment in `crypto/kdf.ts`) — so,
|
|
101
101
|
* unlike a solve loop built on a platform hashing primitive that crosses a
|
|
@@ -6,11 +6,10 @@
|
|
|
6
6
|
*
|
|
7
7
|
* This module is deliberately tiny and imports NOTHING but `expo-crypto`: it
|
|
8
8
|
* backs `@oxy.so/core`'s `globalThis.crypto.getRandomValues` polyfill, which
|
|
9
|
-
* must be fully installed before any module that
|
|
10
|
-
* at evaluation time (`@noble/hashes` 1.x's `crypto.js`
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* `crypto.getRandomValues must be defined` for the lifetime of the app.
|
|
9
|
+
* must be fully installed before any module that reads `globalThis.crypto`
|
|
10
|
+
* at evaluation time is evaluated (`@noble/hashes` 1.x's `crypto.js` did, and
|
|
11
|
+
* threw `crypto.getRandomValues must be defined` for the lifetime of the app).
|
|
12
|
+
* Reaching a crypto library from here would evaluate it before the shim.
|
|
14
13
|
*
|
|
15
14
|
* `expo-crypto` is an OPTIONAL peer, so it is resolved with a string-literal
|
|
16
15
|
* `require` inside a `try` (Metro's optional-dependency form; see
|
package/dist/esm/random.js
CHANGED
|
@@ -2,13 +2,12 @@
|
|
|
2
2
|
* `@oxy.so/protocol/random` — the platform randomness source, and nothing else.
|
|
3
3
|
*
|
|
4
4
|
* `@oxy.so/core`'s crypto polyfill installs `globalThis.crypto.getRandomValues`
|
|
5
|
-
* on hosts that lack it (React Native / Hermes)
|
|
6
|
-
*
|
|
7
|
-
* has to be installed before any `@noble/*` module is evaluated. ES imports are
|
|
5
|
+
* on hosts that lack it (React Native / Hermes), and has to be installed before
|
|
6
|
+
* any module that reads `globalThis.crypto` is evaluated. ES imports are
|
|
8
7
|
* evaluated before the importing module's body, so whatever the polyfill
|
|
9
8
|
* imports is evaluated first: importing the ROOT entry (which reaches
|
|
10
|
-
* `@noble/curves` through the envelope signer) let noble capture
|
|
11
|
-
* and broke identity creation on Android.
|
|
9
|
+
* `@noble/curves` through the envelope signer) let `@noble/hashes` 1.x capture
|
|
10
|
+
* `undefined` at evaluation and broke identity creation on Android.
|
|
12
11
|
*
|
|
13
12
|
* This entry therefore reaches no crypto library, no `@oxy.so/*` package and no
|
|
14
13
|
* third-party module other than the optional `expo-crypto` peer (RN variant
|
package/dist/esm/secp256k1.js
CHANGED
|
@@ -109,10 +109,13 @@ export function normalizeSecp256k1PublicKey(publicKeyHex, compressed = false) {
|
|
|
109
109
|
* accepts both forms; callers that require low-S normalization opt in explicitly.
|
|
110
110
|
*/
|
|
111
111
|
export function signSecp256k1Digest(privateKeyHex, digestHex, options = {}) {
|
|
112
|
+
// The input is already a digest: `prehash: false` keeps noble from hashing it again.
|
|
112
113
|
const signature = secp256k1.sign(parseDigest(digestHex), parsePrivateKey(privateKeyHex), {
|
|
114
|
+
prehash: false,
|
|
113
115
|
lowS: options.lowS ?? false,
|
|
116
|
+
format: 'der',
|
|
114
117
|
});
|
|
115
|
-
return signature
|
|
118
|
+
return bytesToHex(signature);
|
|
116
119
|
}
|
|
117
120
|
/** Verify a DER-encoded ECDSA signature, accepting historical high-S signatures. */
|
|
118
121
|
export function verifySecp256k1Digest(publicKeyHex, digestHex, signatureDerHex) {
|
|
@@ -122,6 +125,7 @@ export function verifySecp256k1Digest(publicKeyHex, digestHex, signatureDerHex)
|
|
|
122
125
|
// Parse once up front so malformed or non-DER input is rejected explicitly.
|
|
123
126
|
secp256k1.Signature.fromBytes(signature, 'der');
|
|
124
127
|
return secp256k1.verify(signature, digest, publicKey, {
|
|
128
|
+
prehash: false,
|
|
125
129
|
format: 'der',
|
|
126
130
|
lowS: false,
|
|
127
131
|
});
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
* platform hashing primitive and is trivially unit-testable with fixed
|
|
25
25
|
* digests. Each side hashes with whatever SHA-256 it already has — Node's
|
|
26
26
|
* `crypto` server-side (`packages/api/src/controllers/session.controller.ts`),
|
|
27
|
-
* `@noble/hashes/sha256` client-side (`packages/core/src/crypto/registrationPow.ts`,
|
|
27
|
+
* `@noble/hashes/sha2.js`'s `sha256` client-side (`packages/core/src/crypto/registrationPow.ts`,
|
|
28
28
|
* already a `@oxy.so/core` dependency — see `crypto/kdf.ts`,
|
|
29
29
|
* `crypto/identityProof.ts`) — and both produce byte-identical digests over
|
|
30
30
|
* the same message, because SHA-256 has exactly one correct output for a
|
|
@@ -67,7 +67,7 @@ export declare function registrationPowMessage(publicKey: string, timestamp: num
|
|
|
67
67
|
* requires of a solved nonce's digest.
|
|
68
68
|
*
|
|
69
69
|
* 16 bits ⇒ 65,536 SHA-256 attempts on average to solve. The client grinds
|
|
70
|
-
* with `@noble/hashes/sha256` — a pure-JS, SYNCHRONOUS implementation with
|
|
70
|
+
* with `@noble/hashes/sha2.js`'s `sha256` — a pure-JS, SYNCHRONOUS implementation with
|
|
71
71
|
* "identical behaviour on web, Node, and React Native with zero WebCrypto /
|
|
72
72
|
* native-module dependency" (its own doc comment in `crypto/kdf.ts`) — so,
|
|
73
73
|
* unlike a solve loop built on a platform hashing primitive that crosses a
|
|
@@ -6,11 +6,10 @@
|
|
|
6
6
|
*
|
|
7
7
|
* This module is deliberately tiny and imports NOTHING but `expo-crypto`: it
|
|
8
8
|
* backs `@oxy.so/core`'s `globalThis.crypto.getRandomValues` polyfill, which
|
|
9
|
-
* must be fully installed before any module that
|
|
10
|
-
* at evaluation time (`@noble/hashes` 1.x's `crypto.js`
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* `crypto.getRandomValues must be defined` for the lifetime of the app.
|
|
9
|
+
* must be fully installed before any module that reads `globalThis.crypto`
|
|
10
|
+
* at evaluation time is evaluated (`@noble/hashes` 1.x's `crypto.js` did, and
|
|
11
|
+
* threw `crypto.getRandomValues must be defined` for the lifetime of the app).
|
|
12
|
+
* Reaching a crypto library from here would evaluate it before the shim.
|
|
14
13
|
*
|
|
15
14
|
* `expo-crypto` is an OPTIONAL peer, so it is resolved with a string-literal
|
|
16
15
|
* `require` inside a `try` (Metro's optional-dependency form; see
|
package/dist/types/random.d.ts
CHANGED
|
@@ -2,13 +2,12 @@
|
|
|
2
2
|
* `@oxy.so/protocol/random` — the platform randomness source, and nothing else.
|
|
3
3
|
*
|
|
4
4
|
* `@oxy.so/core`'s crypto polyfill installs `globalThis.crypto.getRandomValues`
|
|
5
|
-
* on hosts that lack it (React Native / Hermes)
|
|
6
|
-
*
|
|
7
|
-
* has to be installed before any `@noble/*` module is evaluated. ES imports are
|
|
5
|
+
* on hosts that lack it (React Native / Hermes), and has to be installed before
|
|
6
|
+
* any module that reads `globalThis.crypto` is evaluated. ES imports are
|
|
8
7
|
* evaluated before the importing module's body, so whatever the polyfill
|
|
9
8
|
* imports is evaluated first: importing the ROOT entry (which reaches
|
|
10
|
-
* `@noble/curves` through the envelope signer) let noble capture
|
|
11
|
-
* and broke identity creation on Android.
|
|
9
|
+
* `@noble/curves` through the envelope signer) let `@noble/hashes` 1.x capture
|
|
10
|
+
* `undefined` at evaluation and broke identity creation on Android.
|
|
12
11
|
*
|
|
13
12
|
* This entry therefore reaches no crypto library, no `@oxy.so/*` package and no
|
|
14
13
|
* third-party module other than the optional `expo-crypto` peer (RN variant
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oxy.so/protocol",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"description": "Oxy Protocol — the app-agnostic base substrate: signed-record envelope, canonical JSON, signature/verification, and platform crypto. Reused by any Oxy app to decentralize its own content.",
|
|
5
5
|
"main": "dist/cjs/index.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|
|
@@ -98,8 +98,10 @@
|
|
|
98
98
|
"NOTICE",
|
|
99
99
|
"dist",
|
|
100
100
|
"!dist/**/*.tsbuildinfo",
|
|
101
|
-
"src"
|
|
101
|
+
"src",
|
|
102
|
+
"!dist/.oxy-source-digest"
|
|
102
103
|
],
|
|
104
|
+
"oxySourceStamp": "dist",
|
|
103
105
|
"keywords": [
|
|
104
106
|
"oxyhq",
|
|
105
107
|
"protocol",
|
|
@@ -117,10 +119,10 @@
|
|
|
117
119
|
"license": "SEE LICENSE IN LICENSE",
|
|
118
120
|
"homepage": "https://oxy.so",
|
|
119
121
|
"engines": {
|
|
120
|
-
"node": "
|
|
122
|
+
"node": "^20.19.0 || >=22.12.0"
|
|
121
123
|
},
|
|
122
124
|
"scripts": {
|
|
123
|
-
"build": "bun run build:cjs && bun run build:esm && bun run build:types",
|
|
125
|
+
"build": "bun run build:cjs && bun run build:esm && bun run build:types && node -e \"const p='../app-preset/metro/source-stamp.js';require('node:fs').existsSync(p)&&require(p).writeStamp(process.cwd())\"",
|
|
124
126
|
"build:cjs": "tsc -p tsconfig.cjs.json",
|
|
125
127
|
"build:esm": "tsc -p tsconfig.esm.json && node scripts/fix-esm-imports.mjs",
|
|
126
128
|
"build:types": "tsc -p tsconfig.types.json",
|
|
@@ -130,11 +132,11 @@
|
|
|
130
132
|
"lint": "biome lint --error-on-warnings ./src"
|
|
131
133
|
},
|
|
132
134
|
"dependencies": {
|
|
133
|
-
"@noble/curves": "^
|
|
134
|
-
"@oxy.so/contracts": "^6.
|
|
135
|
+
"@noble/curves": "^2.4.0",
|
|
136
|
+
"@oxy.so/contracts": "^6.5.0"
|
|
135
137
|
},
|
|
136
138
|
"peerDependencies": {
|
|
137
|
-
"@react-native-async-storage/async-storage": "<
|
|
139
|
+
"@react-native-async-storage/async-storage": "<4.0.0",
|
|
138
140
|
"expo-crypto": "<59.0.0",
|
|
139
141
|
"expo-secure-store": "<59.0.0",
|
|
140
142
|
"express": "^4.18.0 || ^5.0.0",
|
|
@@ -155,12 +157,12 @@
|
|
|
155
157
|
}
|
|
156
158
|
},
|
|
157
159
|
"devDependencies": {
|
|
158
|
-
"@react-native-async-storage/async-storage": "^
|
|
160
|
+
"@react-native-async-storage/async-storage": "^3.1.1",
|
|
159
161
|
"@types/express": "^4.17.25",
|
|
160
162
|
"@types/node": "^22.20.1",
|
|
161
163
|
"@types/supertest": "^6.0.2",
|
|
162
164
|
"expo-crypto": "~56.0.3",
|
|
163
|
-
"expo-modules-core": "~58.0.
|
|
165
|
+
"expo-modules-core": "~58.0.26",
|
|
164
166
|
"expo-secure-store": "~57.0.4",
|
|
165
167
|
"express": "^4.22.2",
|
|
166
168
|
"jest": "^30.5.1",
|
|
@@ -4,11 +4,10 @@
|
|
|
4
4
|
*
|
|
5
5
|
* `@oxy.so/core`'s crypto polyfill imports this entry to install
|
|
6
6
|
* `globalThis.crypto.getRandomValues` on React Native. Everything the polyfill
|
|
7
|
-
* imports is evaluated BEFORE the polyfill body
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* `crypto.getRandomValues must be defined`. This guard keeps the entry's graph
|
|
7
|
+
* imports is evaluated BEFORE the polyfill body. When the polyfill imported
|
|
8
|
+
* the root entry instead, `@noble/hashes` 1.x was reached through the envelope
|
|
9
|
+
* signer, captured an absent `globalThis.crypto` at evaluation, and every
|
|
10
|
+
* Android identity creation failed with `crypto.getRandomValues must be defined`. This guard keeps the entry's graph
|
|
12
11
|
* dependency-free, including the `.native` siblings Metro substitutes.
|
|
13
12
|
*/
|
|
14
13
|
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
* platform hashing primitive and is trivially unit-testable with fixed
|
|
25
25
|
* digests. Each side hashes with whatever SHA-256 it already has — Node's
|
|
26
26
|
* `crypto` server-side (`packages/api/src/controllers/session.controller.ts`),
|
|
27
|
-
* `@noble/hashes/sha256` client-side (`packages/core/src/crypto/registrationPow.ts`,
|
|
27
|
+
* `@noble/hashes/sha2.js`'s `sha256` client-side (`packages/core/src/crypto/registrationPow.ts`,
|
|
28
28
|
* already a `@oxy.so/core` dependency — see `crypto/kdf.ts`,
|
|
29
29
|
* `crypto/identityProof.ts`) — and both produce byte-identical digests over
|
|
30
30
|
* the same message, because SHA-256 has exactly one correct output for a
|
|
@@ -102,7 +102,7 @@ export function registrationPowMessage(
|
|
|
102
102
|
* requires of a solved nonce's digest.
|
|
103
103
|
*
|
|
104
104
|
* 16 bits ⇒ 65,536 SHA-256 attempts on average to solve. The client grinds
|
|
105
|
-
* with `@noble/hashes/sha256` — a pure-JS, SYNCHRONOUS implementation with
|
|
105
|
+
* with `@noble/hashes/sha2.js`'s `sha256` — a pure-JS, SYNCHRONOUS implementation with
|
|
106
106
|
* "identical behaviour on web, Node, and React Native with zero WebCrypto /
|
|
107
107
|
* native-module dependency" (its own doc comment in `crypto/kdf.ts`) — so,
|
|
108
108
|
* unlike a solve loop built on a platform hashing primitive that crosses a
|
|
@@ -6,11 +6,10 @@
|
|
|
6
6
|
*
|
|
7
7
|
* This module is deliberately tiny and imports NOTHING but `expo-crypto`: it
|
|
8
8
|
* backs `@oxy.so/core`'s `globalThis.crypto.getRandomValues` polyfill, which
|
|
9
|
-
* must be fully installed before any module that
|
|
10
|
-
* at evaluation time (`@noble/hashes` 1.x's `crypto.js`
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* `crypto.getRandomValues must be defined` for the lifetime of the app.
|
|
9
|
+
* must be fully installed before any module that reads `globalThis.crypto`
|
|
10
|
+
* at evaluation time is evaluated (`@noble/hashes` 1.x's `crypto.js` did, and
|
|
11
|
+
* threw `crypto.getRandomValues must be defined` for the lifetime of the app).
|
|
12
|
+
* Reaching a crypto library from here would evaluate it before the shim.
|
|
14
13
|
*
|
|
15
14
|
* `expo-crypto` is an OPTIONAL peer, so it is resolved with a string-literal
|
|
16
15
|
* `require` inside a `try` (Metro's optional-dependency form; see
|
package/src/random.ts
CHANGED
|
@@ -2,13 +2,12 @@
|
|
|
2
2
|
* `@oxy.so/protocol/random` — the platform randomness source, and nothing else.
|
|
3
3
|
*
|
|
4
4
|
* `@oxy.so/core`'s crypto polyfill installs `globalThis.crypto.getRandomValues`
|
|
5
|
-
* on hosts that lack it (React Native / Hermes)
|
|
6
|
-
*
|
|
7
|
-
* has to be installed before any `@noble/*` module is evaluated. ES imports are
|
|
5
|
+
* on hosts that lack it (React Native / Hermes), and has to be installed before
|
|
6
|
+
* any module that reads `globalThis.crypto` is evaluated. ES imports are
|
|
8
7
|
* evaluated before the importing module's body, so whatever the polyfill
|
|
9
8
|
* imports is evaluated first: importing the ROOT entry (which reaches
|
|
10
|
-
* `@noble/curves` through the envelope signer) let noble capture
|
|
11
|
-
* and broke identity creation on Android.
|
|
9
|
+
* `@noble/curves` through the envelope signer) let `@noble/hashes` 1.x capture
|
|
10
|
+
* `undefined` at evaluation and broke identity creation on Android.
|
|
12
11
|
*
|
|
13
12
|
* This entry therefore reaches no crypto library, no `@oxy.so/*` package and no
|
|
14
13
|
* third-party module other than the optional `expo-crypto` peer (RN variant
|
package/src/secp256k1.ts
CHANGED
|
@@ -144,10 +144,13 @@ export function signSecp256k1Digest(
|
|
|
144
144
|
digestHex: string,
|
|
145
145
|
options: Secp256k1SignatureOptions = {},
|
|
146
146
|
): string {
|
|
147
|
+
// The input is already a digest: `prehash: false` keeps noble from hashing it again.
|
|
147
148
|
const signature = secp256k1.sign(parseDigest(digestHex), parsePrivateKey(privateKeyHex), {
|
|
149
|
+
prehash: false,
|
|
148
150
|
lowS: options.lowS ?? false,
|
|
151
|
+
format: 'der',
|
|
149
152
|
});
|
|
150
|
-
return signature
|
|
153
|
+
return bytesToHex(signature);
|
|
151
154
|
}
|
|
152
155
|
|
|
153
156
|
/** Verify a DER-encoded ECDSA signature, accepting historical high-S signatures. */
|
|
@@ -163,6 +166,7 @@ export function verifySecp256k1Digest(
|
|
|
163
166
|
// Parse once up front so malformed or non-DER input is rejected explicitly.
|
|
164
167
|
secp256k1.Signature.fromBytes(signature, 'der');
|
|
165
168
|
return secp256k1.verify(signature, digest, publicKey, {
|
|
169
|
+
prehash: false,
|
|
166
170
|
format: 'der',
|
|
167
171
|
lowS: false,
|
|
168
172
|
});
|