@f0rest8/metamorphic-crypto 0.3.7 → 0.4.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/README.md +42 -0
- package/metamorphic_crypto.d.ts +40 -2
- package/metamorphic_crypto.js +171 -0
- package/metamorphic_crypto_bg.wasm +0 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -134,6 +134,48 @@ const secret = recoveryKeyToSecret("ABCD-EFGH-...");
|
|
|
134
134
|
const restored2 = decryptPrivateKeyWithRecovery(backup, secret);
|
|
135
135
|
```
|
|
136
136
|
|
|
137
|
+
### Hashing (SHA-3 / SHA-2)
|
|
138
|
+
|
|
139
|
+
Public, one-shot digest functions — intended for **public** data only, such as
|
|
140
|
+
key fingerprints, safety numbers, and key-transparency-log entries. Each takes
|
|
141
|
+
**base64-encoded input** and returns the digest as **base64**. Decode with
|
|
142
|
+
`atob`, or re-encode to hex, if you need a hex fingerprint.
|
|
143
|
+
|
|
144
|
+
`sha3_512` is the recommended default (highest assurance, NIST Cat-5). The
|
|
145
|
+
others let you match an existing format.
|
|
146
|
+
|
|
147
|
+
```js
|
|
148
|
+
import { sha3_512, sha3_256, sha256, sha512 } from "@f0rest8/metamorphic-crypto";
|
|
149
|
+
|
|
150
|
+
const dataBase64 = btoa("public key bytes");
|
|
151
|
+
const digestBase64 = sha3_512(dataBase64); // 64-byte digest, base64
|
|
152
|
+
|
|
153
|
+
// Need hex? decode the base64 digest:
|
|
154
|
+
const hex = [...atob(digestBase64)].map(c => c.charCodeAt(0).toString(16).padStart(2, "0")).join("");
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
**Domain separation (recommended for fingerprints / transparency logs).** Use
|
|
158
|
+
`sha3_512WithContext` to bind a digest to a versioned context label, so the same
|
|
159
|
+
bytes hashed for different purposes can never collide or be reinterpreted across
|
|
160
|
+
contexts. It is exactly as strong as `sha3_512`:
|
|
161
|
+
|
|
162
|
+
```js
|
|
163
|
+
import { sha3_512WithContext } from "@f0rest8/metamorphic-crypto";
|
|
164
|
+
|
|
165
|
+
const dataBase64 = btoa("public key bytes");
|
|
166
|
+
const fingerprint = sha3_512WithContext("mosslet/key-fingerprint/v1", dataBase64);
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Stable wire format (reproduce exactly to match native/Elixir):
|
|
170
|
+
`SHA3-512( u64_be(len(context_utf8)) || context_utf8 || data )`.
|
|
171
|
+
|
|
172
|
+
> **Do not hash secrets with these.** A bare hash makes no guarantees about its
|
|
173
|
+
> inputs, and the hashing path intentionally adds no zeroize/constant-time
|
|
174
|
+
> ceremony — wiping a transient copy of already-public data adds cost without
|
|
175
|
+
> protection. To process secret material (passwords, private keys), use the
|
|
176
|
+
> right construction instead: this package's Argon2id `deriveSessionKey` for
|
|
177
|
+
> password-based derivation, or a dedicated KDF/MAC.
|
|
178
|
+
|
|
137
179
|
## Security levels
|
|
138
180
|
|
|
139
181
|
| Level | ML-KEM | NIST Category | Equivalent | Default |
|
package/metamorphic_crypto.d.ts
CHANGED
|
@@ -115,6 +115,39 @@ export function sealForUser(plaintext_b64: string, public_key_b64: string, pq_pu
|
|
|
115
115
|
*/
|
|
116
116
|
export function sealForUserWithLevel(plaintext_b64: string, public_key_b64: string, pq_public_key_b64: string | null | undefined, level: string): string;
|
|
117
117
|
|
|
118
|
+
/**
|
|
119
|
+
* SHA-256 (SHA-2) digest of base64-encoded `data`. Returns the 32-byte digest as base64.
|
|
120
|
+
*/
|
|
121
|
+
export function sha256(data_b64: string): string;
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* SHA3-256 digest of base64-encoded `data`. Returns the 32-byte digest as base64.
|
|
125
|
+
*/
|
|
126
|
+
export function sha3_256(data_b64: string): string;
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* SHA3-512 digest of base64-encoded `data`. Returns the 64-byte digest as base64.
|
|
130
|
+
*
|
|
131
|
+
* This is the recommended default hash (NIST Cat-5).
|
|
132
|
+
*/
|
|
133
|
+
export function sha3_512(data_b64: string): string;
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Domain-separated SHA3-512: binds the digest to a UTF-8 `context` label.
|
|
137
|
+
*
|
|
138
|
+
* `data` is base64; returns the 64-byte digest as base64. Prefer this over
|
|
139
|
+
* `sha3_512` for fingerprints / safety numbers / key-transparency entries.
|
|
140
|
+
*
|
|
141
|
+
* Wire format (reproduce exactly for parity with native/Elixir):
|
|
142
|
+
* `SHA3-512( u64_be(len(context_utf8)) || context_utf8 || data )`.
|
|
143
|
+
*/
|
|
144
|
+
export function sha3_512WithContext(context: string, data_b64: string): string;
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* SHA-512 (SHA-2) digest of base64-encoded `data`. Returns the 64-byte digest as base64.
|
|
148
|
+
*/
|
|
149
|
+
export function sha512(data_b64: string): string;
|
|
150
|
+
|
|
118
151
|
/**
|
|
119
152
|
* Unseal ciphertext using the user's keys. Auto-detects format.
|
|
120
153
|
* Returns base64-encoded plaintext.
|
|
@@ -144,10 +177,15 @@ export interface InitOutput {
|
|
|
144
177
|
readonly generateRecoveryKey: (a: number) => void;
|
|
145
178
|
readonly recoveryKeyToSecret: (a: number, b: number, c: number) => void;
|
|
146
179
|
readonly parseSaltFromKeyHash: (a: number, b: number, c: number) => void;
|
|
147
|
-
readonly
|
|
180
|
+
readonly sha3_512: (a: number, b: number, c: number) => void;
|
|
181
|
+
readonly sha3_512WithContext: (a: number, b: number, c: number, d: number, e: number) => void;
|
|
182
|
+
readonly sha3_256: (a: number, b: number, c: number) => void;
|
|
183
|
+
readonly sha256: (a: number, b: number, c: number) => void;
|
|
184
|
+
readonly sha512: (a: number, b: number, c: number) => void;
|
|
185
|
+
readonly encryptSecretboxString: (a: number, b: number, c: number, d: number, e: number) => void;
|
|
148
186
|
readonly encryptPrivateKeyForRecovery: (a: number, b: number, c: number, d: number, e: number) => void;
|
|
149
187
|
readonly decryptPrivateKeyWithRecovery: (a: number, b: number, c: number, d: number, e: number) => void;
|
|
150
|
-
readonly
|
|
188
|
+
readonly decryptSecretboxToString: (a: number, b: number, c: number, d: number, e: number) => void;
|
|
151
189
|
readonly __wbindgen_export: (a: number, b: number) => number;
|
|
152
190
|
readonly __wbindgen_export2: (a: number, b: number, c: number, d: number) => number;
|
|
153
191
|
readonly __wbindgen_export3: (a: number) => void;
|
package/metamorphic_crypto.js
CHANGED
|
@@ -636,6 +636,177 @@ export function sealForUserWithLevel(plaintext_b64, public_key_b64, pq_public_ke
|
|
|
636
636
|
}
|
|
637
637
|
}
|
|
638
638
|
|
|
639
|
+
/**
|
|
640
|
+
* SHA-256 (SHA-2) digest of base64-encoded `data`. Returns the 32-byte digest as base64.
|
|
641
|
+
* @param {string} data_b64
|
|
642
|
+
* @returns {string}
|
|
643
|
+
*/
|
|
644
|
+
export function sha256(data_b64) {
|
|
645
|
+
let deferred3_0;
|
|
646
|
+
let deferred3_1;
|
|
647
|
+
try {
|
|
648
|
+
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
|
649
|
+
const ptr0 = passStringToWasm0(data_b64, wasm.__wbindgen_export, wasm.__wbindgen_export2);
|
|
650
|
+
const len0 = WASM_VECTOR_LEN;
|
|
651
|
+
wasm.sha256(retptr, ptr0, len0);
|
|
652
|
+
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
|
653
|
+
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
|
654
|
+
var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
|
|
655
|
+
var r3 = getDataViewMemory0().getInt32(retptr + 4 * 3, true);
|
|
656
|
+
var ptr2 = r0;
|
|
657
|
+
var len2 = r1;
|
|
658
|
+
if (r3) {
|
|
659
|
+
ptr2 = 0; len2 = 0;
|
|
660
|
+
throw takeObject(r2);
|
|
661
|
+
}
|
|
662
|
+
deferred3_0 = ptr2;
|
|
663
|
+
deferred3_1 = len2;
|
|
664
|
+
return getStringFromWasm0(ptr2, len2);
|
|
665
|
+
} finally {
|
|
666
|
+
wasm.__wbindgen_add_to_stack_pointer(16);
|
|
667
|
+
wasm.__wbindgen_export4(deferred3_0, deferred3_1, 1);
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
/**
|
|
672
|
+
* SHA3-256 digest of base64-encoded `data`. Returns the 32-byte digest as base64.
|
|
673
|
+
* @param {string} data_b64
|
|
674
|
+
* @returns {string}
|
|
675
|
+
*/
|
|
676
|
+
export function sha3_256(data_b64) {
|
|
677
|
+
let deferred3_0;
|
|
678
|
+
let deferred3_1;
|
|
679
|
+
try {
|
|
680
|
+
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
|
681
|
+
const ptr0 = passStringToWasm0(data_b64, wasm.__wbindgen_export, wasm.__wbindgen_export2);
|
|
682
|
+
const len0 = WASM_VECTOR_LEN;
|
|
683
|
+
wasm.sha3_256(retptr, ptr0, len0);
|
|
684
|
+
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
|
685
|
+
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
|
686
|
+
var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
|
|
687
|
+
var r3 = getDataViewMemory0().getInt32(retptr + 4 * 3, true);
|
|
688
|
+
var ptr2 = r0;
|
|
689
|
+
var len2 = r1;
|
|
690
|
+
if (r3) {
|
|
691
|
+
ptr2 = 0; len2 = 0;
|
|
692
|
+
throw takeObject(r2);
|
|
693
|
+
}
|
|
694
|
+
deferred3_0 = ptr2;
|
|
695
|
+
deferred3_1 = len2;
|
|
696
|
+
return getStringFromWasm0(ptr2, len2);
|
|
697
|
+
} finally {
|
|
698
|
+
wasm.__wbindgen_add_to_stack_pointer(16);
|
|
699
|
+
wasm.__wbindgen_export4(deferred3_0, deferred3_1, 1);
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
/**
|
|
704
|
+
* SHA3-512 digest of base64-encoded `data`. Returns the 64-byte digest as base64.
|
|
705
|
+
*
|
|
706
|
+
* This is the recommended default hash (NIST Cat-5).
|
|
707
|
+
* @param {string} data_b64
|
|
708
|
+
* @returns {string}
|
|
709
|
+
*/
|
|
710
|
+
export function sha3_512(data_b64) {
|
|
711
|
+
let deferred3_0;
|
|
712
|
+
let deferred3_1;
|
|
713
|
+
try {
|
|
714
|
+
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
|
715
|
+
const ptr0 = passStringToWasm0(data_b64, wasm.__wbindgen_export, wasm.__wbindgen_export2);
|
|
716
|
+
const len0 = WASM_VECTOR_LEN;
|
|
717
|
+
wasm.sha3_512(retptr, ptr0, len0);
|
|
718
|
+
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
|
719
|
+
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
|
720
|
+
var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
|
|
721
|
+
var r3 = getDataViewMemory0().getInt32(retptr + 4 * 3, true);
|
|
722
|
+
var ptr2 = r0;
|
|
723
|
+
var len2 = r1;
|
|
724
|
+
if (r3) {
|
|
725
|
+
ptr2 = 0; len2 = 0;
|
|
726
|
+
throw takeObject(r2);
|
|
727
|
+
}
|
|
728
|
+
deferred3_0 = ptr2;
|
|
729
|
+
deferred3_1 = len2;
|
|
730
|
+
return getStringFromWasm0(ptr2, len2);
|
|
731
|
+
} finally {
|
|
732
|
+
wasm.__wbindgen_add_to_stack_pointer(16);
|
|
733
|
+
wasm.__wbindgen_export4(deferred3_0, deferred3_1, 1);
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
/**
|
|
738
|
+
* Domain-separated SHA3-512: binds the digest to a UTF-8 `context` label.
|
|
739
|
+
*
|
|
740
|
+
* `data` is base64; returns the 64-byte digest as base64. Prefer this over
|
|
741
|
+
* `sha3_512` for fingerprints / safety numbers / key-transparency entries.
|
|
742
|
+
*
|
|
743
|
+
* Wire format (reproduce exactly for parity with native/Elixir):
|
|
744
|
+
* `SHA3-512( u64_be(len(context_utf8)) || context_utf8 || data )`.
|
|
745
|
+
* @param {string} context
|
|
746
|
+
* @param {string} data_b64
|
|
747
|
+
* @returns {string}
|
|
748
|
+
*/
|
|
749
|
+
export function sha3_512WithContext(context, data_b64) {
|
|
750
|
+
let deferred4_0;
|
|
751
|
+
let deferred4_1;
|
|
752
|
+
try {
|
|
753
|
+
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
|
754
|
+
const ptr0 = passStringToWasm0(context, wasm.__wbindgen_export, wasm.__wbindgen_export2);
|
|
755
|
+
const len0 = WASM_VECTOR_LEN;
|
|
756
|
+
const ptr1 = passStringToWasm0(data_b64, wasm.__wbindgen_export, wasm.__wbindgen_export2);
|
|
757
|
+
const len1 = WASM_VECTOR_LEN;
|
|
758
|
+
wasm.sha3_512WithContext(retptr, ptr0, len0, ptr1, len1);
|
|
759
|
+
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
|
760
|
+
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
|
761
|
+
var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
|
|
762
|
+
var r3 = getDataViewMemory0().getInt32(retptr + 4 * 3, true);
|
|
763
|
+
var ptr3 = r0;
|
|
764
|
+
var len3 = r1;
|
|
765
|
+
if (r3) {
|
|
766
|
+
ptr3 = 0; len3 = 0;
|
|
767
|
+
throw takeObject(r2);
|
|
768
|
+
}
|
|
769
|
+
deferred4_0 = ptr3;
|
|
770
|
+
deferred4_1 = len3;
|
|
771
|
+
return getStringFromWasm0(ptr3, len3);
|
|
772
|
+
} finally {
|
|
773
|
+
wasm.__wbindgen_add_to_stack_pointer(16);
|
|
774
|
+
wasm.__wbindgen_export4(deferred4_0, deferred4_1, 1);
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
/**
|
|
779
|
+
* SHA-512 (SHA-2) digest of base64-encoded `data`. Returns the 64-byte digest as base64.
|
|
780
|
+
* @param {string} data_b64
|
|
781
|
+
* @returns {string}
|
|
782
|
+
*/
|
|
783
|
+
export function sha512(data_b64) {
|
|
784
|
+
let deferred3_0;
|
|
785
|
+
let deferred3_1;
|
|
786
|
+
try {
|
|
787
|
+
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
|
788
|
+
const ptr0 = passStringToWasm0(data_b64, wasm.__wbindgen_export, wasm.__wbindgen_export2);
|
|
789
|
+
const len0 = WASM_VECTOR_LEN;
|
|
790
|
+
wasm.sha512(retptr, ptr0, len0);
|
|
791
|
+
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
|
792
|
+
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
|
793
|
+
var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
|
|
794
|
+
var r3 = getDataViewMemory0().getInt32(retptr + 4 * 3, true);
|
|
795
|
+
var ptr2 = r0;
|
|
796
|
+
var len2 = r1;
|
|
797
|
+
if (r3) {
|
|
798
|
+
ptr2 = 0; len2 = 0;
|
|
799
|
+
throw takeObject(r2);
|
|
800
|
+
}
|
|
801
|
+
deferred3_0 = ptr2;
|
|
802
|
+
deferred3_1 = len2;
|
|
803
|
+
return getStringFromWasm0(ptr2, len2);
|
|
804
|
+
} finally {
|
|
805
|
+
wasm.__wbindgen_add_to_stack_pointer(16);
|
|
806
|
+
wasm.__wbindgen_export4(deferred3_0, deferred3_1, 1);
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
|
|
639
810
|
/**
|
|
640
811
|
* Unseal ciphertext using the user's keys. Auto-detects format.
|
|
641
812
|
* Returns base64-encoded plaintext.
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@f0rest8/metamorphic-crypto",
|
|
3
3
|
"type": "module",
|
|
4
4
|
"description": "Zero-knowledge end-to-end encryption with post-quantum hybrid KEM (ML-KEM-768/1024 + X25519)",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.4.0",
|
|
6
6
|
"license": "MIT OR Apache-2.0",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|