@oxy.so/protocol 1.1.4 → 1.2.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/.tsbuildinfo +1 -1
- package/dist/cjs/index.js +2 -2
- package/dist/cjs/platform/crypto.js +4 -7
- package/dist/cjs/platform/crypto.native.js +64 -34
- package/dist/cjs/secp256k1.js +24 -0
- package/dist/esm/.tsbuildinfo +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/platform/crypto.js +3 -6
- package/dist/esm/platform/crypto.native.js +63 -33
- package/dist/esm/secp256k1.js +23 -0
- package/dist/types/.tsbuildinfo +1 -1
- package/dist/types/index.d.ts +2 -2
- package/dist/types/platform/crypto.d.ts +3 -3
- package/dist/types/platform/crypto.native.d.ts +3 -3
- package/dist/types/platform/expoTypes.d.ts +52 -20
- package/dist/types/secp256k1.d.ts +8 -0
- package/package.json +2 -2
- package/src/__tests__/commonsIdentityBridge.test.ts +109 -0
- package/src/index.ts +9 -2
- package/src/platform/crypto.native.ts +101 -33
- package/src/platform/crypto.ts +19 -8
- package/src/platform/expoTypes.ts +55 -17
- package/src/secp256k1.ts +27 -0
package/dist/esm/index.js
CHANGED
|
@@ -37,4 +37,4 @@ export { isAuthorizedKey } from './identity/resolver.js';
|
|
|
37
37
|
// Platform — runtime predicates + lazy crypto/storage loaders
|
|
38
38
|
// ---------------------------------------------------------------------------
|
|
39
39
|
export { isReactNative, isNodeJS } from './platform/platform.js';
|
|
40
|
-
export { loadNodeCrypto, loadExpoCrypto, loadSecureStore, loadAsyncStorage, getRandomBytesRN,
|
|
40
|
+
export { loadNodeCrypto, loadExpoCrypto, loadSecureStore, loadAsyncStorage, getRandomBytesRN, loadCommonsIdentityBridge, } from './platform/crypto.js';
|
|
@@ -128,13 +128,10 @@ export async function loadAsyncStorage() {
|
|
|
128
128
|
// `@oxy.so/protocol/random` entry without evaluating any crypto library first.
|
|
129
129
|
export { getRandomBytesRN } from './random.js';
|
|
130
130
|
// ---------------------------------------------------------------------------
|
|
131
|
-
//
|
|
131
|
+
// Commons identity bridge — the `OxyIdentity` native module (native-only).
|
|
132
132
|
//
|
|
133
|
-
//
|
|
134
|
-
// always resolves to `null`. `@oxy.so/core`'s `KeyManager` treats `null` as "no
|
|
135
|
-
// bridge" and falls back to its package-private store — which is correct on web
|
|
136
|
-
// (there is no shared identity there).
|
|
133
|
+
// Web and Node have no Commons to ask, so this always resolves to `null`.
|
|
137
134
|
// ---------------------------------------------------------------------------
|
|
138
|
-
export function
|
|
135
|
+
export function loadCommonsIdentityBridge() {
|
|
139
136
|
return Promise.resolve(null);
|
|
140
137
|
}
|
|
@@ -123,41 +123,71 @@ export async function loadAsyncStorage() {
|
|
|
123
123
|
// any crypto library first. The explicit `.native` specifier keeps tsc and
|
|
124
124
|
// Metro pointed at the same file.
|
|
125
125
|
export { getRandomBytesRN } from './random.native.js';
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
126
|
+
const LOWER_HEX = /^[0-9a-f]+$/;
|
|
127
|
+
function record(value) {
|
|
128
|
+
return typeof value === 'object' && value !== null ? value : null;
|
|
129
|
+
}
|
|
130
|
+
function hexField(value, length) {
|
|
131
|
+
if (typeof value !== 'string' || !LOWER_HEX.test(value))
|
|
132
|
+
return null;
|
|
133
|
+
if (length !== undefined && value.length !== length)
|
|
134
|
+
return null;
|
|
135
|
+
return value;
|
|
136
|
+
}
|
|
137
|
+
function narrowDescription(value) {
|
|
138
|
+
const r = record(value);
|
|
139
|
+
const publicKey = hexField(r?.publicKey, 130);
|
|
140
|
+
const v = typeof r?.v === 'number' ? r.v : Number(r?.v);
|
|
141
|
+
if (!publicKey || !Number.isInteger(v))
|
|
142
|
+
return null;
|
|
143
|
+
return { v, publicKey };
|
|
144
|
+
}
|
|
145
|
+
function narrowProof(value) {
|
|
146
|
+
const r = record(value);
|
|
147
|
+
const publicKey = hexField(r?.publicKey, 130);
|
|
148
|
+
const signature = hexField(r?.signature);
|
|
149
|
+
const timestamp = typeof r?.timestamp === 'number' ? r.timestamp : Number(r?.timestamp);
|
|
150
|
+
if (!publicKey || !signature || !Number.isSafeInteger(timestamp) || timestamp <= 0)
|
|
151
|
+
return null;
|
|
152
|
+
return { publicKey, signature, timestamp };
|
|
153
|
+
}
|
|
154
|
+
function narrowSocialReceive(value) {
|
|
155
|
+
const r = record(value);
|
|
156
|
+
const signature = hexField(r?.signature);
|
|
157
|
+
const publicKey = hexField(r?.publicKey, 66);
|
|
158
|
+
if (!signature || !publicKey)
|
|
159
|
+
return null;
|
|
160
|
+
return { signature, publicKey };
|
|
161
|
+
}
|
|
162
|
+
/** Run one native call; a rejection or an unexpected shape is `null`. */
|
|
163
|
+
async function ask(call, narrow) {
|
|
164
|
+
try {
|
|
165
|
+
return narrow(await call());
|
|
166
|
+
}
|
|
167
|
+
catch {
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
let commonsIdentityBridgePromise = null;
|
|
172
|
+
export function loadCommonsIdentityBridge() {
|
|
173
|
+
if (!commonsIdentityBridgePromise) {
|
|
174
|
+
commonsIdentityBridgePromise = Promise.resolve().then(() => {
|
|
146
175
|
const native = requireOptionalNativeModule('OxyIdentity');
|
|
147
|
-
if (native
|
|
148
|
-
typeof native.
|
|
149
|
-
typeof native.
|
|
150
|
-
typeof native.
|
|
151
|
-
typeof native.
|
|
152
|
-
return
|
|
153
|
-
getShared: native.getShared.bind(native),
|
|
154
|
-
putShared: native.putShared.bind(native),
|
|
155
|
-
hasShared: native.hasShared.bind(native),
|
|
156
|
-
clearShared: native.clearShared.bind(native),
|
|
157
|
-
};
|
|
176
|
+
if (!native ||
|
|
177
|
+
typeof native.describe !== 'function' ||
|
|
178
|
+
typeof native.proveIdentity !== 'function' ||
|
|
179
|
+
typeof native.deriveScopedSeed !== 'function' ||
|
|
180
|
+
typeof native.signSocialReceive !== 'function') {
|
|
181
|
+
return null;
|
|
158
182
|
}
|
|
159
|
-
|
|
183
|
+
const m = native;
|
|
184
|
+
return {
|
|
185
|
+
describe: () => ask(() => m.describe(), narrowDescription),
|
|
186
|
+
proveIdentity: (challenge) => ask(() => m.proveIdentity(challenge), narrowProof),
|
|
187
|
+
deriveScopedSeed: (info) => ask(() => m.deriveScopedSeed(info), (v) => hexField(v, 64)),
|
|
188
|
+
signSocialReceive: (index, digest) => ask(() => m.signSocialReceive(index, digest), narrowSocialReceive),
|
|
189
|
+
};
|
|
160
190
|
});
|
|
161
191
|
}
|
|
162
|
-
return
|
|
192
|
+
return commonsIdentityBridgePromise;
|
|
163
193
|
}
|
package/dist/esm/secp256k1.js
CHANGED
|
@@ -127,6 +127,29 @@ export function verifySecp256k1Digest(publicKeyHex, digestHex, signatureDerHex)
|
|
|
127
127
|
lowS: false,
|
|
128
128
|
});
|
|
129
129
|
}
|
|
130
|
+
/**
|
|
131
|
+
* `(privateKey + tweak) mod n`, the scalar step of BIP32 non-hardened child
|
|
132
|
+
* derivation (`CKDpriv`: the tweak is `IL`, the left half of the HMAC-SHA512).
|
|
133
|
+
*
|
|
134
|
+
* Throws, as BIP32 requires, when the tweak is not below the curve order or
|
|
135
|
+
* the sum is zero: that child is invalid and the caller must not use it.
|
|
136
|
+
*/
|
|
137
|
+
export function tweakAddSecp256k1PrivateKey(privateKeyHex, tweakHex) {
|
|
138
|
+
const n = secp256k1.Point.Fn.ORDER;
|
|
139
|
+
const key = BigInt(`0x${normalizeSecp256k1PrivateKey(privateKeyHex)}`);
|
|
140
|
+
if (typeof tweakHex !== "string" || tweakHex.length !== 64 || !HEX.test(tweakHex)) {
|
|
141
|
+
throw new Error("secp256k1 tweak must be exactly 32 bytes of hexadecimal data");
|
|
142
|
+
}
|
|
143
|
+
const tweak = BigInt(`0x${tweakHex}`);
|
|
144
|
+
if (tweak >= n) {
|
|
145
|
+
throw new Error("secp256k1 tweak is not below the curve order");
|
|
146
|
+
}
|
|
147
|
+
const child = (key + tweak) % n;
|
|
148
|
+
if (child === 0n) {
|
|
149
|
+
throw new Error("secp256k1 tweaked private key is zero");
|
|
150
|
+
}
|
|
151
|
+
return child.toString(16).padStart(64, "0");
|
|
152
|
+
}
|
|
130
153
|
/** Derive the fixed-width 32-byte ECDH x-coordinate shared secret. */
|
|
131
154
|
export function deriveSecp256k1SharedSecret(privateKeyHex, publicKeyHex) {
|
|
132
155
|
const encodedPoint = secp256k1.getSharedSecret(parsePrivateKey(privateKeyHex), parsePublicKey(publicKeyHex), true);
|