{"id":14991211,"url":"https://github.com/plsyssec/haybale-pitchfork","last_synced_at":"2025-10-10T10:34:53.288Z","repository":{"id":45375788,"uuid":"200900594","full_name":"PLSysSec/haybale-pitchfork","owner":"PLSysSec","description":"Verifying constant-time code with symbolic execution","archived":false,"fork":false,"pushed_at":"2021-10-26T03:28:38.000Z","size":1582,"stargazers_count":42,"open_issues_count":1,"forks_count":0,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-04-12T03:36:52.076Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/PLSysSec.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-08-06T18:02:10.000Z","updated_at":"2024-10-10T04:12:51.000Z","dependencies_parsed_at":"2022-07-13T21:34:09.452Z","dependency_job_id":null,"html_url":"https://github.com/PLSysSec/haybale-pitchfork","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/PLSysSec/haybale-pitchfork","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PLSysSec%2Fhaybale-pitchfork","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PLSysSec%2Fhaybale-pitchfork/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PLSysSec%2Fhaybale-pitchfork/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PLSysSec%2Fhaybale-pitchfork/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/PLSysSec","download_url":"https://codeload.github.com/PLSysSec/haybale-pitchfork/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PLSysSec%2Fhaybale-pitchfork/sbom","scorecard":{"id":106920,"data":{"date":"2025-08-11","repo":{"name":"github.com/PLSysSec/haybale-pitchfork","commit":"69a048a66c59118bf88b21008fef2afc40e97263"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3,"checks":[{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'main'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}}]},"last_synced_at":"2025-08-15T11:16:16.582Z","repository_id":45375788,"created_at":"2025-08-15T11:16:16.582Z","updated_at":"2025-08-15T11:16:16.582Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279003544,"owners_count":26083595,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-10T02:00:06.843Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-09-24T14:21:44.919Z","updated_at":"2025-10-10T10:34:53.267Z","avatar_url":"https://github.com/PLSysSec.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# `pitchfork`: Verifying constant-time code with symbolic execution\n\n[![crates.io](https://img.shields.io/crates/v/haybale-pitchfork.svg)](https://crates.io/crates/haybale-pitchfork)\n[![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/PLSysSec/haybale-pitchfork/main/LICENSE)\n\n`pitchfork` is a tool for verifying that constant-time code is, indeed,\nconstant-time.\nIt can analyze code written in C/C++, Rust, or any other language which can\ncompile to LLVM bitcode (e.g., Swift, Go, and others).\nGiven a function to analyze, `pitchfork` will either report that the function\nis constant-time, or give a detailed explanation of why it is not, including\nthe line number of the constant-time violation in the original source, full\nsequence of branch decisions leading to the violation, and values of all\nvariables at the point of the violation.\n\n`pitchfork` is built on the [`haybale`] symbolic execution engine, which is\nalso written in Rust.\n\n## What is constant-time, and what are constant-time violations?\n\nConstant-time programming is the de-facto technique for hardening\ncryptographic implementations against timing side-channel attacks; it has\nbeen adopted by almost all major cryptographic libraries. Constant-time code\nobeys two fundamental principles:\n\n1. Secret values must not influence control flow (e.g., branch conditions or jump targets), and\n2. Secret values must not influence the addresses of memory accesses (e.g., array indexes).\n\nThese principles ensure that a program's timing characteristics and memory\naccess patterns are completely independent of the secret values which it\noperates on.\nThus, even powerful timing side-channel attacks - and in particular, _cache\nattacks_, which glean information from timing attacks on the processor\ncache - are unable to recover any information about these secret values.\n\n## Getting started\n\n### 1. Install\n\n`pitchfork` is on [crates.io](https://crates.io/crates/haybale-pitchfork), under\nthe name `haybale-pitchfork`. You can add it as a dependency in your\n`Cargo.toml`, selecting the feature corresponding to the LLVM version you want:\n\n```toml\n[dependencies]\nhaybale-pitchfork = { version = \"0.4.1\", features = [\"llvm-12\"] }\n```\n\nCurrently, the supported LLVM versions are `llvm-9`, `llvm-10`, `llvm-11`, and\n`llvm-12`.\n\nIf you want to use the name `pitchfork` instead of `haybale_pitchfork` in\nyour code, you can use Cargo's [dependency renaming] feature:\n\n```toml\n[dependencies]\npitchfork = { package = \"haybale-pitchfork\", version = \"0.4.1\", features = [\"llvm-12\"] }\n```\n\nBecause it is built on [`haybale`], `pitchfork` also depends (indirectly) on\nthe LLVM and Boolector libraries, which must both be available on your\nsystem.\nSee the [`llvm-sys`] or [`boolector-sys`] READMEs for more details and\ninstructions.\n\n### 2. Acquire bitcode to analyze\n\nSince `pitchfork` operates on LLVM bitcode, you'll need some bitcode to get\nstarted.\nIf the program or function you want to analyze is written in C, you can\ngenerate LLVM bitcode (`*.bc` files) with `clang`'s `-c` and `-emit-llvm`\nflags:\n\n```bash\nclang -c -emit-llvm source.c -o source.bc\n```\n\nFor debugging purposes, you may also want LLVM text-format (`*.ll`) files,\nwhich you can generate with `clang`'s `-S` and `-emit-llvm` flags:\n\n```bash\nclang -S -emit-llvm source.c -o source.ll\n```\n\nIf the program or function you want to analyze is written in Rust, you can\nlikewise use `rustc`'s `--emit=llvm-bc` and `--emit=llvm-ir` flags.\n\nNote that in order for `pitchfork` to print source-location information\n(e.g., source filename and line number) for constant-time violations and\nother errors, the LLVM bitcode will need to include debuginfo.\nYou can ensure debuginfo is included by passing the `-g` flag to `clang`,\n`clang++`, or `rustc` when generating bitcode.\n\n### 3. Create a Project\n\nA `Project` contains all of the code currently being analyzed, which may be\none or more LLVM modules.\nTo get started, simply create a `Project` from a single bitcode file:\n\n```rust\nlet project = Project::from_bc_path(\u0026Path::new(\"/path/to/file.bc\"))?;\n```\n\nFor more ways to create `Project`s, including analyzing entire libraries, see\nthe [`Project` documentation].\n\n### 4. Check a function for constant-time violations\n\nLet's suppose we want to check for constant-time violations in the following\nC function:\n\n```c\nint foo(int x) {\n    if (x \u003e 10) {\n        return x % 200 * 3;\n    } else {\n        return x + 10;\n    }\n}\n```\n\nWe can use [`check_for_ct_violation_in_inputs()`] to analyze this function,\nconsidering all of its inputs (in this case just `x`) to be secret:\n\n```rust\nlet result = check_for_ct_violation_in_inputs(\"foo\", \u0026project, Config::default(), \u0026PitchforkConfig::default());\n```\n\nand then pretty-print the result of the analysis:\n\n```rust\nprintln!(\"{}\", result);\n```\n\nSince `x` influences a branch condition, `pitchfork` reports a constant-time\nviolation.\n\n## User Guide: Analyzing Functions\n\nIn the \"Getting Started\" example above, we used\n[`check_for_ct_violation_in_inputs()`], which considers all inputs to the\nfunction to be secret.\nHowever, sometimes some inputs are public and others secret.\nOr sometimes we have arguments which are pointers to secret data, or the\nsecret data is hidden deep inside a struct.\n\nThe more general function [`check_for_ct_violation()`] takes two additional\narguments which aid in annotating data as public or secret: `args` and `sd`.\nIn this section we'll walk through analyzing some more examples of functions,\nshowing more ways to annotate public and secret data.\n\n### Specifying some function arguments as public\n\nConsider this C function:\n\n```c\nint ct(int x, int y, int option) {\n    volatile int z[3] = { 0, 2, 300 };\n    z[2] = y;\n    if (option \u003e 3) {\n        return z[1];\n    } else {\n        return z[2];\n    }\n}\n```\n\nIf we analyze this function using [`check_for_ct_violation_in_inputs()`],\nwe'll see a constant-time violation, since the `option` argument is used in a\nbranch condition:\n\n```rust\nprintln!(\"{}\", check_for_ct_violation_in_inputs(\"ct\", \u0026project, Config::default(), \u0026PitchforkConfig::default()));\n```\n\nHowever, let's suppose the `option` argument to this function actually\njust denotes some configuration option and shouldn't be considered secret.\nWe can communicate this to `pitchfork` by using the `args` argument to\nthe more general function [`check_for_ct_violation()`].\n\nEach element of the `args` iterator describes the corresponding argument to\n`ct()`.\nThe elements of `args` are of type [`AbstractData`]; there's a lot of\ndifferent options for how we could describe the argument, but let's focus on\nthe two most basic ones:\n\n- `AbstractData::default()` is the most important option. It uses the\ninformation in the `StructDescriptions` and the type information in the\nLLVM bitcode to automatically generate an appropriate description for the\nargument. We'll discuss `StructDescriptions` in more detail later; for now,\nall that's important is that unless the `StructDescriptions` say differently,\nanything marked `default()` will be considered _public_.\n- `AbstractData::secret()` is the easiest way to mark an argument secret.\nIt uses the type information in the LLVM bitcode to automatically generate\nan appropriate description for the argument based on its size, this time\nmarking it secret. Note that this may not work how you want if the argument\nis a pointer; see the section on pointer arguments below.\n\nFor the function `ct()` above, we can analyze it using the following argument\ndescriptions:\n\n```rust\nprintln!(\"{}\", check_for_ct_violation(\n    \"ct\",\n    \u0026project,\n    Some(vec![AbstractData::secret(), AbstractData::secret(), AbstractData::default()]),\n    \u0026StructDescriptions::new(),\n    Config::default(),\n    \u0026PitchforkConfig::default(),\n));\n```\n\nThis time, `pitchfork` should report that the function is constant-time.\n\n### Specifying particular values for some function arguments\n\nLet's consider the following slight variant of the `ct()` function above:\n\n```c\nint ct(int x, int y, int option) {\n    volatile int z[3] = { 0, 2, 300 };\n    z[2] = y;\n    if (option \u003e 3) {\n        return z[1];\n    } else {\n        return z[x % 3];\n    }\n}\n```\n\nIf we analyze this function with the annotations given above, `pitchfork` will\n(correctly) report a constant-time violation, because the `z[x % 3]` uses an\narray index which depends on secret data.\n\nBut, let's suppose we're only interested in analyzing the function in the case\nwhere the value of `option` is `5`.\nWe can express that using `AbstractData` like this:\n\n```rust\nprintln!(\"{}\", check_for_ct_violation(\n    \"ct\",\n    \u0026project,\n    Some(vec![\n        AbstractData::secret(),\n        AbstractData::secret(),\n        AbstractData::pub_i32(AbstractValue::ExactValue(5)),\n    ]),\n    \u0026StructDescriptions::new(),\n    Config::default(),\n    \u0026PitchforkConfig::default(),\n));\n```\n\nHere we used `AbstractData::pub_i32()` to specify a public 32-bit integer,\nand `AbstractValue::ExactValue(5)` to give that integer the exact value `5`.\nThis means that the analysis will only consider the case when the value of\nthat argument is `5`, and as a result, will report that there are no\nconstant-time violations in the function.\n\n`ExactValue` is also useful for when a function argument specifies something\nlike an input array length, and you only want to consider a particular array\nlength in the analysis.\nSee the docs on [`AbstractValue`] for more ways to specify argument values.\n\nAs a side note, notice that you can't specify the value of something marked\nsecret.\nThis is because the value of anything marked secret doesn't matter for the\nsymbolic analysis.\nIn fact, if the value of something marked secret would matter for the\nanalysis (e.g., for determining which paths were valid, or which address in\nmemory was loaded), that would already be a constant-time violation, as it\nwould mean a secret value had influenced a branch condition or memory\naddress.\n\n### Pointers to arrays of secret data\n\nLet's suppose we have a C function which takes a pointer to an array of 32\nsecret integers, and adds `1` to each element of the array:\n\n```c\nuint32_t secret_array(uint32_t* arr) {\n    for (int i = 0; i \u003c 32; i++) {\n        arr[i] += 1;\n    }\n    return arr[0];\n}\n```\n\nUsing `AbstractData::secret()` for `arr` might not work how you expect:\n\n```rust\nprintln!(\"{}\", check_for_ct_violation(\n    \"secret_array\",\n    \u0026project,\n    Some(vec![AbstractData::secret()]),\n    \u0026StructDescriptions::new(),\n    Config::default(),\n    \u0026PitchforkConfig::default(),\n));\n```\n\nThis function looks fine, but `pitchfork` will report a constant-time violation!\nThis is because it applies `secret` to the argument itself, which in this\ncase is a pointer.\nSince the pointer value `arr` is secret, the access `arr[i]` results in an\naddress which depends on the secret value of the pointer `arr`.\n\nInstead, we can tell `pitchfork` that `arr` itself (the pointer) is public, but\npoints to an array of secret data:\n```rust\nAbstractData::pub_pointer_to(AbstractData::array_of(AbstractData::secret(), 32))\n```\n\nWe'll also need to raise the \"loop bound\", which defaults to 10 as of this\nwriting. (For more details, see the [docs on\n`Config.loop_bound`](https://PLSysSec.github.io/haybale-pitchfork/haybale_pitchfork/struct.Config.html#structfield.loop_bound).)\n```rust\nlet mut config = Config::default();\nconfig.loop_bound = 100;\n// then pass this `config` to `check_for_ct_violation()`\n```\n\nNow, `pitchfork` should verify that the function is constant-time.\n\n### More constraints regarding arrays\n\nThe following C function takes pointers to two arrays: `public_arr` which\ncontains public values and has length `public_arr_len`, and `secret_arr`\nwhich contains secret values and has length 32.\nLet's suppose that `public_arr_len` and `i` are also public - the only secret\nvalues are the values in `secret_arr`.\n\n```c\nuint32_t secret_array_var_length(uint32_t* public_arr, uint32_t public_arr_len, uint32_t* secret_arr, uint32_t i) {\n    uint32_t x = public_arr[i];\n    for (int j = 0; j \u003c 32; j++) {\n        secret_arr[j] += x;\n    }\n    if (x \u003e 10) {\n        return public_arr[0] + secret_arr[0];\n    } else {\n        return public_arr[1] + secret_arr[1];\n    }\n}\n```\n\nIf we check this function for constant-time violations as-is, with these\nannotations...\n\n```rust\nprintln!(\"{}\", check_for_ct_violation(\n    \"secret_array_var_length\",\n    \u0026project,\n    Some(vec![\n        AbstractData::default(),\n        AbstractData::default(),\n        AbstractData::pub_pointer_to(AbstractData::array_of(AbstractData::secret(), 32)),\n        AbstractData::default(),\n    ]),\n    \u0026StructDescriptions::new(),\n    config,  // with loop_bound set to 100 as above\n    \u0026PitchforkConfig::default(),\n));\n```\n\n...we'll find that `pitchfork` reports a constant-time violation.\nSpecifically, if `i` is too large, `public_arr[i]` could actually load secret\ndata from `secret_arr` (off the end of `public_arr`), which is then used in a\nbranch condition.\n\nIn this case, the function is actually safe as long as callers pass an `i`\nwhich is in-bounds.\nTo analyze only the case where `i` is in-bounds, we can specify a maximum\nlength for `public_arr` (in this example, let's say 72 elements), and\nconstrain both `public_arr_len` and `i` to be within this maximum length:\n\n```rust\nprintln!(\"{}\", check_for_ct_violation(\n    \"secret_array_var_length\",\n    \u0026project,\n    Some(vec![\n        AbstractData::pub_pointer_to(AbstractData::array_of(AbstractData::default(), 72)),\n        AbstractData::pub_i32(AbstractValue::Range(0, 72)),\n        AbstractData::pub_pointer_to(AbstractData::array_of(AbstractData::secret(), 32)),\n        AbstractData::pub_i32(AbstractValue::Range(0, 71)),\n    ]),\n    \u0026StructDescriptions::new(),\n    config,  // with loop_bound set to 100 as above\n    \u0026PitchforkConfig::default(),\n));\n```\n\nWith these annotations, `pitchfork` will verify that the function is\nconstant-time, given these assumptions.\n\nNotice two more things about this function: first, we can choose a large maximum\nlength for `public_arr` without knowing what its actual length will be.\nAssuming a large size for arrays doesn't really harm anything: `pitchfork`\nwill \"allocate\" extra memory for the array, but that memory will go unused\nand (probably) not affect the analysis.\nSecond, the above analysis will still consider inputs where `i \u003e public_arr_len`;\nit just happens that the function above is still constant-time in these cases,\nsince we made the assumption that `i` is within the actual allocated size of\n`public_arr` (which is 72, despite `public_arr_len` being potentially smaller).\nIf we wanted to consider only those cases where additionally `i \u003c public_arr_len`,\nwe could use this for `public_arr_len`:\n```rust\nAbstractData::pub_i32(AbstractValue::named(\"public_arr_len\", AbstractValue::Range(0, 72)))\n```\nand this for `i`:\n```rust\nAbstractData::pub_i32(AbstractValue::UnsignedLessThan(\"public_arr_len\".into()))\n```\n\nYou might wonder what `pitchfork` assumed about `public_arr` in the first\nplace when we used `AbstractData::default()`. The answer is that it assumed\nan array of length `AbstractData::DEFAULT_ARRAY_LENGTH` (currently 1024 as of\nthis writing).\nFor more details on the precise behavior of `default()`, see the docs on\n[`AbstractData::default()`].\n\n### Structs containing secret data\n\nLet's consider this C function:\n\n```c\nuint32_t uses_a_struct(Context* ctx, uint32_t* public_input, uint32_t* public_output) {\n    for (int i = 0; i \u003c 32; i++) {\n        public_output[i] = public_input[i] ^ ctx-\u003esecret_key;\n    }\n    if (ctx-\u003epublic_option) {\n        return public_output[0];\n    } else {\n        return public_output[1];\n    }\n}\n```\nwhere the `Context` struct is defined as\n```c\ntypedef struct {\n    uint32_t public_option;\n    uint32_t another_thing;\n    uint32_t secret_key;\n} Context;\n```\n\nWe want to specify that the `ctx` argument points to a struct with some\nsecret data (`secret_key`) and some public data (`public_option`).\nWe can do this using `AbstractData::_struct`:\n```rust\nprintln!(\"{}\", check_for_ct_violation(\n    \"uses_a_struct\",\n    \u0026project,\n    Some(vec![\n        AbstractData::pub_pointer_to(AbstractData::_struct(\"Context\", vec![\n            AbstractData::default(),  // public_option\n            AbstractData::default(),  // another_thing\n            AbstractData::secret(),   // secret_key\n        ])),\n        AbstractData::default(),  // public_input\n        AbstractData::default(),  // public_output\n    ]),\n    \u0026StructDescriptions::new(),\n    config,  // with loop_bound set to 100 as above\n    \u0026PitchforkConfig::default(),\n));\n```\n\nWith this description, `pitchfork` should correctly report that the function\nis constant-time.\n\nAnother way to do the same thing---which is more useful if there are multiple\n`Context` structs floating around, or if there are other structs which contain\npointers to `Context` structs, etc---is via the `StructDescriptions`.\nWe can give `pitchfork` a description of the `Context` struct:\n```rust\nlet sd: StructDescriptions = vec![\n    (\"struct.Context\".into(), AbstractData::_struct(\"Context\", vec![\n        AbstractData::default(),  // public_option\n        AbstractData::default(),  // another_thing\n        AbstractData::secret(),   // secret_key\n    ])),\n].into_iter().collect();\n```\nThen, when we use `AbstractData::default()`, it will automatically take into\naccount the description of the `Context` struct which we give in the\n`StructDescriptions` argument:\n```rust\nprintln!(\"{}\", check_for_ct_violation(\n    \"uses_a_struct\",\n    \u0026project,\n    Some(vec![\n        AbstractData::default(),  // ctx\n        AbstractData::default(),  // public_input\n        AbstractData::default(),  // public_output\n    ]),\n    \u0026sd,\n    config,  // with loop_bound set to 100 as above\n    \u0026PitchforkConfig::default(),\n));\n```\n\nFurthermore, any other `Context` structs it encounters as part of the same or\nother arguments will also use this description.\n\n### Using Pitchfork's `main_func`\n\nPitchfork also provides a [`main_func()`] with numerous command-line options\nfor doing constant-time checking on a library of your choice.\nAll you have to do is provide your `Project`, `StructDescriptions`, `Config`,\netc, and then call `main_func()` in your own `main()`.\n\n[`haybale`]: https://github.com/PLSysSec/haybale\n[dependency renaming]: https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#renaming-dependencies-in-cargotoml\n[`llvm-sys`]: https://crates.io/crates/llvm-sys\n[`boolector-sys`]: https://crates.io/crates/boolector-sys\n[`Project` documentation]: https://docs.rs/haybale/0.7.1/haybale/project/struct.Project.html\n[`Project`]: https://docs.rs/haybale/0.7.1/haybale/project/struct.Project.html\n[`Config`]: https://docs.rs/haybale/0.7.1/haybale/config/struct.Config.html\n[`check_for_ct_violation_in_inputs()`]: https://docs.rs/haybale-pitchfork/0.4.1/haybale_pitchfork/fn.check_for_ct_violation_in_inputs.html\n[`check_for_ct_violation()`]: https://docs.rs/haybale-pitchfork/0.4.1/haybale_pitchfork/fn.check_for_ct_violation.html\n[`AbstractData`]: https://docs.rs/haybale-pitchfork/0.4.1/haybale_pitchfork/struct.AbstractData.html\n[`AbstractValue`]: https://docs.rs/haybale-pitchfork/0.4.1/haybale_pitchfork/enum.AbstractValue.html\n[`AbstractData::default()`]: https://docs.rs/haybale-pitchfork/0.4.1/haybale_pitchfork/struct.AbstractData.html#method.default\n[`main_func()`]: https://docs.rs/haybale-pitchfork/0.4.1/haybale_pitchfork/fn.main_func.html\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fplsyssec%2Fhaybale-pitchfork","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fplsyssec%2Fhaybale-pitchfork","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fplsyssec%2Fhaybale-pitchfork/lists"}