rsigma-ir
rsigma-ir
rsigma-ir
Added in v0.20.0Shared intermediate representation (HIR) for Sigma rules. Sits between the parser AST and the eval/convert consumers so modifier resolution happens once.
When to use
- Lower a parsed
SigmaRuleinto a modifier-resolved form before custom analysis. - Share one canonical rule shape between evaluation and query conversion.
- Inspect detections, conditions, correlation, or filter shapes without compiling regex/
IpNetmatchers.
Most embedders never depend on rsigma-ir directly: rsigma-eval routes compile_rule through lower_rule → compile_to_compiled already.
Install
[dependencies]
rsigma-parser = "0.25.0"
rsigma-ir = "0.25.0"
The crate is sync-only (no tokio/reqwest).
Public surface
| Type / function | Purpose |
|---|---|
IrRule / IrDetection / IrMatcher / IrCondition |
Detection-rule HIR. IrCondition::Selector keeps the quantifier and name pattern. |
IrMatcher::Str + IrPattern |
Faithful, wildcard-aware, original-case string match. |
IrMatcher::Encoded + IrEncoding |
Explicit encoding transforms (base64, wide, windash, …) over a wildcard-aware pattern.
Added in v0.24.0 |
encoding::expand_encoded / encoding::expand_encoded_detections / encoding::expand_encoded_matcher |
Replay an Encoded matcher into the plain string matches its encodings produce (windash variants, UTF-16, base64 and base64offset), for one value, a whole detection map, or one matcher. Eval compiles them and conversion renders them, so both agree on the variants. encoding::MAX_WINDASH_DASHES caps windash expansion.
Added in v0.24.0 |
IrMatcher::Expand |
A |expand value with placeholders left for match time, with the string operator in op.
Added in v0.24.0 |
IrNumber / NumericLiteral |
A numeric matcher value. NumericLiteral keeps a rule integer as an exact i64 and a fractional value as an f64, and its Display renders integers digit for digit.
Added in v0.25.0 |
IrCorrelation / IrFilter |
Correlation and filter HIR. |
IrRuleMetadata |
Metadata superset used when projecting eval RuleHeader. |
lower_rule / lower_detection / lower_condition |
AST → HIR. |
lower_correlation / lower_filter |
Parallel walkers for those shapes. |
LowerOptions |
Strict (default) vs placeholder-preserving lowering. |
optimize_rule / flatten_condition / eliminate_dead_detections |
Opt-in, semantics-preserving HIR passes. |
common_subexpressions / CseReport |
Non-mutating analysis of repeated detection items. |
encode_rules / decode_rules / HirCacheHeader |
Versioned HIR cache (CBOR) with a schema-version check. |
HIR cache
cache::* serializes lowered rules to a versioned, self-describing blob, the on-disk HIR cache. It is what rsigma-eval’s Engine::save_hir / load_hir use for a restart cache that skips parse, pipeline, and lowering; the engine keeps the HIR to save only after Engine::set_retain_hir(true).
- The blob is a
HirCacheHeader(schema version + producing crate version) followed by the rules.decode_rulesreads and version-checks the header before decoding the rules, rejecting a blob written under an incompatibleHIR_SCHEMA_VERSION. - CBOR is the binary format: the HIR embeds
LogSource, whose#[serde(flatten)]custom-key map serializes with an unknown length that fixed-layout encoders reject. cache::to_jsongives a human-readable debug export of the same header-plus-rules shape.- All HIR types derive
serde::{Serialize, Deserialize}; the embeddedrsigma-parsertypes gainedDeserializeso the HIR round-trips.
Optimization passes
optimize::* provides opt-in, total functions on the HIR for offline tooling (pack building, analysis). They are not run by the default eval or convert paths, so compiled-matcher behavior and byte-identical backend output are unchanged.
flatten_conditionmerges nested same-kind boolean groups, collapsesNot(Not(x)), unwraps single-childAnd/Or, and drops idempotent duplicate siblings.eliminate_dead_detectionsremoves detections no condition can reference (honoringthem/glob selector patterns) and recurses intoConditionalbodies.common_subexpressionsreports detection items that occur more than once, the candidates a consumer could evaluate once and share.optimize_ruleapplies the two structural passes in order.
Each pass preserves the match decision and the set of matched selections and fields. Reported order and multiplicity of matched selections are not part of the contract: dropping a duplicate reference reports a selection once, and pruning changes a selector’s HashMap-ordered reporting.
Lowering notes
- Lowering is purely structural: it resolves which comparison applies but never lowercases, compiles regexes, or expands encodings. Eval does that at compile time; convert expands encodings with
encoding::expand_encoded_detectionsand renders wildcards to backend tokens. This keeps the HIR lossless. - Selectors such as
1 of selection_*andall of themare preserved asIrCondition::Selector, so evaluation stays count-based and reports every matching detection.themand every pattern that does not start with_skip_-prefixed detection names; a pattern that starts with_, such as1 of _filter*, selects them. A selector that matches no detection name fails lowering withIrError::NoSelectorMatches, so evaluation and conversion reject the rule alike. Added in v0.24.0 - Modifier contradictions (
|cidr|contains,|base64|base64offset, …) fail at lower time with the same error kinds eval previously surfaced fromcompile_rule. So do values an encoding cannot represent: a wildcard under|base64or|base64offset, and a non-ASCII value under a UTF-16 encoding with no base64 step. Added in v0.24.0 - An
|expandvalue whose placeholders are all resolved by the pipeline lowers to an ordinary string matcher; only values with placeholders left becomeIrMatcher::Expand. Added in v0.24.0 - An empty value list (
Field: []) lowers toIrMatcher::Null, orNot(Null)under|neq. Added in v0.24.0
Related
rsigma-eval:compile_rule(IR path) andEngine::save_hir/load_hir(HIR restart cache).rsigma-parser: source AST.