Skip to content

Instantly share code, notes, and snippets.

@mingyang91
Last active November 14, 2025 15:59
Show Gist options
  • Select an option

  • Save mingyang91/4d95186e6b97e22d3fb3c984f32b201f to your computer and use it in GitHub Desktop.

Select an option

Save mingyang91/4d95186e6b97e22d3fb3c984f32b201f to your computer and use it in GitHub Desktop.
Paranoid entropy generator: combines 6 independent sources (OS, random.org, Solana, Google TLS, AWS KMS HSM, system state) into 256-bit secure random. Generates BIP39 24-word mnemonics. Pure bash, no Python needed. Defense-in-depth: even if 5 sources fail, output stays secure.
#!/bin/bash
#
# Secure Random Number Generator
#
# Combines 6 independent entropy sources to generate a cryptographically
# secure 256-bit random number. Even if 5 out of 6 sources are compromised,
# the output remains secure.
#
# Sources:
# 1. OS entropy (/dev/urandom)
# 2. System state (hardware RNG or process state)
# 3. random.org (atmospheric noise)
# 4. Solana blockchain (latest transaction hash or error page)
# 5. TLS handshakes (Google server random data)
# 6. AWS KMS (FIPS 140-2 validated HSM)
#
# BIP39 Note: For OneKey compatibility, the hex entropy is treated as UTF-8 text
# and hashed with SHA256 before BIP39 encoding. This matches OneKey's behavior.
#
# Usage:
# ./generate-entropy.sh - Output hex string
# ./generate-entropy.sh --bip39 - Also output BIP39 mnemonic (24 words)
# ./generate-entropy.sh -b - Short form for --bip39
# ./generate-entropy.sh --dotmap - BIP39 with visual dot-map grid
#
# Output: 64-character hex string (256 bits)
#
set -euo pipefail
# Colors for output
GREEN='\033[0;32m'
BLUE='\033[0;34m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# Create temp directory
TEMP_DIR=$(mktemp -d)
trap "rm -rf ${TEMP_DIR}" EXIT
echo -e "${BLUE}=== Secure Random Number Generator ===${NC}"
echo -e "${BLUE}Combining 6 independent entropy sources...${NC}\n"
# Source 1: OS entropy (/dev/urandom)
echo -e "${YELLOW}[1/6]${NC} Collecting OS entropy (/dev/urandom)..."
dd if=/dev/urandom bs=32 count=1 2>/dev/null > "${TEMP_DIR}/entropy1.bin"
echo -e "${GREEN}✓${NC} OS entropy collected\n"
# Source 2: Hardware RNG or system state
echo -e "${YELLOW}[2/6]${NC} Collecting system entropy..."
if [ -e /dev/hwrng ]; then
dd if=/dev/hwrng bs=32 count=1 2>/dev/null > "${TEMP_DIR}/entropy2.bin"
echo -e "${GREEN}✓${NC} Hardware RNG entropy collected\n"
else
# Portable system state collection (works on Linux and macOS)
{
uname -a
uptime
df
ps aux 2>/dev/null | head -20 || true
date
hostname
} | openssl dgst -sha256 -binary > "${TEMP_DIR}/entropy2.bin"
echo -e "${GREEN}✓${NC} System state entropy collected\n"
fi
# Source 3: random.org atmospheric noise
echo -e "${YELLOW}[3/6]${NC} Collecting atmospheric noise from random.org..."
if curl -s --max-time 10 "https://www.random.org/cgi-bin/randbyte?nbytes=32&format=h" | \
xxd -r -p > "${TEMP_DIR}/entropy3.bin" 2>/dev/null && \
[ -s "${TEMP_DIR}/entropy3.bin" ]; then
echo -e "${GREEN}✓${NC} random.org entropy collected\n"
else
echo -e "${YELLOW}⚠${NC} random.org unavailable, using timestamp fallback\n"
date +%s%N | openssl dgst -sha256 -binary > "${TEMP_DIR}/entropy3.bin"
fi
# Source 4: Solana blockchain latest transaction
echo -e "${YELLOW}[4/6]${NC} Collecting Solana blockchain entropy..."
# Try to fetch Solana API (success or error page, both contain random data)
SOLANA_RESPONSE=$(curl -s --connect-timeout 5 --max-time 10 \
'https://api-v2.solscan.io/v2/transaction/list' \
-H 'accept: application/json' \
-H 'origin: https://solscan.io' \
-H 'referer: https://solscan.io/' 2>&1 || echo "curl_failed_$(date +%s%N)")
if [ -n "$SOLANA_RESPONSE" ] && [ "$SOLANA_RESPONSE" != "curl_failed"* ]; then
# Try to extract transaction hash if successful
if command -v jq &> /dev/null; then
TX_HASH=$(echo "$SOLANA_RESPONSE" | jq -r '.data[0].txHash // empty' 2>/dev/null || echo "")
if [ -n "$TX_HASH" ] && [ "$TX_HASH" != "empty" ] && [ "$TX_HASH" != "null" ]; then
echo "$TX_HASH" | xxd -r -p > "${TEMP_DIR}/entropy4.bin" 2>/dev/null && \
echo -e "${GREEN}✓${NC} Solana transaction hash collected\n" || {
# Failed to decode, use raw response
echo "$SOLANA_RESPONSE" | openssl dgst -sha256 -binary > "${TEMP_DIR}/entropy4.bin"
echo -e "${GREEN}✓${NC} Solana response data collected (trace IDs, timestamps)\n"
}
else
# API denied or error, but use the response page (contains trace IDs, timestamps)
echo "$SOLANA_RESPONSE" | openssl dgst -sha256 -binary > "${TEMP_DIR}/entropy4.bin"
echo -e "${GREEN}✓${NC} Solana response data collected (trace IDs, timestamps)\n"
fi
else
# No jq, just hash the entire response (contains random data regardless)
echo "$SOLANA_RESPONSE" | openssl dgst -sha256 -binary > "${TEMP_DIR}/entropy4.bin"
echo -e "${GREEN}✓${NC} Solana response data collected\n"
fi
else
# Complete failure, use system state
echo -e "${YELLOW}⚠${NC} Solana unreachable, using system state fallback\n"
{
ps aux 2>/dev/null | head -30 || true
netstat -an 2>/dev/null | head -50 || ss -an 2>/dev/null | head -50 || true
date +%s%N
} | openssl dgst -sha256 -binary > "${TEMP_DIR}/entropy4.bin"
fi
# Source 5: TLS handshake entropy from Google
echo -e "${YELLOW}[5/6]${NC} Collecting TLS handshake entropy..."
# Use gtimeout on macOS (brew install coreutils) or fallback
TIMEOUT_CMD="timeout"
if ! command -v timeout &> /dev/null && command -v gtimeout &> /dev/null; then
TIMEOUT_CMD="gtimeout"
fi
if command -v $TIMEOUT_CMD &> /dev/null; then
if echo | $TIMEOUT_CMD 5 openssl s_client -connect google.com:443 2>&1 | \
openssl dgst -sha256 -binary > "${TEMP_DIR}/entropy5.bin" 2>/dev/null && \
[ -s "${TEMP_DIR}/entropy5.bin" ]; then
echo -e "${GREEN}✓${NC} TLS entropy collected\n"
else
echo -e "${YELLOW}⚠${NC} TLS connection failed, using hostname fallback\n"
(hostname; who 2>/dev/null; w 2>/dev/null; date +%s%N) | \
openssl dgst -sha256 -binary > "${TEMP_DIR}/entropy5.bin"
fi
else
# No timeout command, just try the connection
if echo | openssl s_client -connect google.com:443 -timeout 5 2>&1 | head -100 | \
openssl dgst -sha256 -binary > "${TEMP_DIR}/entropy5.bin" 2>/dev/null && \
[ -s "${TEMP_DIR}/entropy5.bin" ]; then
echo -e "${GREEN}✓${NC} TLS entropy collected\n"
else
echo -e "${YELLOW}⚠${NC} TLS connection failed, using hostname fallback\n"
(hostname; who 2>/dev/null; w 2>/dev/null; date +%s%N) | \
openssl dgst -sha256 -binary > "${TEMP_DIR}/entropy5.bin"
fi
fi
# Source 6: AWS KMS (HSM-backed)
echo -e "${YELLOW}[6/6]${NC} Collecting AWS KMS entropy (HSM-backed)..."
if command -v aws &> /dev/null; then
# AWS KMS returns base64-encoded random bytes
if aws kms generate-random \
--number-of-bytes 32 \
--output text \
--query Plaintext 2>/dev/null | \
base64 -d > "${TEMP_DIR}/entropy6.bin" 2>/dev/null && \
[ -s "${TEMP_DIR}/entropy6.bin" ]; then
echo -e "${GREEN}✓${NC} AWS KMS HSM entropy collected\n"
else
echo -e "${YELLOW}⚠${NC} AWS KMS unavailable (credentials/permissions), using timestamp fallback\n"
date +%s%N | openssl dgst -sha256 -binary > "${TEMP_DIR}/entropy6.bin"
fi
else
echo -e "${YELLOW}⚠${NC} AWS CLI not installed, using timestamp fallback\n"
date +%s%N | openssl dgst -sha256 -binary > "${TEMP_DIR}/entropy6.bin"
fi
# Combine all entropy sources
echo -e "${BLUE}Combining all entropy sources with SHA-256...${NC}"
RESULT=$(cat "${TEMP_DIR}/entropy1.bin" \
"${TEMP_DIR}/entropy2.bin" \
"${TEMP_DIR}/entropy3.bin" \
"${TEMP_DIR}/entropy4.bin" \
"${TEMP_DIR}/entropy5.bin" \
"${TEMP_DIR}/entropy6.bin" | \
openssl dgst -sha256 -binary | \
xxd -p -c 32)
echo -e "${GREEN}✓${NC} Entropy combined\n"
# Output result
echo -e "${BLUE}=== Result ===${NC}"
echo -e "${GREEN}${RESULT}${NC}"
echo ""
# Generate BIP39 mnemonic if requested
if [ "${1}" = "--bip39" ] || [ "${1}" = "-b" ] || [ "${1}" = "--dotmap" ]; then
echo -e "${BLUE}=== BIP39 Mnemonic (24 words) ===${NC}"
# Check if wordlist exists
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
WORDLIST="${SCRIPT_DIR}/bip39-english.txt"
if [ ! -f "$WORDLIST" ]; then
echo -e "${YELLOW}Downloading BIP39 wordlist...${NC}"
curl -sL "https://github.com/bitcoin/bips/raw/refs/heads/master/bip-0039/english.txt" \
-o "$WORDLIST" 2>/dev/null || {
echo -e "${YELLOW}⚠${NC} Failed to download wordlist"
WORDLIST=""
}
fi
if [ -f "$WORDLIST" ]; then
# Pure bash BIP39 implementation (OneKey compatible)
# OneKey treats hex string as UTF-8 text, then hashes it
# 1. Hash the hex string as text (OneKey behavior)
ENTROPY_FOR_BIP39=$(echo -n "${RESULT}" | openssl dgst -sha256 -binary | xxd -p -c 32)
# 2. Calculate checksum (first 8 bits of SHA256)
ENTROPY_BYTES=$(echo "${ENTROPY_FOR_BIP39}" | xxd -r -p)
CHECKSUM_FULL=$(echo -n "${ENTROPY_BYTES}" | openssl dgst -sha256 -binary | xxd -p -c 32)
CHECKSUM_BYTE=$(echo "${CHECKSUM_FULL}" | cut -c1-2)
# 3. Combine entropy + checksum first byte (256 bits + 8 bits = 264 bits)
FULL_BITS="${ENTROPY_FOR_BIP39}${CHECKSUM_BYTE}"
# 4. Convert hex to binary string (portable method)
BINARY=""
for ((i=0; i<${#FULL_BITS}; i+=2)); do
HEX_BYTE="${FULL_BITS:$i:2}"
# Convert hex to decimal, then to binary
DEC=$((16#${HEX_BYTE}))
BIN=$(echo "obase=2; ${DEC}" | bc)
# Pad to 8 bits
BINARY="${BINARY}$(printf "%08d" ${BIN})"
done
# 5. Split into 11-bit chunks and map to words
MNEMONIC=""
for ((i=0; i<264; i+=11)); do
# Extract 11 bits
BITS="${BINARY:$i:11}"
# Convert to decimal (word index)
INDEX=$((2#${BITS}))
# Get word from wordlist (line INDEX+1 since lines are 1-indexed)
WORD=$(sed -n "$((INDEX + 1))p" "$WORDLIST")
MNEMONIC="${MNEMONIC}${WORD} "
done
MNEMONIC_CLEAN="${MNEMONIC% }" # Remove trailing space
echo "${MNEMONIC_CLEAN}"
# Generate dot-map if requested
if [ "${1}" = "--dotmap" ]; then
echo ""
echo -e "${BLUE}=== BIP39 Binary Dot-Map ===${NC}"
echo "12 dots per word represent: 2048, 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 1"
echo "● = filled, ○ = empty (punch filled dots on metal plate)"
echo ""
echo "Word# Word [BIP39] | Col1 | Col2 | Col3 |"
echo "------|------------|--------|------|------|------|"
# Convert mnemonic to array
read -ra WORDS <<< "${MNEMONIC_CLEAN}"
# Print binary dot-map
for i in "${!WORDS[@]}"; do
WORD="${WORDS[$i]}"
# Find word line number in wordlist (OneKey uses 1-based indexing)
WORD_LINE=$(grep -n "^${WORD}$" "$WORDLIST" | cut -d: -f1)
# Convert line number to 12-bit binary (OneKey format uses line numbers, not 0-based indices)
BINARY=$(printf "%012d" $(echo "obase=2; ${WORD_LINE}" | bc))
# Split into 3 columns of 4 bits each
COL1=""
COL2=""
COL3=""
for ((j=0; j<4; j++)); do
# Column 1: bits 0-3 (most significant)
[ "${BINARY:$j:1}" = "1" ] && COL1="${COL1}●" || COL1="${COL1}○"
# Column 2: bits 4-7
[ "${BINARY:$((j+4)):1}" = "1" ] && COL2="${COL2}●" || COL2="${COL2}○"
# Column 3: bits 8-11 (least significant)
[ "${BINARY:$((j+8)):1}" = "1" ] && COL3="${COL3}●" || COL3="${COL3}○"
done
# Format output
# Word position in mnemonic (1-24), word text, line number (1-2048), binary dots
printf " %2d %-12s [%04d] | %s | %s | %s |\n" \
$((i + 1)) "$WORD" "$WORD_LINE" "$COL1" "$COL2" "$COL3"
done
echo ""
echo "Reference: https://github.com/OneKeyHQ/bip39-dotmap"
fi
else
echo -e "${YELLOW}⚠${NC} BIP39 wordlist not available"
fi
echo ""
fi
echo -e "${BLUE}=== Details ===${NC}"
echo "Length: 64 hex characters (256 bits)"
echo "Format: Hexadecimal"
echo "Sources: 6 independent entropy sources"
echo " - Local: OS (/dev/urandom), System state"
echo " - External: random.org, Solana, Google TLS, AWS KMS HSM"
echo ""
if [ "${1}" = "--bip39" ] || [ "${1}" = "-b" ] || [ "${1}" = "--dotmap" ]; then
echo "BIP39: 24-word mnemonic phrase generated"
if [ "${1}" = "--dotmap" ]; then
echo "Dot-map: Grid coordinates for metal backup"
fi
echo ""
fi
echo -e "${GREEN}✓ Secure random number generated successfully${NC}"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment