BlueWallet/entropy.js

70 lines
2.2 KiB
JavaScript

import { AppStorage } from './class';
import Expo from 'expo';
import { AsyncStorage } from 'react-native';
const bitcoin = require('bitcoinjs-lib');
const REQUIRE_NUM_CHUNKS = 16;
// 256 priv key = 32 bytes x 8 chunks
// each chunk needs 32 bits of entropy (since ISAAC is 32 bit)
// 8 * 32 = 256 bits of entropy for one private key
// we read accelerometer 10 times per sec, getting 2 bits of entropy => 20 bits of entropy per sec
// 256/20 = 13 sec of gathering entropy
let chunks = []; // array of 32bit ints
let currenChunk = ''; // temp storage of bits (string)
let runningListeners = 0;
let listener = function(accelerometerData) {
let hex = bitcoin.crypto.sha256(accelerometerData.x + '\t' + accelerometerData.y + '\t' + accelerometerData.z).toString('hex'); // whitening
let dec = parseInt('0x' + hex[0] + hex[1]);
let entropyBits = dec & 0b11;
currenChunk += ((entropyBits < 2 && '0') || '') + entropyBits.toString(2); // always 2-char string
if (currenChunk.length === 32) {
// got enough bits for 32bit int
console.log(currenChunk, parseInt(currenChunk, 2));
chunks.push(currenChunk);
chunks.push(parseInt(currenChunk, 2));
currenChunk = '';
}
if (chunks.length >= REQUIRE_NUM_CHUNKS) {
console.log('got enough entropy, saving to storage');
Expo.Accelerometer.removeAllListeners();
runningListeners--;
AsyncStorage.setItem(AppStorage.ENTROPY, JSON.stringify(chunks));
}
};
async function start() {
let entropy = await AsyncStorage.getItem(AppStorage.ENTROPY);
try {
entropy = JSON.parse(entropy);
} catch (Err) {
entropy = [];
}
chunks = entropy || [];
console.log('got', chunks.length * 32, 'bits of entropy');
setInterval(() => {
if (chunks.length < REQUIRE_NUM_CHUNKS && runningListeners === 0) {
console.log('not enough entropy, starting listener to gather');
Expo.Accelerometer.addListener(listener);
runningListeners++;
}
}, 1000);
}
function gotEnoughEntropy() {
return chunks.length >= 8; // enough for at least one priv key
}
function get32bitInt() {
return chunks.pop();
}
module.exports.get32bitInt = get32bitInt;
module.exports.start = start;
module.exports.gotEnoughEntropy = gotEnoughEntropy;