A React Native module for post-quantum cryptography, providing both Kyber768 for key exchange and Dilithium3 for digital signatures. This package enables developers to implement quantum-resistant cryptographic operations in React Native applications for both iOS and Android platforms.
Why Post-Quantum Cryptography? As quantum computers advance, they pose a threat to current cryptographic standards. This package helps future-proof your applications with NIST-approved post-quantum algorithms.
- Features
- Installation
- Quick Start
- API Reference
- Error Handling
- Security Considerations
- Use Cases
- Troubleshooting
- Performance
- Compatibility
- Contributing
- License
- Local Testing Guide
- Repository Information
- Support
- Project Structure
- π Post-Quantum Security: Implementation of Kyber768 (key exchange) and Dilithium3 (digital signatures)
- π± Cross-Platform: Works on both iOS and Android
- π Easy Integration: Simple NPM install with auto-linking
- πͺ TypeScript Support: Full type definitions included
- β‘ Performance: Native C implementation for optimal speed
- π‘οΈ Memory Safe: Proper memory management on both platforms
- π Dual Functionality: Both key exchange and digital signatures in one package
Kyber768: Key encapsulation mechanism for secure key exchange Dilithium3: Digital signature algorithm for authentication and integrity
npm install react-native-kyber
# or
yarn add react-native-kybercd ios && pod installTesting has been done on iPhone 15 and up.
No additional setup required. The module uses auto-linking.
import { Kyber, Dilithium } from 'react-native-kyber';
async function demonstratePostQuantumCrypto() {
try {
// === KYBER KEY EXCHANGE ===
console.log('π Testing Kyber Key Exchange...');
// Generate a key pair
const kyberKeyPair = await Kyber.generateKeyPair();
console.log('Kyber key pair generated!');
// Encrypt (generates ciphertext and shared secret)
const encryptResult = await Kyber.encrypt(kyberKeyPair.publicKey);
console.log('Kyber encryption complete!');
// Decrypt (recovers the same shared secret)
const decryptResult = await Kyber.decrypt(
encryptResult.ciphertext,
kyberKeyPair.secretKey
);
// Verify the shared secrets match
const secretsMatch = encryptResult.sharedSecret === decryptResult.sharedSecret;
console.log('Kyber shared secrets match:', secretsMatch);
// === DILITHIUM DIGITAL SIGNATURES ===
console.log('βοΈ Testing Dilithium Digital Signatures...');
// Generate a key pair
const dilithiumKeyPair = await Dilithium.generateKeyPair();
console.log('Dilithium key pair generated!');
// Sign a message
const message = "Hello, post-quantum world!";
const signature = await Dilithium.sign(message, dilithiumKeyPair.secretKey);
console.log('Message signed!');
// Verify the signature
const isValid = await Dilithium.verify(message, signature.signature, dilithiumKeyPair.publicKey);
console.log('Signature verification:', isValid.isValid);
} catch (error) {
console.error('Post-quantum operation failed:', error);
}
}Generates a new Kyber768 key pair.
Returns:
interface KyberKeyPair {
publicKey: string; // Base64 encoded public key (1184 bytes)
secretKey: string; // Base64 encoded secret key (2400 bytes)
}Encrypts using a public key to generate ciphertext and shared secret.
Parameters:
publicKeyBase64(string): Base64 encoded public key
Returns:
interface KyberEncryptResult {
ciphertext: string; // Base64 encoded ciphertext (1088 bytes)
sharedSecret: string; // Base64 encoded shared secret (32 bytes)
}Decrypts ciphertext using secret key to recover shared secret.
Parameters:
ciphertextBase64(string): Base64 encoded ciphertextsecretKeyBase64(string): Base64 encoded secret key
Returns:
interface KyberDecryptResult {
sharedSecret: string; // Base64 encoded shared secret (32 bytes)
}Simple test method to verify the Kyber module is working correctly.
Generates a new Dilithium3 key pair.
Returns:
interface DilithiumKeyPair {
publicKey: string; // Base64 encoded public key (1952 bytes)
secretKey: string; // Base64 encoded secret key (4000 bytes)
}Signs a message using a secret key.
Parameters:
message(string): The message to signsecretKeyBase64(string): Base64 encoded secret key
Returns:
interface DilithiumSignResult {
signature: string; // Base64 encoded signature (2701 bytes)
}Dilithium.verify(message: string, signatureBase64: string, publicKeyBase64: string): Promise<DilithiumVerifyResult>
Verifies a signature using a public key.
Parameters:
message(string): The original messagesignatureBase64(string): Base64 encoded signaturepublicKeyBase64(string): Base64 encoded public key
Returns:
interface DilithiumVerifyResult {
isValid: boolean; // Whether the signature is valid
}Simple test method to verify the Dilithium module is working correctly.
All methods return promises that will reject with descriptive error messages:
try {
const kyberKeyPair = await Kyber.generateKeyPair();
const dilithiumKeyPair = await Dilithium.generateKeyPair();
} catch (error) {
switch (error.code) {
case 'ERR_KEYGEN':
console.error('Key generation failed');
break;
case 'ERR_ENCRYPT':
console.error('Encryption failed');
break;
case 'ERR_DECRYPT':
console.error('Decryption failed');
break;
case 'ERR_SIGN':
console.error('Signing failed');
break;
case 'ERR_VERIFY':
console.error('Verification failed');
break;
case 'ERR_INVALID_KEY':
console.error('Invalid key provided');
break;
default:
console.error('Unknown error:', error.message);
}
}- Never store secret keys in plain text
- Use secure storage solutions like:
- iOS: Keychain Services
- Android: Android Keystore or EncryptedSharedPreferences
- React Native: react-native-keychain
Kyber768:
- Public Key: 1184 bytes
- Secret Key: 2400 bytes
- Ciphertext: 1088 bytes
- Shared Secret: 32 bytes
Dilithium3:
- Public Key: 1952 bytes
- Secret Key: 4000 bytes
- Signature: 2701 bytes
- Keys are automatically cleared from memory after use
- No manual memory management required
// Alice generates key pair
const aliceKeyPair = await Kyber.generateKeyPair();
// Alice sends public key to Bob (this can be sent over insecure channel)
const alicePublicKey = aliceKeyPair.publicKey;
// Bob encrypts using Alice's public key
const bobEncryptResult = await Kyber.encrypt(alicePublicKey);
// Bob sends ciphertext to Alice (this can be sent over insecure channel)
const ciphertext = bobEncryptResult.ciphertext;
// Alice decrypts to get the same shared secret
const aliceDecryptResult = await Kyber.decrypt(ciphertext, aliceKeyPair.secretKey);
// Both parties now have the same shared secret
const sharedSecret = aliceDecryptResult.sharedSecret;// Generate a key pair for signing
const signerKeyPair = await Dilithium.generateKeyPair();
// Sign a message
const message = "Important document content";
const signature = await Dilithium.sign(message, signerKeyPair.secretKey);
// Send message and signature to verifier
// (public key can be shared publicly)
// Verifier checks the signature
const isValid = await Dilithium.verify(message, signature.signature, signerKeyPair.publicKey);
console.log('Signature is valid:', isValid.isValid);// Generate keys for both operations
const kyberKeyPair = await Kyber.generateKeyPair();
const dilithiumKeyPair = await Dilithium.generateKeyPair();
// Establish secure channel with Kyber
const encryptResult = await Kyber.encrypt(kyberKeyPair.publicKey);
const decryptResult = await Kyber.decrypt(encryptResult.ciphertext, kyberKeyPair.secretKey);
// Sign the shared secret with Dilithium
const signature = await Dilithium.sign(decryptResult.sharedSecret, dilithiumKeyPair.secretKey);
// Verify the signature
const isValid = await Dilithium.verify(decryptResult.sharedSecret, signature.signature, dilithiumKeyPair.publicKey);Pod install fails:
cd ios
pod deintegrate
pod installBuild errors:
- Ensure Xcode 16.0+ is being used
- Check that all C files are included in the build
Library not found:
- Clean and rebuild:
cd android && ./gradlew clean - Verify NDK is properly installed
CMake errors:
- Ensure CMake 3.18.1+ is available
- Check that all C files are in the correct directory
Module not found:
# Clear React Native cache
npx react-native start --reset-cache
# Reinstall node modules
rm -rf node_modules package-lock.json
npm installTypeScript errors:
# Ensure types are properly installed
npm install --save-dev @types/react-native- Kyber Key Generation: ~1-2ms on modern devices
- Kyber Encryption: ~0.5-1ms on modern devices
- Kyber Decryption: ~0.5-1ms on modern devices
- Dilithium Key Generation: ~2-3ms on modern devices
- Dilithium Signing: ~1-2ms on modern devices
- Dilithium Verification: ~0.5-1ms on modern devices
- Memory Usage: Minimal, automatic cleanup
- React Native: 0.72.6+
- iOS: 11.0+
- Android: API 21+ (Android 5.0)
- Node.js: 16+
We welcome contributions! Please see our Contributing Guide for details.
- Clone the repository
- Install dependencies:
npm install - Set up the example app:
npm run example - Run tests:
npm test
MIT
This package is published as react-native-kyber on npm, while the source repository may appear as react-native-crystals. Both refer to the same project.
- NPM Package: react-native-kyber
- GitHub Repository: CypherTechnologiesCo/react-native-kyber
For detailed testing instructions, see TESTING.md.
Before testing, ensure you have:
- Node.js 16+
- React Native CLI
- iOS: Xcode 12.0+, CocoaPods
- Android: Android Studio, NDK
# Run the automated test script
chmod +x test-local.sh
./test-local.shThis will create a sample application that can run on both iOS and Android to demonstrate the library functionality.
If you prefer manual testing:
# In your react-native-kyber directory
npm run prepack
npm pack# Go to parent directory
cd ..
# Create new React Native project
npx react-native init KyberTestApp --version 0.72.6
cd KyberTestApp
# Install your local package
npm install ../react-native-kyber/react-native-kyber-*.tgz
# iOS setup
cd ios && pod install && cd ..Create TestBoth.js:
import React, { useState } from 'react';
import { View, Text, TouchableOpacity, StyleSheet, ScrollView } from 'react-native';
import { Kyber, Dilithium } from 'react-native-kyber';
const TestBoth = () => {
const [log, setLog] = useState('Ready to test...\n');
const addLog = (msg) => setLog(prev => prev + `${msg}\n`);
const testBoth = async () => {
setLog('Testing Kyber & Dilithium...\n');
try {
// Test Kyber
addLog('π Testing Kyber...');
const kyberKeys = await Kyber.generateKeyPair();
addLog('β
Kyber Keys generated');
const kyberEnc = await Kyber.encrypt(kyberKeys.publicKey);
addLog('β
Kyber Encrypted');
const kyberDec = await Kyber.decrypt(kyberEnc.ciphertext, kyberKeys.secretKey);
const kyberMatch = kyberEnc.sharedSecret === kyberDec.sharedSecret;
addLog(kyberMatch ? 'π Kyber SUCCESS' : 'β Kyber FAIL');
// Test Dilithium
addLog('βοΈ Testing Dilithium...');
const dilithiumKeys = await Dilithium.generateKeyPair();
addLog('β
Dilithium Keys generated');
const message = "Hello, post-quantum world!";
const signature = await Dilithium.sign(message, dilithiumKeys.secretKey);
addLog('β
Dilithium Signed');
const verify = await Dilithium.verify(message, signature.signature, dilithiumKeys.publicKey);
addLog(verify.isValid ? 'π Dilithium SUCCESS' : 'β Dilithium FAIL');
} catch (error) {
addLog(`β Error: ${error.message}`);
}
};
return (
<View style={styles.container}>
<TouchableOpacity style={styles.button} onPress={testBoth}>
<Text style={styles.buttonText}>Test Both</Text>
</TouchableOpacity>
<ScrollView style={styles.log}>
<Text style={styles.logText}>{log}</Text>
</ScrollView>
</View>
);
};
const styles = StyleSheet.create({
container: { flex: 1, padding: 20 },
button: { backgroundColor: '#007AFF', padding: 15, borderRadius: 8, marginBottom: 20 },
buttonText: { color: 'white', textAlign: 'center', fontSize: 18 },
log: { flex: 1, backgroundColor: '#000', borderRadius: 8, padding: 10 },
logText: { color: '#0f0', fontFamily: 'Courier', fontSize: 14 },
});
export default TestBoth;# iOS
npx react-native run-ios
# Android
npx react-native run-androidWhen the tests run successfully, you should see:
- β Kyber hello message from native module
- β Kyber key pair generation with proper lengths
- β Kyber encryption producing ciphertext and shared secret
- β Kyber decryption recovering the same shared secret
- β Kyber shared secrets matching between encrypt/decrypt
- β Dilithium hello message from native module
- β Dilithium key pair generation with proper lengths
- β Dilithium signing producing valid signature
- β Dilithium verification confirming signature validity
# Clear cache
npx react-native start --reset-cache
rm -rf node_modules && npm installcd ios
pod deintegrate
pod installcd android
./gradlew clean
cd ..
npx react-native run-androidThe Source code can be found here: https://github.com/pq-crystals this is the Official reference implementation for Kyber and Dilithium as defined here: https://pq-crystals.org/
We exposed the recommended Kyber and Dilithium modes, we may expand to all modes in the future, if the source code is updated, this package will also implement the update
Cypher Technologies Co DID NOT make this code, nor do we claim any ownership over it.
This is open source software provided as is.
To see how the package works, fork the project and run ./test-local.sh. This will create a folder called KyberTestApp -> run npx-react-native run-ios or run-android to have a project to validate cryptographic operations.
If you encounter any issues or have questions about this package:
- Open an issue on GitHub
- Contact the maintainers at info@cyphertechnologies.co
For security-related issues, please refer to our Security Policy.
βββ android/ # Android native code
βββ ios/ # iOS native code
βββ src/ # TypeScript source code
βββ lib/ # Compiled JavaScript (generated)
βββ example/ # Example application
βββ test-local.sh # Testing script