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
2 changes: 1 addition & 1 deletion .clang-format
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

# Standard
BasedOnStyle: llvm
Standard: c++14
Standard: c++20

# Indentation
IndentWidth: 2
Expand Down
21 changes: 0 additions & 21 deletions .clangd

This file was deleted.

35 changes: 25 additions & 10 deletions .github/workflows/build-ios.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,20 +58,35 @@ jobs:
${{ runner.os }}-pods-

- name: Install Pods
env:
RCT_NEW_ARCH_ENABLED: 1
SODIUM_ENABLED: 1
run: bun pods

- name: Install xcpretty
run: gem install xcpretty

- name: List available simulators
run: xcrun simctl list devices available

- name: List available SDKs
run: xcodebuild -showsdks

- name: Build App
working-directory: example/ios
run: "set -o pipefail && xcodebuild \
CC=clang CPLUSPLUS=clang++ LD=clang LDPLUSPLUS=clang++ \
-derivedDataPath build -UseModernBuildSystem=YES \
-workspace QuickCryptoExample.xcworkspace \
-scheme QuickCryptoExample \
-sdk iphonesimulator \
-configuration Debug \
-destination 'platform=iOS Simulator,name=iPhone 16 Pro' \
build \
CODE_SIGNING_ALLOWED=NO | xcpretty"
env:
RCT_NEW_ARCH_ENABLED: 1
SODIUM_ENABLED: 1
run: |
set -o pipefail
sudo xcode-select --switch /Applications/Xcode_16.4.app
xcodebuild \
CC=clang CPLUSPLUS=clang++ LD=clang LDPLUSPLUS=clang++ \
-derivedDataPath build -UseModernBuildSystem=YES \
-workspace QuickCryptoExample.xcworkspace \
-scheme QuickCryptoExample \
-sdk iphonesimulator \
-configuration Debug \
-destination 'platform=iOS Simulator,name=iPhone 16 Pro,OS=18.6' \
build \
CODE_SIGNING_ALLOWED=NO | xcpretty
1 change: 0 additions & 1 deletion .rules
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ Every time you choose to apply a rule(s), explicitly state the rule(s) in the ou

## Rules

- For C++ includes, do not try to add absolute paths. They have to be resolved by the build system.
- Use smart pointers in C++.
- Use modern C++ features.
- Attempt to reduce the amount of code rather than add more.
Expand Down
13 changes: 13 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,19 @@ bun i

> While it's possible to use [`npm`](https://github.com/npm/cli), [`yarn`](https://classic.yarnpkg.com/), or [`pnpm`](https://pnpm.io), the tooling is built around [`bun`](https://bun.sh), so you'll have an easier time if you use `bun` for development.

If you are using a VSCode-flavored IDE and the `clangd` extension, you can use the `scripts/setup_clang_env.sh` script to set up the environment for C++ development. This will create a `compile_commands.json` file in the root directory of the project, which will allow the IDE to provide proper includes, better code completion and navigation. After that, add the following to your `.vscode/settings.json` file:

```json
{
"clangd.arguments": [
"-log=verbose",
"-pretty",
"--background-index",
"--compile-commands-dir=${workspaceFolder}/packages/react-native-quick-crypto/"
],
}
```

While developing, you can run the [example app](/example/) to test your changes. Any changes you make in your library's JavaScript code will be reflected in the example app without a rebuild. If you change any native code, then you'll need to rebuild the example app.

To start the packager:
Expand Down
417 changes: 258 additions & 159 deletions bun.lock

Large diffs are not rendered by default.

10 changes: 9 additions & 1 deletion docs/implementation-coverage.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ This document attempts to describe the implementation status of Crypto APIs/Inte
* ❌ `crypto.createSecretKey(key[, encoding])`
* ❌ `crypto.createSign(algorithm[, options])`
* ❌ `crypto.createVerify(algorithm[, options])`
* `crypto.diffieHellman(options)`
* 🚧 `crypto.diffieHellman(options[, callback])`
* ❌ `crypto.hash(algorithm, data[, outputEncoding])`
* ❌ `crypto.generateKey(type, options, callback)`
* 🚧 `crypto.generateKeyPair(type, options, callback)`
Expand Down Expand Up @@ -149,6 +149,14 @@ This document attempts to describe the implementation status of Crypto APIs/Inte

🚧 Details below still a work in progress 🚧

## `crypto.diffieHellman`
| type | Status |
| --------- | :----: |
| `dh` | ❌ |
| `ec` | ❌ |
| `x448` | ✅ |
| `x25519` | ✅ |

## `crypto.generateKey`
| type | Status |
| --------- | :----: |
Expand Down
Binary file modified docs/test_suite_results_android.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/test_suite_results_ios.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 3 additions & 3 deletions example/android/settings.gradle
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import com.facebook.react.ReactSettingsExtension

pluginManagement { includeBuild("../../node_modules/@react-native/gradle-plugin") }
plugins { id("com.facebook.react.settings") }
extensions.configure(com.facebook.react.ReactSettingsExtension){ ex -> ex.autolinkLibrariesFromCommand() }
extensions.configure(ReactSettingsExtension){ ex -> ex.autolinkLibrariesFromCommand() }
rootProject.name = 'QuickCryptoExample'


include ':app'
includeBuild('../../node_modules/@react-native/gradle-plugin')
19 changes: 18 additions & 1 deletion example/ios/Podfile
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,24 @@ target 'QuickCryptoExample' do
# https://github.com/mrousavy/nitro/issues/422#issuecomment-2545988256
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '16.0'
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '18.0'
config.build_settings['CLANG_CXX_LANGUAGE_STANDARD'] = 'c++20'

# Force C++20 for all targets, especially problematic ones
config.build_settings['GCC_C_LANGUAGE_STANDARD'] = 'gnu11'
config.build_settings['CLANG_CXX_LIBRARY'] = 'libc++'

# Remove any conflicting C++ standard flags
config.build_settings.delete('CLANG_CXX_LANGUAGE_STANDARD_OVERRIDE')
end
end

# Specifically target RCT-Folly and other React Native core pods
installer.pods_project.targets.each do |target|
if target.name.include?('Folly') || target.name.include?('React-') || target.name.include?('RCT')
target.build_configurations.each do |config|
config.build_settings['CLANG_CXX_LANGUAGE_STANDARD'] = 'c++20'
end
end
end
end
Expand Down
10 changes: 5 additions & 5 deletions example/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ PODS:
- hermes-engine (0.76.9):
- hermes-engine/Pre-built (= 0.76.9)
- hermes-engine/Pre-built (0.76.9)
- NitroModules (0.25.2):
- NitroModules (0.26.4):
- DoubleConversion
- glog
- hermes-engine
Expand Down Expand Up @@ -1752,7 +1752,7 @@ DEPENDENCIES:
- fmt (from `../../node_modules/react-native/third-party-podspecs/fmt.podspec`)
- glog (from `../../node_modules/react-native/third-party-podspecs/glog.podspec`)
- hermes-engine (from `../../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec`)
- NitroModules (from `../../node_modules/react-native-nitro-modules`)
- NitroModules (from `../node_modules/react-native-nitro-modules`)
- QuickCrypto (from `../../node_modules/react-native-quick-crypto`)
- RCT-Folly (from `../../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`)
- RCT-Folly/Fabric (from `../../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`)
Expand Down Expand Up @@ -1840,7 +1840,7 @@ EXTERNAL SOURCES:
:podspec: "../../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec"
:tag: hermes-2024-11-12-RNv0.76.2-5b4aa20c719830dcf5684832b89a6edb95ac3d64
NitroModules:
:path: "../../node_modules/react-native-nitro-modules"
:path: "../node_modules/react-native-nitro-modules"
QuickCrypto:
:path: "../../node_modules/react-native-quick-crypto"
RCT-Folly:
Expand Down Expand Up @@ -1974,7 +1974,7 @@ SPEC CHECKSUMS:
fmt: 01b82d4ca6470831d1cc0852a1af644be019e8f6
glog: 08b301085f15bcbb6ff8632a8ebaf239aae04e6a
hermes-engine: 9e868dc7be781364296d6ee2f56d0c1a9ef0bb11
NitroModules: fdc6fcf8f397091615951004ae81022b759e27bc
NitroModules: a93d85b07601390249d7816b59d95afc6317f09d
OpenSSL-Universal: 6082b0bf950e5636fe0d78def171184e2b3899c2
QuickCrypto: 108a3cec847d30cd9a465dc52a9c77bd0e01f98d
RCT-Folly: ea9d9256ba7f9322ef911169a9f696e5857b9e17
Expand Down Expand Up @@ -2040,6 +2040,6 @@ SPEC CHECKSUMS:
SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748
Yoga: feb4910aba9742cfedc059e2b2902e22ffe9954a

PODFILE CHECKSUM: 63c4c1ca9d3ee6394f468b17e19efd3e548b5357
PODFILE CHECKSUM: 800c5bf165ac9d74dcded58110e453f82283c73f

COCOAPODS: 1.15.2
9 changes: 4 additions & 5 deletions example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"start": "react-native start",
"pods": "bundle exec pod install --project-directory=ios",
"build:android": "cd android && ./gradlew assembleDebug --no-daemon --console=plain -PreactNativeArchitectures=arm64-v8a",
"build:ios": "cd ios && xcodebuild -workspace QuickCrytpExample.xcworkspace -scheme QuickCrytpExample -configuration Debug -sdk iphonesimulator CC=clang CPLUSPLUS=clang++ LD=clang LDPLUSPLUS=clang++ GCC_OPTIMIZATION_LEVEL=0 GCC_PRECOMPILE_PREFIX_HEADER=YES ASSETCATALOG_COMPILER_OPTIMIZATION=time DEBUG_INFORMATION_FORMAT=dwarf COMPILER_INDEX_STORE_ENABLE=NO"
"build:ios": "cd ios && xcodebuild -workspace QuickCryptoExample.xcworkspace -scheme QuickCryptoExample -configuration Debug -sdk iphonesimulator CC=clang CPLUSPLUS=clang++ LD=clang LDPLUSPLUS=clang++ GCC_OPTIMIZATION_LEVEL=0 GCC_PRECOMPILE_PREFIX_HEADER=YES ASSETCATALOG_COMPILER_OPTIMIZATION=time DEBUG_INFORMATION_FORMAT=dwarf COMPILER_INDEX_STORE_ENABLE=NO"
},
"dependencies": {
"@craftzdog/react-native-buffer": "6.1.0",
Expand All @@ -35,9 +35,9 @@
"react": "18.3.1",
"react-native": "0.76.9",
"react-native-bouncy-checkbox": "4.1.2",
"react-native-nitro-modules": "0.25.2",
"react-native-nitro-modules": "0.26.4",
"react-native-quick-base64": "2.2.0",
"react-native-quick-crypto": "1.0.0-beta.20",
"react-native-quick-crypto": "workspace:*",
"react-native-safe-area-context": "5.1.0",
"react-native-screens": "3.35.0",
"react-native-vector-icons": "^10.1.0",
Expand Down Expand Up @@ -65,8 +65,7 @@
"@types/react-test-renderer": "18.3.0",
"babel-jest": "29.7.0",
"babel-plugin-module-resolver": "5.0.2",
"jest": "29.7.0",
"pod-install": "^0.3.9"
"jest": "29.7.0"
},
"engines": {
"node": ">=18"
Expand Down
3 changes: 3 additions & 0 deletions example/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import * as React from 'react';
import { Root } from './navigators/Root';
import { LogBox } from 'react-native';

export default function App() {
return <Root />;
}

LogBox.ignoreLogs(['Open debugger to view warnings']);
1 change: 1 addition & 0 deletions example/src/hooks/useTestsList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import '../tests/cipher/cipher_tests';
import '../tests/cipher/chacha_tests';
import '../tests/cipher/xsalsa20_tests';
import '../tests/ed25519/ed25519_tests';
import '../tests/ed25519/x25519_tests';
import '../tests/hash/hash_tests';
import '../tests/hmac/hmac_tests';
import '../tests/pbkdf2/pbkdf2_tests';
Expand Down
88 changes: 50 additions & 38 deletions example/src/tests/ed25519/ed25519_tests.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
/* eslint-disable @typescript-eslint/no-unused-expressions */
import { Ed, randomBytes, ab2str } from 'react-native-quick-crypto';
import { Buffer } from '@craftzdog/react-native-buffer';
import { expect } from 'chai';
import { ab2str, Ed, randomBytes } from 'react-native-quick-crypto';
import { test } from '../util';

const SUITE = 'ed25519';
const SUITE = 'cfrg';

const encoder = new TextEncoder();
// eslint-disable-next-line @typescript-eslint/no-explicit-any
Expand Down Expand Up @@ -46,15 +46,15 @@ types.map((type) => {

const data1 = Buffer.from('hello world');

test(SUITE, 'sign/verify - round trip happy', async () => {
test(SUITE, 'ed25519 - sign/verify - round trip happy', async () => {
const ed = new Ed('ed25519', {});
await ed.generateKeyPair();
const signature = await ed.sign(data1.buffer);
const verified = await ed.verify(signature, data1.buffer);
expect(verified).to.be.true;
});

test(SUITE, 'sign/verify - round trip sad', async () => {
test(SUITE, 'ed25519 - sign/verify - round trip sad', async () => {
const data2 = Buffer.from('goodbye cruel world');
const ed = new Ed('ed25519', {});
await ed.generateKeyPair();
Expand All @@ -63,42 +63,54 @@ test(SUITE, 'sign/verify - round trip sad', async () => {
expect(verified).to.be.false;
});

test(SUITE, 'sign/verify - bad signature does not verify', async () => {
const ed = new Ed('ed25519', {});
await ed.generateKeyPair();
const signature = await ed.sign(data1.buffer);
const signature2 = randomBytes(64).buffer;
expect(ab2str(signature2)).not.to.equal(ab2str(signature));
const verified = await ed.verify(signature2, data1.buffer);
expect(verified).to.be.false;
});
test(
SUITE,
'ed25519 - sign/verify - bad signature does not verify',
async () => {
const ed = new Ed('ed25519', {});
await ed.generateKeyPair();
const signature = await ed.sign(data1.buffer);
const signature2 = randomBytes(64).buffer;
expect(ab2str(signature2)).not.to.equal(ab2str(signature));
const verified = await ed.verify(signature2, data1.buffer);
expect(verified).to.be.false;
},
);

test(SUITE, 'sign/verify - switched args does not verify', async () => {
const ed = new Ed('ed25519', {});
await ed.generateKeyPair();
const signature = await ed.sign(data1.buffer);
// verify(message, signature) is switched
const verified = await ed.verify(data1.buffer, signature);
expect(verified).to.be.false;
});
test(
SUITE,
'ed25519 - sign/verify - switched args does not verify',
async () => {
const ed = new Ed('ed25519', {});
await ed.generateKeyPair();
const signature = await ed.sign(data1.buffer);
// verify(message, signature) is switched
const verified = await ed.verify(data1.buffer, signature);
expect(verified).to.be.false;
},
);

test(SUITE, 'sign/verify - non-internally generated private key', async () => {
const pub = Buffer.from(
'e106bf015ad54a64022295c7af2c35f9511eb37264a7722a9642eaac6c59a494',
'hex',
);
const priv = Buffer.from(
'5f27e170afc5091c4933d980c5fe86af997b91375115c6ee2c0fe4ea12400ed0',
'hex',
);
test(
SUITE,
'ed25519 - sign/verify - non-internally generated private key',
async () => {
const pub = Buffer.from(
'e106bf015ad54a64022295c7af2c35f9511eb37264a7722a9642eaac6c59a494',
'hex',
);
const priv = Buffer.from(
'5f27e170afc5091c4933d980c5fe86af997b91375115c6ee2c0fe4ea12400ed0',
'hex',
);

const ed2 = new Ed('ed25519', {});
const signature = await ed2.sign(data1.buffer, priv);
const verified = await ed2.verify(signature, data1.buffer, pub);
expect(verified).to.be.true;
});
const ed2 = new Ed('ed25519', {});
const signature = await ed2.sign(data1.buffer, priv);
const verified = await ed2.verify(signature, data1.buffer, pub);
expect(verified).to.be.true;
},
);

test(SUITE, 'sign/verify - bad signature', async () => {
test(SUITE, 'ed25519 - sign/verify - bad signature', async () => {
let ed1: Ed | null = new Ed('ed25519', {});
await ed1.generateKeyPair();
const pub = ed1.getPublicKey();
Expand All @@ -115,7 +127,7 @@ test(SUITE, 'sign/verify - bad signature', async () => {

test(
SUITE,
'sign/verify - bad verify with private key, not public',
'ed25519 - sign/verify - bad verify with private key, not public',
async () => {
let ed1: Ed | null = new Ed('ed25519', {});
await ed1.generateKeyPair();
Expand All @@ -129,7 +141,7 @@ test(
},
);

test(SUITE, 'sign/verify - Uint8Arrays', () => {
test(SUITE, 'ed25519 - sign/verify - Uint8Arrays', () => {
const data = { b: 'world', a: 'hello' };

const ed1 = new Ed('ed25519', {});
Expand Down
Loading
Loading