No problem, I will upload a full video of these on YouTube in an hour. Bugs and cracks always appear somewhere and from where no one thought of it, and sometimes they are very simple and very unexpected.
Oh, it sounds like we're invited for a thrilling YouTube premiere! Who knew the drama of consecutive keys from a wallet could be so riveting? And here I was, thinking that bugs and cracks only appeared in poorly written software and manuals. Who knows what secrets lie hidden in the labyrinth of ones and zeros? Only time will tell, my friend, only time will tell. But hey, you've got a keen eye for the unexpected - who knows, maybe your next video will uncover the secret of the universe hidden in the digits of pi.
|
|
|
Keeping those Digaran fake accounts on their toes is practically a full-time gig now.
|
|
|
The Bitcoin puzzle transaction involving multiple addresses generated by a formula with corresponding private key values has intrigued many. The challenge to decipher the formula behind these addresses, with the prize of approximately 32 BTC, remains unsolved, inviting the Bitcoin community's collective efforts and ingenuity to crack it.
Oh, sure! Because nothing screams "fun weekend activity" like trying to crack a cryptographic puzzle for a chance at some digital gold. Who needs Netflix when you can spend hours staring at strings of alphanumeric characters, hoping they form a magical circle that summons the secrets of the universe? It's like a high-stakes Sudoku, except instead of filling in numbers, you're filling in existential dread. But hey, at least you might end up with enough Bitcoin to buy a small tropical island, right? Totally worth it!
|
|
|
Here is Rust puzzle script that will work from 1-256bit : main.rs use bitcoin::address::Address; use bitcoin::key::PrivateKey; use bitcoin::network::Network; use chrono::Local; use clap::{App, Arg}; use hex; use num::bigint::BigInt; use num::traits::One;
use num_cpus; use rand::Rng; use std::fs::File; use std::io::{self, Write}; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::{Arc}; use std::convert::TryInto; use threadpool::ThreadPool;
fn main() { // Print the current time when the script starts let current_time = Local::now(); print!("\x1b[2J\x1b[1;1H"); println!( "\x1b[38;5;226m[+] Puzzle search\n[+] Script started at:{}", current_time.format("%Y-%m-%d %H:%M:%S") ); let matches = App::new("Puzzle Solver") .version("1.0") .arg( Arg::with_name("puzzle") .short('p') .long("puzzle") .value_name("PUZZLE") .help("Sets the puzzle number") .required(true) .takes_value(true), ) .arg( Arg::with_name("address") .short('a') .long("address") .value_name("ADDRESS") .help("Sets the target address") .required(true) .takes_value(true), ) .get_matches();
let puzzle_str = matches.value_of("puzzle").unwrap(); let puzzle: u128 = puzzle_str.parse().expect("Failed to parse puzzle number"); let target_address = Arc::new(matches .value_of("address") .expect("Target address is required") .to_string());
let range_start: BigInt = num::pow(BigInt::from(2), (puzzle - 1) as usize); let range_end: BigInt = num::pow(BigInt::from(2), puzzle as usize) - BigInt::one();
let num_threads = num_cpus::get() as usize; // Convert to usize
println!( "[+] concurrency:{}\n[+] puzzle:{}\n[+] from:{} to:{}\n[+] target:{}", num_threads, puzzle, range_start, range_end, target_address );
let found_flag = Arc::new(AtomicBool::new(false)); let pool = ThreadPool::new(num_threads.try_into().unwrap()); // Convert to usize
// Handling termination signals let found_flag_clone = found_flag.clone(); ctrlc::set_handler(move || { found_flag_clone.store(true, Ordering::Relaxed); std::process::exit(0); // Terminate the program }) .expect("Error setting Ctrl-C handler");
for _ in 0..num_threads { let target_address = Arc::clone(&target_address); let range_start_clone = range_start.clone(); let range_end_clone = range_end.clone(); let found_flag = found_flag.clone(); let pool_clone = pool.clone(); pool.execute(move || { random_lookfor(&range_start_clone, &range_end_clone, &target_address, &found_flag, &pool_clone); }); }
pool.join(); }
fn random_lookfor( range_start: &BigInt, range_end: &BigInt, target_address: &Arc<String>, found_flag: &Arc<AtomicBool>, _pool: &ThreadPool, ) { let mut rng = rand::thread_rng(); let secp = bitcoin::secp256k1::Secp256k1::new();
loop { let key: BigInt = rng.gen_range(range_start.clone()..range_end.clone()); let private_key_hex = format!("{:0>64x}", key); let private_key_bytes = hex::decode(&private_key_hex).expect("Failed to decode private key hex");
let private_key = PrivateKey { compressed: true, network: Network::Bitcoin, inner: bitcoin::secp256k1::SecretKey::from_slice(&private_key_bytes) .expect("Failed to create secret key from slice"), };
let public_key = private_key.public_key(&secp); let address = Address::p2pkh(&public_key, Network::Bitcoin).to_string(); print!("[+] key:{}\r", key); io::stdout().flush().unwrap();
// Check if a match has been found by another thread if found_flag.load(Ordering::Relaxed) { break; }
if address == **target_address { let current_time = Local::now(); let line_of_dashes = "-".repeat(80); println!( "\n[+] {}\n[+] KEY FOUND! {}\n[+] decimal: {} \n[+] private key: {} \n[+] public key: {} \n[+] address: {}\n[+] {}", line_of_dashes, current_time.format("%Y-%m-%d %H:%M:%S"), key, private_key, public_key, address, line_of_dashes );
// Set the flag to true to signal other threads to exit found_flag.store(true, Ordering::Relaxed);
if let Ok(mut file) = File::create("KEYFOUNDKEYFOUND.txt") { let line_of_dashes = "-".repeat(130); writeln!( &mut file, "\n{}\nKEY FOUND! {}\ndecimal: {} \nprivate key: {} \npublic key: {} \naddress: {}\n{}", line_of_dashes, current_time.format("%Y-%m-%d %H:%M:%S"), key, private_key, public_key, address, line_of_dashes ) .expect("Failed to write to file"); } else { eprintln!("Error: Failed to create or write to KEYFOUNDKEYFOUND.txt"); } io::stdout().flush().unwrap(); break; } } } Cargo.toml [package] name = "puzzle" version = "0.1.0" edition = "2021"
[dependencies] num = "0.4.1" num-traits = "0.2" num-bigint = { version = "0.4.4", features = ["rand"] } threadpool = "1.8.0" bitcoin_hashes = "0.14.0" bitcoin = "0.31.2" hex = "0.4.3" rand = "0.8.5" secp256k1 = "0.29.0" num_cpus = "1.16.0" chrono = "0.4.38" clap = "3.0" ctrlc = "3.4.4" Build program RUSTFLAGS="-C target-feature=+ssse3" cargo build --release --target=x86_64-unknown-linux-gnu Usage example ./puzzle -p 20 -a 1HsMJxNiV7TLxmoF6uJNkydxPFDog4NQum ./puzzle -p 30 -a 1LHtnpd8nU5VHEMkG2TMYYNUjjLc992bps ./puzzle -p 66 -a 13zb1hQbWVsc2S7ZTZnP2G4undNNpdh5so ./puzzle -p 130 -a 1Fo65aKq8s8iquMt6weF1rku1moWVEd5Ua
|
|
|
The problem is what are you going to use for the dinosaur numbers above Puzzle 128. I wrote above additionally. These test scripts will not work configured like this with Puzzle 130. This will work whatever number you insert - use gmp.h #include <iostream> #include <gmp.h> #include <gmpxx.h> #include <cstdlib> #include <ctime> #include <iomanip>
int main() { mpz_class min_range("18446744073709551615"); mpz_class max_range("36893488147419103231"); mpz_class counter = 0; mpz_class dec; gmp_randstate_t state;
gmp_randinit_default(state); std::time_t start_time = std::time(nullptr); double total_time = 0;
mpz_t range; mpz_sub(range, max_range.get_mpz_t(), min_range.get_mpz_t());
while (true) { mpz_urandomm(dec.get_mpz_t(), state, range); mpz_add(dec.get_mpz_t(), dec.get_mpz_t(), min_range.get_mpz_t()); counter++;
std::time_t current_time = std::time(nullptr); double elapsed_time = difftime(current_time, start_time);
if (elapsed_time > total_time) { std::cout << "Total " << counter << " numbers in " << elapsed_time << " seconds: " << std::setprecision(0) << std::fixed << counter / elapsed_time << " numbers/s" << std::endl; total_time = elapsed_time; }
}
gmp_randclear(state); mpz_clear(range); return 0; }
|
|
|
I can't squeeze out more than 852.000 affine point additions per second
I have 249457 hops per second in python converting this script with cpython into .so import time import os import sys import random import secp256k1 as ice import gmpy2
if os.name == 'nt': os.system('cls') else: os.system('clear') t = time.ctime() sys.stdout.write(f"\033[?25l") sys.stdout.write(f"\033[01;33m[+] Kangaroo: {t}\n") sys.stdout.flush()
modulo = gmpy2.mpz(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F) order = gmpy2.mpz(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141) Gx = gmpy2.mpz(0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798) Gy = gmpy2.mpz(0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8)
# Define Point class class Point: def __init__(self, x=0, y=0): self.x = gmpy2.mpz(x) self.y = gmpy2.mpz(y)
PG = Point(Gx, Gy) Z = Point(0, 0) # zero-point, infinite in real x, y - plane
def add(P, Q, p=modulo): if P == Z: return Q elif Q == Z: return P elif P.x == Q.x and (P.y != Q.y or P.y == 0): return Z elif P.x == Q.x: m = (3 * P.x * P.x) * gmpy2.invert(2 * P.y, p) % p else: m = (Q.y - P.y) * gmpy2.invert(Q.x - P.x, p) % p x = (m * m - P.x - Q.x) % p y = (m * (P.x - x) - P.y) % p return Point(x, y)
def mul2(P, p=modulo): if P == Z: return Z m = gmpy2.f_mod(3 * P.x * P.x * gmpy2.invert(2 * P.y, p), p) x = gmpy2.f_mod(m * m - 2 * P.x, p) y = gmpy2.f_mod(m * (P.x - x) - P.y, p) return Point(x, y)
def mulk(k, P=PG, p=modulo): if k == 0: return Z elif k == 1: return P elif k % 2 == 0: return mulk(k // 2, mul2(P, p), p) else: return add(P, mulk((k - 1) // 2, mul2(P, p), p), p)
def X2Y(X, y_parity, p=modulo): X_cubed = gmpy2.powmod(X, 3, p) X_squared = gmpy2.powmod(X, 2, p) tmp = gmpy2.f_mod(X_cubed + 7, p) Y = gmpy2.powmod(tmp, gmpy2.f_div(gmpy2.add(p, 1), 4), p) if y_parity == 1: Y = gmpy2.f_mod(-Y, p) return Y
def comparator(A, Ak, B, Bk): result = set(A).intersection(set(B)) if result: sol_kt = A.index(next(iter(result))) sol_kw = B.index(next(iter(result))) HEX = "%064x" % abs(Ak[sol_kt] - Bk[sol_kw]) dec = int(HEX, 16) wifc = ice.btc_pvk_to_wif(HEX) wifu = ice.btc_pvk_to_wif(HEX, False) caddr = ice.privatekey_to_address(0, True, dec) uaddr = ice.privatekey_to_address(0, False, dec) total_time = time.time() - starttime print('\n[+] total time: %.2f sec' % (total_time)) t = time.ctime() print(f"\033[32m[+] PUZZLE SOLVED: {t} \033[0m") print(f"\033[32m[+] Private key (wif) Compressed : {wifc} \033[0m") with open("KEYFOUNDKEYFOUND.txt", "a") as file: file.write("\n\nSOLVED " + t) file.write(f"\nTotal Time: {total_time:.2f} sec") file.write(f"\nRandom seed: {seed}") file.write("\nPrivate Key (decimal): " + str(dec)) file.write("\nPrivate Key (hex): " + HEX) file.write("\nPrivate key (wif) Compressed : " + wifc) file.write("\nPrivate key (wif) Uncompressed: " + wifu) file.write("\nBitcoin address Compressed: " + caddr) file.write("\nBitcoin address Uncompressed: " + uaddr) file.write( "\n-------------------------------------------------------------------------------------------------------------------------------------------\n" ) file.close() return True else: return False
def check(P, Pindex, DP_rarity, A, Ak, B, Bk): if P.x % DP_rarity == 0: A.append(gmpy2.mpz(P.x)) Ak.append(gmpy2.mpz(Pindex)) return comparator(A, Ak, B, Bk) else: return False
# Generate a list of powers of two for faster access
def generate_powers_of_two(hop_modulo): return [gmpy2.mpz(1 << pw) for pw in range(hop_modulo)]
def search(P, W0, DP_rarity, Nw, Nt, hop_modulo, upper_range_limit, lower_range_limit, powers_of_two): solved = False t = [gmpy2.mpz(lower_range_limit + gmpy2.mpz(random.randint(0, upper_range_limit - lower_range_limit))) for _ in range(Nt)] T = [mulk(ti) for ti in t] dt = [gmpy2.mpz(0) for _ in range(Nt)] w = [gmpy2.mpz(random.randint(0, upper_range_limit - lower_range_limit)) for _ in range(Nw)] W = [add(W0, mulk(wk)) for wk in w] dw = [gmpy2.mpz(0) for _ in range(Nw)] print('[+] tame and wild herds are prepared') Hops, Hops_old = 0, 0 t0 = time.time() while not solved: for k in range(Nt): Hops += 1 pw = T[k].x % hop_modulo dt[k] = powers_of_two[pw] solved = check(T[k], t[k], DP_rarity, T, t, W, w) if solved: break t[k] += dt[k] T[k] = add(P[int(pw)], T[k]) if solved: break for k in range(Nw): Hops += 1 pw = W[k].x % hop_modulo dw[k] = powers_of_two[pw] solved = check(W[k], w[k], DP_rarity, W, w, T, t) if solved: break w[k] += dw[k] W[k] = add(P[int(pw)], W[k]) if solved: break t1 = time.time() if (t1 - t0) > 5: print('\r[+] Hops: %.0f h/s' % ((Hops - Hops_old) / (t1 - t0)), end='', flush=True) t0 = t1 Hops_old = Hops print('[+] Hops:', Hops) return 'sol. time: %.2f sec' % (time.time() - starttime)
puzzles = [\ ('0209c58240e50e3ba3f833c82655e8725c037a2294e14cf5d73a5df8d56159de69',32),\ ('03a2efa402fd5268400c77c20e574ba86409ededee7c4020e4b9f0edbee53de0d4',40),\ ('025e466e97ed0e7910d3d90ceb0332df48ddf67d456b9e7303b50a3d89de357336',44),\ ('026ecabd2d22fdb737be21975ce9a694e108eb94f3649c586cc7461c8abf5da71a',45),\ ('03f46f41027bbf44fafd6b059091b900dad41e6845b2241dc3254c7cdd3c5a16c6',50),\ ('0230210c23b1a047bc9bdbb13448e67deddc108946de6de639bcc75d47c0216b1b',65),\ ('03633cbe3ec02b9401c5effa144c5b4d22f87940259634858fc7e59b1c09937852',130)]
puzzle = 40 for elem in puzzles: s, n = elem if puzzle == n: break
kangaroo_power = 4 DP_rarity = 1 << int(((puzzle - 2*kangaroo_power)/2 - 2)) hop_modulo = ((puzzle - 1) // 2) + kangaroo_power Nt = Nw = 2**kangaroo_power
X = gmpy2.mpz(s[2:66], 16) Y = X2Y(X, gmpy2.mpz(s[:2]) - 2)
W0 = Point(X,Y) starttime = oldtime = time.time() search_range = 2**(puzzle-1)
lower_range_limit = 2 ** (puzzle - 1) upper_range_limit = (2 ** puzzle) - 1
print(f"[+] [Puzzle]: {puzzle}") print(f"[+] [Lower range limit]: {lower_range_limit}") print(f"[+] [Upper range limit]: {upper_range_limit}")
# Precompute powers of two for faster access powers_of_two = generate_powers_of_two(hop_modulo)
# Initialize variables T, t, dt = [], [], [] W, w, dw = [], [], []
#Random seed Config seed = os.urandom(9) print(f"[+] [Random seed]: {seed}") random.seed(seed)
Hops = 0 N_tests = 1
P = [PG] for k in range(255): P.append(mul2(P[k])) print('[+] P-table prepared')
for k in range(N_tests): solved = False search(P, W0, DP_rarity, Nw, Nt, hop_modulo, upper_range_limit, lower_range_limit, powers_of_two)
print('[+] Average time to solve: %.2f sec' % ((time.time()-starttime)/N_tests)) It normally goes to 207301 h/s Imagine this in Rust, how fast would it go? u128
const uint64_t
uint64 in C & u128 in Rust not work for Puzzle 130 (try to deal with dinosaur numbers) BigUint/BIGINT from SSL works or GMP can be used
|
|
|
ahahah soo hilarious. Try test with custom script address build then, it's faster. private key > Compresssed public key > custom script > address format. i try that method it's faster enough. I would like someone to make a Pollard's kangaroo for SECPK1 in Rust. Maybe it could work faster, Rust programs also optimize quite well, sometimes better than C. Enforces thread-safety of all code and data, even in 3rd party libraries. It has incredible possibilities for compiling. I was able to run this on an ARM processor as well on Amd Zen 2, 3 and 4 on almost everything.....on potatoe https://doc.rust-lang.org/rustc/platform-support.htmlIt's a pity that I don't have more time to deal with this.
|
|
|
Here's the reality: /dev/urandom is not a secure random number generator.
What kind of security are you talking about when we a brute-force BTC here? I want to crack the random number generator not to improve it ! To break down random.seed. Here is example: import random import os import time import secp256k1 as ice
puzzle = 30 target = "d39c4704664e1deb76c9331e637564c257d68a08" lower_range_limit = 2 ** (puzzle - 1) upper_range_limit = (2 ** puzzle) - 1
start_time = time.time()
for x in range(10000000): #Random seed Config #constant_prefix = b'' #back to no constant constant_prefix = b'yx\xcb\x08\xb70l' prefix_length = len(constant_prefix) length = 8 ending_length = length - prefix_length ending_bytes = os.urandom(ending_length) random_bytes = constant_prefix + ending_bytes random.seed(random_bytes) dec = random.randint(lower_range_limit, upper_range_limit) h160 = ice.privatekey_to_h160(0, True, dec).hex() if h160 == target: HEX = "%064x" % dec caddr = ice.privatekey_to_address(0, True, dec) wifc = ice.btc_pvk_to_wif(HEX) print("Bitcoin address Compressed: " + caddr) print("Private Key (decimal): " + str(dec)) print("Private key (wif) Compressed : " + wifc) print(f"Random seed: {random_bytes}") break
end_time = time.time() execution_time_ms = (end_time - start_time) * 1000
print("Execution Time (ms):", execution_time_ms) This is a millisecond puzzle 30 solver. Bitcoin address Compressed: 1LHtnpd8nU5VHEMkG2TMYYNUjjLc992bps Private Key (decimal): 1033162084 Private key (wif) Compressed : KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M8diLSC5MyERoW Random seed: b'yx\xcb\x08\xb70l\xf1' Execution Time (ms): 2.8727054595947266
|
|
|
I know it is still far away for the required number, but is 100x Times faster.... I have not tried the same script in C++ I also deal with other things. More with hardware than software. p.s. i have almost the same result Total 653409355 numbers in 39 seconds: 16754086 numbers/s Total 670648654 numbers in 40 seconds: 16766216 numbers/s Total 687812315 numbers in 41 seconds: 16775910 numbers/s Total 705075122 numbers in 42 seconds: 16787502 numbers/s #include <iostream> #include <gmp.h> #include <gmpxx.h> #include <cstdlib> #include <ctime> #include <iomanip>
int main() { mpz_class min_range("18446744073709551615"); mpz_class max_range("36893488147419103231"); mpz_class counter = 0; mpz_class dec; gmp_randstate_t state;
gmp_randinit_default(state); std::time_t start_time = std::time(nullptr); double total_time = 0;
mpz_t range; mpz_sub(range, max_range.get_mpz_t(), min_range.get_mpz_t());
while (true) { mpz_urandomm(dec.get_mpz_t(), state, range); mpz_add(dec.get_mpz_t(), dec.get_mpz_t(), min_range.get_mpz_t()); counter++;
std::time_t current_time = std::time(nullptr); double elapsed_time = difftime(current_time, start_time);
if (elapsed_time > total_time) { std::cout << "Total " << counter << " numbers in " << elapsed_time << " seconds: " << std::setprecision(0) << std::fixed << counter / elapsed_time << " numbers/s" << std::endl; total_time = elapsed_time; }
}
gmp_randclear(state); mpz_clear(range); return 0; }
|
|
|
There are algorithms that are actually getting the uniform real randomness (not some deterministic PRNG bullshit like someone mentioned earlier, I mean really lol? Haven't they heard about os.urandom and how it works?)
import os, sys, random import time
min_range = 18446744073709551615 max_range = 36893488147419103231 counter = 0 # Initialize counter start_time = time.time()
while True: random_bytes = os.urandom(9) initial_bytes = b'\x00' * 23 full_bytes = initial_bytes + random_bytes dec = int.from_bytes(full_bytes, byteorder='big') counter += 1 # Increment counter message = "\rPrivate Keys per second: {:.2f}".format(counter / (time.time() - start_time)) messages = [] messages.append(message) output = "\033[01;33m" + ''.join(messages) + "\r" sys.stdout.write(output) sys.stdout.flush() if min_range <= dec <= max_range: if dec == 30568377312064202855: print("\nSeed :", random_bytes) print("Generated number:", dec) break
This is Python script that will test os.urandom speed. The example works for Puzzle 65. There is no hash or secp256k1 operations here - just numbers. Result is (on my PC) : Private Keys per second: 170893.39 Do you know how many numbers need to be generated per second to find Puzzle 65 in 10 minutes? 30744573456182586 Private Keys per second ! It's an mission impossible . Even in C++ We need Grey aliens hardware to solve this. From Zeta Reticuli
|
|
|
wish me luck, current speed is 100K keys per sec.
No luck here.
|
|
|
Randomly Satoshi has hidden 6.6 BTC in that rule... FIND IT! Here's the challenge! When using Pollard's kangaroo algorithm with a known public key, it's like having a warp drive that efficiently navigates through space, jumping through distances equivalent to 3.9 light years, leveraging the known structure provided by the public key. However, if the public key were unknown, it would be akin to being in an unmapped region of space. Without the reference point provided by the known public key, a program attempting to find the solution would face difficulty in efficiently traversing the vast number space, much like navigating through uncharted space would require exploring the entire area. So, in summary, the known public key acts as a mapped star system, enabling the algorithm to efficiently navigate through the vast number space of puzzle 66.
|
|
|
Astrology for btc...
Some make good money from BTC astrology. But that doesn't work here . You'll need to wait until the end of the galaxy we live in (times many billions) until you stumble upon a key with wallet balance.
Can you imagine idiots who buying Python scripts to solve this puzzle for billions of years? Two things are infinite: the universe and human stupidity.
|
|
|
Just because someone opens a thread on a forum and opens the starting gun for a 32BTC, is that legal? How do you know who the coins originally belonged to and what source they came from?
He is an honorable and honest hacker. Trust me bro™
|
|
|
The creator just sent some bitcoin to some random addresses, that's nothing special.
The puzzle creator already stated the reasons for the challenge. To prove the bitcoin security: It is simply a crude measuring instrument, of the cracking strength of the community.
Nothing else to say. computing resources to stuff like hundreds of last-gen GPUs
For #130 356-400 RTX 4090s For #66 thousands of GPUs You need a GPU farm for this. That's nothing special if you are already a millionaire.
|
|
|
There is no error or bug in this puzzle. I think this puzzle was made by one of the first users here, casascius or satoshi himself. We're scr**** to solve this. There is no easy way.
|
|
|
Errors are possible.
Nope. There is an exact math formula for making this puzzle with some script, errors = ZERO. He used used a custom method like: "Type 1 Deterministic Wallet" Masked with leading 000...0001 to set difficulty. There is no error here in arithemitic precision. https://thebookofbitcoin.github.io/html/storage/deterministic_wallets.htmlEverything else is a conspiracy theory.
|
|
|
It's kind of delusion... You know. our mind looks for pattern for anything and finally it finds Apophenia is a mental disorder to see connections and patterns between unrelated or random things that are not really there—gives rise to conspiracy theories.
|
|
|
|