react-native-quick-crypto 1.1.1 → 1.1.2

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.
Files changed (181) hide show
  1. package/QuickCrypto.podspec +1 -0
  2. package/android/CMakeLists.txt +4 -0
  3. package/cpp/cipher/CCMCipher.cpp +7 -11
  4. package/cpp/cipher/ChaCha20Cipher.cpp +6 -10
  5. package/cpp/cipher/ChaCha20Poly1305Cipher.cpp +10 -16
  6. package/cpp/cipher/GCMCipher.cpp +3 -5
  7. package/cpp/cipher/HybridCipher.cpp +7 -13
  8. package/cpp/cipher/HybridRsaCipher.cpp +19 -27
  9. package/cpp/cipher/OCBCipher.cpp +2 -3
  10. package/cpp/cipher/XChaCha20Poly1305Cipher.cpp +13 -19
  11. package/cpp/cipher/XSalsa20Cipher.cpp +8 -12
  12. package/cpp/cipher/XSalsa20Poly1305Cipher.cpp +11 -16
  13. package/cpp/keys/HybridKeyObjectHandle.cpp +630 -2
  14. package/cpp/keys/HybridKeyObjectHandle.hpp +21 -1
  15. package/cpp/sign/HybridSignHandle.cpp +26 -8
  16. package/cpp/sign/HybridVerifyHandle.cpp +28 -11
  17. package/cpp/slhdsa/HybridSlhDsaKeyPair.cpp +245 -0
  18. package/cpp/slhdsa/HybridSlhDsaKeyPair.hpp +48 -0
  19. package/cpp/turboshake/HybridTurboShake.cpp +379 -0
  20. package/cpp/turboshake/HybridTurboShake.hpp +28 -0
  21. package/cpp/utils/HybridUtils.cpp +26 -14
  22. package/deps/blake3/README.md +6 -7
  23. package/deps/blake3/c/blake3.c +3 -2
  24. package/deps/blake3/c/blake3.h +2 -2
  25. package/deps/blake3/c/blake3_dispatch.c +2 -2
  26. package/deps/blake3/c/blake3_impl.h +1 -1
  27. package/deps/blake3/c/blake3_neon.c +5 -4
  28. package/deps/ncrypto/include/ncrypto/version.h +2 -2
  29. package/deps/ncrypto/include/ncrypto.h +9 -2
  30. package/deps/ncrypto/src/ncrypto.cpp +130 -35
  31. package/lib/commonjs/dhKeyPair.js +3 -0
  32. package/lib/commonjs/dhKeyPair.js.map +1 -1
  33. package/lib/commonjs/dsa.js +3 -0
  34. package/lib/commonjs/dsa.js.map +1 -1
  35. package/lib/commonjs/ec.js +37 -30
  36. package/lib/commonjs/ec.js.map +1 -1
  37. package/lib/commonjs/ed.js +60 -6
  38. package/lib/commonjs/ed.js.map +1 -1
  39. package/lib/commonjs/hash.js +52 -5
  40. package/lib/commonjs/hash.js.map +1 -1
  41. package/lib/commonjs/keys/classes.js +33 -7
  42. package/lib/commonjs/keys/classes.js.map +1 -1
  43. package/lib/commonjs/keys/generateKeyPair.js +85 -4
  44. package/lib/commonjs/keys/generateKeyPair.js.map +1 -1
  45. package/lib/commonjs/keys/index.js +50 -2
  46. package/lib/commonjs/keys/index.js.map +1 -1
  47. package/lib/commonjs/keys/signVerify.js +9 -2
  48. package/lib/commonjs/keys/signVerify.js.map +1 -1
  49. package/lib/commonjs/keys/utils.js +59 -1
  50. package/lib/commonjs/keys/utils.js.map +1 -1
  51. package/lib/commonjs/random.js +63 -9
  52. package/lib/commonjs/random.js.map +1 -1
  53. package/lib/commonjs/rsa.js +3 -0
  54. package/lib/commonjs/rsa.js.map +1 -1
  55. package/lib/commonjs/slhdsa.js +70 -0
  56. package/lib/commonjs/slhdsa.js.map +1 -0
  57. package/lib/commonjs/specs/slhDsaKeyPair.nitro.js +6 -0
  58. package/lib/commonjs/specs/slhDsaKeyPair.nitro.js.map +1 -0
  59. package/lib/commonjs/specs/turboshake.nitro.js +6 -0
  60. package/lib/commonjs/specs/turboshake.nitro.js.map +1 -0
  61. package/lib/commonjs/subtle.js +926 -275
  62. package/lib/commonjs/subtle.js.map +1 -1
  63. package/lib/commonjs/utils/conversion.js +53 -19
  64. package/lib/commonjs/utils/conversion.js.map +1 -1
  65. package/lib/commonjs/utils/errors.js +63 -4
  66. package/lib/commonjs/utils/errors.js.map +1 -1
  67. package/lib/commonjs/utils/types.js.map +1 -1
  68. package/lib/commonjs/utils/validation.js +46 -0
  69. package/lib/commonjs/utils/validation.js.map +1 -1
  70. package/lib/module/dhKeyPair.js +3 -0
  71. package/lib/module/dhKeyPair.js.map +1 -1
  72. package/lib/module/dsa.js +3 -0
  73. package/lib/module/dsa.js.map +1 -1
  74. package/lib/module/ec.js +38 -31
  75. package/lib/module/ec.js.map +1 -1
  76. package/lib/module/ed.js +61 -7
  77. package/lib/module/ed.js.map +1 -1
  78. package/lib/module/hash.js +52 -5
  79. package/lib/module/hash.js.map +1 -1
  80. package/lib/module/keys/classes.js +31 -5
  81. package/lib/module/keys/classes.js.map +1 -1
  82. package/lib/module/keys/generateKeyPair.js +86 -5
  83. package/lib/module/keys/generateKeyPair.js.map +1 -1
  84. package/lib/module/keys/index.js +50 -2
  85. package/lib/module/keys/index.js.map +1 -1
  86. package/lib/module/keys/signVerify.js +9 -2
  87. package/lib/module/keys/signVerify.js.map +1 -1
  88. package/lib/module/keys/utils.js +57 -1
  89. package/lib/module/keys/utils.js.map +1 -1
  90. package/lib/module/random.js +63 -10
  91. package/lib/module/random.js.map +1 -1
  92. package/lib/module/rsa.js +3 -0
  93. package/lib/module/rsa.js.map +1 -1
  94. package/lib/module/slhdsa.js +64 -0
  95. package/lib/module/slhdsa.js.map +1 -0
  96. package/lib/module/specs/slhDsaKeyPair.nitro.js +4 -0
  97. package/lib/module/specs/slhDsaKeyPair.nitro.js.map +1 -0
  98. package/lib/module/specs/turboshake.nitro.js +4 -0
  99. package/lib/module/specs/turboshake.nitro.js.map +1 -0
  100. package/lib/module/subtle.js +927 -276
  101. package/lib/module/subtle.js.map +1 -1
  102. package/lib/module/utils/conversion.js +51 -19
  103. package/lib/module/utils/conversion.js.map +1 -1
  104. package/lib/module/utils/errors.js +61 -4
  105. package/lib/module/utils/errors.js.map +1 -1
  106. package/lib/module/utils/types.js.map +1 -1
  107. package/lib/module/utils/validation.js +44 -0
  108. package/lib/module/utils/validation.js.map +1 -1
  109. package/lib/typescript/dhKeyPair.d.ts.map +1 -1
  110. package/lib/typescript/dsa.d.ts.map +1 -1
  111. package/lib/typescript/ec.d.ts.map +1 -1
  112. package/lib/typescript/ed.d.ts.map +1 -1
  113. package/lib/typescript/hash.d.ts.map +1 -1
  114. package/lib/typescript/index.d.ts +12 -7
  115. package/lib/typescript/index.d.ts.map +1 -1
  116. package/lib/typescript/keys/classes.d.ts +10 -1
  117. package/lib/typescript/keys/classes.d.ts.map +1 -1
  118. package/lib/typescript/keys/generateKeyPair.d.ts +12 -1
  119. package/lib/typescript/keys/generateKeyPair.d.ts.map +1 -1
  120. package/lib/typescript/keys/index.d.ts +3 -1
  121. package/lib/typescript/keys/index.d.ts.map +1 -1
  122. package/lib/typescript/keys/signVerify.d.ts.map +1 -1
  123. package/lib/typescript/keys/utils.d.ts +21 -4
  124. package/lib/typescript/keys/utils.d.ts.map +1 -1
  125. package/lib/typescript/random.d.ts +5 -1
  126. package/lib/typescript/random.d.ts.map +1 -1
  127. package/lib/typescript/rsa.d.ts.map +1 -1
  128. package/lib/typescript/slhdsa.d.ts +19 -0
  129. package/lib/typescript/slhdsa.d.ts.map +1 -0
  130. package/lib/typescript/specs/keyObjectHandle.nitro.d.ts +9 -0
  131. package/lib/typescript/specs/keyObjectHandle.nitro.d.ts.map +1 -1
  132. package/lib/typescript/specs/slhDsaKeyPair.nitro.d.ts +16 -0
  133. package/lib/typescript/specs/slhDsaKeyPair.nitro.d.ts.map +1 -0
  134. package/lib/typescript/specs/turboshake.nitro.d.ts +11 -0
  135. package/lib/typescript/specs/turboshake.nitro.d.ts.map +1 -0
  136. package/lib/typescript/subtle.d.ts +3 -2
  137. package/lib/typescript/subtle.d.ts.map +1 -1
  138. package/lib/typescript/utils/conversion.d.ts +4 -3
  139. package/lib/typescript/utils/conversion.d.ts.map +1 -1
  140. package/lib/typescript/utils/errors.d.ts +12 -0
  141. package/lib/typescript/utils/errors.d.ts.map +1 -1
  142. package/lib/typescript/utils/types.d.ts +32 -15
  143. package/lib/typescript/utils/types.d.ts.map +1 -1
  144. package/lib/typescript/utils/validation.d.ts +3 -1
  145. package/lib/typescript/utils/validation.d.ts.map +1 -1
  146. package/nitrogen/generated/android/QuickCrypto+autolinking.cmake +2 -0
  147. package/nitrogen/generated/android/QuickCryptoOnLoad.cpp +20 -0
  148. package/nitrogen/generated/ios/QuickCryptoAutolinking.mm +20 -0
  149. package/nitrogen/generated/shared/c++/AsymmetricKeyType.hpp +48 -0
  150. package/nitrogen/generated/shared/c++/HybridKeyObjectHandleSpec.cpp +9 -0
  151. package/nitrogen/generated/shared/c++/HybridKeyObjectHandleSpec.hpp +9 -0
  152. package/nitrogen/generated/shared/c++/HybridSlhDsaKeyPairSpec.cpp +29 -0
  153. package/nitrogen/generated/shared/c++/HybridSlhDsaKeyPairSpec.hpp +72 -0
  154. package/nitrogen/generated/shared/c++/HybridTurboShakeSpec.cpp +22 -0
  155. package/nitrogen/generated/shared/c++/HybridTurboShakeSpec.hpp +70 -0
  156. package/nitrogen/generated/shared/c++/JWK.hpp +9 -1
  157. package/nitrogen/generated/shared/c++/JWKkty.hpp +4 -0
  158. package/nitrogen/generated/shared/c++/KangarooTwelveVariant.hpp +76 -0
  159. package/nitrogen/generated/shared/c++/TurboShakeVariant.hpp +76 -0
  160. package/package.json +2 -3
  161. package/src/dhKeyPair.ts +8 -0
  162. package/src/dsa.ts +8 -0
  163. package/src/ec.ts +52 -29
  164. package/src/ed.ts +95 -16
  165. package/src/hash.ts +108 -5
  166. package/src/keys/classes.ts +46 -5
  167. package/src/keys/generateKeyPair.ts +151 -5
  168. package/src/keys/index.ts +73 -3
  169. package/src/keys/signVerify.ts +13 -2
  170. package/src/keys/utils.ts +78 -5
  171. package/src/random.ts +93 -9
  172. package/src/rsa.ts +8 -0
  173. package/src/slhdsa.ts +146 -0
  174. package/src/specs/keyObjectHandle.nitro.ts +17 -0
  175. package/src/specs/slhDsaKeyPair.nitro.ts +29 -0
  176. package/src/specs/turboshake.nitro.ts +21 -0
  177. package/src/subtle.ts +1191 -360
  178. package/src/utils/conversion.ts +72 -21
  179. package/src/utils/errors.ts +72 -4
  180. package/src/utils/types.ts +80 -15
  181. package/src/utils/validation.ts +70 -1
@@ -0,0 +1,379 @@
1
+ #include <NitroModules/ArrayBuffer.hpp>
2
+ #include <cstring>
3
+ #include <memory>
4
+ #include <optional>
5
+ #include <stdexcept>
6
+ #include <string>
7
+ #include <vector>
8
+
9
+ #include "HybridTurboShake.hpp"
10
+ #include "QuickCryptoUtils.hpp"
11
+
12
+ // TurboSHAKE128/256 and KangarooTwelve KT128/256 (RFC 9861).
13
+ // Implementation adapted from Node.js src/crypto/crypto_turboshake.cc
14
+ // (commit e0cab9dcf75), which itself adapts the OpenSSL keccak1600.c
15
+ // reference variant. OpenSSL does not yet expose these algorithms via EVP,
16
+ // so the Keccak-p[1600, n_r=12] permutation and sponge are provided here.
17
+
18
+ namespace margelo::nitro::crypto {
19
+
20
+ namespace {
21
+
22
+ // ---------------------------------------------------------------------------
23
+ // Keccak-p[1600, n_r=12] permutation (FIPS 202 §3.3-3.4, RFC 9861 §2.2).
24
+ // ---------------------------------------------------------------------------
25
+
26
+ inline uint64_t ROL64(uint64_t val, int offset) {
27
+ if (offset == 0)
28
+ return val;
29
+ return (val << offset) | (val >> (64 - offset));
30
+ }
31
+
32
+ inline uint64_t LoadLE64(const uint8_t* src) {
33
+ return static_cast<uint64_t>(src[0]) | (static_cast<uint64_t>(src[1]) << 8) | (static_cast<uint64_t>(src[2]) << 16) |
34
+ (static_cast<uint64_t>(src[3]) << 24) | (static_cast<uint64_t>(src[4]) << 32) | (static_cast<uint64_t>(src[5]) << 40) |
35
+ (static_cast<uint64_t>(src[6]) << 48) | (static_cast<uint64_t>(src[7]) << 56);
36
+ }
37
+
38
+ inline void StoreLE64(uint8_t* dst, uint64_t val) {
39
+ dst[0] = static_cast<uint8_t>(val);
40
+ dst[1] = static_cast<uint8_t>(val >> 8);
41
+ dst[2] = static_cast<uint8_t>(val >> 16);
42
+ dst[3] = static_cast<uint8_t>(val >> 24);
43
+ dst[4] = static_cast<uint8_t>(val >> 32);
44
+ dst[5] = static_cast<uint8_t>(val >> 40);
45
+ dst[6] = static_cast<uint8_t>(val >> 48);
46
+ dst[7] = static_cast<uint8_t>(val >> 56);
47
+ }
48
+
49
+ constexpr unsigned char kRhoTates[5][5] = {
50
+ {0, 1, 62, 28, 27}, {36, 44, 6, 55, 20}, {3, 10, 43, 25, 39}, {41, 45, 15, 21, 8}, {18, 2, 61, 56, 14},
51
+ };
52
+
53
+ // Round constants for Keccak-f[1600]; TurboSHAKE uses indices 12..23.
54
+ constexpr uint64_t kIotas[24] = {
55
+ 0x0000000000000001ULL, 0x0000000000008082ULL, 0x800000000000808aULL, 0x8000000080008000ULL, 0x000000000000808bULL,
56
+ 0x0000000080000001ULL, 0x8000000080008081ULL, 0x8000000000008009ULL, 0x000000000000008aULL, 0x0000000000000088ULL,
57
+ 0x0000000080008009ULL, 0x000000008000000aULL, 0x000000008000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL,
58
+ 0x8000000000008003ULL, 0x8000000000008002ULL, 0x8000000000000080ULL, 0x000000000000800aULL, 0x800000008000000aULL,
59
+ 0x8000000080008081ULL, 0x8000000000008080ULL, 0x0000000080000001ULL, 0x8000000080008008ULL,
60
+ };
61
+
62
+ void KeccakP1600_12(uint64_t A[5][5]) {
63
+ for (size_t round = 12; round < 24; round++) {
64
+ uint64_t C[5];
65
+ for (size_t x = 0; x < 5; x++) {
66
+ C[x] = A[0][x] ^ A[1][x] ^ A[2][x] ^ A[3][x] ^ A[4][x];
67
+ }
68
+ uint64_t D[5];
69
+ for (size_t x = 0; x < 5; x++) {
70
+ D[x] = C[(x + 4) % 5] ^ ROL64(C[(x + 1) % 5], 1);
71
+ }
72
+ for (size_t y = 0; y < 5; y++) {
73
+ for (size_t x = 0; x < 5; x++) {
74
+ A[y][x] ^= D[x];
75
+ }
76
+ }
77
+ for (size_t y = 0; y < 5; y++) {
78
+ for (size_t x = 0; x < 5; x++) {
79
+ A[y][x] = ROL64(A[y][x], kRhoTates[y][x]);
80
+ }
81
+ }
82
+ uint64_t T[5][5];
83
+ memcpy(T, A, sizeof(T));
84
+ for (size_t y = 0; y < 5; y++) {
85
+ for (size_t x = 0; x < 5; x++) {
86
+ A[y][x] = T[x][(3 * y + x) % 5];
87
+ }
88
+ }
89
+ for (size_t y = 0; y < 5; y++) {
90
+ uint64_t row[5];
91
+ for (size_t x = 0; x < 5; x++) {
92
+ row[x] = A[y][x] ^ (~A[y][(x + 1) % 5] & A[y][(x + 2) % 5]);
93
+ }
94
+ memcpy(A[y], row, sizeof(row));
95
+ }
96
+ A[0][0] ^= kIotas[round];
97
+ }
98
+ }
99
+
100
+ // ---------------------------------------------------------------------------
101
+ // TurboSHAKE sponge (RFC 9861 §2.2, App. A.2/A.3).
102
+ // TurboSHAKE128: rate = 168 bytes (capacity 256 bits).
103
+ // TurboSHAKE256: rate = 136 bytes (capacity 512 bits).
104
+ // ---------------------------------------------------------------------------
105
+
106
+ constexpr size_t kTurboSHAKE128Rate = 168;
107
+ constexpr size_t kTurboSHAKE256Rate = 136;
108
+
109
+ void TurboSHAKE(const uint8_t* input, size_t input_len, size_t rate, uint8_t domain_sep, uint8_t* output, size_t output_len) {
110
+ uint64_t A[5][5] = {};
111
+ size_t lane_count = rate / 8;
112
+
113
+ size_t offset = 0;
114
+ while (offset + rate <= input_len) {
115
+ for (size_t i = 0; i < lane_count; i++) {
116
+ A[i / 5][i % 5] ^= LoadLE64(input + offset + i * 8);
117
+ }
118
+ KeccakP1600_12(A);
119
+ offset += rate;
120
+ }
121
+
122
+ size_t remaining = input_len - offset;
123
+ // Sized for the larger TurboSHAKE128 rate (168); also fits the 136-byte TurboSHAKE256 rate.
124
+ uint8_t pad[kTurboSHAKE128Rate] = {};
125
+ if (remaining > 0) {
126
+ memcpy(pad, input + offset, remaining);
127
+ }
128
+ pad[remaining] ^= domain_sep;
129
+ pad[rate - 1] ^= 0x80;
130
+
131
+ for (size_t i = 0; i < lane_count; i++) {
132
+ A[i / 5][i % 5] ^= LoadLE64(pad + i * 8);
133
+ }
134
+ KeccakP1600_12(A);
135
+
136
+ size_t out_offset = 0;
137
+ while (out_offset < output_len) {
138
+ size_t block = output_len - out_offset;
139
+ if (block > rate)
140
+ block = rate;
141
+ size_t full_lanes = block / 8;
142
+ for (size_t i = 0; i < full_lanes; i++) {
143
+ StoreLE64(output + out_offset + i * 8, A[i / 5][i % 5]);
144
+ }
145
+ size_t rem = block % 8;
146
+ if (rem > 0) {
147
+ uint8_t tmp[8];
148
+ StoreLE64(tmp, A[full_lanes / 5][full_lanes % 5]);
149
+ memcpy(output + out_offset + full_lanes * 8, tmp, rem);
150
+ }
151
+ out_offset += block;
152
+ if (out_offset < output_len) {
153
+ KeccakP1600_12(A);
154
+ }
155
+ }
156
+ }
157
+
158
+ void TurboSHAKE128(const uint8_t* input, size_t input_len, uint8_t domain_sep, uint8_t* output, size_t output_len) {
159
+ TurboSHAKE(input, input_len, kTurboSHAKE128Rate, domain_sep, output, output_len);
160
+ }
161
+
162
+ void TurboSHAKE256(const uint8_t* input, size_t input_len, uint8_t domain_sep, uint8_t* output, size_t output_len) {
163
+ TurboSHAKE(input, input_len, kTurboSHAKE256Rate, domain_sep, output, output_len);
164
+ }
165
+
166
+ // ---------------------------------------------------------------------------
167
+ // KangarooTwelve tree hashing (RFC 9861 §3).
168
+ // ---------------------------------------------------------------------------
169
+
170
+ constexpr size_t kChunkSize = 8192;
171
+
172
+ // length_encode(x) per RFC 9861 §3.3.
173
+ std::vector<uint8_t> LengthEncode(size_t x) {
174
+ if (x == 0) {
175
+ return {0x00};
176
+ }
177
+ std::vector<uint8_t> result;
178
+ size_t val = x;
179
+ while (val > 0) {
180
+ result.push_back(static_cast<uint8_t>(val & 0xFF));
181
+ val >>= 8;
182
+ }
183
+ size_t n = result.size();
184
+ for (size_t i = 0; i < n / 2; i++) {
185
+ std::swap(result[i], result[n - 1 - i]);
186
+ }
187
+ result.push_back(static_cast<uint8_t>(n));
188
+ return result;
189
+ }
190
+
191
+ using TurboSHAKEFn = void (*)(const uint8_t* input, size_t input_len, uint8_t domain_sep, uint8_t* output, size_t output_len);
192
+
193
+ void KangarooTwelve(const uint8_t* message, size_t msg_len, const uint8_t* customization, size_t custom_len, uint8_t* output,
194
+ size_t output_len, TurboSHAKEFn turboshake, size_t cv_len) {
195
+ auto len_enc = LengthEncode(custom_len);
196
+ size_t s_len = msg_len + custom_len + len_enc.size();
197
+
198
+ // Short message: |S| <= 8192.
199
+ if (s_len <= kChunkSize) {
200
+ std::vector<uint8_t> s(s_len);
201
+ size_t pos = 0;
202
+ if (msg_len > 0) {
203
+ memcpy(s.data() + pos, message, msg_len);
204
+ pos += msg_len;
205
+ }
206
+ if (custom_len > 0) {
207
+ memcpy(s.data() + pos, customization, custom_len);
208
+ pos += custom_len;
209
+ }
210
+ memcpy(s.data() + pos, len_enc.data(), len_enc.size());
211
+
212
+ turboshake(s.data(), s_len, 0x07, output, output_len);
213
+ return;
214
+ }
215
+
216
+ // S is virtual: M || C || length_encode(|C|). Read on demand.
217
+ auto read_s = [&](size_t s_offset, uint8_t* buf, size_t len) {
218
+ size_t copied = 0;
219
+ if (s_offset < msg_len && copied < len) {
220
+ size_t avail = msg_len - s_offset;
221
+ size_t to_copy = avail < (len - copied) ? avail : (len - copied);
222
+ memcpy(buf + copied, message + s_offset, to_copy);
223
+ copied += to_copy;
224
+ s_offset += to_copy;
225
+ }
226
+ size_t custom_start = msg_len;
227
+ if (s_offset < custom_start + custom_len && copied < len) {
228
+ size_t off_in_custom = s_offset - custom_start;
229
+ size_t avail = custom_len - off_in_custom;
230
+ size_t to_copy = avail < (len - copied) ? avail : (len - copied);
231
+ memcpy(buf + copied, customization + off_in_custom, to_copy);
232
+ copied += to_copy;
233
+ s_offset += to_copy;
234
+ }
235
+ size_t le_start = msg_len + custom_len;
236
+ if (s_offset < le_start + len_enc.size() && copied < len) {
237
+ size_t off_in_le = s_offset - le_start;
238
+ size_t avail = len_enc.size() - off_in_le;
239
+ size_t to_copy = avail < (len - copied) ? avail : (len - copied);
240
+ memcpy(buf + copied, len_enc.data() + off_in_le, to_copy);
241
+ copied += to_copy;
242
+ }
243
+ };
244
+
245
+ std::vector<uint8_t> first_chunk(kChunkSize);
246
+ read_s(0, first_chunk.data(), kChunkSize);
247
+
248
+ std::vector<uint8_t> final_node;
249
+ final_node.reserve(kChunkSize + 8 + ((s_len / kChunkSize) * cv_len) + 16);
250
+ final_node.insert(final_node.end(), first_chunk.begin(), first_chunk.end());
251
+ final_node.push_back(0x03);
252
+ final_node.insert(final_node.end(), 7, 0x00);
253
+
254
+ size_t offset = kChunkSize;
255
+ size_t num_blocks = 0;
256
+ std::vector<uint8_t> chunk(kChunkSize);
257
+ std::vector<uint8_t> cv(cv_len);
258
+
259
+ while (offset < s_len) {
260
+ size_t block_size = s_len - offset;
261
+ if (block_size > kChunkSize)
262
+ block_size = kChunkSize;
263
+
264
+ chunk.resize(block_size);
265
+ read_s(offset, chunk.data(), block_size);
266
+
267
+ turboshake(chunk.data(), block_size, 0x0B, cv.data(), cv_len);
268
+ final_node.insert(final_node.end(), cv.begin(), cv.end());
269
+ num_blocks++;
270
+ offset += block_size;
271
+ }
272
+
273
+ auto num_blocks_enc = LengthEncode(num_blocks);
274
+ final_node.insert(final_node.end(), num_blocks_enc.begin(), num_blocks_enc.end());
275
+ final_node.push_back(0xFF);
276
+ final_node.push_back(0xFF);
277
+
278
+ turboshake(final_node.data(), final_node.size(), 0x06, output, output_len);
279
+ }
280
+
281
+ void KT128(const uint8_t* message, size_t msg_len, const uint8_t* customization, size_t custom_len, uint8_t* output, size_t output_len) {
282
+ KangarooTwelve(message, msg_len, customization, custom_len, output, output_len, TurboSHAKE128, 32);
283
+ }
284
+
285
+ void KT256(const uint8_t* message, size_t msg_len, const uint8_t* customization, size_t custom_len, uint8_t* output, size_t output_len) {
286
+ KangarooTwelve(message, msg_len, customization, custom_len, output, output_len, TurboSHAKE256, 64);
287
+ }
288
+
289
+ uint8_t parseDomainSeparation(double value) {
290
+ if (!(value >= 0x01 && value <= 0x7F) || value != static_cast<double>(static_cast<uint8_t>(value))) {
291
+ throw std::runtime_error("TurboSHAKE domainSeparation must be an integer in 0x01..0x7F");
292
+ }
293
+ return static_cast<uint8_t>(value);
294
+ }
295
+
296
+ uint32_t parseOutputLength(double value) {
297
+ if (!(value > 0)) {
298
+ throw std::runtime_error("outputLength must be > 0");
299
+ }
300
+ // 16 MiB upper bound matches HybridHash::setParams to keep memory bounded.
301
+ constexpr double kMaxOutputBytes = 16.0 * 1024.0 * 1024.0;
302
+ if (value > kMaxOutputBytes) {
303
+ throw std::runtime_error("outputLength exceeds maximum allowed size");
304
+ }
305
+ if (value != static_cast<double>(static_cast<uint32_t>(value))) {
306
+ throw std::runtime_error("outputLength must be an integer");
307
+ }
308
+ return static_cast<uint32_t>(value);
309
+ }
310
+
311
+ } // namespace
312
+
313
+ std::shared_ptr<Promise<std::shared_ptr<ArrayBuffer>>> HybridTurboShake::turboShake(TurboShakeVariant variant, double domainSeparation,
314
+ double outputLength,
315
+ const std::shared_ptr<ArrayBuffer>& data) {
316
+ uint8_t ds = parseDomainSeparation(domainSeparation);
317
+ uint32_t outLen = parseOutputLength(outputLength);
318
+
319
+ bool is128 = variant == TurboShakeVariant::TURBOSHAKE128;
320
+
321
+ auto nativeData = ToNativeArrayBuffer(data);
322
+
323
+ return Promise<std::shared_ptr<ArrayBuffer>>::async([is128, ds, outLen, nativeData]() -> std::shared_ptr<ArrayBuffer> {
324
+ auto outBuf = std::make_unique<uint8_t[]>(outLen);
325
+ const uint8_t* in = reinterpret_cast<const uint8_t*>(nativeData->data());
326
+ size_t inLen = nativeData->size();
327
+ if (is128) {
328
+ TurboSHAKE128(in, inLen, ds, outBuf.get(), outLen);
329
+ } else {
330
+ TurboSHAKE256(in, inLen, ds, outBuf.get(), outLen);
331
+ }
332
+ uint8_t* raw = outBuf.get();
333
+ return std::make_shared<NativeArrayBuffer>(outBuf.release(), outLen, [raw]() { delete[] raw; });
334
+ });
335
+ }
336
+
337
+ std::shared_ptr<Promise<std::shared_ptr<ArrayBuffer>>>
338
+ HybridTurboShake::kangarooTwelve(KangarooTwelveVariant variant, double outputLength, const std::shared_ptr<ArrayBuffer>& data,
339
+ const std::optional<std::shared_ptr<ArrayBuffer>>& customization) {
340
+ uint32_t outLen = parseOutputLength(outputLength);
341
+
342
+ bool is128 = variant == KangarooTwelveVariant::KT128;
343
+
344
+ auto nativeData = ToNativeArrayBuffer(data);
345
+ std::optional<std::shared_ptr<ArrayBuffer>> nativeCustom;
346
+ if (customization.has_value()) {
347
+ nativeCustom = ToNativeArrayBuffer(customization.value());
348
+ }
349
+
350
+ return Promise<std::shared_ptr<ArrayBuffer>>::async(
351
+ [is128, outLen, nativeData, nativeCustom = std::move(nativeCustom)]() -> std::shared_ptr<ArrayBuffer> {
352
+ const uint8_t* in = reinterpret_cast<const uint8_t*>(nativeData->data());
353
+ size_t inLen = nativeData->size();
354
+ const uint8_t* custom = nullptr;
355
+ size_t customLen = 0;
356
+ if (nativeCustom.has_value() && nativeCustom.value()->size() > 0) {
357
+ custom = reinterpret_cast<const uint8_t*>(nativeCustom.value()->data());
358
+ customLen = nativeCustom.value()->size();
359
+ }
360
+
361
+ // Mirror Node's overflow guard for s_len = msg + custom + length_encode(|custom|).
362
+ // length_encode produces at most sizeof(size_t) + 1 bytes.
363
+ constexpr size_t kMaxLengthEncodeSize = sizeof(size_t) + 1;
364
+ if (inLen > SIZE_MAX - customLen || inLen + customLen > SIZE_MAX - kMaxLengthEncodeSize) {
365
+ throw std::runtime_error("KangarooTwelve input length overflow");
366
+ }
367
+
368
+ auto outBuf = std::make_unique<uint8_t[]>(outLen);
369
+ if (is128) {
370
+ KT128(in, inLen, custom, customLen, outBuf.get(), outLen);
371
+ } else {
372
+ KT256(in, inLen, custom, customLen, outBuf.get(), outLen);
373
+ }
374
+ uint8_t* raw = outBuf.get();
375
+ return std::make_shared<NativeArrayBuffer>(outBuf.release(), outLen, [raw]() { delete[] raw; });
376
+ });
377
+ }
378
+
379
+ } // namespace margelo::nitro::crypto
@@ -0,0 +1,28 @@
1
+ #pragma once
2
+
3
+ #include <NitroModules/ArrayBuffer.hpp>
4
+ #include <NitroModules/Promise.hpp>
5
+ #include <memory>
6
+ #include <optional>
7
+ #include <string>
8
+
9
+ #include "HybridTurboShakeSpec.hpp"
10
+
11
+ namespace margelo::nitro::crypto {
12
+
13
+ using namespace facebook;
14
+
15
+ class HybridTurboShake : public HybridTurboShakeSpec {
16
+ public:
17
+ HybridTurboShake() : HybridObject(TAG) {}
18
+
19
+ public:
20
+ std::shared_ptr<Promise<std::shared_ptr<ArrayBuffer>>> turboShake(TurboShakeVariant variant, double domainSeparation, double outputLength,
21
+ const std::shared_ptr<ArrayBuffer>& data) override;
22
+
23
+ std::shared_ptr<Promise<std::shared_ptr<ArrayBuffer>>>
24
+ kangarooTwelve(KangarooTwelveVariant variant, double outputLength, const std::shared_ptr<ArrayBuffer>& data,
25
+ const std::optional<std::shared_ptr<ArrayBuffer>>& customization) override;
26
+ };
27
+
28
+ } // namespace margelo::nitro::crypto
@@ -1,6 +1,6 @@
1
1
  #include "HybridUtils.hpp"
2
2
 
3
- #include <NitroModules/JSIConverter+ArrayBuffer.hpp>
3
+ #include <NitroModules/JSIConverter.hpp>
4
4
  #include <bit>
5
5
  #include <cstring>
6
6
  #include <openssl/crypto.h>
@@ -234,44 +234,56 @@ bool HybridUtils::timingSafeEqual(const std::shared_ptr<ArrayBuffer>& a, const s
234
234
  facebook::jsi::Value HybridUtils::bufferToJsiString(facebook::jsi::Runtime& runtime, const facebook::jsi::Value&,
235
235
  const facebook::jsi::Value* args, size_t argCount) {
236
236
  // Runtime argument check from react-native-nitro-modules/cpp/core/HybridFunction.hpp
237
- if (argCount != 2) [[unlikely]] {
237
+ if (argCount != 4) [[unlikely]] {
238
238
  throw facebook::jsi::JSError(runtime,
239
- "`Utils.bufferToString(...)` expected 2 arguments, but received " + std::to_string(argCount) + "!");
239
+ "`Utils.bufferToString(...)` expected 4 arguments, but received " + std::to_string(argCount) + "!");
240
240
  }
241
241
 
242
242
  // Exception wrapper from react-native-nitro-modules/cpp/core/HybridFunction.hpp
243
243
  try {
244
- // bufferToString(buffer: ArrayBuffer, encoding: string): string; Defined in utils/conversion.ts
244
+ // bufferToString(buffer: ArrayBuffer, encoding: string, start: number, end: number): string;
245
+ // Defined in utils/conversion.ts
245
246
  auto buffer = JSIConverter<std::shared_ptr<ArrayBuffer>>::fromJSI(runtime, args[0]);
246
247
  std::string encoding = JSIConverter<std::string>::fromJSI(runtime, args[1]);
248
+ const size_t bufferSize = buffer->size();
249
+ // `start` and `end` are normalized in the TS code
250
+ // so it's safe to use `static_cast<size_t>` here
251
+ const size_t start = static_cast<size_t>(JSIConverter<double>::fromJSI(runtime, args[2]));
252
+ const size_t end = static_cast<size_t>(JSIConverter<double>::fromJSI(runtime, args[3]));
253
+ if (start > end || end > bufferSize) {
254
+ // This should never happen if called from the TS wrapper
255
+ // Add this check to avoid out of bounds access
256
+ throw std::runtime_error("Invalid start/end value");
257
+ }
258
+ const size_t offset = start;
259
+ const size_t length = end - start;
247
260
 
248
- const auto* data = reinterpret_cast<const uint8_t*>(buffer->data());
249
- size_t len = buffer->size();
261
+ const auto* data = reinterpret_cast<const uint8_t*>(buffer->data() + offset);
250
262
 
251
263
  if (encoding == "hex") {
252
- return facebook::jsi::String::createFromUtf8(runtime, encodeHex(data, len));
264
+ return facebook::jsi::String::createFromUtf8(runtime, encodeHex(data, length));
253
265
  }
254
266
  if (encoding == "base64") {
255
- return facebook::jsi::String::createFromUtf8(runtime, encodeBase64(data, len));
267
+ return facebook::jsi::String::createFromUtf8(runtime, encodeBase64(data, length));
256
268
  }
257
269
  if (encoding == "base64url") {
258
- return facebook::jsi::String::createFromUtf8(runtime, encodeBase64Url(data, len));
270
+ return facebook::jsi::String::createFromUtf8(runtime, encodeBase64Url(data, length));
259
271
  }
260
272
  if (encoding == "utf8" || encoding == "utf-8") {
261
- return facebook::jsi::String::createFromUtf8(runtime, data, len);
273
+ return facebook::jsi::String::createFromUtf8(runtime, data, length);
262
274
  }
263
275
  if (encoding == "latin1" || encoding == "binary") {
264
- return facebook::jsi::String::createFromUtf8(runtime, encodeLatin1(data, len));
276
+ return facebook::jsi::String::createFromUtf8(runtime, encodeLatin1(data, length));
265
277
  }
266
278
  if (encoding == "ascii") {
267
- std::string result(reinterpret_cast<const char*>(data), len);
279
+ std::string result(reinterpret_cast<const char*>(data), length);
268
280
  for (auto& c : result) {
269
281
  c &= 0x7F;
270
282
  }
271
283
  return facebook::jsi::String::createFromUtf8(runtime, result);
272
284
  }
273
285
  if (encoding == "utf16le") {
274
- return createUtf16LeString(runtime, data, len);
286
+ return createUtf16LeString(runtime, data, length);
275
287
  }
276
288
  throw std::runtime_error("Unsupported encoding: " + encoding);
277
289
  } catch (const std::exception& exception) {
@@ -329,7 +341,7 @@ facebook::jsi::Value HybridUtils::jsiStringToBuffer(facebook::jsi::Runtime& runt
329
341
  void HybridUtils::loadHybridMethods() {
330
342
  HybridUtilsSpec::loadHybridMethods();
331
343
  registerHybrids(this, [](Prototype& prototype) {
332
- prototype.registerRawHybridMethod("bufferToString", 2, &HybridUtils::bufferToJsiString);
344
+ prototype.registerRawHybridMethod("bufferToString", 4, &HybridUtils::bufferToJsiString);
333
345
  prototype.registerRawHybridMethod("stringToBuffer", 2, &HybridUtils::jsiStringToBuffer);
334
346
  });
335
347
  }
@@ -176,14 +176,13 @@ See [`c/README.md`](c/README.md).
176
176
 
177
177
  ### Other implementations
178
178
 
179
- We post links to third-party bindings and implementations on the
180
- [@BLAKE3team Twitter account](https://twitter.com/BLAKE3team) whenever
181
- we hear about them. Some highlights include [an optimized Go
179
+ There are too many implementations out there for us to keep track of,
180
+ but some highlights include [an optimized Go
182
181
  implementation](https://github.com/zeebo/blake3), [Wasm bindings for
183
182
  Node.js and browsers](https://github.com/connor4312/blake3), [binary
184
183
  wheels for Python](https://github.com/oconnor663/blake3-py), [.NET
185
- bindings](https://github.com/xoofx/Blake3.NET), and [JNI
186
- bindings](https://github.com/sken77/BLAKE3jni).
184
+ bindings](https://github.com/xoofx/Blake3.NET), and [a pure Java
185
+ implementation](https://commons.apache.org/proper/commons-codec/apidocs/org/apache/commons/codec/digest/Blake3.html).
187
186
 
188
187
  ## Contributing
189
188
 
@@ -202,7 +201,7 @@ Alternatively, it is licensed under any of the following:
202
201
 
203
202
  * [Bazel](https://github.com/bazelbuild/bazel/releases/tag/6.4.0)
204
203
  * [Cargo](https://github.com/rust-lang/cargo/pull/14137)
205
- * [Ccache](https://github.com/ccache/ccache/pull/519)
204
+ * [Ccache](https://ccache.dev/releasenotes.html#_ccache_4_0)
206
205
  * [Chia](https://github.com/Chia-Network/chia-blockchain/blob/main/CHANGELOG.md#10beta8-aka-beta-18---2020-07-16)
207
206
  * [Clickhouse](https://github.com/ClickHouse/ClickHouse/blob/master/rust/chcache/Cargo.toml#L7)
208
207
  * [Farcaster](https://www.farcaster.xyz/)
@@ -220,7 +219,7 @@ Alternatively, it is licensed under any of the following:
220
219
 
221
220
  ## Miscellany
222
221
 
223
- - [@veorq] and [@oconnor663] did [an interview with Cryptography FM](https://www.cryptography.fm/3).
222
+ - [@veorq] and [@oconnor663] did [an interview with Cryptography FM](https://cryptography.fireside.fm/3).
224
223
  - [@oconnor663] did [an interview with Saito](https://www.youtube.com/watch?v=cJkmIt7yN_E).
225
224
 
226
225
  [@oconnor663]: https://github.com/oconnor663
@@ -1,6 +1,7 @@
1
1
  #include <assert.h>
2
2
  #include <stdbool.h>
3
3
  #include <string.h>
4
+ #include <stdint.h>
4
5
 
5
6
  #include "blake3.h"
6
7
  #include "blake3_impl.h"
@@ -303,8 +304,8 @@ size_t blake3_compress_subtree_wide(const uint8_t *input, size_t input_len,
303
304
  uint8_t *right_cvs = &cv_array[degree * BLAKE3_OUT_LEN];
304
305
 
305
306
  // Recurse!
306
- size_t left_n = -1;
307
- size_t right_n = -1;
307
+ size_t left_n = SIZE_MAX;
308
+ size_t right_n = SIZE_MAX;
308
309
 
309
310
  #if defined(BLAKE3_USE_TBB)
310
311
  blake3_compress_subtree_wide_join_tbb(
@@ -30,7 +30,7 @@
30
30
  extern "C" {
31
31
  #endif
32
32
 
33
- #define BLAKE3_VERSION_STRING "1.8.2"
33
+ #define BLAKE3_VERSION_STRING "1.8.5"
34
34
  #define BLAKE3_KEY_LEN 32
35
35
  #define BLAKE3_OUT_LEN 32
36
36
  #define BLAKE3_BLOCK_LEN 64
@@ -38,7 +38,7 @@ extern "C" {
38
38
  #define BLAKE3_MAX_DEPTH 54
39
39
 
40
40
  // This struct is a private implementation detail. It has to be here because
41
- // it's part of blake3_hasher below.
41
+ // it's part of the blake3_hasher structure defined below.
42
42
  typedef struct {
43
43
  uint32_t cv[8];
44
44
  uint64_t chunk_counter;
@@ -89,7 +89,6 @@ static void cpuidex(uint32_t out[4], uint32_t id, uint32_t sid) {
89
89
  #endif
90
90
  }
91
91
 
92
- #endif
93
92
 
94
93
  enum cpu_feature {
95
94
  SSE2 = 1 << 0,
@@ -164,6 +163,7 @@ static
164
163
  #endif
165
164
  }
166
165
  }
166
+ #endif
167
167
 
168
168
  void blake3_compress_in_place(uint32_t cv[8],
169
169
  const uint8_t block[BLAKE3_BLOCK_LEN],
@@ -235,7 +235,7 @@ void blake3_xof_many(const uint32_t cv[8],
235
235
  #if defined(IS_X86)
236
236
  const enum cpu_feature features = get_cpu_features();
237
237
  MAYBE_UNUSED(features);
238
- #if !defined(_WIN32) && !defined(BLAKE3_NO_AVX512)
238
+ #if !defined(_WIN32) && !defined(__CYGWIN__) && !defined(BLAKE3_NO_AVX512)
239
239
  if (features & AVX512VL) {
240
240
  blake3_xof_many_avx512(cv, block, block_len, counter, flags, out, outblocks);
241
241
  return;
@@ -309,7 +309,7 @@ void blake3_hash_many_avx512(const uint8_t *const *inputs, size_t num_inputs,
309
309
  uint8_t flags, uint8_t flags_start,
310
310
  uint8_t flags_end, uint8_t *out);
311
311
 
312
- #if !defined(_WIN32)
312
+ #if !defined(_WIN32) && !defined(__CYGWIN__)
313
313
  void blake3_xof_many_avx512(const uint32_t cv[8],
314
314
  const uint8_t block[BLAKE3_BLOCK_LEN],
315
315
  uint8_t block_len, uint64_t counter, uint8_t flags,
@@ -243,10 +243,11 @@ INLINE void load_counters4(uint64_t counter, bool increment_counter,
243
243
  counter_high(counter + (mask & 2)), counter_high(counter + (mask & 3)));
244
244
  }
245
245
 
246
- void blake3_hash4_neon(const uint8_t *const *inputs, size_t blocks,
247
- const uint32_t key[8], uint64_t counter,
248
- bool increment_counter, uint8_t flags,
249
- uint8_t flags_start, uint8_t flags_end, uint8_t *out) {
246
+ static void blake3_hash4_neon(const uint8_t *const *inputs, size_t blocks,
247
+ const uint32_t key[8], uint64_t counter,
248
+ bool increment_counter, uint8_t flags,
249
+ uint8_t flags_start, uint8_t flags_end,
250
+ uint8_t *out) {
250
251
  uint32x4_t h_vecs[8] = {
251
252
  set1_128(key[0]), set1_128(key[1]), set1_128(key[2]), set1_128(key[3]),
252
253
  set1_128(key[4]), set1_128(key[5]), set1_128(key[6]), set1_128(key[7]),
@@ -3,12 +3,12 @@
3
3
  #ifndef NCRYPTO_VERSION_H_
4
4
  #define NCRYPTO_VERSION_H_
5
5
 
6
- #define NCRYPTO_VERSION "1.1.3" // x-release-please-version
6
+ #define NCRYPTO_VERSION "1.1.4" // x-release-please-version
7
7
 
8
8
  enum {
9
9
  NCRYPTO_VERSION_MAJOR = 1, // x-release-please-major
10
10
  NCRYPTO_VERSION_MINOR = 1, // x-release-please-minor
11
- NCRYPTO_VERSION_REVISION = 3, // x-release-please-patch
11
+ NCRYPTO_VERSION_REVISION = 4, // x-release-please-patch
12
12
  };
13
13
 
14
14
  #endif // NCRYPTO_VERSION_H_
@@ -690,6 +690,8 @@ class DataPointer final {
690
690
  bool isSecure() const { return secure_; }
691
691
 
692
692
  private:
693
+ void free();
694
+
693
695
  void* data_ = nullptr;
694
696
  size_t len_ = 0;
695
697
  bool secure_ = false;
@@ -897,6 +899,9 @@ class EVPKeyPointer final {
897
899
  DER,
898
900
  PEM,
899
901
  JWK,
902
+ RAW_PUBLIC,
903
+ RAW_PRIVATE,
904
+ RAW_SEED,
900
905
  };
901
906
 
902
907
  enum class PKParseError { NOT_RECOGNIZED, NEED_PASSPHRASE, FAILED };
@@ -906,6 +911,7 @@ class EVPKeyPointer final {
906
911
  bool output_key_object = false;
907
912
  PKFormatType format = PKFormatType::DER;
908
913
  PKEncodingType type = PKEncodingType::PKCS8;
914
+ int ec_point_form = POINT_CONVERSION_UNCOMPRESSED;
909
915
  AsymmetricKeyEncodingConfig() = default;
910
916
  AsymmetricKeyEncodingConfig(bool output_key_object,
911
917
  PKFormatType format,
@@ -1620,8 +1626,9 @@ int NoPasswordCallback(char* buf, int size, int rwflag, void* u);
1620
1626
 
1621
1627
  int PasswordCallback(char* buf, int size, int rwflag, void* u);
1622
1628
 
1623
- bool SafeX509SubjectAltNamePrint(const BIOPointer& out, X509_EXTENSION* ext);
1624
- bool SafeX509InfoAccessPrint(const BIOPointer& out, X509_EXTENSION* ext);
1629
+ bool SafeX509SubjectAltNamePrint(const BIOPointer& out,
1630
+ const X509_EXTENSION* ext);
1631
+ bool SafeX509InfoAccessPrint(const BIOPointer& out, const X509_EXTENSION* ext);
1625
1632
 
1626
1633
  // ============================================================================
1627
1634
  // SPKAC