Skip to main content

ed25519_fast_sv_docs/
lib.rs

1#![doc = include_str!("../docs/index.md")]
2#![forbid(unsafe_code)]
3
4/// A reading guide for the SystemVerilog constructs used by the backend.
5#[doc = include_str!("../docs/reading_systemverilog.md")]
6pub mod reading_systemverilog {}
7
8/// Source status, elaboration hierarchy, dataflow, and build boundaries.
9#[doc = include_str!("../docs/overview.md")]
10pub mod overview {}
11
12/// Field addition, subtraction, and multiplication datapaths.
13#[doc = include_str!("../docs/field.md")]
14pub mod field {}
15
16/// SHA-512 compression worker and multi-worker request pool.
17#[doc = include_str!("../docs/sha512.md")]
18pub mod sha512 {}
19
20/// Scalar reduction, multiplication, and multiply-add datapaths.
21#[doc = include_str!("../docs/scalar.md")]
22pub mod scalar {}
23
24/// Fixed-base lookup, recoding, and signed multi-comb multiplication.
25#[doc = include_str!("../docs/fixed_base.md")]
26pub mod fixed_base {}
27
28/// Projective Edwards point compression and paired batch inversion.
29#[doc = include_str!("../docs/point_codec.md")]
30pub mod point_codec {}
31
32/// Cached and legacy fixed-64 signing cores, including every helper function.
33#[doc = include_str!("../docs/signing_core.md")]
34pub mod signing_core {}
35
36/// AXI kernel, benchmark engines, register maps, and traffic behavior.
37#[doc = include_str!("../docs/shells_and_benchmarks.md")]
38pub mod shells_and_benchmarks {}
39
40/// Source manifests, simulation entry points, synthesis scripts, and evidence rules.
41#[doc = include_str!("../docs/build_and_verification.md")]
42pub mod build_and_verification {}
43
44#[cfg(test)]
45mod tests {
46    use std::collections::BTreeSet;
47    use std::fs;
48    use std::path::{Path, PathBuf};
49
50    const MANUAL: &str = concat!(
51        include_str!("../docs/index.md"),
52        include_str!("../docs/reading_systemverilog.md"),
53        include_str!("../docs/overview.md"),
54        include_str!("../docs/field.md"),
55        include_str!("../docs/sha512.md"),
56        include_str!("../docs/scalar.md"),
57        include_str!("../docs/fixed_base.md"),
58        include_str!("../docs/point_codec.md"),
59        include_str!("../docs/signing_core.md"),
60        include_str!("../docs/shells_and_benchmarks.md"),
61        include_str!("../docs/build_and_verification.md"),
62    );
63
64    fn repository_root() -> PathBuf {
65        Path::new(env!("CARGO_MANIFEST_DIR"))
66            .join("../..")
67            .canonicalize()
68            .unwrap()
69    }
70
71    fn collect_sv_files(directory: &Path, files: &mut Vec<PathBuf>) {
72        for entry in fs::read_dir(directory).unwrap() {
73            let path = entry.unwrap().path();
74            if path.is_dir() {
75                collect_sv_files(&path, files);
76            } else if path.extension().is_some_and(|extension| extension == "sv") {
77                files.push(path);
78            }
79        }
80    }
81
82    fn fast_sv_files() -> Vec<PathBuf> {
83        let root = repository_root();
84        let mut files = Vec::new();
85        for crate_name in [
86            "rhdl_ed25519_fast_field",
87            "rhdl_ed25519_fast_fixed_base",
88            "rhdl_ed25519_fast_sha512",
89            "rhdl_ed25519_fast_point_codec",
90            "rhdl_ed25519_fast_scalar",
91            "rhdl_ed25519_fast_sign",
92        ] {
93            collect_sv_files(
94                &root.join("crates").join(crate_name).join("rtl"),
95                &mut files,
96            );
97        }
98        for entry in fs::read_dir(root.join("bench/rhdl/rtl")).unwrap() {
99            let path = entry.unwrap().path();
100            if path.extension().is_some_and(|extension| extension == "sv")
101                && path
102                    .file_name()
103                    .unwrap()
104                    .to_string_lossy()
105                    .starts_with("fast64_")
106            {
107                files.push(path);
108            }
109        }
110        files.sort();
111        files
112    }
113
114    fn identifier_before_equals(line: &str) -> Option<&str> {
115        let declaration = line.split('=').next()?;
116        declaration.split_whitespace().last()
117    }
118
119    #[test]
120    fn every_fast_sv_source_is_named_in_the_manual() {
121        for path in fast_sv_files() {
122            let file_name = path.file_name().unwrap().to_string_lossy();
123            assert!(
124                MANUAL.contains(&format!("`{file_name}`")),
125                "SystemVerilog source {file_name} is absent from the manual"
126            );
127        }
128    }
129
130    #[test]
131    fn every_module_parameter_and_function_is_named_in_the_manual() {
132        let mut expected = BTreeSet::new();
133        for path in fast_sv_files() {
134            let source = fs::read_to_string(&path).unwrap();
135            for line in source.lines() {
136                let trimmed = line.trim_start();
137                if let Some(rest) = trimmed.strip_prefix("module ") {
138                    let name = rest
139                        .split(|character: char| {
140                            character.is_whitespace() || character == '#' || character == '('
141                        })
142                        .next()
143                        .unwrap();
144                    expected.insert(("module", name.to_owned()));
145                } else if trimmed.starts_with("parameter ") {
146                    if let Some(name) = identifier_before_equals(trimmed) {
147                        expected.insert(("parameter", name.trim_end_matches(',').to_owned()));
148                    }
149                } else if let Some(rest) = trimmed.strip_prefix("function automatic ") {
150                    let signature = rest.split(';').next().unwrap();
151                    let declaration = signature.split('(').next().unwrap();
152                    let name = declaration.split_whitespace().last().unwrap();
153                    expected.insert(("function", name.to_owned()));
154                }
155            }
156        }
157
158        for (kind, name) in expected {
159            assert!(
160                MANUAL.contains(&format!("`{name}`")),
161                "SystemVerilog {kind} {name} is absent from the manual"
162            );
163        }
164    }
165}