Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
4 changes: 3 additions & 1 deletion .github/workflows/validate-cpp.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,12 @@ jobs:
github_token: ${{ secrets.github_token }}
reporter: github-pr-review
flags: --linelength=230
targets: --recursive packages/react-native-quick-crypto/cpp packages/react-native-quick-crypto/android/src/main/cpp packages/react-native-quick-crypto/nitrogen/generated/shared/c++
targets: --recursive packages/react-native-quick-crypto/cpp packages/react-native-quick-crypto/android/src/main/cpp
filter: "-legal/copyright\
,-readability/todo\
,-build/namespaces\
,-whitespace/comments\
,-build/include_order\
,-whitespace/indent_namespace\
,-whitespace/parens\
"
Binary file modified bun.lockb
Binary file not shown.
43 changes: 31 additions & 12 deletions docs/implementation-coverage.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,8 @@ This document attempts to describe the implementation status of Crypto APIs/Inte
* ❌ `crypto.diffieHellman(options)`
* ❌ `crypto.hash(algorithm, data[, outputEncoding])`
* ❌ `crypto.generateKey(type, options, callback)`
* `crypto.generateKeyPair(type, options, callback)`
* `crypto.generateKeyPairSync(type, options)`
* 🚧 `crypto.generateKeyPair(type, options, callback)`
* 🚧 `crypto.generateKeyPairSync(type, options)`
* ❌ `crypto.generateKeySync(type, options)`
* ❌ `crypto.generatePrime(size[, options[, callback]])`
* ❌ `crypto.generatePrimeSync(size[, options])`
Expand Down Expand Up @@ -141,10 +141,10 @@ This document attempts to describe the implementation status of Crypto APIs/Inte
* ❌ `crypto.secureHeapUsed()`
* ❌ `crypto.setEngine(engine[, flags])`
* ❌ `crypto.setFips(bool)`
* `crypto.sign(algorithm, data, key[, callback])`
* 🚧 `crypto.sign(algorithm, data, key[, callback])`
* ❌ `crypto.subtle` (see below)
* ❌ `crypto.timingSafeEqual(a, b)`
* `crypto.verify(algorithm, data, key, signature[, callback])`
* 🚧 `crypto.verify(algorithm, data, key, signature[, callback])`
* ❌ `crypto.webcrypto` (see below)

🚧 Details below still a work in progress 🚧
Expand All @@ -162,10 +162,10 @@ This document attempts to describe the implementation status of Crypto APIs/Inte
| `rsa-pss` | ❌ |
| `dsa` | ❌ |
| `ec` | ❌ |
| `ed25519` | |
| `ed448` | |
| `x25519` | |
| `x448` | |
| `ed25519` | |
| `ed448` | |
| `x25519` | |
| `x448` | |
| `dh` | ❌ |

## `crypto.generateKeyPairSync`
Expand All @@ -175,10 +175,10 @@ This document attempts to describe the implementation status of Crypto APIs/Inte
| `rsa-pss` | ❌ |
| `dsa` | ❌ |
| `ec` | ❌ |
| `ed25519` | |
| `ed448` | |
| `x25519` | |
| `x448` | |
| `ed25519` | |
| `ed448` | |
| `x25519` | |
| `x448` | |
| `dh` | ❌ |

## `crypto.generateKeySync`
Expand All @@ -187,6 +187,25 @@ This document attempts to describe the implementation status of Crypto APIs/Inte
| `aes` | ❌ |
| `hmac` | ❌ |

## `crypto.sign`
| Algorithm | Status |
| --------- | :----: |
| `RSASSA-PKCS1-v1_5` | |
| `RSA-PSS` | |
| `ECDSA` | |
| `Ed25519` | ✅ |
| `Ed448` | ✅ |
| `HMAC` | |

## `crypto.verify`
| Algorithm | Status |
| --------- | :----: |
| `RSASSA-PKCS1-v1_5` | |
| `RSA-PSS` | |
| `ECDSA` | |
| `Ed25519` | ✅ |
| `Ed448` | ✅ |
| `HMAC` | |

# `WebCrypto`

Expand Down
3 changes: 3 additions & 0 deletions example/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
import { install } from 'react-native-quick-crypto';
install();

// event-target-shim
import 'event-target-polyfill';

// readable-stream
// @ts-expect-error - although process.version is readonly, we're setting it for readable-stream
global.process.version = 'v22.0.0';
Expand Down
14 changes: 8 additions & 6 deletions example/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,21 @@ PODS:
- hermes-engine (0.76.1):
- hermes-engine/Pre-built (= 0.76.1)
- hermes-engine/Pre-built (0.76.1)
- NitroModules (0.14.0):
- NitroModules (0.18.1):
- DoubleConversion
- glog
- hermes-engine
- RCT-Folly (= 2024.01.01.00)
- RCTRequired
- RCTTypeSafety
- React-callinvoker
- React-Core
- React-debug
- React-Fabric
- React-featureflags
- React-graphics
- React-ImageManager
- React-jsi
- React-NativeModulesApple
- React-RCTFabric
- React-rendererdebug
Expand All @@ -28,8 +30,8 @@ PODS:
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- Yoga
- OpenSSL-Universal (3.2.2000)
- QuickCrypto (1.0.0-beta.3):
- OpenSSL-Universal (3.3.2000)
- QuickCrypto (1.0.0-beta.5):
- DoubleConversion
- glog
- hermes-engine
Expand Down Expand Up @@ -1936,9 +1938,9 @@ SPEC CHECKSUMS:
fmt: 10c6e61f4be25dc963c36bd73fc7b1705fe975be
glog: 08b301085f15bcbb6ff8632a8ebaf239aae04e6a
hermes-engine: 46f1ffbf0297f4298862068dd4c274d4ac17a1fd
NitroModules: 69a6524b390ed8ca220e15f00bcfbd2f7c24472e
OpenSSL-Universal: f8a9c4fdab7e21cb70bda471c269e86e9212439c
QuickCrypto: 452b6fe586fa5c0a93e7ccca0a619387763d5adf
NitroModules: 55f64932b4581a7d02103bc35b84c7bd3204106b
OpenSSL-Universal: b60a3702c9fea8b3145549d421fdb018e53ab7b4
QuickCrypto: 8d76ae3a0bf60509f671193eb4ed666a80da34cb
RCT-Folly: 84578c8756030547307e4572ab1947de1685c599
RCTDeprecation: fde92935b3caa6cb65cbff9fbb7d3a9867ffb259
RCTRequired: 75c6cee42d21c1530a6f204ba32ff57335d19007
Expand Down
11 changes: 8 additions & 3 deletions example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,24 +21,27 @@
},
"dependencies": {
"@craftzdog/react-native-buffer": "6.0.5",
"@noble/curves": "^1.7.0",
"@noble/hashes": "^1.5.0",
"@react-navigation/bottom-tabs": "^6.6.1",
"@react-navigation/native": "6.1.18",
"@react-navigation/native-stack": "6.11.0",
"buffer": "6.0.3",
"chai": "<5.0.0",
"crypto-browserify": "^3.12.0",
"event-target-polyfill": "^0.0.4",
"events": "3.3.0",
"react": "18.3.1",
"react-native": "0.76.1",
"react-native-bouncy-checkbox": "4.0.1",
"react-native-nitro-modules": "0.14.0",
"react-native-nitro-modules": "0.18.1",
"react-native-quick-base64": "2.1.2",
"react-native-quick-crypto": "1.0.0-beta.5",
"react-native-quick-crypto": "workspace:*",
"react-native-safe-area-context": "4.14.0",
"react-native-screens": "3.35.0",
"react-native-vector-icons": "^10.1.0",
"readable-stream": "4.5.2",
"tinybench": "^3.0.6",
"util": "0.12.5"
},
"devDependencies": {
Expand Down Expand Up @@ -86,7 +89,9 @@
"@release-it/bumper": {
"out": {
"file": "package.json",
"path": ["dependencies.react-native-quick-crypto"]
"path": [
"dependencies.react-native-quick-crypto"
]
}
}
}
Expand Down
95 changes: 30 additions & 65 deletions example/src/benchmarks/benchmarks.ts
Original file line number Diff line number Diff line change
@@ -1,92 +1,57 @@
import type {
BenchmarkFn,
BenchmarkResult,
Challenger,
ImportedBenchmark,
SuiteState,
} from '../types/benchmarks';
import { calculateTimes } from './utils';
import type { Bench } from 'tinybench';
import type { BenchFn, BenchmarkResult, SuiteState } from '../types/benchmarks';

export class BenchmarkSuite {
name: string;
enabled: boolean;
benchmarks: Benchmark[];
benchmarks: BenchFn[];
state: SuiteState;
results: BenchmarkResult[] = [];
notes?: Record<string, string>;

constructor(name: string) {
constructor(
name: string,
benchmarks: BenchFn[],
notes?: Record<string, string>,
) {
this.name = name;
this.enabled = false;
this.state = 'idle';
this.benchmarks = [];
this.benchmarks = benchmarks;
this.results = [];
}

addBenchmark(imported: ImportedBenchmark) {
this.benchmarks.push(new Benchmark(imported));
this.notes = notes;
}

addResult(result: BenchmarkResult) {
this.results.push(result);
}

run(multiplier: number = 1) {
async run() {
this.results = [];
this.benchmarks.forEach(benchmark => {
benchmark.run(this, multiplier);
const promises = this.benchmarks.map(async benchFn => {
const b = await benchFn();
await b.run();
this.processResults(b);
this.state = 'done';
});
await Promise.all(promises);
}
}

export class Benchmark {
name: string; // function name
runCount: number;
us?: BenchmarkFn;
them: Challenger[];

constructor(benchmark: ImportedBenchmark) {
this.name = benchmark.name;
this.runCount = benchmark.runCount;
this.us = benchmark.us;
this.them = benchmark.them;
}
processResults = (b: Bench): void => {
const tasks = b.tasks;
const us = tasks.find(t => t.name === 'rnqc');
const themTasks = tasks.filter(t => t.name !== 'rnqc');

run(suite: BenchmarkSuite, multiplier: number = 1) {
const usTime = this.timeFn(this.us!, multiplier);
this.them.forEach(them => {
const themTime = this.timeFn(them.fn, multiplier);
const type = usTime < themTime ? 'faster' : 'slower';
const times = calculateTimes(usTime, themTime);
const result: BenchmarkResult = {
themTasks.map(them => {
const notes = this.notes?.[them.name] ?? '';
this.addResult({
errorMsg: undefined,
challenger: them.name,
notes: them.notes,
runCount: this.runCount * multiplier,
fnName: this.name,
time: themTime,
us: usTime,
type,
times,
};
suite.addResult(result);
notes,
benchName: b.name,
them: them.result,
us: us?.result,
});
});
}

/**
* @returns time in ms
*/
timeFn = (fn: BenchmarkFn, multiplier: number = 1): number => {
// warm up imports, etc.
fn();

const totalRunCount = this.runCount * multiplier;

// do the actual benchmark
const start = performance.now();
for (let i = 0; i < totalRunCount; i++) {
fn();
}
const end = performance.now();
return end - start;
};
}
80 changes: 80 additions & 0 deletions example/src/benchmarks/ed/ed25519.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { Bench } from 'tinybench';
import rnqc from 'react-native-quick-crypto';
import { ed25519 as noble } from '@noble/curves/ed25519';
import type { BenchFn } from '../../types/benchmarks';

const TIME_MS = 1000;
const message = 'hello world';
const buffer = Buffer.from(message);
const ab = buffer.buffer;
const arr = new Uint8Array(buffer);

const ed25519_sign_verify_async: BenchFn = async () => {
// rnqc setup
const ed = new rnqc.Ed('ed25519', {});
await ed.generateKeyPair();

// noble setup
const noblePrivateKey = noble.utils.randomPrivateKey();
const noblePublicKey = noble.getPublicKey(noblePrivateKey);

const bench = new Bench({
name: 'ed25519 sign/verify (async)',
time: TIME_MS,
});

bench.add('rnqc', async () => {
const signature = await ed.sign(ab);
const verified = await ed.verify(signature, ab);
if (!verified) {
throw new Error('Signature verification failed');
}
});

bench.add('@noble/curves/ed25519', () => {
const signature = noble.sign(arr, noblePrivateKey);
const verified = noble.verify(signature, arr, noblePublicKey);
if (!verified) {
throw new Error('Signature verification failed');
}
});

bench.warmupTime = 100;
return bench;
};

const ed25519_sign_verify_sync: BenchFn = () => {
// rnqc setup
const ed = new rnqc.Ed('ed25519', {});
ed.generateKeyPairSync();

// noble setup
const noblePrivateKey = noble.utils.randomPrivateKey();
const noblePublicKey = noble.getPublicKey(noblePrivateKey);

const bench = new Bench({
name: 'ed25519 sign/verify (sync)',
time: TIME_MS,
});

bench.add('rnqc', () => {
const signature = ed.signSync(ab);
const verified = ed.verifySync(signature, ab);
if (!verified) {
throw new Error('Signature verification failed');
}
});

bench.add('@noble/curves/ed25519', () => {
const signature = noble.sign(arr, noblePrivateKey);
const verified = noble.verify(signature, arr, noblePublicKey);
if (!verified) {
throw new Error('Signature verification failed');
}
});

bench.warmupTime = 100;
return bench;
};

export default [ed25519_sign_verify_async, ed25519_sign_verify_sync];
Loading
Loading