Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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