diff --git a/README.md b/README.md index 35aae8e..01132a1 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,30 @@ Next-gen React Native library for Bcrypt hashing using pure C++ with Turbo Modul **_NOTE:_** This library can be used only with New Architecture (more information about New Architecture [here](https://github.com/reactwg/react-native-new-architecture)) +## Features + +- **50x faster than JS implementation** ๐Ÿš€ +- **Multithreaded for high performance without blocking the JS thread** ๐Ÿงต +- **Seamless integration with Turbo Modules** ๐Ÿ”Œ +- **Native C++ hashing for maximum security** ๐Ÿ”’ +- **Supports both asynchronous and synchronous operations** โšก๏ธ +- **Optimized for React Native's New Architecture** ๐Ÿ“ฑ + +## Performance + +The C++ implementation of Bcrypt hashing is significantly faster than the JavaScript implementation, especially for high-cost factors. Here are some benchmarks comparing the two implementations: + +![Comparisons](./assets/comparisons) + +## Demo + +After running "Generate Hash" function on JS side, it blocks JS Thread while the function runs (approximately 14 seconds). On the other hand, the C++ implementation runs the same function in a separate thread, allowing the JS thread to continue executing other tasks without blocking (approximately 0.3 seconds). This demonstrates the superior performance of the C++ implementation over the JavaScript implementation. + +| JavaScript Demo | C++ Demo | +| :---------------------------------------: | :-----------------------------------------: | +| ![JS Demo](./assets/JS_GENERATE_HASH.gif) | ![C++ Demo](./assets/C++_GENERATE_HASH.gif) | +| **JavaScript Hashing** | **C++ Hashing** | + ## Installation ```sh @@ -16,6 +40,10 @@ or yarn add react-native-bcrypt-cpp ``` +### Linking + +TBD + ## Usage ### Asynchronous Hashing (Multithreaded) @@ -101,6 +129,11 @@ Synchronously validates the given password against the Bcrypt hash. - A `boolean` indicating whether the password is valid. +## Bcrypt Algorithm Source + +This library implements the Bcrypt hashing algorithm in C++, adapted from the [Bcrypt.cpp project](https://github.com/hilch/Bcrypt.cpp?tab=License-1-ov-file) by Hilko Bengen. +This product includes software developed by Niels Provos. + ## Contributing See the [contributing guide](CONTRIBUTING.md) to learn how to contribute to the repository and the development workflow. diff --git a/assets/C++_GENERATE_HASH.gif b/assets/C++_GENERATE_HASH.gif new file mode 100644 index 0000000..d83bcfc Binary files /dev/null and b/assets/C++_GENERATE_HASH.gif differ diff --git a/assets/JS_GENERATE_HASH.gif b/assets/JS_GENERATE_HASH.gif new file mode 100644 index 0000000..3f7f0d4 Binary files /dev/null and b/assets/JS_GENERATE_HASH.gif differ diff --git a/assets/comparisons b/assets/comparisons new file mode 100644 index 0000000..6e6f473 Binary files /dev/null and b/assets/comparisons differ diff --git a/example/ios/BcryptCppExample.xcodeproj/project.pbxproj b/example/ios/BcryptCppExample.xcodeproj/project.pbxproj index 0d3ce22..ac75872 100644 --- a/example/ios/BcryptCppExample.xcodeproj/project.pbxproj +++ b/example/ios/BcryptCppExample.xcodeproj/project.pbxproj @@ -592,7 +592,10 @@ "-DFOLLY_CFG_NO_COROUTINES=1", "-DFOLLY_HAVE_CLOCK_GETTIME=1", ); - OTHER_LDFLAGS = "$(inherited) "; + OTHER_LDFLAGS = ( + "$(inherited)", + " ", + ); REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; SDKROOT = iphoneos; USE_HERMES = true; @@ -664,7 +667,10 @@ "-DFOLLY_CFG_NO_COROUTINES=1", "-DFOLLY_HAVE_CLOCK_GETTIME=1", ); - OTHER_LDFLAGS = "$(inherited) "; + OTHER_LDFLAGS = ( + "$(inherited)", + " ", + ); REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; SDKROOT = iphoneos; USE_HERMES = true; diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 66dbd1d..f60d1c0 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -956,6 +956,8 @@ PODS: - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - Yoga + - react-native-randombytes (3.6.1): + - React-Core - React-nativeconfig (0.74.5) - React-NativeModulesApple (0.74.5): - glog @@ -1222,6 +1224,7 @@ DEPENDENCIES: - React-logger (from `../node_modules/react-native/ReactCommon/logger`) - React-Mapbuffer (from `../node_modules/react-native/ReactCommon`) - react-native-bcrypt-cpp (from `../..`) + - react-native-randombytes (from `../node_modules/react-native-randombytes`) - React-nativeconfig (from `../node_modules/react-native/ReactCommon`) - React-NativeModulesApple (from `../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios`) - React-perflogger (from `../node_modules/react-native/ReactCommon/reactperflogger`) @@ -1315,6 +1318,8 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native/ReactCommon" react-native-bcrypt-cpp: :path: "../.." + react-native-randombytes: + :path: "../node_modules/react-native-randombytes" React-nativeconfig: :path: "../node_modules/react-native/ReactCommon" React-NativeModulesApple: @@ -1395,7 +1400,8 @@ SPEC CHECKSUMS: React-jsitracing: 3b6060bbf5317663667e1dd93560c7943ab86ccc React-logger: 257858bd55f3a4e1bc0cf07ddc8fb9faba6f8c7c React-Mapbuffer: 6c1cacdbf40b531f549eba249e531a7d0bfd8e7f - react-native-bcrypt-cpp: 4e7cb1f3c64413bd84b3e8b13db0ce7bcb52b581 + react-native-bcrypt-cpp: 3a7a9427b6aa068c1fa462ee0465eb05d3cd198c + react-native-randombytes: 421f1c7d48c0af8dbcd471b0324393ebf8fe7846 React-nativeconfig: ba9a2e54e2f0882cf7882698825052793ed4c851 React-NativeModulesApple: 8d11ff8955181540585c944cf48e9e7236952697 React-perflogger: ed4e0c65781521e0424f2e5e40b40cc7879d737e diff --git a/example/package.json b/example/package.json index b86ecc9..661a8bd 100644 --- a/example/package.json +++ b/example/package.json @@ -11,7 +11,8 @@ }, "dependencies": { "react": "18.2.0", - "react-native": "0.74.5" + "react-native": "0.74.5", + "react-native-randombytes": "^3.6.1" }, "devDependencies": { "@babel/core": "^7.20.0", diff --git a/example/src/App.tsx b/example/src/App.tsx index 892ce98..f63d617 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -1,79 +1,217 @@ -import { Button, StyleSheet, View } from 'react-native'; +import { useCallback, useState } from 'react'; import { - generateHash, - generateHashSync, - validatePassword, - validatePasswordSync, -} from 'react-native-bcrypt-cpp'; + ActivityIndicator, + SafeAreaView, + StyleSheet, + Text, + TouchableOpacity, + View, +} from 'react-native'; +import { generateHash, validatePassword } from 'react-native-bcrypt-cpp'; import { MovingRectangle } from './MovingRectangle'; +import { + genSaltSync, + hashSync as generateHashJS, + compareSync as validatePasswordJS, +} from './bcryptjs'; -const workload = 15; +const workload = 12; const password = 'asdcds-sdjakl12313841skdnanczdeioaj'; -const hash = '$2b$15$wX0mKtpwGwzdfbz099nUnu5R.NN/huUK9XBra0sS4xj4XfjfPOkzO'; - -async function measureTime(fn: () => T): Promise { - const start = performance.now(); - const res = await fn(); - const end = performance.now(); - const timeTaken = end - start; - console.log('Time taken :', timeTaken, 'ms'); - return res; -} export default function App() { + const [hash, setHash] = useState( + '$2a$12$a7aUL27hsWw0x2V8pJfK4eUNeANOCtAEOxJA6V4N3FIOfgoZuJz2W' + ); + const [timeTaken, setTimeTaken] = useState(0); + const [isValid, setIsValid] = useState(); + const [loading, setLoading] = useState(false); + + const measureTime = useCallback(async function (fn: () => T): Promise { + setLoading(true); + const start = performance.now(); + const res = await fn(); + const end = performance.now(); + const _timeTaken = end - start; + console.log('Time taken :', _timeTaken, 'ms'); + setTimeTaken(_timeTaken); + setLoading(false); + return res; + }, []); + return ( - + + + Bcrypt Performance Test + + Password: + {password} + Generated Hash: + {hash} + Time taken: + + {Math.round((timeTaken / 1000) * 100) / 100} s + + Is Valid: + + {isValid === undefined + ? 'Not checked' + : isValid + ? 'โœ… Yes' + : 'โŒ No'} + + + + -