@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 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 |
@@ -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 decryptSecretboxToString: (a: number, b: number, c: number, d: number, e: number) => void;
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 encryptSecretboxString: (a: number, b: number, c: number, d: number, e: number) => void;
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;
@@ -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.3.7",
5
+ "version": "0.4.0",
6
6
  "license": "MIT OR Apache-2.0",
7
7
  "repository": {
8
8
  "type": "git",