Unverified Commit 9d89d6e3 authored by Hanwen Cheng's avatar Hanwen Cheng Committed by GitHub
Browse files

feat: add support for 12 mnemonic option (#515)



* add rust support for different mnemonic size

* binding to android and ios

* add support in javascript

* reverse colors for seed phrase word count btn

button shoud indicate not own, but phrase's current state

* still use default with 24 words
Co-authored-by: default avatargoldsteinsveta <svetlana.goldstein@gmail.com>
parent 253c7fd3
Pipeline #73998 passed with stages
in 15 minutes and 59 seconds
......@@ -101,8 +101,8 @@ public class EthkeyBridge extends ReactContextBaseJavaModule {
}
@ReactMethod
public void randomPhrase(Promise promise) {
promise.resolve(ethkeyRandomPhrase());
public void randomPhrase(int wordsNumber, Promise promise) {
promise.resolve(ethkeyRandomPhrase(wordsNumber));
}
@ReactMethod
......@@ -172,7 +172,7 @@ public class EthkeyBridge extends ReactContextBaseJavaModule {
private static native String ethkeyBlake(String data);
private static native String ethkeyEthSign(String data);
private static native String ethkeyBlockiesIcon(String seed);
private static native String ethkeyRandomPhrase();
private static native String ethkeyRandomPhrase(int wordsNumber);
private static native String ethkeyEncryptData(String data, String password);
private static native String ethkeyDecryptData(String data, String password);
private static native String ethkeyQrCode(String data);
......
......@@ -43,7 +43,7 @@ RCT_EXTERN_METHOD(rlpItem:(NSString*)rlp position:(NSUInteger)position resolve:(
RCT_EXTERN_METHOD(keccak:(NSString*)data resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject)
RCT_EXTERN_METHOD(ethSign:(NSString*)data resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject)
RCT_EXTERN_METHOD(blockiesIcon:(NSString*)seed resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject)
RCT_EXTERN_METHOD(randomPhrase:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject)
RCT_EXTERN_METHOD(randomPhrase:(NSInteger*)wordsNumber resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject)
RCT_EXTERN_METHOD(encryptData:(NSString*)data password:(NSString*)password resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject)
RCT_EXTERN_METHOD(decryptData:(NSString*)data password:(NSString*)password resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject)
RCT_EXTERN_METHOD(qrCode:(NSString*)data resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject)
......
......@@ -109,9 +109,10 @@ class EthkeyBridge: NSObject {
}
}
@objc func randomPhrase(_ resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void {
@objc func randomPhrase(_ wordsNumber:NSInteger, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void {
var error: UInt32 = 0
let words_rust_str = random_phrase(&error)
let words_number: Int32 = Int32(wordsNumber)
let words_rust_str = random_phrase(&error, words_number)
let words_rust_str_ptr = rust_string_ptr(words_rust_str)
let words = String.fromStringPtr(ptr: words_rust_str_ptr!.pointee)
rust_string_ptr_destroy(words_rust_str_ptr)
......
......@@ -60,7 +60,7 @@ struct rust_string* eth_sign(unsigned* error, const struct rust_string_ptr* data
struct rust_string* blockies_icon(unsigned* error, const struct rust_string_ptr* blockies_seed);
struct rust_string* random_phrase(unsigned* error);
struct rust_string* random_phrase(unsigned* error, int words_number);
struct rust_string* encrypt_data(unsigned* error, const struct rust_string_ptr* data, const struct rust_string_ptr* password);
......@@ -77,4 +77,4 @@ struct rust_string* substrate_brainwallet_address(unsigned* error, const struct
struct rust_string* substrate_brainwallet_sign(unsigned* error, const struct rust_string_ptr* seed, const struct rust_string_ptr* data);
struct rust_string* schnorrkel_verify(unsigned* error, const struct rust_string_ptr* seed, const struct rust_string_ptr* msg, const struct rust_string_ptr* signature);
\ No newline at end of file
struct rust_string* schnorrkel_verify(unsigned* error, const struct rust_string_ptr* seed, const struct rust_string_ptr* msg, const struct rust_string_ptr* signature);
......@@ -14,19 +14,20 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
mod eth;
mod sr25519;
mod util;
use util::StringPtr;
use eth::{KeyPair, PhraseKind};
use ethsign::{Protected, keyfile::Crypto};
use bip39::{Language, Mnemonic, MnemonicType};
use blake2_rfc::blake2b::blake2b;
use ethsign::{keyfile::Crypto, Protected};
use rlp::decode_list;
use rustc_hex::{ToHex, FromHex};
use rustc_hex::{FromHex, ToHex};
use tiny_keccak::Keccak;
use tiny_keccak::keccak256 as keccak;
use blake2_rfc::blake2b::blake2b;
use eth::{KeyPair, PhraseKind};
use util::StringPtr;
mod eth;
mod sr25519;
mod util;
const CRYPTO_ITERATIONS: u32 = 10240;
......@@ -58,15 +59,6 @@ pub unsafe extern fn rust_string_ptr_destroy(s: *mut StringPtr) {
let _ = Box::from_raw(s);
}
// TODO: REMOVE, use ethkey_brainwallet_sign!
#[no_mangle]
pub unsafe extern fn ethkey_keypair_sign(keypair: *mut KeyPair, message: *mut StringPtr) -> *mut String {
let keypair = &*keypair;
let message: Vec<u8> = (*message).as_str().from_hex().unwrap();
let signature = keypair.sign(&message).unwrap().to_hex();
Box::into_raw(Box::new(signature))
}
fn qrcode_bytes(data: &[u8]) -> Option<String> {
use qrcodegen::{QrCode, QrCodeEcc};
use pixelate::{Image, Color, BLACK};
......@@ -175,9 +167,12 @@ export! {
}
@Java_io_parity_signer_EthkeyBridge_ethkeyRandomPhrase
fn random_phrase() -> String {
use bip39::{Mnemonic, MnemonicType, Language};
let mnemonic = Mnemonic::new(MnemonicType::Words24, Language::English);
fn random_phrase(words_number:u32) -> String {
let mnemonic_type = match MnemonicType::for_word_count(words_number as usize) {
Ok(t) => t,
Err(_e) => MnemonicType::Words24,
};
let mnemonic = Mnemonic::new(mnemonic_type, Language::English);
mnemonic.into_phrase()
}
......@@ -244,7 +239,17 @@ mod tests {
static DERIVED_SURI: &str = "grant jaguar wish bench exact find voice habit tank pony state salmon//hard/soft/0";
#[test]
#[test]
fn test_random_phrase() {
let result_12 = random_phrase(12);
assert_eq!(12, result_12.split_whitespace().count());
let result_24 = random_phrase(24);
assert_eq!(24, result_24.split_whitespace().count());
let result_17 = random_phrase(17);
assert_eq!(12, result_17.split_whitespace().count());
}
#[test]
fn test_blake() {
let data = "454545454545454545454545454545454545454545454545454545454545454501\
000000000000002481853da20b9f4322f34650fea5f240dcbfb266d02db94bfa01\
......
......@@ -105,8 +105,7 @@ const styles = StyleSheet.create({
elevation: 4,
height: 56,
justifyContent: 'center',
marginHorizontal: 8,
marginVertical: 8,
margin: 8,
paddingHorizontal: 64
},
buttonDisabled: {
......
......@@ -34,9 +34,11 @@ import { withAccountStore } from '../util/HOC';
import testIDs from '../../e2e/testIDs';
import ScreenHeading from '../components/ScreenHeading';
import { alertBackupDone, alertCopyBackupPhrase } from '../util/alertUtils';
import Button from '../components/Button';
function IdentityBackup({ navigation, accounts }) {
const [seedPhrase, setSeedPhrase] = useState('');
const [wordsNumber, setWordsNumber] = useState(24);
const isNew = navigation.getParam('isNew', false);
const onBackupDone = async () => {
const pin = await setPin(navigation);
......@@ -45,10 +47,24 @@ function IdentityBackup({ navigation, accounts }) {
navigateToNewIdentityNetwork(navigation);
};
const renderTextButton = buttonWordsNumber => {
const textStyles =
wordsNumber === buttonWordsNumber
? { ...fontStyles.t_codeS, color: colors.label_text }
: fontStyles.t_codeS;
return (
<Button
buttonStyles={styles.mnemonicSelectionButton}
textStyles={textStyles}
title={`${buttonWordsNumber} words`}
onPress={() => setWordsNumber(buttonWordsNumber)}
/>
);
};
useEffect(() => {
const setSeedPhraseAsync = async () => {
if (isNew) {
setSeedPhrase(await words());
setSeedPhrase(await words(wordsNumber));
} else {
const backupSeedPhrase = await unlockSeedPhrase(navigation);
navigation.pop();
......@@ -60,7 +76,7 @@ function IdentityBackup({ navigation, accounts }) {
return () => {
setSeedPhrase('');
};
}, [isNew, navigation]);
}, [isNew, navigation, wordsNumber]);
return (
<ScrollView style={styles.body}>
......@@ -71,6 +87,12 @@ function IdentityBackup({ navigation, accounts }) {
}
/>
<View />
{isNew && (
<View style={styles.mnemonicSelectionRow}>
{renderTextButton(12)}
{renderTextButton(24)}
</View>
)}
<TouchableItem
onPress={() => {
// only allow the copy of the recovery phrase in dev environment
......@@ -106,5 +128,17 @@ const styles = StyleSheet.create({
flex: 1,
flexDirection: 'column',
padding: 16
},
mnemonicSelectionButton: {
backgroundColor: colors.bg,
flex: 1,
height: 30,
paddingHorizontal: 5,
paddingVertical: 5
},
mnemonicSelectionRow: {
flex: 1,
flexDirection: 'row',
justifyContent: 'space-around'
}
});
......@@ -97,8 +97,8 @@ export function blockiesIcon(seed) {
return EthkeyBridge.blockiesIcon(seed.toLowerCase());
}
export function words() {
return EthkeyBridge.randomPhrase();
export function words(wordsNumber) {
return EthkeyBridge.randomPhrase(wordsNumber);
}
export function encryptData(data, password) {
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment