initial commit
Some checks failed
CI / lint (push) Successful in 1m37s
CI / test-python (push) Successful in 1m49s
CI / test-zig (push) Successful in 1m39s
CI / test-wasm (push) Successful in 1m54s
CI / test (push) Successful in 14m44s
CI / miri (push) Successful in 14m18s
CI / build (push) Successful in 1m9s
CI / fuzz-regression (push) Successful in 9m9s
CI / publish (push) Failing after 1m10s
CI / publish-python (push) Failing after 1m46s
CI / publish-wasm (push) Has been cancelled
Some checks failed
CI / lint (push) Successful in 1m37s
CI / test-python (push) Successful in 1m49s
CI / test-zig (push) Successful in 1m39s
CI / test-wasm (push) Successful in 1m54s
CI / test (push) Successful in 14m44s
CI / miri (push) Successful in 14m18s
CI / build (push) Successful in 1m9s
CI / fuzz-regression (push) Successful in 9m9s
CI / publish (push) Failing after 1m10s
CI / publish-python (push) Failing after 1m46s
CI / publish-wasm (push) Has been cancelled
Signed-off-by: Kamal Tufekcic <kamal@lo.sh>
This commit is contained in:
commit
1d99048c95
165830 changed files with 79062 additions and 0 deletions
113
soliton/build.rs
Normal file
113
soliton/build.rs
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
//! Build script for soliton.
|
||||
//!
|
||||
//! Embeds the EFF large wordlist for verification phrase generation.
|
||||
//! The wordlist is checked into the repo at `src/eff_large_wordlist.txt`
|
||||
//! and SHA-256 verified at build time.
|
||||
//!
|
||||
//! All cryptographic dependencies are pure Rust — no C compilation or linking needed.
|
||||
|
||||
use sha2::{Digest, Sha256};
|
||||
use std::env;
|
||||
use std::fs;
|
||||
use std::io::Write;
|
||||
use std::path::PathBuf;
|
||||
|
||||
/// SHA-256 hash of the canonical EFF large wordlist (7776 lines).
|
||||
/// <https://www.eff.org/files/2016/07/18/eff_large_wordlist.txt>
|
||||
const EFF_WORDLIST_SHA256: &str =
|
||||
"addd35536511597a02fa0a9ff1e5284677b8883b83e986e43f15a3db996b903e";
|
||||
|
||||
fn main() {
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
println!("cargo:rerun-if-changed=src/eff_large_wordlist.txt");
|
||||
|
||||
generate_wordlist();
|
||||
}
|
||||
|
||||
/// Read the EFF large wordlist from the in-repo cached copy and generate
|
||||
/// a Rust source file with the words as a static array. The file is
|
||||
/// written to OUT_DIR and included via `include!` in the verification
|
||||
/// module.
|
||||
///
|
||||
/// The EFF large wordlist contains 7776 words (6^5), one per line, prefixed
|
||||
/// with a dice roll number and a tab. We strip the prefix and keep only the
|
||||
/// words.
|
||||
fn generate_wordlist() {
|
||||
// Cargo guarantees OUT_DIR and CARGO_MANIFEST_DIR for build scripts.
|
||||
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
|
||||
let wordlist_rs = out_dir.join("eff_wordlist.rs");
|
||||
let cache_path = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap())
|
||||
.join("src")
|
||||
.join("eff_large_wordlist.txt");
|
||||
|
||||
// Skip regeneration if the output already exists AND the cached source
|
||||
// passes SHA-256 verification. Safe because the output is deterministically
|
||||
// generated from the source — same input always produces identical output.
|
||||
// The SHA-256 check protects against tampered build caches.
|
||||
if wordlist_rs.exists() {
|
||||
if let Ok(cached) = fs::read_to_string(&cache_path) {
|
||||
verify_wordlist_hash(&cached);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let raw = fs::read_to_string(&cache_path)
|
||||
.expect("EFF wordlist not available: src/eff_large_wordlist.txt missing from repo");
|
||||
|
||||
verify_wordlist_hash(&raw);
|
||||
|
||||
// Parse: each line is "DDDDD\tword\n" (5-digit dice roll, tab, word).
|
||||
let words: Vec<&str> = raw
|
||||
.lines()
|
||||
.filter_map(|line| {
|
||||
let line = line.trim();
|
||||
if line.is_empty() {
|
||||
return None;
|
||||
}
|
||||
line.split('\t').nth(1)
|
||||
})
|
||||
.collect();
|
||||
|
||||
// Panic: build scripts communicate errors by panicking. A count mismatch
|
||||
// indicates a corrupted or non-canonical wordlist that passed SHA-256
|
||||
// (hash collision or wrong file).
|
||||
assert_eq!(
|
||||
words.len(),
|
||||
7776,
|
||||
"EFF wordlist should have 7776 entries, got {}",
|
||||
words.len()
|
||||
);
|
||||
|
||||
// Panic on I/O failure: build scripts have no recovery path — Cargo
|
||||
// treats a panic as a build error and reports the message to the user.
|
||||
let mut out = fs::File::create(&wordlist_rs).unwrap();
|
||||
writeln!(out, "/// EFF large wordlist (7776 words).").unwrap();
|
||||
writeln!(
|
||||
out,
|
||||
"/// Source: <https://www.eff.org/dice>, checked into repo at src/eff_large_wordlist.txt."
|
||||
)
|
||||
.unwrap();
|
||||
writeln!(out, "pub(crate) static EFF_WORDLIST: [&str; 7776] = [").unwrap();
|
||||
for word in &words {
|
||||
writeln!(out, " \"{word}\",").unwrap();
|
||||
}
|
||||
writeln!(out, "];").unwrap();
|
||||
}
|
||||
|
||||
/// Verify the SHA-256 hash of the EFF wordlist content.
|
||||
///
|
||||
/// # Security
|
||||
///
|
||||
/// Panics with a clear message if the hash doesn't match, preventing
|
||||
/// use of a tampered or corrupted wordlist in verification phrases.
|
||||
/// This is the sole integrity gate for the in-repo wordlist.
|
||||
fn verify_wordlist_hash(content: &str) {
|
||||
let computed = format!("{:x}", Sha256::digest(content.as_bytes()));
|
||||
|
||||
assert_eq!(
|
||||
computed, EFF_WORDLIST_SHA256,
|
||||
"EFF wordlist SHA-256 mismatch!\n expected: {}\n computed: {}\n\
|
||||
The wordlist may be corrupted or tampered with.",
|
||||
EFF_WORDLIST_SHA256, computed
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue