use super::{GenericDiagram, Result};
use crate::macros::ImpDeref;
use bitcoin::hashes::{Hash, sha256};
#[derive(Debug, Default, Clone, PartialEq)]
pub struct SimpleDiagram(pub [[Option<char>; 7]; 7]);
ImpDeref!(SimpleDiagram, [[Option<char>; 7]; 7]);
impl GenericDiagram for SimpleDiagram {
type Item = char;
fn to_bytes(&self) -> Result<Vec<u8>> {
let mut chars = Vec::with_capacity(7 * 7);
let mut indices = [0; 7];
(0..7).rev().for_each(|col| {
(0..7).rev().for_each(|row| {
if let Some(ch) = self[row][col] {
chars.push(ch);
indices[row] |= 1 << (6 - col);
}
});
});
let str = chars.into_iter().collect::<String>();
let mut secret = [str.as_bytes(), &indices].concat();
let check = sha256::Hash::hash(&secret).as_byte_array()[0];
secret.push(check);
Ok(secret)
}
}
impl SimpleDiagram {
#[deprecated(since = "1.7.2", note = "Use `Diagram` instead")]
pub fn new() -> Self {
Self([[None; 7]; 7])
}
#[deprecated(since = "1.7.2", note = "Use `Diagram` instead")]
pub fn from_values(items: &[char], indices: &[(usize, usize)]) -> Self {
let mut data = [[None; 7]; 7];
indices
.iter()
.zip(items)
.for_each(|(&(r, c), &v)| data[r][c] = Some(v));
SimpleDiagram(data)
}
}
#[cfg(test)]
#[allow(deprecated)]
mod simple_diagram_test {
use super::*;
use bitcoin::hex::DisplayHex;
#[test]
fn test_simple_diagram() -> Result<()> {
const CHARS_STR: &str = "A&*王😊";
const CHARS_INDICES: &[(usize, usize)] = &[(0, 6), (1, 1), (1, 3), (4, 2), (6, 6)];
const SECRET_HEX: &str = "f09f988a412ae78e8b26012800001000012d";
const WARP_ENTROPY: &str =
"ad1a1825c929a7381cc74e29583796ee0a00be0913b78e03a5d2ca1ae00236b6";
const SALT_STR: &str = "123abc";
const SALT_ENTROPY: &str =
"916e697f2fd6b1d1f29d85eace1793bd80a7ab1bd595892f5567a5f20d6fc2e0";
#[cfg(not(feature = "testnet"))]
mod wif {
pub const MASTER_WIF_V1: &str = "xprv9s21ZrQH143K2r6v9GGWezApYmVuaGiZYoCpsQFVe9Vwh47yZ2CCgqXJY6g2Kk8Ajrz2PbVNnY5HLw4dPkshmcqX8YBEhcwj4wWQ8UgY5m7";
pub const SALT_MASTER_V1: &str = "xprv9s21ZrQH143K3m9k6SE8k9kYgPUS2YiuWyV2LZN43xMPSWe8w1vriyFgPh4BnFGevHto27pmDCcnpJRAWLybqaaZeucx9fmJHFd2CWFMwkw";
pub const MASTER_WIF: &str = "xprv9s21ZrQH143K38UmyXgTiRxiPAbzzfbvAM1VDkBWKbsRQsmJLxtwLn5DZ5vfhjTumysk6vQHcYje6hcc5h8fa6csha7vRn57oUW1iiJF4wC";
pub const SALT_MASTER: &str = "xprv9s21ZrQH143K2yXvw7czAjfgb5omTUH8JB5JzUSzd8akT49vGeQwK6MbN6rkzrFFMw9ZhqCLNACAuD265pRJTAY6qPQdB1GvAbgoN2ifKpa";
}
#[cfg(feature = "testnet")]
mod wif {
pub const MASTER_WIF_V1: &str = "tprv8ZgxMBicQKsPdfLSoq81pdnortv7onkZtM7wjpfx87zRUes4YPXxCatkTGqgL7WV7JWoPh78wtf5oncNWyDeag77fBPYMyfmz3FpaCED928";
pub const SALT_MASTER_V1: &str = "tprv8ZgxMBicQKsPeaPGm15duoNXzWteG4kurXQ9CynWXvqsE7PDvPGcEid8JsDqnceyHjRa2DSXNZCbH9xudZKYedrABYqFp2VMCMNSeBkeo4Y";
pub const MASTER_WIF: &str = "tprv8ZgxMBicQKsPdwiJe6Xxt5ahhJ2DEBdvVtvc6AbxoaMuCUWPLLEgrXSfUG6Ki6rE9RQX7223muKSZZAMCuUcP9tUEDLE68oAiaFSAS4KtVH";
pub const SALT_MASTER: &str = "tprv8ZgxMBicQKsPdnmTbgUVLPHfuDDygzK8dizRrtsT775EEeu1G1kgpqj3HH2R1DdZjNgLhvp6XWmyN4ZqD2mFGDohN2cvqMzy5hSDoiX6FTt";
}
let items: Vec<char> = CHARS_STR.chars().collect();
let sdm = SimpleDiagram::from_values(&items, CHARS_INDICES);
assert_eq!(sdm.to_bytes()?.to_lower_hex_string(), SECRET_HEX);
assert_eq!(sdm[6][6], Some('😊'));
let entropy = sdm.to_entropy(Default::default())?;
assert_eq!(entropy.to_lower_hex_string(), WARP_ENTROPY);
assert_eq!(sdm.to_master(&[])?.to_string(), wif::MASTER_WIF);
assert_eq!(sdm.to_master_v1(&[])?.to_string(), wif::MASTER_WIF_V1);
let entropy = sdm.to_entropy(SALT_STR.as_bytes())?;
assert_eq!(entropy.to_lower_hex_string(), SALT_ENTROPY);
let master = sdm.to_master(SALT_STR.as_bytes())?;
assert_eq!(master.to_string(), wif::SALT_MASTER);
let master_v1 = sdm.to_master_v1(SALT_STR.as_bytes())?;
assert_eq!(master_v1.to_string(), wif::SALT_MASTER_V1);
Ok(())
}
#[test]
fn test_simple_diagram2() -> Result<()> {
const CHARS_STR: &str = "A王&*😊";
const CHARS_INDICES: &[(usize, usize)] = &[(0, 6), (1, 1), (1, 3), (4, 2), (6, 0)];
const SECRET_HEX: &str = "41262ae78e8bf09f988a012800001000406d";
const WARP_ENTROPY: &str =
"8db994dbd6481561dd4b92740f3ba517c9fb2ee9500882e4481e0e2991cb0271";
const SALT_STR: &str = "123abc";
const SALT_ENTROPY: &str =
"f3355cc989e82d61dcc382c3919f22a6a928fe3284399994e774f8c7a5ce69e4";
let items: Vec<char> = CHARS_STR.chars().collect();
let sdm = SimpleDiagram::from_values(&items, CHARS_INDICES);
assert_eq!(sdm.to_bytes()?.to_lower_hex_string(), SECRET_HEX);
assert_eq!(sdm[6][0], Some('😊'));
let entropy = sdm.to_entropy(Default::default())?;
assert_eq!(entropy.to_lower_hex_string(), WARP_ENTROPY);
let entropy = sdm.to_entropy(SALT_STR.as_bytes())?;
assert_eq!(entropy.to_lower_hex_string(), SALT_ENTROPY);
Ok(())
}
}