@k9o/kibo-react-native 0.0.0-stage → 1.1.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/LICENSE +201 -0
- package/NOTICE +4 -0
- package/README.md +172 -2
- package/package.json +41 -4
- package/src/KiboError.ts +24 -0
- package/src/crypto-types.ts +118 -0
- package/src/crypto.ts +115 -0
- package/src/index.ts +33 -0
- package/wasm/kibo_kms_rest_ffi.d.ts +105 -0
- package/wasm/kibo_kms_rest_ffi.js +977 -0
- package/wasm/kibo_kms_rest_ffi_bg.wasm +0 -0
- package/wasm/kibo_kms_rest_ffi_bg.wasm.d.ts +26 -0
package/src/crypto.ts
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ZK encrypt/decrypt — the thin React Native wrapper over the bound crypto core
|
|
3
|
+
* (`kibo-kms-rest-ffi`, piece C) compiled to wasm. ZERO crypto here: every
|
|
4
|
+
* wrap/unwrap, envelope framing, posture-floor enforcement, and KMS round-trip
|
|
5
|
+
* lives in the audited Rust core. This layer only marshals the typed input
|
|
6
|
+
* across the wasm boundary and maps the core's error string → `KiboError`.
|
|
7
|
+
*
|
|
8
|
+
* Unlike the Node `@k9o/kibo` package, RN cannot dynamically `import()` the
|
|
9
|
+
* vendored wasm at runtime — the host must load the core wasm (per its bundler /
|
|
10
|
+
* `react-native-wasm` runtime) and inject it via `setZkWasm` before the first
|
|
11
|
+
* `encrypt` / `decrypt`. This mirrors `@k9o/kibo`'s `setZkWasm` escape hatch.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { KiboError } from "./KiboError";
|
|
15
|
+
import type {
|
|
16
|
+
KiboEncryptInput,
|
|
17
|
+
KiboEncryptOutput,
|
|
18
|
+
KiboDecryptInput,
|
|
19
|
+
KiboDecryptOutput,
|
|
20
|
+
} from "./crypto-types";
|
|
21
|
+
|
|
22
|
+
/** The minimal surface the bound ZK-core wasm exposes. */
|
|
23
|
+
export interface ZkWasm {
|
|
24
|
+
zk_encrypt(input: unknown): Promise<unknown>;
|
|
25
|
+
zk_decrypt(input: unknown): Promise<unknown>;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
let zkWasm: ZkWasm | undefined;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Inject the host-loaded core wasm module. MUST be called once at app start
|
|
32
|
+
* (before any `encrypt` / `decrypt`) with the provider-matched core build.
|
|
33
|
+
*/
|
|
34
|
+
export function setZkWasm(mod: ZkWasm): void {
|
|
35
|
+
zkWasm = mod;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function requireWasm(): ZkWasm {
|
|
39
|
+
if (!zkWasm) {
|
|
40
|
+
throw new KiboError({
|
|
41
|
+
code: "KIBO_WASM_NOT_LOADED",
|
|
42
|
+
message:
|
|
43
|
+
"ZK core wasm not loaded. Call setZkWasm(coreModule) once at app start before encrypt/decrypt.",
|
|
44
|
+
context: {},
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
return zkWasm;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Encrypt `input.plaintext` via the customer KMS, client-side. Returns the
|
|
52
|
+
* opaque ZKFE envelope — store it via the gateway ZK-DEK surface (F.5) or keep
|
|
53
|
+
* it yourself; it is meaningless to the platform.
|
|
54
|
+
*/
|
|
55
|
+
export async function encrypt(input: KiboEncryptInput): Promise<KiboEncryptOutput> {
|
|
56
|
+
const wasm = requireWasm();
|
|
57
|
+
let out: unknown;
|
|
58
|
+
try {
|
|
59
|
+
out = await wasm.zk_encrypt(input);
|
|
60
|
+
} catch (e) {
|
|
61
|
+
throw mapZkError(e);
|
|
62
|
+
}
|
|
63
|
+
return { envelope: toBytes((out as { envelope?: unknown }).envelope) };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Decrypt a ZKFE `input.envelope`. `strategy`, `attestation_tier`, and
|
|
68
|
+
* `encryption_context` MUST match the values used at encrypt — they are AAD-bound
|
|
69
|
+
* and never recovered from the envelope (anti-substitution discipline).
|
|
70
|
+
*/
|
|
71
|
+
export async function decrypt(input: KiboDecryptInput): Promise<KiboDecryptOutput> {
|
|
72
|
+
const wasm = requireWasm();
|
|
73
|
+
let out: unknown;
|
|
74
|
+
try {
|
|
75
|
+
out = await wasm.zk_decrypt(input);
|
|
76
|
+
} catch (e) {
|
|
77
|
+
throw mapZkError(e);
|
|
78
|
+
}
|
|
79
|
+
return { plaintext: toBytes((out as { plaintext?: unknown }).plaintext) };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** Normalise wasm byte output (serde-wasm-bindgen emits `Vec<u8>` as a number
|
|
83
|
+
* array; some hosts return a `Uint8Array`) to `Uint8Array`. */
|
|
84
|
+
function toBytes(v: unknown): Uint8Array {
|
|
85
|
+
if (v instanceof Uint8Array) return v;
|
|
86
|
+
if (Array.isArray(v)) return Uint8Array.from(v as number[]);
|
|
87
|
+
throw new KiboError({
|
|
88
|
+
code: "KIBO_WASM_DECODE_ERROR",
|
|
89
|
+
message: "ZK core returned a non-byte value where bytes were expected",
|
|
90
|
+
context: {},
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Map the core's rejected error → `KiboError`. The wasm path flattens
|
|
96
|
+
* `ZkFfiError` to its display string: `"<CODE>: <message>"` where `<CODE>` is a
|
|
97
|
+
* `K9O_*` wire code (or `UPSTREAM_KMS_ERROR` for the customer's own KMS
|
|
98
|
+
* failures), optionally followed by `"(dimension: …, requested: …, declared: …)"`
|
|
99
|
+
* for a posture-floor violation. Codes are passed through (never hardcoded).
|
|
100
|
+
*/
|
|
101
|
+
function mapZkError(e: unknown): KiboError {
|
|
102
|
+
if (e instanceof KiboError) return e;
|
|
103
|
+
const raw = e instanceof Error ? e.message : String(e);
|
|
104
|
+
const head = /^([A-Z][A-Z0-9_]*):\s*([\s\S]*)$/.exec(raw);
|
|
105
|
+
const code = head?.[1] ?? "KIBO_WASM_ERROR";
|
|
106
|
+
let message = head?.[2] ?? raw;
|
|
107
|
+
|
|
108
|
+
let context: Record<string, unknown> = {};
|
|
109
|
+
const pv = /\(dimension:\s*([^,]+),\s*requested:\s*([^,]+),\s*declared:\s*([^)]+)\)\s*$/.exec(message);
|
|
110
|
+
if (pv) {
|
|
111
|
+
context = { dimension: pv[1]!.trim(), requested: pv[2]!.trim(), declared: pv[3]!.trim() };
|
|
112
|
+
message = message.slice(0, pv.index).trim();
|
|
113
|
+
}
|
|
114
|
+
return new KiboError({ code, message, context });
|
|
115
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@k9o/kibo-react-native` — Zero-Knowledge BYOK/HYOK vault SDK for React Native.
|
|
3
|
+
*
|
|
4
|
+
* `encrypt` / `decrypt` run entirely client-side against the customer's own KMS;
|
|
5
|
+
* the platform never sees plaintext or unwrapped keys. All cryptography lives in
|
|
6
|
+
* the audited Rust core (`kibo-kms-rest-ffi`) compiled to wasm; this package only
|
|
7
|
+
* marshals typed input across the wasm boundary.
|
|
8
|
+
*
|
|
9
|
+
* The host loads the core wasm and injects it via `setZkWasm` once at app start
|
|
10
|
+
* (RN cannot dynamically import the artifact). The F.5 ZK-DEK store/fetch surface
|
|
11
|
+
* (envelope persistence over the gateway) is separate + decoupled.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
export { encrypt, decrypt, setZkWasm, type ZkWasm } from "./crypto";
|
|
15
|
+
export { KiboError } from "./KiboError";
|
|
16
|
+
export type {
|
|
17
|
+
KmsProvider,
|
|
18
|
+
KiboPosture,
|
|
19
|
+
KiboStrategy,
|
|
20
|
+
KiboOracleMode,
|
|
21
|
+
KiboAttestationTier,
|
|
22
|
+
KiboMinPosture,
|
|
23
|
+
KiboAllowedOracleModes,
|
|
24
|
+
KiboPosturePolicy,
|
|
25
|
+
KiboCredential,
|
|
26
|
+
KiboKeyRef,
|
|
27
|
+
KiboProviderConfig,
|
|
28
|
+
KiboKvPair,
|
|
29
|
+
KiboEncryptInput,
|
|
30
|
+
KiboEncryptOutput,
|
|
31
|
+
KiboDecryptInput,
|
|
32
|
+
KiboDecryptOutput,
|
|
33
|
+
} from "./crypto-types";
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/* tslint:disable */
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
/**
|
|
4
|
+
* The `ReadableStreamType` enum.
|
|
5
|
+
*
|
|
6
|
+
* *This API requires the following crate features to be activated: `ReadableStreamType`*
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
type ReadableStreamType = "bytes";
|
|
10
|
+
|
|
11
|
+
export class IntoUnderlyingByteSource {
|
|
12
|
+
private constructor();
|
|
13
|
+
free(): void;
|
|
14
|
+
[Symbol.dispose](): void;
|
|
15
|
+
cancel(): void;
|
|
16
|
+
pull(controller: ReadableByteStreamController): Promise<any>;
|
|
17
|
+
start(controller: ReadableByteStreamController): void;
|
|
18
|
+
readonly autoAllocateChunkSize: number;
|
|
19
|
+
readonly type: ReadableStreamType;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export class IntoUnderlyingSink {
|
|
23
|
+
private constructor();
|
|
24
|
+
free(): void;
|
|
25
|
+
[Symbol.dispose](): void;
|
|
26
|
+
abort(reason: any): Promise<any>;
|
|
27
|
+
close(): Promise<any>;
|
|
28
|
+
write(chunk: any): Promise<any>;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export class IntoUnderlyingSource {
|
|
32
|
+
private constructor();
|
|
33
|
+
free(): void;
|
|
34
|
+
[Symbol.dispose](): void;
|
|
35
|
+
cancel(): void;
|
|
36
|
+
pull(controller: ReadableStreamDefaultController): Promise<any>;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Decrypt a ZKFE envelope (browser / React Native).
|
|
41
|
+
*
|
|
42
|
+
* `input_json` — JSON-serialized `DecryptInput`.
|
|
43
|
+
* Returns a `Promise<string>` resolving to JSON-serialized `DecryptOutput`.
|
|
44
|
+
*/
|
|
45
|
+
export function zk_decrypt(input_json: any): Promise<any>;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Encrypt via the customer KMS (browser / React Native).
|
|
49
|
+
*
|
|
50
|
+
* `input_json` — JSON-serialized `EncryptInput`.
|
|
51
|
+
* Returns a `Promise<string>` resolving to JSON-serialized `EncryptOutput`,
|
|
52
|
+
* or rejecting with a `JsValue` error string.
|
|
53
|
+
*/
|
|
54
|
+
export function zk_encrypt(input_json: any): Promise<any>;
|
|
55
|
+
|
|
56
|
+
export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
|
|
57
|
+
|
|
58
|
+
export interface InitOutput {
|
|
59
|
+
readonly memory: WebAssembly.Memory;
|
|
60
|
+
readonly zk_decrypt: (a: number) => number;
|
|
61
|
+
readonly zk_encrypt: (a: number) => number;
|
|
62
|
+
readonly __wbg_intounderlyingbytesource_free: (a: number, b: number) => void;
|
|
63
|
+
readonly __wbg_intounderlyingsink_free: (a: number, b: number) => void;
|
|
64
|
+
readonly __wbg_intounderlyingsource_free: (a: number, b: number) => void;
|
|
65
|
+
readonly intounderlyingbytesource_autoAllocateChunkSize: (a: number) => number;
|
|
66
|
+
readonly intounderlyingbytesource_cancel: (a: number) => void;
|
|
67
|
+
readonly intounderlyingbytesource_pull: (a: number, b: number) => number;
|
|
68
|
+
readonly intounderlyingbytesource_start: (a: number, b: number) => void;
|
|
69
|
+
readonly intounderlyingbytesource_type: (a: number) => number;
|
|
70
|
+
readonly intounderlyingsink_abort: (a: number, b: number) => number;
|
|
71
|
+
readonly intounderlyingsink_close: (a: number) => number;
|
|
72
|
+
readonly intounderlyingsink_write: (a: number, b: number) => number;
|
|
73
|
+
readonly intounderlyingsource_cancel: (a: number) => void;
|
|
74
|
+
readonly intounderlyingsource_pull: (a: number, b: number) => number;
|
|
75
|
+
readonly __wasm_bindgen_func_elem_441: (a: number, b: number, c: number, d: number) => void;
|
|
76
|
+
readonly __wasm_bindgen_func_elem_722: (a: number, b: number, c: number, d: number) => void;
|
|
77
|
+
readonly __wasm_bindgen_func_elem_1519: (a: number, b: number) => void;
|
|
78
|
+
readonly __wbindgen_export: (a: number, b: number) => number;
|
|
79
|
+
readonly __wbindgen_export2: (a: number, b: number, c: number, d: number) => number;
|
|
80
|
+
readonly __wbindgen_export3: (a: number) => void;
|
|
81
|
+
readonly __wbindgen_export4: (a: number, b: number) => void;
|
|
82
|
+
readonly __wbindgen_add_to_stack_pointer: (a: number) => number;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export type SyncInitInput = BufferSource | WebAssembly.Module;
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Instantiates the given `module`, which can either be bytes or
|
|
89
|
+
* a precompiled `WebAssembly.Module`.
|
|
90
|
+
*
|
|
91
|
+
* @param {{ module: SyncInitInput }} module - Passing `SyncInitInput` directly is deprecated.
|
|
92
|
+
*
|
|
93
|
+
* @returns {InitOutput}
|
|
94
|
+
*/
|
|
95
|
+
export function initSync(module: { module: SyncInitInput } | SyncInitInput): InitOutput;
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* If `module_or_path` is {RequestInfo} or {URL}, makes a request and
|
|
99
|
+
* for everything else, calls `WebAssembly.instantiate` directly.
|
|
100
|
+
*
|
|
101
|
+
* @param {{ module_or_path: InitInput | Promise<InitInput> }} module_or_path - Passing `InitInput` directly is deprecated.
|
|
102
|
+
*
|
|
103
|
+
* @returns {Promise<InitOutput>}
|
|
104
|
+
*/
|
|
105
|
+
export default function __wbg_init (module_or_path?: { module_or_path: InitInput | Promise<InitInput> } | InitInput | Promise<InitInput>): Promise<InitOutput>;
|