react-native-ufsecp 3.10.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.
@@ -0,0 +1,483 @@
1
+ #import "UltrafastSecp256k1.h"
2
+ #import <React/RCTUtils.h>
3
+ #include "ultrafast_secp256k1.h"
4
+
5
+ @implementation UltrafastSecp256k1
6
+
7
+ RCT_EXPORT_MODULE()
8
+
9
+ + (BOOL)requiresMainQueueSetup { return NO; }
10
+
11
+ // ── Hex helpers ──────────────────────────────────────────────────────────────
12
+
13
+ static NSData *hexToData(NSString *hex) {
14
+ NSMutableData *data = [NSMutableData dataWithCapacity:hex.length / 2];
15
+ unsigned char byte;
16
+ char buf[3] = {0};
17
+ for (NSUInteger i = 0; i < hex.length; i += 2) {
18
+ buf[0] = [hex characterAtIndex:i];
19
+ buf[1] = [hex characterAtIndex:i + 1];
20
+ byte = strtol(buf, NULL, 16);
21
+ [data appendBytes:&byte length:1];
22
+ }
23
+ return data;
24
+ }
25
+
26
+ static NSString *dataToHex(const uint8_t *bytes, size_t length) {
27
+ NSMutableString *hex = [NSMutableString stringWithCapacity:length * 2];
28
+ for (size_t i = 0; i < length; i++) {
29
+ [hex appendFormat:@"%02x", bytes[i]];
30
+ }
31
+ return hex;
32
+ }
33
+
34
+ // ── Init ─────────────────────────────────────────────────────────────────────
35
+
36
+ - (instancetype)init {
37
+ self = [super init];
38
+ if (self) { secp256k1_init(); }
39
+ return self;
40
+ }
41
+
42
+ RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(version) {
43
+ return [NSString stringWithUTF8String:secp256k1_version()];
44
+ }
45
+
46
+ // ── Key Operations ───────────────────────────────────────────────────────────
47
+
48
+ RCT_EXPORT_METHOD(ecPubkeyCreate:(NSString *)privkeyHex
49
+ resolve:(RCTPromiseResolveBlock)resolve
50
+ reject:(RCTPromiseRejectBlock)reject) {
51
+ NSData *pk = hexToData(privkeyHex);
52
+ uint8_t out[33];
53
+ if (secp256k1_ec_pubkey_create(pk.bytes, out) != 0) {
54
+ reject(@"ERR", @"Invalid private key", nil);
55
+ return;
56
+ }
57
+ resolve(dataToHex(out, 33));
58
+ }
59
+
60
+ RCT_EXPORT_METHOD(ecPubkeyCreateUncompressed:(NSString *)privkeyHex
61
+ resolve:(RCTPromiseResolveBlock)resolve
62
+ reject:(RCTPromiseRejectBlock)reject) {
63
+ NSData *pk = hexToData(privkeyHex);
64
+ uint8_t out[65];
65
+ if (secp256k1_ec_pubkey_create_uncompressed(pk.bytes, out) != 0) {
66
+ reject(@"ERR", @"Invalid private key", nil);
67
+ return;
68
+ }
69
+ resolve(dataToHex(out, 65));
70
+ }
71
+
72
+ RCT_EXPORT_METHOD(ecPubkeyParse:(NSString *)pubkeyHex
73
+ resolve:(RCTPromiseResolveBlock)resolve
74
+ reject:(RCTPromiseRejectBlock)reject) {
75
+ NSData *inp = hexToData(pubkeyHex);
76
+ uint8_t out[33];
77
+ if (secp256k1_ec_pubkey_parse(inp.bytes, inp.length, out) != 0) {
78
+ reject(@"ERR", @"Invalid public key", nil);
79
+ return;
80
+ }
81
+ resolve(dataToHex(out, 33));
82
+ }
83
+
84
+ RCT_EXPORT_METHOD(ecSeckeyVerify:(NSString *)privkeyHex
85
+ resolve:(RCTPromiseResolveBlock)resolve
86
+ reject:(RCTPromiseRejectBlock)reject) {
87
+ NSData *pk = hexToData(privkeyHex);
88
+ resolve(@(secp256k1_ec_seckey_verify(pk.bytes) == 1));
89
+ }
90
+
91
+ RCT_EXPORT_METHOD(ecPrivkeyNegate:(NSString *)privkeyHex
92
+ resolve:(RCTPromiseResolveBlock)resolve
93
+ reject:(RCTPromiseRejectBlock)reject) {
94
+ NSMutableData *pk = [hexToData(privkeyHex) mutableCopy];
95
+ secp256k1_ec_privkey_negate(pk.mutableBytes);
96
+ resolve(dataToHex(pk.bytes, 32));
97
+ }
98
+
99
+ RCT_EXPORT_METHOD(ecPrivkeyTweakAdd:(NSString *)privkeyHex
100
+ tweak:(NSString *)tweakHex
101
+ resolve:(RCTPromiseResolveBlock)resolve
102
+ reject:(RCTPromiseRejectBlock)reject) {
103
+ NSMutableData *pk = [hexToData(privkeyHex) mutableCopy];
104
+ NSData *tw = hexToData(tweakHex);
105
+ if (secp256k1_ec_privkey_tweak_add(pk.mutableBytes, tw.bytes) != 0) {
106
+ reject(@"ERR", @"Tweak add failed", nil);
107
+ return;
108
+ }
109
+ resolve(dataToHex(pk.bytes, 32));
110
+ }
111
+
112
+ RCT_EXPORT_METHOD(ecPrivkeyTweakMul:(NSString *)privkeyHex
113
+ tweak:(NSString *)tweakHex
114
+ resolve:(RCTPromiseResolveBlock)resolve
115
+ reject:(RCTPromiseRejectBlock)reject) {
116
+ NSMutableData *pk = [hexToData(privkeyHex) mutableCopy];
117
+ NSData *tw = hexToData(tweakHex);
118
+ if (secp256k1_ec_privkey_tweak_mul(pk.mutableBytes, tw.bytes) != 0) {
119
+ reject(@"ERR", @"Tweak mul failed", nil);
120
+ return;
121
+ }
122
+ resolve(dataToHex(pk.bytes, 32));
123
+ }
124
+
125
+ // ── ECDSA ────────────────────────────────────────────────────────────────────
126
+
127
+ RCT_EXPORT_METHOD(ecdsaSign:(NSString *)msgHashHex
128
+ privkey:(NSString *)privkeyHex
129
+ resolve:(RCTPromiseResolveBlock)resolve
130
+ reject:(RCTPromiseRejectBlock)reject) {
131
+ NSData *mh = hexToData(msgHashHex);
132
+ NSData *pk = hexToData(privkeyHex);
133
+ uint8_t sig[64];
134
+ if (secp256k1_ecdsa_sign(mh.bytes, pk.bytes, sig) != 0) {
135
+ reject(@"ERR", @"ECDSA signing failed", nil);
136
+ return;
137
+ }
138
+ resolve(dataToHex(sig, 64));
139
+ }
140
+
141
+ RCT_EXPORT_METHOD(ecdsaVerify:(NSString *)msgHashHex
142
+ sig:(NSString *)sigHex
143
+ pubkey:(NSString *)pubkeyHex
144
+ resolve:(RCTPromiseResolveBlock)resolve
145
+ reject:(RCTPromiseRejectBlock)reject) {
146
+ NSData *mh = hexToData(msgHashHex);
147
+ NSData *s = hexToData(sigHex);
148
+ NSData *pk = hexToData(pubkeyHex);
149
+ resolve(@(secp256k1_ecdsa_verify(mh.bytes, s.bytes, pk.bytes) == 1));
150
+ }
151
+
152
+ RCT_EXPORT_METHOD(ecdsaSerializeDer:(NSString *)sigHex
153
+ resolve:(RCTPromiseResolveBlock)resolve
154
+ reject:(RCTPromiseRejectBlock)reject) {
155
+ NSData *s = hexToData(sigHex);
156
+ uint8_t der[72];
157
+ size_t der_len = 72;
158
+ if (secp256k1_ecdsa_signature_serialize_der(s.bytes, der, &der_len) != 0) {
159
+ reject(@"ERR", @"DER serialization failed", nil);
160
+ return;
161
+ }
162
+ resolve(dataToHex(der, der_len));
163
+ }
164
+
165
+ // ── Recovery ─────────────────────────────────────────────────────────────────
166
+
167
+ RCT_EXPORT_METHOD(ecdsaSignRecoverable:(NSString *)msgHashHex
168
+ privkey:(NSString *)privkeyHex
169
+ resolve:(RCTPromiseResolveBlock)resolve
170
+ reject:(RCTPromiseRejectBlock)reject) {
171
+ NSData *mh = hexToData(msgHashHex);
172
+ NSData *pk = hexToData(privkeyHex);
173
+ uint8_t sig[64];
174
+ int recid;
175
+ if (secp256k1_ecdsa_sign_recoverable(mh.bytes, pk.bytes, sig, &recid) != 0) {
176
+ reject(@"ERR", @"Recoverable signing failed", nil);
177
+ return;
178
+ }
179
+ resolve(@{@"signature": dataToHex(sig, 64), @"recid": @(recid)});
180
+ }
181
+
182
+ RCT_EXPORT_METHOD(ecdsaRecover:(NSString *)msgHashHex
183
+ sig:(NSString *)sigHex
184
+ recid:(int)recid
185
+ resolve:(RCTPromiseResolveBlock)resolve
186
+ reject:(RCTPromiseRejectBlock)reject) {
187
+ NSData *mh = hexToData(msgHashHex);
188
+ NSData *s = hexToData(sigHex);
189
+ uint8_t pubkey[33];
190
+ if (secp256k1_ecdsa_recover(mh.bytes, s.bytes, recid, pubkey) != 0) {
191
+ reject(@"ERR", @"Recovery failed", nil);
192
+ return;
193
+ }
194
+ resolve(dataToHex(pubkey, 33));
195
+ }
196
+
197
+ // ── Schnorr ──────────────────────────────────────────────────────────────────
198
+
199
+ RCT_EXPORT_METHOD(schnorrSign:(NSString *)msgHex
200
+ privkey:(NSString *)privkeyHex
201
+ auxRand:(NSString *)auxRandHex
202
+ resolve:(RCTPromiseResolveBlock)resolve
203
+ reject:(RCTPromiseRejectBlock)reject) {
204
+ NSData *m = hexToData(msgHex);
205
+ NSData *pk = hexToData(privkeyHex);
206
+ NSData *ar = hexToData(auxRandHex);
207
+ uint8_t sig[64];
208
+ if (secp256k1_schnorr_sign(m.bytes, pk.bytes, ar.bytes, sig) != 0) {
209
+ reject(@"ERR", @"Schnorr sign failed", nil);
210
+ return;
211
+ }
212
+ resolve(dataToHex(sig, 64));
213
+ }
214
+
215
+ RCT_EXPORT_METHOD(schnorrVerify:(NSString *)msgHex
216
+ sig:(NSString *)sigHex
217
+ pubkeyX:(NSString *)pubkeyXHex
218
+ resolve:(RCTPromiseResolveBlock)resolve
219
+ reject:(RCTPromiseRejectBlock)reject) {
220
+ NSData *m = hexToData(msgHex);
221
+ NSData *s = hexToData(sigHex);
222
+ NSData *px = hexToData(pubkeyXHex);
223
+ resolve(@(secp256k1_schnorr_verify(m.bytes, s.bytes, px.bytes) == 1));
224
+ }
225
+
226
+ RCT_EXPORT_METHOD(schnorrPubkey:(NSString *)privkeyHex
227
+ resolve:(RCTPromiseResolveBlock)resolve
228
+ reject:(RCTPromiseRejectBlock)reject) {
229
+ NSData *pk = hexToData(privkeyHex);
230
+ uint8_t out[32];
231
+ if (secp256k1_schnorr_pubkey(pk.bytes, out) != 0) {
232
+ reject(@"ERR", @"Invalid private key", nil);
233
+ return;
234
+ }
235
+ resolve(dataToHex(out, 32));
236
+ }
237
+
238
+ // ── ECDH ─────────────────────────────────────────────────────────────────────
239
+
240
+ RCT_EXPORT_METHOD(ecdh:(NSString *)privkeyHex
241
+ pubkey:(NSString *)pubkeyHex
242
+ resolve:(RCTPromiseResolveBlock)resolve
243
+ reject:(RCTPromiseRejectBlock)reject) {
244
+ NSData *pk = hexToData(privkeyHex);
245
+ NSData *pub = hexToData(pubkeyHex);
246
+ uint8_t out[32];
247
+ if (secp256k1_ecdh(pk.bytes, pub.bytes, out) != 0) {
248
+ reject(@"ERR", @"ECDH failed", nil); return;
249
+ }
250
+ resolve(dataToHex(out, 32));
251
+ }
252
+
253
+ RCT_EXPORT_METHOD(ecdhXonly:(NSString *)privkeyHex
254
+ pubkey:(NSString *)pubkeyHex
255
+ resolve:(RCTPromiseResolveBlock)resolve
256
+ reject:(RCTPromiseRejectBlock)reject) {
257
+ NSData *pk = hexToData(privkeyHex);
258
+ NSData *pub = hexToData(pubkeyHex);
259
+ uint8_t out[32];
260
+ if (secp256k1_ecdh_xonly(pk.bytes, pub.bytes, out) != 0) {
261
+ reject(@"ERR", @"ECDH xonly failed", nil); return;
262
+ }
263
+ resolve(dataToHex(out, 32));
264
+ }
265
+
266
+ RCT_EXPORT_METHOD(ecdhRaw:(NSString *)privkeyHex
267
+ pubkey:(NSString *)pubkeyHex
268
+ resolve:(RCTPromiseResolveBlock)resolve
269
+ reject:(RCTPromiseRejectBlock)reject) {
270
+ NSData *pk = hexToData(privkeyHex);
271
+ NSData *pub = hexToData(pubkeyHex);
272
+ uint8_t out[32];
273
+ if (secp256k1_ecdh_raw(pk.bytes, pub.bytes, out) != 0) {
274
+ reject(@"ERR", @"ECDH raw failed", nil); return;
275
+ }
276
+ resolve(dataToHex(out, 32));
277
+ }
278
+
279
+ // ── Hashing ──────────────────────────────────────────────────────────────────
280
+
281
+ RCT_EXPORT_METHOD(sha256:(NSString *)dataHex
282
+ resolve:(RCTPromiseResolveBlock)resolve
283
+ reject:(RCTPromiseRejectBlock)reject) {
284
+ NSData *d = hexToData(dataHex);
285
+ uint8_t out[32];
286
+ secp256k1_sha256(d.bytes, d.length, out);
287
+ resolve(dataToHex(out, 32));
288
+ }
289
+
290
+ RCT_EXPORT_METHOD(hash160:(NSString *)dataHex
291
+ resolve:(RCTPromiseResolveBlock)resolve
292
+ reject:(RCTPromiseRejectBlock)reject) {
293
+ NSData *d = hexToData(dataHex);
294
+ uint8_t out[20];
295
+ secp256k1_hash160(d.bytes, d.length, out);
296
+ resolve(dataToHex(out, 20));
297
+ }
298
+
299
+ RCT_EXPORT_METHOD(taggedHash:(NSString *)tag
300
+ data:(NSString *)dataHex
301
+ resolve:(RCTPromiseResolveBlock)resolve
302
+ reject:(RCTPromiseRejectBlock)reject) {
303
+ NSData *d = hexToData(dataHex);
304
+ uint8_t out[32];
305
+ secp256k1_tagged_hash(tag.UTF8String, d.bytes, d.length, out);
306
+ resolve(dataToHex(out, 32));
307
+ }
308
+
309
+ // ── Addresses ────────────────────────────────────────────────────────────────
310
+
311
+ RCT_EXPORT_METHOD(addressP2PKH:(NSString *)pubkeyHex
312
+ network:(int)network
313
+ resolve:(RCTPromiseResolveBlock)resolve
314
+ reject:(RCTPromiseRejectBlock)reject) {
315
+ NSData *pk = hexToData(pubkeyHex);
316
+ char addr[128]; size_t alen = 128;
317
+ if (secp256k1_address_p2pkh(pk.bytes, network, addr, &alen) != 0) {
318
+ reject(@"ERR", @"P2PKH failed", nil); return;
319
+ }
320
+ resolve([[NSString alloc] initWithBytes:addr length:alen encoding:NSUTF8StringEncoding]);
321
+ }
322
+
323
+ RCT_EXPORT_METHOD(addressP2WPKH:(NSString *)pubkeyHex
324
+ network:(int)network
325
+ resolve:(RCTPromiseResolveBlock)resolve
326
+ reject:(RCTPromiseRejectBlock)reject) {
327
+ NSData *pk = hexToData(pubkeyHex);
328
+ char addr[128]; size_t alen = 128;
329
+ if (secp256k1_address_p2wpkh(pk.bytes, network, addr, &alen) != 0) {
330
+ reject(@"ERR", @"P2WPKH failed", nil); return;
331
+ }
332
+ resolve([[NSString alloc] initWithBytes:addr length:alen encoding:NSUTF8StringEncoding]);
333
+ }
334
+
335
+ RCT_EXPORT_METHOD(addressP2TR:(NSString *)internalKeyXHex
336
+ network:(int)network
337
+ resolve:(RCTPromiseResolveBlock)resolve
338
+ reject:(RCTPromiseRejectBlock)reject) {
339
+ NSData *ik = hexToData(internalKeyXHex);
340
+ char addr[128]; size_t alen = 128;
341
+ if (secp256k1_address_p2tr(ik.bytes, network, addr, &alen) != 0) {
342
+ reject(@"ERR", @"P2TR failed", nil); return;
343
+ }
344
+ resolve([[NSString alloc] initWithBytes:addr length:alen encoding:NSUTF8StringEncoding]);
345
+ }
346
+
347
+ // ── WIF ──────────────────────────────────────────────────────────────────────
348
+
349
+ RCT_EXPORT_METHOD(wifEncode:(NSString *)privkeyHex
350
+ compressed:(BOOL)compressed
351
+ network:(int)network
352
+ resolve:(RCTPromiseResolveBlock)resolve
353
+ reject:(RCTPromiseRejectBlock)reject) {
354
+ NSData *pk = hexToData(privkeyHex);
355
+ char wif[128]; size_t wlen = 128;
356
+ if (secp256k1_wif_encode(pk.bytes, compressed ? 1 : 0, network, wif, &wlen) != 0) {
357
+ reject(@"ERR", @"WIF encode failed", nil); return;
358
+ }
359
+ resolve([[NSString alloc] initWithBytes:wif length:wlen encoding:NSUTF8StringEncoding]);
360
+ }
361
+
362
+ RCT_EXPORT_METHOD(wifDecode:(NSString *)wif
363
+ resolve:(RCTPromiseResolveBlock)resolve
364
+ reject:(RCTPromiseRejectBlock)reject) {
365
+ uint8_t pk[32]; int comp, net;
366
+ if (secp256k1_wif_decode(wif.UTF8String, pk, &comp, &net) != 0) {
367
+ reject(@"ERR", @"Invalid WIF", nil); return;
368
+ }
369
+ resolve(@{
370
+ @"privkey": dataToHex(pk, 32),
371
+ @"compressed": @(comp == 1),
372
+ @"network": @(net)
373
+ });
374
+ }
375
+
376
+ // ── BIP-32 ───────────────────────────────────────────────────────────────────
377
+
378
+ RCT_EXPORT_METHOD(bip32MasterKey:(NSString *)seedHex
379
+ resolve:(RCTPromiseResolveBlock)resolve
380
+ reject:(RCTPromiseRejectBlock)reject) {
381
+ NSData *seed = hexToData(seedHex);
382
+ secp256k1_bip32_key key;
383
+ if (secp256k1_bip32_master_key(seed.bytes, seed.length, &key) != 0) {
384
+ reject(@"ERR", @"Master key failed", nil); return;
385
+ }
386
+ resolve(dataToHex((const uint8_t *)&key, 79));
387
+ }
388
+
389
+ RCT_EXPORT_METHOD(bip32DeriveChild:(NSString *)parentKeyHex
390
+ index:(int)index
391
+ resolve:(RCTPromiseResolveBlock)resolve
392
+ reject:(RCTPromiseRejectBlock)reject) {
393
+ NSData *pdata = hexToData(parentKeyHex);
394
+ secp256k1_bip32_key parent, child;
395
+ memcpy(&parent, pdata.bytes, 79);
396
+ if (secp256k1_bip32_derive_child(&parent, (uint32_t)index, &child) != 0) {
397
+ reject(@"ERR", @"Derive child failed", nil); return;
398
+ }
399
+ resolve(dataToHex((const uint8_t *)&child, 79));
400
+ }
401
+
402
+ RCT_EXPORT_METHOD(bip32DerivePath:(NSString *)masterKeyHex
403
+ path:(NSString *)path
404
+ resolve:(RCTPromiseResolveBlock)resolve
405
+ reject:(RCTPromiseRejectBlock)reject) {
406
+ NSData *mdata = hexToData(masterKeyHex);
407
+ secp256k1_bip32_key master, out;
408
+ memcpy(&master, mdata.bytes, 79);
409
+ if (secp256k1_bip32_derive_path(&master, path.UTF8String, &out) != 0) {
410
+ reject(@"ERR", @"Path derivation failed", nil); return;
411
+ }
412
+ resolve(dataToHex((const uint8_t *)&out, 79));
413
+ }
414
+
415
+ RCT_EXPORT_METHOD(bip32GetPrivkey:(NSString *)keyHex
416
+ resolve:(RCTPromiseResolveBlock)resolve
417
+ reject:(RCTPromiseRejectBlock)reject) {
418
+ NSData *kdata = hexToData(keyHex);
419
+ secp256k1_bip32_key k;
420
+ memcpy(&k, kdata.bytes, 79);
421
+ uint8_t pk[32];
422
+ if (secp256k1_bip32_get_privkey(&k, pk) != 0) {
423
+ reject(@"ERR", @"Not a private key", nil); return;
424
+ }
425
+ resolve(dataToHex(pk, 32));
426
+ }
427
+
428
+ RCT_EXPORT_METHOD(bip32GetPubkey:(NSString *)keyHex
429
+ resolve:(RCTPromiseResolveBlock)resolve
430
+ reject:(RCTPromiseRejectBlock)reject) {
431
+ NSData *kdata = hexToData(keyHex);
432
+ secp256k1_bip32_key k;
433
+ memcpy(&k, kdata.bytes, 79);
434
+ uint8_t pub[33];
435
+ if (secp256k1_bip32_get_pubkey(&k, pub) != 0) {
436
+ reject(@"ERR", @"Pubkey extraction failed", nil); return;
437
+ }
438
+ resolve(dataToHex(pub, 33));
439
+ }
440
+
441
+ // ── Taproot ──────────────────────────────────────────────────────────────────
442
+
443
+ RCT_EXPORT_METHOD(taprootOutputKey:(NSString *)internalKeyXHex
444
+ merkleRoot:(NSString *)merkleRootHex
445
+ resolve:(RCTPromiseResolveBlock)resolve
446
+ reject:(RCTPromiseRejectBlock)reject) {
447
+ NSData *ik = hexToData(internalKeyXHex);
448
+ NSData *mr = merkleRootHex ? hexToData(merkleRootHex) : nil;
449
+ uint8_t out[32]; int parity;
450
+ if (secp256k1_taproot_output_key(ik.bytes, mr ? mr.bytes : NULL, out, &parity) != 0) {
451
+ reject(@"ERR", @"Taproot output key failed", nil); return;
452
+ }
453
+ resolve(@{@"outputKeyX": dataToHex(out, 32), @"parity": @(parity)});
454
+ }
455
+
456
+ RCT_EXPORT_METHOD(taprootTweakPrivkey:(NSString *)privkeyHex
457
+ merkleRoot:(NSString *)merkleRootHex
458
+ resolve:(RCTPromiseResolveBlock)resolve
459
+ reject:(RCTPromiseRejectBlock)reject) {
460
+ NSData *pk = hexToData(privkeyHex);
461
+ NSData *mr = merkleRootHex ? hexToData(merkleRootHex) : nil;
462
+ uint8_t out[32];
463
+ if (secp256k1_taproot_tweak_privkey(pk.bytes, mr ? mr.bytes : NULL, out) != 0) {
464
+ reject(@"ERR", @"Taproot tweak failed", nil); return;
465
+ }
466
+ resolve(dataToHex(out, 32));
467
+ }
468
+
469
+ RCT_EXPORT_METHOD(taprootVerifyCommitment:(NSString *)outputKeyXHex
470
+ parity:(int)parity
471
+ internalKeyX:(NSString *)internalKeyXHex
472
+ merkleRoot:(NSString *)merkleRootHex
473
+ resolve:(RCTPromiseResolveBlock)resolve
474
+ reject:(RCTPromiseRejectBlock)reject) {
475
+ NSData *ok = hexToData(outputKeyXHex);
476
+ NSData *ik = hexToData(internalKeyXHex);
477
+ NSData *mr = merkleRootHex ? hexToData(merkleRootHex) : nil;
478
+ int rc = secp256k1_taproot_verify_commitment(
479
+ ok.bytes, parity, ik.bytes, mr ? mr.bytes : NULL, mr ? mr.length : 0);
480
+ resolve(@(rc == 1));
481
+ }
482
+
483
+ @end
package/lib/ufsecp.js ADDED
@@ -0,0 +1,176 @@
1
+ /**
2
+ * UltrafastSecp256k1 — React Native binding (ufsecp stable C ABI v1).
3
+ *
4
+ * Bridges to native via NativeModules.Ufsecp (Android: Java JNI, iOS: ObjC bridge).
5
+ *
6
+ * Usage:
7
+ * import { Ufsecp } from 'react-native-ufsecp';
8
+ * const ctx = await Ufsecp.create();
9
+ * const pubkey = await ctx.pubkeyCreate(privkeyHex);
10
+ * ctx.destroy();
11
+ */
12
+
13
+ import { NativeModules, Platform } from 'react-native';
14
+
15
+ const { Ufsecp: NativeUfsecp } = NativeModules;
16
+
17
+ if (!NativeUfsecp) {
18
+ throw new Error(
19
+ 'react-native-ufsecp: NativeModule not linked. Run `npx react-native link react-native-ufsecp` or rebuild.',
20
+ );
21
+ }
22
+
23
+ const hex2buf = (hex) => {
24
+ const bytes = [];
25
+ for (let i = 0; i < hex.length; i += 2) bytes.push(parseInt(hex.substr(i, 2), 16));
26
+ return bytes;
27
+ };
28
+
29
+ const buf2hex = (arr) =>
30
+ (Array.isArray(arr) ? arr : [...arr]).map((b) => ('0' + (b & 0xff).toString(16)).slice(-2)).join('');
31
+
32
+ class UfsecpError extends Error {
33
+ constructor(op, msg) {
34
+ super(`ufsecp ${op}: ${msg}`);
35
+ this.name = 'UfsecpError';
36
+ this.operation = op;
37
+ }
38
+ }
39
+
40
+ class UfsecpContext {
41
+ constructor(handle) {
42
+ this._h = handle;
43
+ }
44
+
45
+ static async create() {
46
+ const h = await NativeUfsecp.create();
47
+ return new UfsecpContext(h);
48
+ }
49
+
50
+ async destroy() {
51
+ if (this._h != null) {
52
+ await NativeUfsecp.destroy(this._h);
53
+ this._h = null;
54
+ }
55
+ }
56
+
57
+ // ── Version ──────────────────────────────────────────────────────
58
+
59
+ static version() { return NativeUfsecp.version(); }
60
+ static versionString() { return NativeUfsecp.versionString(); }
61
+
62
+ // ── Key ops ──────────────────────────────────────────────────────
63
+
64
+ /** @param {string} privkeyHex - 32-byte hex */
65
+ async pubkeyCreate(privkeyHex) {
66
+ this._alive();
67
+ return NativeUfsecp.pubkeyCreate(this._h, privkeyHex);
68
+ }
69
+
70
+ async pubkeyCreateUncompressed(privkeyHex) {
71
+ this._alive();
72
+ return NativeUfsecp.pubkeyCreateUncompressed(this._h, privkeyHex);
73
+ }
74
+
75
+ async seckeyVerify(privkeyHex) {
76
+ this._alive();
77
+ return NativeUfsecp.seckeyVerify(this._h, privkeyHex);
78
+ }
79
+
80
+ // ── ECDSA ────────────────────────────────────────────────────────
81
+
82
+ async ecdsaSign(msgHashHex, privkeyHex) {
83
+ this._alive();
84
+ return NativeUfsecp.ecdsaSign(this._h, msgHashHex, privkeyHex);
85
+ }
86
+
87
+ async ecdsaVerify(msgHashHex, sigHex, pubkeyHex) {
88
+ this._alive();
89
+ return NativeUfsecp.ecdsaVerify(this._h, msgHashHex, sigHex, pubkeyHex);
90
+ }
91
+
92
+ async ecdsaSignRecoverable(msgHashHex, privkeyHex) {
93
+ this._alive();
94
+ return NativeUfsecp.ecdsaSignRecoverable(this._h, msgHashHex, privkeyHex);
95
+ }
96
+
97
+ async ecdsaRecover(msgHashHex, sigHex, recid) {
98
+ this._alive();
99
+ return NativeUfsecp.ecdsaRecover(this._h, msgHashHex, sigHex, recid);
100
+ }
101
+
102
+ // ── Schnorr ──────────────────────────────────────────────────────
103
+
104
+ async schnorrSign(msgHex, privkeyHex, auxRandHex) {
105
+ this._alive();
106
+ return NativeUfsecp.schnorrSign(this._h, msgHex, privkeyHex, auxRandHex);
107
+ }
108
+
109
+ async schnorrVerify(msgHex, sigHex, pubkeyXHex) {
110
+ this._alive();
111
+ return NativeUfsecp.schnorrVerify(this._h, msgHex, sigHex, pubkeyXHex);
112
+ }
113
+
114
+ // ── ECDH ─────────────────────────────────────────────────────────
115
+
116
+ async ecdh(privkeyHex, pubkeyHex) {
117
+ this._alive();
118
+ return NativeUfsecp.ecdh(this._h, privkeyHex, pubkeyHex);
119
+ }
120
+
121
+ // ── Hashing ──────────────────────────────────────────────────────
122
+
123
+ static sha256(dataHex) { return NativeUfsecp.sha256(dataHex); }
124
+ static hash160(dataHex) { return NativeUfsecp.hash160(dataHex); }
125
+
126
+ // ── Addresses ────────────────────────────────────────────────────
127
+
128
+ async addrP2pkh(pubkeyHex, network = 0) { this._alive(); return NativeUfsecp.addrP2pkh(this._h, pubkeyHex, network); }
129
+ async addrP2wpkh(pubkeyHex, network = 0) { this._alive(); return NativeUfsecp.addrP2wpkh(this._h, pubkeyHex, network); }
130
+ async addrP2tr(xonlyHex, network = 0) { this._alive(); return NativeUfsecp.addrP2tr(this._h, xonlyHex, network); }
131
+
132
+ // ── WIF ──────────────────────────────────────────────────────────
133
+
134
+ async wifEncode(privkeyHex, compressed = true, network = 0) {
135
+ this._alive();
136
+ return NativeUfsecp.wifEncode(this._h, privkeyHex, compressed, network);
137
+ }
138
+
139
+ // ── BIP-32 ───────────────────────────────────────────────────────
140
+
141
+ async bip32Master(seedHex) {
142
+ this._alive();
143
+ return NativeUfsecp.bip32Master(this._h, seedHex);
144
+ }
145
+
146
+ async bip32Derive(parentHex, index) {
147
+ this._alive();
148
+ return NativeUfsecp.bip32Derive(this._h, parentHex, index);
149
+ }
150
+
151
+ async bip32DerivePath(masterHex, path) {
152
+ this._alive();
153
+ return NativeUfsecp.bip32DerivePath(this._h, masterHex, path);
154
+ }
155
+
156
+ // ── Taproot ──────────────────────────────────────────────────────
157
+
158
+ async taprootOutputKey(internalXHex, merkleRootHex = null) {
159
+ this._alive();
160
+ return NativeUfsecp.taprootOutputKey(this._h, internalXHex, merkleRootHex);
161
+ }
162
+
163
+ async taprootTweakSeckey(privkeyHex, merkleRootHex = null) {
164
+ this._alive();
165
+ return NativeUfsecp.taprootTweakSeckey(this._h, privkeyHex, merkleRootHex);
166
+ }
167
+
168
+ // ── Internal ─────────────────────────────────────────────────────
169
+
170
+ _alive() {
171
+ if (this._h == null) throw new UfsecpError('context', 'already destroyed');
172
+ }
173
+ }
174
+
175
+ export { UfsecpContext, UfsecpError };
176
+ export default UfsecpContext;
package/package.json ADDED
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "react-native-ufsecp",
3
+ "version": "3.10.0",
4
+ "description": "React Native bindings for UltrafastSecp256k1 — high-performance secp256k1 ECC (ufsecp C ABI v1)",
5
+ "main": "lib/ufsecp.js",
6
+ "react-native": "lib/ufsecp.js",
7
+ "files": ["lib/ufsecp.js", "android/", "ios/", "react-native-ufsecp.podspec", "README.md"],
8
+ "scripts": {},
9
+ "keywords": [
10
+ "react-native", "secp256k1", "bitcoin", "crypto", "ecdsa",
11
+ "schnorr", "taproot", "ufsecp"
12
+ ],
13
+ "author": "UltrafastSecp256k1",
14
+ "license": "AGPL-3.0-only",
15
+ "peerDependencies": {
16
+ "react": ">=18.0.0",
17
+ "react-native": ">=0.71.0"
18
+ },
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "https://github.com/AvraSasmo/UltrafastSecp256k1"
22
+ },
23
+ "homepage": "https://github.com/AvraSasmo/UltrafastSecp256k1"
24
+ }