{"id":27968645,"url":"https://github.com/nethermindeth/halva","last_synced_at":"2025-05-07T21:05:54.809Z","repository":{"id":264519038,"uuid":"624723323","full_name":"NethermindEth/Halva","owner":"NethermindEth","description":null,"archived":false,"fork":false,"pushed_at":"2025-04-26T00:24:24.000Z","size":410,"stargazers_count":6,"open_issues_count":0,"forks_count":2,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-05-07T21:05:50.043Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/NethermindEth.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"license.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2023-04-07T05:30:10.000Z","updated_at":"2025-04-26T00:24:29.000Z","dependencies_parsed_at":"2024-11-24T20:36:59.058Z","dependency_job_id":"8ab318e3-34ae-4f21-81eb-56928e06d415","html_url":"https://github.com/NethermindEth/Halva","commit_stats":null,"previous_names":["nethermindeth/halo2-extractor","nethermindeth/halva"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NethermindEth%2FHalva","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NethermindEth%2FHalva/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NethermindEth%2FHalva/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NethermindEth%2FHalva/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/NethermindEth","download_url":"https://codeload.github.com/NethermindEth/Halva/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252954427,"owners_count":21830903,"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","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":"2025-05-07T21:05:54.244Z","updated_at":"2025-05-07T21:05:54.779Z","avatar_url":"https://github.com/NethermindEth.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"A brief tutorial\n---------------------\nTo extract a circuit into Lean4 one needs to write an extracting program first. It is a stand alone executable that depends on the circuit being extracted and the extraction library provided by this repository. It can be as simple as one `main.rs` file. Let us outline how one can write an extracting program.\n1. Import the necessary dependencies:\n```rust\nuse halo2_extr::{\n    // The extractor that constructs the circuit and generates Lean\n    extraction::ExtractingAssignment,\n    // Our symbolic field type\n    field::TermField\n};\nuse halo2_proofs::{\n    arithmetic::Field,\n    circuit::Value,\n    plonk::Circuit,\n};\n``` \n2. If we have a circuit of the form\n```rust\nstruct MyCircuit\u003cF: Field\u003e {\n    a: Value\u003cF\u003e,\n    b: Value\u003cF\u003e,\n    c: Value\u003cF\u003e,\n}\nimpl \u003cF: Field\u003e Circuit \u003cF\u003e for MyCircuit\u003cF\u003e {\n    ...\n}\n```\nwhere `a`, `b` and `c` are private inputs to the circuit we will assign them symbolic values\n```rust\nlet a = TermField::create_symbol(\"a\");\nlet b = TermField::create_symbol(\"b\");\nlet c = TermField::create_symbol(\"c\");\n```\nand instantiate the circuit\n```rust\nlet circuit = MyCircuit {\n    a: Value::known(a.into()),\n    b: Value::known(b.into()),\n    c: Value::known(c.into()),\n};\n```\nThese symbolic values will show up in the Lean as members of the circuit structure named `sym_a`, `sym_b`, and `sym_c` respectively.\n\n3. Finally, we run the extractor to generator Lean code.\n```rust\nExtractingAssignment::run(\n    \u0026circuit,\n    \"Tutorial.MyCircuit\", // The Lean namespace to create the circuit in\n    \u0026[\"a\", \"b\", \"c\"] // The names of any symbolic values\n).unwrap();\n```\nThe code will be output to stdout, so you will likely want to redirect it into a file in a Lean project. At the end of the output you will find `meets_constraints`, a proposition which asserts that all of the constraints hold for a given instantiation of the circuit.\n\nSeveral full examples can be found in the `examples` directory, and corresponding Lean proofs can be found in our repo [here](https://github.com/NethermindEth/halo2-fv).\n\n\n\nUnsafe features\n---------------------\nSome methods in Halo2's Field type return something concrete depending on the value of the field element. Because TermField is symbolic, it is not generally possible to make claims about its concrete value during Rust execution. Oftentimes making sure you only run constraint generation code and not witness generation code will avoid this, however sometimes this is not enough. For such cases we have the following features: `unsafe-equality`, `unsafe-ord`, `unsafe-invert`. These should only be used if you are sure the following behaviour will be correct for your circuit:\n\nUnsafe Equality\nIn general unsafe equality checks whether the two TermFields are exactly identical. Note that when the result of calculations on `TermField::Val` fit correctly in an i64 we evaluate them, but if they don't then the result is an unevaluated expression of the calculation. Additionally, the circuit's constraints may, for example, assert that a symbolic value x is always 0, but we won't know this in the Rust and so comparing x to 0 would produce false because they are not textually identical.\n\nUnsafe Ord\nFor similar reasons to above we cannot order TermFields based on value. If you absolutely require `Ord` or `PartialOrd` but are okay with the ordering being undefined and potentially unpredictable, `unsafe-ord` will cause the `cmp` and `partial_cmp` methods to always return `Less`, as opposed to panicking if the feature is not enabled.\n\nUnsafe Invert\nThe Field invert method returns a Choice depending on whether the input is 0. As described above, we cannot know definitively if a TermField is 0, so we default to always inverting the value. For totality, Lean's `inv` (which is what will be used for such expressions) returns 0 for an input of 0.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnethermindeth%2Fhalva","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnethermindeth%2Fhalva","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnethermindeth%2Fhalva/lists"}