Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion example/ios/QuickCryptoExample.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,7 @@
"-DFOLLY_HAVE_CLOCK_GETTIME=1",
);
OTHER_LDFLAGS = "$(inherited)";
REACT_NATIVE_PATH = "${PODS_ROOT}/../../../node_modules/react-native";
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You have to fix this on your local somehow.

SDKROOT = iphoneos;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) DEBUG";
SWIFT_ENABLE_EXPLICIT_MODULES = NO;
Expand Down
59 changes: 59 additions & 0 deletions example/src/benchmarks/dh/dh.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import rnqc from 'react-native-quick-crypto';
// @ts-expect-error crypto-browserify missing types
import browserify from 'crypto-browserify';
import type { BenchFn } from '../../types/benchmarks';
import { Bench } from 'tinybench';

const dh_modp14_genKeys: BenchFn = () => {
const bench = new Bench({
name: 'DH modp14 KeyGen',
time: 200,
iterations: 10, // Cap iterations for slow JS implementations
});

bench
.add('rnqc', () => {
const dh = rnqc.getDiffieHellman('modp14');
dh.generateKeys();
})
.add('browserify', () => {
const dh = browserify.getDiffieHellman('modp14');
dh.generateKeys();
});

bench.warmupTime = 100;
return bench;
};

const dh_modp14_computeSecret: BenchFn = () => {
const bench = new Bench({
name: 'DH modp14 Compute',
time: 200,
iterations: 10,
});

const alice = rnqc.getDiffieHellman('modp14');
alice.generateKeys();
const bob = rnqc.getDiffieHellman('modp14');
bob.generateKeys();
const bobPub = bob.getPublicKey();

const bAlice = browserify.getDiffieHellman('modp14');
bAlice.generateKeys();
const bBob = browserify.getDiffieHellman('modp14');
bBob.generateKeys();
const bBobPub = bBob.getPublicKey();

bench
.add('rnqc', () => {
alice.computeSecret(bobPub);
})
.add('browserify', () => {
bAlice.computeSecret(bBobPub);
});

bench.warmupTime = 100;
return bench;
};

export default [dh_modp14_genKeys, dh_modp14_computeSecret];
55 changes: 55 additions & 0 deletions example/src/benchmarks/ecdh/ecdh.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import rnqc from 'react-native-quick-crypto';
import { p256 } from '@noble/curves/p256';
import type { BenchFn } from '../../types/benchmarks';
import { Bench } from 'tinybench';

const TIME_MS = 1000;

const ecdh_p256_genKeys: BenchFn = () => {
const bench = new Bench({
name: 'ECDH P-256 KeyGen',
time: TIME_MS,
});

bench
.add('rnqc', () => {
const ecdh = rnqc.createECDH('prime256v1');
ecdh.generateKeys();
})
.add('@noble/curves', () => {
p256.utils.randomPrivateKey();
});

bench.warmupTime = 100;
return bench;
};

const ecdh_p256_computeSecret: BenchFn = () => {
const bench = new Bench({
name: 'ECDH P-256 Compute',
time: TIME_MS,
});

const alice = rnqc.createECDH('prime256v1');
alice.generateKeys();
const bob = rnqc.createECDH('prime256v1');
bob.generateKeys();
const bobPub = bob.getPublicKey();

const nobleAlicePriv = p256.utils.randomPrivateKey();
const nobleBobPriv = p256.utils.randomPrivateKey();
const nobleBobPub = p256.getPublicKey(nobleBobPriv);

bench
.add('rnqc', () => {
alice.computeSecret(bobPub);
})
.add('@noble/curves', () => {
p256.getSharedSecret(nobleAlicePriv, nobleBobPub);
});

bench.warmupTime = 100;
return bench;
};

export default [ecdh_p256_genKeys, ecdh_p256_computeSecret];
4 changes: 4 additions & 0 deletions example/src/hooks/useBenchmarks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import hkdf from '../benchmarks/hkdf/hkdf';
import hash from '../benchmarks/hash/hash';
import hmac from '../benchmarks/hmac/hmac';
import pbkdf2 from '../benchmarks/pbkdf2/pbkdf2';
import ecdh from '../benchmarks/ecdh/ecdh';
import dh from '../benchmarks/dh/dh';
import random from '../benchmarks/random/randomBytes';
import scrypt from '../benchmarks/scrypt/scrypt';
import xsalsa20 from '../benchmarks/cipher/xsalsa20';
Expand All @@ -32,6 +34,8 @@ export const useBenchmarks = (): [
newSuites.push(new BenchmarkSuite('hash', hash));
newSuites.push(new BenchmarkSuite('hmac', hmac));
newSuites.push(new BenchmarkSuite('hkdf', hkdf));
newSuites.push(new BenchmarkSuite('ecdh', ecdh));
newSuites.push(new BenchmarkSuite('dh', dh));
newSuites.push(
new BenchmarkSuite('random', random, {
'browserify/randombytes':
Expand Down
2 changes: 2 additions & 0 deletions example/src/hooks/useTestsList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import '../tests/keys/generate_keypair';
import '../tests/keys/public_cipher';
import '../tests/keys/sign_verify_streaming';
import '../tests/pbkdf2/pbkdf2_tests';
import '../tests/ecdh/ecdh_tests';
import '../tests/dh/dh_tests';
import '../tests/random/random_tests';
import '../tests/scrypt/scrypt_tests';
import '../tests/subtle/deriveBits';
Expand Down
76 changes: 76 additions & 0 deletions example/src/tests/dh/dh_tests.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { test } from '../util';
import { Buffer } from '@craftzdog/react-native-buffer';
import crypto from 'react-native-quick-crypto';
import { assert } from 'chai';

const SUITE = 'dh';

test(SUITE, 'should create DiffieHellman with size', () => {
const dh = crypto.createDiffieHellman(512);
const prime = dh.getPrime();
assert.isOk(prime);
// Size check approx
assert.isAtLeast(prime.length, 64);
});

test(SUITE, 'should create DiffieHellman with prime', () => {
// 512-bit prime (Group 1 from RFC 2409)
const prime = Buffer.from(
'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1' +
'29024E088A67CC74020BBEA63B139B22514A08798E3404DD' +
'EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245' +
'E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' +
'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381' +
'FFFFFFFFFFFFFFFF',
'hex',
);
const generator = Buffer.from([2]);
const dh = crypto.createDiffieHellman(prime, generator);

assert.strictEqual(dh.getPrime('hex'), prime.toString('hex').toLowerCase());
assert.strictEqual(
dh.getGenerator('hex'),
generator.toString('hex').toLowerCase(),
);
});

test(SUITE, 'should compute shared secret', () => {
const alice = crypto.createDiffieHellman(512);
const aliceKeys = alice.generateKeys();

const bob = crypto.createDiffieHellman(
alice.getPrime(),
alice.getGenerator(),
);
const bobKeys = bob.generateKeys();

const aliceSecret = alice.computeSecret(bobKeys);
const bobSecret = bob.computeSecret(aliceKeys);

assert.strictEqual(aliceSecret.toString('hex'), bobSecret.toString('hex'));
});

test(SUITE, 'should set keys', () => {
const alice = crypto.createDiffieHellman(512);
alice.generateKeys();

const dh2 = crypto.createDiffieHellman(
alice.getPrime(),
alice.getGenerator(),
);
dh2.setPublicKey(alice.getPublicKey());
dh2.setPrivateKey(alice.getPrivateKey());

assert.strictEqual(dh2.getPublicKey('hex'), alice.getPublicKey('hex'));
assert.strictEqual(dh2.getPrivateKey('hex'), alice.getPrivateKey('hex'));
});

test(SUITE, 'should create DiffieHellman from standard group', () => {
const dh = crypto.getDiffieHellman('modp14');
assert.isOk(dh);
const prime = dh.getPrime();
assert.isTrue(Buffer.isBuffer(prime));
// modp14 is 2048-bit group
assert.strictEqual(prime.length, 256);
assert.strictEqual(dh.getGenerator('hex'), '02');
});
75 changes: 75 additions & 0 deletions example/src/tests/ecdh/ecdh_tests.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { test } from '../util';
import { Buffer } from '@craftzdog/react-native-buffer';
import crypto from 'react-native-quick-crypto';
import { assert } from 'chai';

const SUITE = 'ecdh';

test(SUITE, 'should create ECDH instance with P-256', () => {
const ecdh = crypto.createECDH('prime256v1');
assert.isOk(ecdh);
});

test(SUITE, 'should generate keys for P-256', () => {
const ecdh = crypto.createECDH('prime256v1');
const keys = ecdh.generateKeys();
assert.isOk(keys);
assert.isTrue(Buffer.isBuffer(keys), 'keys should be a Buffer');
assert.isOk(ecdh.getPublicKey());
assert.isOk(ecdh.getPrivateKey());
});

test(SUITE, 'should switch between curves', () => {
const ecdh1 = crypto.createECDH('prime256v1');
ecdh1.generateKeys();

const ecdh2 = crypto.createECDH('secp384r1');
ecdh2.generateKeys();

assert.notEqual(
ecdh1.getPrivateKey().toString('hex'),
ecdh2.getPrivateKey().toString('hex'),
);
});

test(SUITE, 'should compute shared secret', () => {
const alice = crypto.createECDH('prime256v1');
alice.generateKeys();

const bob = crypto.createECDH('prime256v1');
bob.generateKeys();

const aliceSecret = alice.computeSecret(bob.getPublicKey());
const bobSecret = bob.computeSecret(alice.getPublicKey());

assert.strictEqual(aliceSecret.toString('hex'), bobSecret.toString('hex'));
});

test(SUITE, 'should set private key', () => {
const alice = crypto.createECDH('prime256v1');
alice.generateKeys();
const priv = alice.getPrivateKey();

const alice2 = crypto.createECDH('prime256v1');
alice2.setPrivateKey(priv);

// Public key should be derived/set (depending on impl, but usually settable)
// In our implementation setPrivateKey derives public key?
// Let's check consistency.
// If setPrivateKey derives public key, we can check it matches
const pub1 = alice.getPublicKey();
const pub2 = alice2.getPublicKey();

assert.strictEqual(pub1.toString('hex'), pub2.toString('hex'));
});

test(SUITE, 'should work with string input', () => {
const alice = crypto.createECDH('prime256v1');
alice.generateKeys();
const bob = crypto.createECDH('prime256v1');
bob.generateKeys();

const bobPubHex = bob.getPublicKey().toString('hex');
const secret = alice.computeSecret(bobPubHex, 'hex');
assert.isOk(secret);
});
3 changes: 3 additions & 0 deletions packages/react-native-quick-crypto/QuickCrypto.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,9 @@ Pod::Spec.new do |s|
cpp_headers = [
"\"$(PODS_TARGET_SRCROOT)/cpp/utils\"",
"\"$(PODS_TARGET_SRCROOT)/cpp/hkdf\"",
"\"$(PODS_TARGET_SRCROOT)/cpp/dh\"",
"\"$(PODS_TARGET_SRCROOT)/cpp/ecdh\"",
"\"$(PODS_TARGET_SRCROOT)/nitrogen/generated/shared/c++\"",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

required? There are no other nitro ones, are there?

"\"$(PODS_TARGET_SRCROOT)/deps/ncrypto/include\"",
"\"$(PODS_TARGET_SRCROOT)/deps/blake3/c\"",
"\"$(PODS_TARGET_SRCROOT)/deps/fastpbkdf2\""
Expand Down
4 changes: 4 additions & 0 deletions packages/react-native-quick-crypto/android/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ add_library(
../cpp/cipher/XSalsa20Cipher.cpp
../cpp/cipher/ChaCha20Cipher.cpp
../cpp/cipher/ChaCha20Poly1305Cipher.cpp
../cpp/dh/HybridDiffieHellman.cpp
../cpp/ec/HybridEcKeyPair.cpp
../cpp/ecdh/HybridECDH.cpp
../cpp/ed25519/HybridEdKeyPair.cpp
../cpp/hash/HybridHash.cpp
../cpp/hmac/HybridHmac.cpp
Expand Down Expand Up @@ -62,7 +64,9 @@ include_directories(
"src/main/cpp"
"../cpp/blake3"
"../cpp/cipher"
"../cpp/dh"
"../cpp/ec"
"../cpp/ecdh"
"../cpp/ed25519"
"../cpp/hash"
"../cpp/hkdf"
Expand Down
Loading
Loading