what did i do?

This commit is contained in:
nganhkhoa 2024-06-18 20:57:54 +07:00
commit 9448b6f84b
16 changed files with 1907 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/target

580
Cargo.lock generated Normal file
View File

@ -0,0 +1,580 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "aho-corasick"
version = "0.7.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac"
dependencies = [
"memchr",
]
[[package]]
name = "ascii-canvas"
version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6"
dependencies = [
"term",
]
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi",
"libc",
"winapi",
]
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "bit-set"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1"
dependencies = [
"bit-vec",
]
[[package]]
name = "bit-vec"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "crunchy"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
[[package]]
name = "diff"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
[[package]]
name = "dirs-next"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1"
dependencies = [
"cfg-if",
"dirs-sys-next",
]
[[package]]
name = "dirs-sys-next"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d"
dependencies = [
"libc",
"redox_users",
"winapi",
]
[[package]]
name = "either"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797"
[[package]]
name = "ena"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7402b94a93c24e742487327a7cd839dc9d36fec9de9fb25b09f2dae459f36c3"
dependencies = [
"log",
]
[[package]]
name = "fixedbitset"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
[[package]]
name = "getrandom"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "hashbrown"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]]
name = "hermit-abi"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [
"libc",
]
[[package]]
name = "indexmap"
version = "1.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399"
dependencies = [
"autocfg",
"hashbrown",
]
[[package]]
name = "itertools"
version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
dependencies = [
"either",
]
[[package]]
name = "lalrpop"
version = "0.19.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b30455341b0e18f276fa64540aff54deafb54c589de6aca68659c63dd2d5d823"
dependencies = [
"ascii-canvas",
"atty",
"bit-set",
"diff",
"ena",
"itertools",
"lalrpop-util",
"petgraph",
"pico-args",
"regex",
"regex-syntax",
"string_cache",
"term",
"tiny-keccak",
"unicode-xid",
]
[[package]]
name = "lalrpop-util"
version = "0.19.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bcf796c978e9b4d983414f4caedc9273aa33ee214c5b887bd55fde84c85d2dc4"
dependencies = [
"regex",
]
[[package]]
name = "libc"
version = "0.2.138"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8"
[[package]]
name = "lock_api"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df"
dependencies = [
"autocfg",
"scopeguard",
]
[[package]]
name = "log"
version = "0.4.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
dependencies = [
"cfg-if",
]
[[package]]
name = "memchr"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]]
name = "modinverse"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f62f577f148cc1a9466e7065a22e59466a7d537cceba5e77e57181d0f706633"
dependencies = [
"num-integer",
]
[[package]]
name = "new_debug_unreachable"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
[[package]]
name = "num-integer"
version = "0.1.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
dependencies = [
"autocfg",
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
dependencies = [
"autocfg",
]
[[package]]
name = "once_cell"
version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
[[package]]
name = "parking_lot"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
dependencies = [
"lock_api",
"parking_lot_core",
]
[[package]]
name = "parking_lot_core"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ff9f3fef3968a3ec5945535ed654cb38ff72d7495a25619e2247fb15a2ed9ba"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"smallvec",
"windows-sys",
]
[[package]]
name = "petgraph"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6d5014253a1331579ce62aa67443b4a658c5e7dd03d4bc6d302b94474888143"
dependencies = [
"fixedbitset",
"indexmap",
]
[[package]]
name = "phf_shared"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096"
dependencies = [
"siphasher",
]
[[package]]
name = "pico-args"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db8bcd96cb740d03149cbad5518db9fd87126a10ab519c011893b1754134c468"
[[package]]
name = "polynomial"
version = "0.2.5"
dependencies = [
"modinverse",
"num-traits",
]
[[package]]
name = "precomputed-hash"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
[[package]]
name = "proc-macro2"
version = "1.0.47"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
dependencies = [
"proc-macro2",
]
[[package]]
name = "redox_syscall"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
dependencies = [
"bitflags",
]
[[package]]
name = "redox_users"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b"
dependencies = [
"getrandom",
"redox_syscall",
"thiserror",
]
[[package]]
name = "regex"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.6.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"
[[package]]
name = "rustversion"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97477e48b4cf8603ad5f7aaf897467cf42ab4218a38ef76fb14c2d6773a6d6a8"
[[package]]
name = "scopeguard"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "siphasher"
version = "0.3.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de"
[[package]]
name = "small-simple-snark"
version = "0.1.0"
dependencies = [
"lalrpop",
"lalrpop-util",
"modinverse",
"polynomial",
"regex",
]
[[package]]
name = "smallvec"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
[[package]]
name = "string_cache"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "213494b7a2b503146286049378ce02b482200519accc31872ee8be91fa820a08"
dependencies = [
"new_debug_unreachable",
"once_cell",
"parking_lot",
"phf_shared",
"precomputed-hash",
]
[[package]]
name = "syn"
version = "1.0.105"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b9b43d45702de4c839cb9b51d9f529c5dd26a4aff255b42b1ebc03e88ee908"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "term"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f"
dependencies = [
"dirs-next",
"rustversion",
"winapi",
]
[[package]]
name = "thiserror"
version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "tiny-keccak"
version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237"
dependencies = [
"crunchy",
]
[[package]]
name = "unicode-ident"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3"
[[package]]
name = "unicode-xid"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-sys"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e"
[[package]]
name = "windows_aarch64_msvc"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4"
[[package]]
name = "windows_i686_gnu"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7"
[[package]]
name = "windows_i686_msvc"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246"
[[package]]
name = "windows_x86_64_gnu"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028"
[[package]]
name = "windows_x86_64_msvc"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5"

16
Cargo.toml Normal file
View File

@ -0,0 +1,16 @@
[package]
name = "small-simple-snark"
version = "0.1.0"
edition = "2021"
author = "nganhkhoa"
build = "build.rs"
[dependencies]
lalrpop-util = { version = "0.19.8", features = ["lexer"] }
modinverse = "0.1.1"
polynomial = { path="polynomial-rs" }
regex = "1.7.0"
[build-dependencies]
lalrpop = "0.19.8"

5
build.rs Normal file
View File

@ -0,0 +1,5 @@
extern crate lalrpop;
fn main() {
lalrpop::process_root().unwrap();
}

7
examples/a.bsnark Normal file
View File

@ -0,0 +1,7 @@
a, b, c
d = a * a
e = b * b
f = c * c
f = d + e

15
polynomial-rs/.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,15 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: "github-actions" # See documentation for possible values
directory: "/" # Location of package manifests
schedule:
interval: "daily"
- package-ecosystem: "cargo" # See documentation for possible values
directory: "/" # Location of package manifests
schedule:
interval: "daily"

View File

@ -0,0 +1,118 @@
name: Rust CI
on: push
env:
CARGO_TERM_COLOR: always
jobs:
rustfmt_check:
name: Rustfmt Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
profile: minimal
components: rustfmt
override: true
- name: rustfmt-check
run: cargo fmt --all --check
clippy_check:
name: Clippy Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Check workflow permissions
id: check_permissions
uses: scherermichael-oss/action-has-permission@1.0.6
with:
required-permission: write
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Run clippy action to produce annotations
uses: actions-rs/clippy-check@v1
if: ${{ steps.check_permissions.outputs.has-permission }}
with:
# GitHub displays the clippy job and its results as separate entries
name: Clippy (stable) Results
token: ${{ secrets.GITHUB_TOKEN }}
args: --all-features --all-targets -- -D warnings
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
profile: minimal
components: clippy
override: true
- name: Run clippy manually without annotations
if: ${{ !steps.check_permissions.outputs.has-permission }}
run: cargo clippy --all-features --all-targets -- -D warnings
security_audit:
name: Security Audit
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions-rs/audit-check@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
test:
name: Test
runs-on: ubuntu-latest
strategy:
matrix:
rust:
- stable
- 1.56.1
steps:
- uses: actions/checkout@v3
- uses: actions-rs/toolchain@v1
with:
toolchain: ${{ matrix.rust }}
profile: minimal
override: true
- name: cargo test
run: cargo test --workspace --all-targets --all-features
build:
name: Build
runs-on: ubuntu-latest
strategy:
matrix:
rust:
- stable
- 1.56.1
steps:
- uses: actions/checkout@v3
- uses: actions-rs/toolchain@v1
with:
toolchain: ${{ matrix.rust }}
profile: minimal
override: true
- name: cargo build
run: cargo build --workspace --all-targets --all-features
coverage:
name: Code coverage
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
profile: minimal
override: true
components: llvm-tools-preview
- name: Install cargo-llvm-cov
uses: taiki-e/install-action@cargo-llvm-cov
- name: Generate code coverage
run: cargo llvm-cov --all-features --workspace --lcov --output-path lcov.info
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
files: lcov.info
fail_ci_if_error: true

2
polynomial-rs/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/target
/Cargo.lock

26
polynomial-rs/Cargo.toml Normal file
View File

@ -0,0 +1,26 @@
[package]
name = "polynomial"
version = "0.2.5"
edition = "2021"
rust-version = "1.56.1"
authors = ["gifnksm <makoto.nksm+github@gmail.com>"]
license = "MIT"
readme = "README.md"
repository = "https://github.com/gifnksm/polynomial-rs"
description = "A library for manipulating polynomials"
[badges]
maintenance = { status = "passively-maintained" }
[dependencies]
num-traits = "0.2"
serde = { version = "1.0", features = ["derive"], optional = true }
modinverse = "0.1.1"
[features]
serde = ["dep:serde"]
[package.metadata.release]
pre-release-replacements = [
{ file = "README.md", search = "polynomial = \"[0-9\\.]+\"", replace = "{{crate_name}} = \"{{version}}\"" }
]

22
polynomial-rs/LICENSE Normal file
View File

@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2015 NAKASHIMA, Makoto
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

30
polynomial-rs/README.md Normal file
View File

@ -0,0 +1,30 @@
# polynomial-rs
[![maintenance status: passively-maintained](https://img.shields.io/badge/maintenance-passively--maintained-yellowgreen.svg)](https://doc.rust-lang.org/cargo/reference/manifest.html#the-badges-section)
[![license](https://img.shields.io/crates/l/polynomial.svg)](LICENSE)
[![crates.io](https://img.shields.io/crates/v/polynomial.svg)](https://crates.io/crates/polynomial)
[![docs.rs](https://img.shields.io/docsrs/polynomial/latest)](https://docs.rs/polynomial/latest/)
[![rust 1.56.1+ badge](https://img.shields.io/badge/rust-1.56.1+-93450a.svg)](https://doc.rust-lang.org/cargo/reference/manifest.html#the-rust-version-field)
[![Rust CI](https://github.com/gifnksm/polynomial-rs/actions/workflows/rust-ci.yml/badge.svg)](https://github.com/gifnksm/polynomial-rs/actions/workflows/rust-ci.yml)
[![codecov](https://codecov.io/gh/gifnksm/polynomial-rs/branch/master/graph/badge.svg?token=0RxeiNjQNM)](https://codecov.io/gh/gifnksm/polynomial-rs)
A library for manipulating polynomials.
[Documentation](https://docs.rs/polynomial/latest/polynomial/)
## How to use?
Add this to your `Cargo.toml`:
```toml
[dependencies]
polynomial = "0.2.5"
```
## Minimum supported Rust version (MSRV)
The minimum supported Rust version is **Rust 1.56.1**.
At least the last 3 versions of stable Rust are supported at any given time.
While a crate is pre-release status (0.x.x) it may have its MSRV bumped in a patch release.
Once a crate has reached 1.x, any MSRV bump will be accompanied with a new minor version.

616
polynomial-rs/src/lib.rs Normal file
View File

@ -0,0 +1,616 @@
//! A library for manipulating polynomials.
#![warn(bad_style)]
#![warn(missing_docs)]
#![warn(trivial_casts)]
#![warn(trivial_numeric_casts)]
#![warn(unused)]
#![warn(unused_extern_crates)]
#![warn(unused_import_braces)]
#![warn(unused_qualifications)]
#![warn(unused_results)]
use num_traits::{FromPrimitive, One, Zero};
use std::ops::{Add, Div, Mul, Neg, Sub, Rem};
use std::{cmp, fmt};
/// A polynomial.
#[derive(Eq, PartialEq, Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Polynomial<T> {
data: Vec<T>,
}
impl<T: Zero> Polynomial<T> {
/// Creates a new `Polynomial` from a `Vec` of coefficients.
///
/// # Examples
///
/// ```
/// use polynomial::Polynomial;
/// let poly = Polynomial::new(vec![1, 2, 3]);
/// assert_eq!("1+2*x+3*x^2", poly.pretty("x"));
/// ```
#[inline]
pub fn new(mut data: Vec<T>) -> Self {
while let Some(true) = data.last().map(|x| x.is_zero()) {
let _ = data.pop();
}
Self { data }
}
}
impl<T> Polynomial<T>
where
T: One
+ Zero
+ Clone
+ Copy
+ Neg<Output = T>
+ Div<Output = T>
+ Mul<Output = T>
+ Sub<Output = T>
+ Rem<Output = T>
+ Ord
+ fmt::Display,
{
fn egcd(a: T, b: T) -> (T, T, T) {
if a == T::zero() {
(b, T::zero(), T::one())
}
else {
let (g, x, y) = Self::egcd(b % a, a);
(g, y - (b / a) * x, x)
}
}
fn modinverse(a: T, m: T) -> Option<T> {
let (g, x, _) = Self::egcd(a, m);
if g != T::one() {
None
}
else {
Some((x % m + m) % m)
}
}
/// Creates the [Lagrange polynomial] that fits a number of points.
///
/// [Lagrange polynomial]: https://en.wikipedia.org/wiki/Lagrange_polynomial
///
/// Returns `None` if any two x-coordinates are the same.
///
/// # Examples
///
/// ```
/// use polynomial::Polynomial;
/// let poly = Polynomial::lagrange(&[1, 2, 3], &[10, 40, 90]).unwrap();
/// println!("{}", poly.pretty("x"));
/// assert_eq!("10*x^2", poly.pretty("x"));
/// ```
#[inline]
pub fn lagrange(xs: &[T], ys: &[T], field: Option<&T>) -> Option<Self> {
let mut res = Polynomial::new(vec![Zero::zero()]);
for ((i, x), y) in (0..).zip(xs.iter()).zip(ys.iter()) {
let mut p: Polynomial<T> = Polynomial::new(vec![T::one()]);
let mut denom = T::one();
let mut negative = false;
for (j, x2) in (0..).zip(xs.iter()) {
if i != j {
p = p * &Polynomial::new(vec![-x2.clone(), T::one()]);
let diff = if x < x2 {
x2.clone() - x.clone()
} else {
x.clone() - x2.clone()
};
if diff.is_zero() {
return None;
}
negative = !(negative ^ (x < x2));
denom = denom * diff;
}
}
let scalar = match field {
Some(f) => {
let denom_inv = Self::modinverse(denom, f.clone()).unwrap();
if negative {
- y.clone() * denom_inv
} else {
y.clone() * denom_inv
}
},
None => {
if negative {
- y.clone() / denom
} else {
y.clone() / denom
}
}
};
println!("{}/{} = {}", y.to_string(), denom.to_string(), scalar);
res = res + p * &Polynomial::<T>::new(vec![scalar]);
}
Some(res)
}
}
impl<T> Polynomial<T>
where
T: One
+ Zero
+ Clone
+ Copy
+ Neg<Output = T>
+ Div<Output = T>
+ Mul<Output = T>
+ Sub<Output = T>
+ Rem<Output = T>
+ Ord
+ FromPrimitive
+ fmt::Display,
{
/// [Chebyshev approximation] fits a function to a polynomial over a range of values.
///
/// [Chebyshev approximation]: https://en.wikipedia.org/wiki/Approximation_theory#Chebyshev_approximation
///
/// This attempts to minimize the maximum error.
///
/// Retrurns `None` if `n < 1` or `xmin >= xmax`.
///
/// # Examples
///
/// ```
/// use polynomial::Polynomial;
/// use std::f64::consts::PI;
/// let p = Polynomial::chebyshev(&f64::sin, 7, -PI/4., PI/4.).unwrap();
/// assert!((p.eval(0.) - (0.0_f64).sin()).abs() < 0.0001);
/// assert!((p.eval(0.1) - (0.1_f64).sin()).abs() < 0.0001);
/// assert!((p.eval(-0.1) - (-0.1_f64).sin()).abs() < 0.0001);
/// ```
#[inline]
pub fn chebyshev<F: Fn(T) -> T>(f: &F, n: usize, xmin: f64, xmax: f64) -> Option<Self> {
if n < 1 || xmin >= xmax {
return None;
}
let mut xs = Vec::new();
for i in 0..n {
use std::f64::consts::PI;
let x = T::from_f64(
(xmax + xmin) * 0.5
+ (xmin - xmax) * 0.5 * ((2 * i + 1) as f64 * PI / (2 * n) as f64).cos(),
)
.unwrap();
xs.push(x);
}
let ys: Vec<T> = xs.iter().map(|x| f(x.clone())).collect();
Polynomial::lagrange(&xs[0..], &ys[0..], None)
}
}
impl<T: Zero + Mul<Output = T> + Clone> Polynomial<T> {
/// Evaluates the polynomial at a point.
///
/// # Examples
///
/// ```
/// use polynomial::Polynomial;
/// let poly = Polynomial::new(vec![1, 2, 3]);
/// assert_eq!(1, poly.eval(0));
/// assert_eq!(6, poly.eval(1));
/// assert_eq!(17, poly.eval(2));
/// ```
#[inline]
pub fn eval(&self, x: T) -> T {
let mut result: T = Zero::zero();
for n in self.data.iter().rev() {
result = n.clone() + result * x.clone();
}
result
}
}
impl<T> Polynomial<T> {
/// Gets the slice of internal data.
#[inline]
pub fn data(&self) -> &[T] {
&self.data
}
}
impl<T> Polynomial<T>
where
T: Zero + One + Eq + Neg<Output = T> + Ord + fmt::Display + Clone,
{
/// Pretty prints the polynomial.
pub fn pretty(&self, x: &str) -> String {
if self.is_zero() {
return "0".to_string();
}
let one = One::one();
let mut s = Vec::new();
for (i, n) in self.data.iter().enumerate() {
// output n*x^i / -n*x^i
if n.is_zero() {
continue;
}
let term = if i.is_zero() {
n.to_string()
} else if i == 1 {
if (*n) == one {
x.to_string()
} else if (*n) == -one.clone() {
format!("-{}", x)
} else {
format!("{}*{}", n, x)
}
} else if (*n) == one {
format!("{}^{}", x, i)
} else if (*n) == -one.clone() {
format!("-{}^{}", x, i)
} else {
format!("{}*{}^{}", n, x, i)
};
if !s.is_empty() && (*n) > Zero::zero() {
s.push("+".to_string());
}
s.push(term);
}
s.concat()
}
}
impl<T> Neg for Polynomial<T>
where
T: Neg + Zero + Clone,
<T as Neg>::Output: Zero,
{
type Output = Polynomial<<T as Neg>::Output>;
#[inline]
fn neg(self) -> Polynomial<<T as Neg>::Output> {
-&self
}
}
impl<'a, T> Neg for &'a Polynomial<T>
where
T: Neg + Zero + Clone,
<T as Neg>::Output: Zero,
{
type Output = Polynomial<<T as Neg>::Output>;
#[inline]
fn neg(self) -> Polynomial<<T as Neg>::Output> {
Polynomial::new(self.data.iter().map(|x| -x.clone()).collect())
}
}
macro_rules! forward_val_val_binop {
(impl $imp:ident, $method:ident) => {
impl<Lhs, Rhs> $imp<Polynomial<Rhs>> for Polynomial<Lhs>
where
Lhs: Zero + $imp<Rhs> + Clone,
Rhs: Zero + Clone,
<Lhs as $imp<Rhs>>::Output: Zero,
{
type Output = Polynomial<<Lhs as $imp<Rhs>>::Output>;
#[inline]
fn $method(self, other: Polynomial<Rhs>) -> Polynomial<<Lhs as $imp<Rhs>>::Output> {
(&self).$method(&other)
}
}
};
}
macro_rules! forward_ref_val_binop {
(impl $imp:ident, $method:ident) => {
impl<'a, Lhs, Rhs> $imp<Polynomial<Rhs>> for &'a Polynomial<Lhs>
where
Lhs: Zero + $imp<Rhs> + Clone,
Rhs: Zero + Clone,
<Lhs as $imp<Rhs>>::Output: Zero,
{
type Output = Polynomial<<Lhs as $imp<Rhs>>::Output>;
#[inline]
fn $method(self, other: Polynomial<Rhs>) -> Polynomial<<Lhs as $imp<Rhs>>::Output> {
self.$method(&other)
}
}
};
}
macro_rules! forward_val_ref_binop {
(impl $imp:ident, $method:ident) => {
impl<'a, Lhs, Rhs> $imp<&'a Polynomial<Rhs>> for Polynomial<Lhs>
where
Lhs: Zero + $imp<Rhs> + Clone,
Rhs: Zero + Clone,
<Lhs as $imp<Rhs>>::Output: Zero,
{
type Output = Polynomial<<Lhs as $imp<Rhs>>::Output>;
#[inline]
fn $method(self, other: &Polynomial<Rhs>) -> Polynomial<<Lhs as $imp<Rhs>>::Output> {
(&self).$method(other)
}
}
};
}
macro_rules! forward_all_binop {
(impl $imp:ident, $method:ident) => {
forward_val_val_binop!(impl $imp, $method);
forward_ref_val_binop!(impl $imp, $method);
forward_val_ref_binop!(impl $imp, $method);
};
}
forward_all_binop!(impl Add, add);
impl<'a, 'b, Lhs, Rhs> Add<&'b Polynomial<Rhs>> for &'a Polynomial<Lhs>
where
Lhs: Zero + Add<Rhs> + Clone,
Rhs: Zero + Clone,
<Lhs as Add<Rhs>>::Output: Zero,
{
type Output = Polynomial<<Lhs as Add<Rhs>>::Output>;
fn add(self, other: &Polynomial<Rhs>) -> Polynomial<<Lhs as Add<Rhs>>::Output> {
let max_len = cmp::max(self.data.len(), other.data.len());
let min_len = cmp::min(self.data.len(), other.data.len());
let mut sum = Vec::with_capacity(max_len);
for i in 0..min_len {
sum.push(self.data[i].clone() + other.data[i].clone());
}
if self.data.len() <= other.data.len() {
for i in min_len..max_len {
sum.push(num_traits::zero::<Lhs>() + other.data[i].clone());
}
} else {
for i in min_len..max_len {
sum.push(self.data[i].clone() + num_traits::zero::<Rhs>());
}
}
Polynomial::new(sum)
}
}
forward_all_binop!(impl Sub, sub);
impl<'a, 'b, Lhs, Rhs> Sub<&'b Polynomial<Rhs>> for &'a Polynomial<Lhs>
where
Lhs: Zero + Sub<Rhs> + Clone,
Rhs: Zero + Clone,
<Lhs as Sub<Rhs>>::Output: Zero,
{
type Output = Polynomial<<Lhs as Sub<Rhs>>::Output>;
fn sub(self, other: &Polynomial<Rhs>) -> Polynomial<<Lhs as Sub<Rhs>>::Output> {
let min_len = cmp::min(self.data.len(), other.data.len());
let max_len = cmp::max(self.data.len(), other.data.len());
let mut sub = Vec::with_capacity(max_len);
for i in 0..min_len {
sub.push(self.data[i].clone() - other.data[i].clone());
}
if self.data.len() <= other.data.len() {
for i in min_len..max_len {
sub.push(num_traits::zero::<Lhs>() - other.data[i].clone())
}
} else {
for i in min_len..max_len {
sub.push(self.data[i].clone() - num_traits::zero::<Rhs>())
}
}
Polynomial::new(sub)
}
}
forward_all_binop!(impl Mul, mul);
impl<'a, 'b, Lhs, Rhs> Mul<&'b Polynomial<Rhs>> for &'a Polynomial<Lhs>
where
Lhs: Zero + Mul<Rhs> + Clone,
Rhs: Zero + Clone,
<Lhs as Mul<Rhs>>::Output: Zero,
{
type Output = Polynomial<<Lhs as Mul<Rhs>>::Output>;
fn mul(self, other: &Polynomial<Rhs>) -> Polynomial<<Lhs as Mul<Rhs>>::Output> {
if self.is_zero() || other.is_zero() {
return Polynomial::new(vec![]);
}
let slen = self.data.len();
let olen = other.data.len();
let prod = (0..slen + olen - 1)
.map(|i| {
let mut p = num_traits::zero::<<Lhs as Mul<Rhs>>::Output>();
let kstart = cmp::max(olen, i + 1) - olen;
let kend = cmp::min(slen, i + 1);
for k in kstart..kend {
p = p + self.data[k].clone() * other.data[i - k].clone();
}
p
})
.collect();
Polynomial::new(prod)
}
}
impl<T: Zero + Clone> Zero for Polynomial<T> {
#[inline]
fn zero() -> Self {
Self { data: vec![] }
}
#[inline]
fn is_zero(&self) -> bool {
self.data.is_empty()
}
}
impl<T: Zero + One + Clone> One for Polynomial<T> {
#[inline]
fn one() -> Self {
Self {
data: vec![One::one()],
}
}
}
#[cfg(test)]
mod tests {
use super::Polynomial;
#[test]
fn new() {
fn check(dst: Vec<i32>, src: Vec<i32>) {
assert_eq!(dst, Polynomial::new(src).data);
}
check(vec![1, 2, 3], vec![1, 2, 3]);
check(vec![1, 2, 3], vec![1, 2, 3, 0, 0]);
check(vec![], vec![0, 0, 0]);
}
#[test]
fn neg_add_sub() {
fn check(a: &[i32], b: &[i32], c: &[i32]) {
fn check_eq(a: &Polynomial<i32>, b: &Polynomial<i32>) {
assert_eq!(*a, *b);
assert_eq!(-a, -b);
}
fn check_add(sum: &Polynomial<i32>, a: &Polynomial<i32>, b: &Polynomial<i32>) {
check_eq(sum, &(a + b));
check_eq(sum, &(b + a));
}
fn check_sub(sum: &Polynomial<i32>, a: &Polynomial<i32>, b: &Polynomial<i32>) {
check_eq(a, &(sum - b));
check_eq(b, &(sum - a));
}
let a = &Polynomial::new(a.to_vec());
let b = &Polynomial::new(b.to_vec());
let c = &Polynomial::new(c.to_vec());
check_add(c, a, b);
check_add(&(-c), &(-a), &(-b));
check_sub(c, a, b);
check_sub(&(-c), &(-a), &(-b));
}
check(&[], &[], &[]);
check(&[], &[1], &[1]);
check(&[1], &[1], &[2]);
check(&[1, 0, 1], &[1], &[2, 0, 1]);
check(&[1, 0, -1], &[-1, 0, 1], &[]);
}
#[test]
fn mul() {
fn check(a: &[i32], b: &[i32], c: &[i32]) {
let a = Polynomial::new(a.to_vec());
let b = Polynomial::new(b.to_vec());
let c = Polynomial::new(c.to_vec());
assert_eq!(c, &a * &b);
assert_eq!(c, &b * &a);
}
check(&[], &[], &[]);
check(&[0, 0], &[], &[]);
check(&[0, 0], &[1], &[]);
check(&[1, 0], &[1], &[1]);
check(&[1, 0, 1], &[1], &[1, 0, 1]);
check(&[1, 1], &[1, 1], &[1, 2, 1]);
check(&[1, 1], &[1, 0, 1], &[1, 1, 1, 1]);
check(&[0, 0, 1], &[0, 0, 1], &[0, 0, 0, 0, 1]);
}
#[test]
fn eval() {
fn check<F: Fn(i32) -> i32>(pol: &[i32], f: F) {
for n in -10..10 {
assert_eq!(f(n), Polynomial::new(pol.to_vec()).eval(n));
}
}
check(&[], |_x| 0);
check(&[1], |_x| 1);
check(&[1, 1], |x| x + 1);
check(&[0, 1], |x| x);
check(&[10, -10, 10], |x| 10 * x * x - 10 * x + 10);
}
#[test]
fn pretty() {
fn check(slice: &[i32], s: &str) {
assert_eq!(s.to_string(), Polynomial::new(slice.to_vec()).pretty("x"));
}
check(&[0], "0");
check(&[1], "1");
check(&[1, 1], "1+x");
check(&[1, 1, 1], "1+x+x^2");
check(&[2, 2, 2], "2+2*x+2*x^2");
check(&[0, 0, 0, 1], "x^3");
check(&[0, 0, 0, -1], "-x^3");
check(&[-1, 0, 0, -1], "-1-x^3");
check(&[-1, 1, 0, -1], "-1+x-x^3");
check(&[-1, 1, -1, -1], "-1+x-x^2-x^3");
}
#[test]
fn lagrange() {
// Evaluate the lagrange polynomial at the x coordinates.
// The error should be close to zero.
fn check(xs: &[f64], ys: &[f64]) {
let p = Polynomial::lagrange(xs, ys).unwrap();
for (x, y) in xs.iter().zip(ys) {
assert!((p.eval(*x) - y).abs() < 1e-9);
}
}
// Squares
check(&[1., 2., 3.], &[10., 40., 90.]);
// Cubes
check(&[-1., 0., 1., 2.], &[-1000., 0., 1000., 8000.]);
// Non linear x.
check(&[1., 9., 10., 11.], &[1., 2., 3., 4.]);
// Test double x failure case.
assert_eq!(
Polynomial::lagrange(&[1., 9., 9., 11.], &[1., 2., 3., 4.]),
None
);
}
#[test]
fn chebyshev() {
// Construct a Chebyshev approximation for a function
// and evaulate it at 100 points.
fn check<F: Fn(f64) -> f64>(f: &F, n: usize, xmin: f64, xmax: f64) {
let p = Polynomial::chebyshev(f, n, xmin, xmax).unwrap();
for i in 0..=100 {
let x = xmin + (i as f64) * ((xmax - xmin) / 100.0);
let diff = (f(x) - p.eval(x)).abs();
assert!(diff < 0.0001);
}
}
// Approximate some common functions.
use std::f64::consts::PI;
check(&f64::sin, 7, -PI / 2., PI / 2.);
check(&f64::cos, 7, 0., PI / 4.);
// Test n >= 1 condition
assert!(Polynomial::chebyshev(&f64::exp, 0, 0., 1.) == None);
// Test xmax > xmin condition
assert!(Polynomial::chebyshev(&f64::ln, 1, 1., 0.) == None);
}
}

41
src/ast.rs Normal file
View File

@ -0,0 +1,41 @@
#[derive(Debug)]
pub struct Constraints<'input> {
pub iden: Operand<'input>,
pub expr: Expr<'input>,
}
impl<'input> Constraints<'input> {
pub fn new(iden: Operand<'input>, expr: Expr<'input>) -> Self {
Self {
iden, expr
}
}
}
#[derive(Debug)]
pub struct Expr<'input> {
pub left: Operand<'input>,
pub right: Operand<'input>,
pub op: Opcode,
}
impl<'input> Expr<'input> {
pub fn new(left: Operand<'input>, op: Opcode, right: Operand<'input>) -> Self {
Self {
left, right, op
}
}
}
#[derive(Debug)]
pub enum Operand<'input> {
Identifier(&'input str),
Num(&'input str),
}
#[derive(Debug)]
pub enum Opcode {
Add,
Mul,
}

37
src/bsnark.lalrpop Normal file
View File

@ -0,0 +1,37 @@
use crate::ast::{Expr, Constraints, Opcode, Operand};
grammar;
pub Declaration: Vec<Operand<'input>> = {
<s:(Iden ",")*> <i:Iden> => {
let mut s: Vec<Operand<'input>> = s.into_iter().map(|x| x.0).collect();
s.push(i);
s
},
};
pub Constraints: Box<Constraints<'input>> = {
<i:Iden> "=" <e:Expr> => Box::new(Constraints::new(i, e))
};
pub Expr: Expr<'input> = {
Operand ExprOp Operand => Expr::new(<>),
};
Operand: Operand<'input> = {
Iden,
Num,
};
Iden: Operand<'input> = {
r"[a-zA-Z][0-9a-zA-Z]*" => Operand::Identifier(<>),
};
Num: Operand<'input> = {
r"[0-9]+" => Operand::Num(<>),
};
ExprOp: Opcode = {
"+" => Opcode::Add,
"*" => Opcode::Mul,
};

165
src/field.rs Normal file
View File

@ -0,0 +1,165 @@
use std::fmt;
use modinverse::modinverse;
pub struct G1 {
p: u64,
x: u64,
y: u64,
}
impl fmt::Display for G1 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "({}, {}) in F_{}", self.x, self.y, self.p)
}
}
impl fmt::Debug for G1 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "({}, {}) in F_{}", self.x, self.y, self.p)
}
}
impl G1 {
pub fn new(p: u64, x: u64, y: u64) -> Self {
G1 {
p, x, y
}
}
pub fn add(self: &mut Self, other: &G1) {
let yp = &self.y;
let yq = &other.y;
let xp = &self.x;
let xq = &other.x;
if *xq == 0 && *yq == 0 {
return;
}
if *xp == 0 && *yp == 0 {
self.x = *xq;
self.y = *yq;
return;
}
if yp == yq && xp == xq {
self.double();
return;
}
let p = &self.p;
let xq_xp = xq + (p - xp);
let yq_yp = yq + (p - yp);
if xq_xp == *p {
self.x = 0;
self.y = 0;
return;
}
let xq_xp_inv = modinverse(xq_xp as i64, *p as i64).unwrap();
let lambda = (yq_yp * xq_xp_inv as u64) % p;
let xr = (lambda * lambda + (p - xp) + (p - xq)) % p;
let yr = (lambda * (xp + (p - xr)) + (p - yp)) % p;
self.x = xr;
self.y = yr;
}
pub fn double(self: &mut Self) {
let x = &self.x;
let y = &self.y;
let p = &self.p;
let y2_inv = modinverse((2 * y) as i64, *p as i64).unwrap();
let m = (3 * x * x * y2_inv as u64) % p;
let m2 = (m * m) % p;
let x_new = (m2 + (p - ((2 * x) % p))) % p;
let y_new = (m * (3 * x + (p - m2)) + (p - y)) % p;
self.x = x_new;
self.y = y_new;
}
pub fn mul(self: &mut Self, times: u64) {
let mut g = self.clone();
let mut count = times;
let mut res = G1::new(self.p, 0, 0);
while count != 0 {
if count & 1 == 1 {
res.add(&g);
}
g.double();
count = count >> 1;
}
self.x = res.x;
self.y = res.y;
println!("{}", self);
}
pub fn inv(self: Self) -> Self {
Self {
p: self.p,
x: self.x,
y: self.p - self.y,
}
}
pub fn clone(self: &Self) -> Self {
Self {
p: self.p,
x: self.x,
y: self.y,
}
}
}
#[test]
fn test_double() {
let mut g1 = G1::new(101, 1, 2);
println!("g1 = {}", g1);
g1.double();
println!("2g1 = {}", g1);
}
#[test]
fn test_0add() {
let g1 = G1::new(101, 1, 2);
let mut inf = G1::new(101, 0, 0);
inf.add(&g1);
println!("O+g1 = {}", inf);
}
#[test]
fn test_add0() {
let mut g1 = G1::new(101, 1, 2);
let inf = G1::new(101, 0, 0);
g1.add(&inf);
println!("g1+O = {}", g1);
}
#[test]
fn test_mul() {
let mut g1 = G1::new(101, 1, 2);
println!("g1 = {}", g1);
let x = 121;
g1.mul(x);
println!("{}g1 = {}g1 = {}", x, x % 17, g1);
}
#[test]
fn test_add() {
let mut g1 = G1::new(101, 1, 2);
println!("g1 = {}", g1);
g1.mul(7);
println!("7g1 = {}", g1);
}

226
src/main.rs Normal file
View File

@ -0,0 +1,226 @@
#[macro_use]
extern crate lalrpop_util;
lalrpop_mod!(pub bsnark);
pub mod ast;
pub mod field;
use ast::{Operand, Constraints};
use std::collections::HashMap;
use std::vec::Vec;
use std::{env, fs};
use std::error::Error;
use polynomial::Polynomial;
#[derive(Debug)]
struct Context<'a> {
content: &'a str,
inputs: Vec<Operand<'a>>,
outputs: Vec<Operand<'a>>,
publics: Vec<Operand<'a>>,
constraints: Vec<Constraints<'a>>,
}
impl<'a> Context<'a> {
fn new(content: &'a str, inputs: Vec<Operand<'a>>, outputs: Vec<Operand<'a>>, publics: Vec<Operand<'a>>) -> Self {
Self {
content,
inputs,
outputs,
publics,
constraints: Vec::new(),
}
}
fn add_constraint(&mut self, constraint: Constraints<'a>) {
self.constraints.push(constraint);
}
fn make_trace(&mut self, input_values: Vec<u64>) {
// building gates
let mut q_left: Vec<i64> = Vec::new();
let mut q_right: Vec<i64> = Vec::new();
let mut q_output: Vec<i64> = Vec::new();
let mut q_mul: Vec<i64> = Vec::new();
let mut q_const: Vec<i64> = Vec::new();
let mut a_values: Vec<i64> = Vec::new();
let mut b_values: Vec<i64> = Vec::new();
let mut c_values: Vec<i64> = Vec::new();
let mut values_map: HashMap<String, u64> = HashMap::new();
for (i, input) in self.inputs.iter().enumerate() {
match input {
Operand::Identifier(id) => {
values_map.insert(id.to_string(), input_values[i]);
}
_ => {}
}
}
println!("{:?}", values_map);
// let mut execution_trace = ExecutionTrace::new(inputs, input_values);
let polynomials = self.constraints
.iter()
.enumerate()
.for_each(|(idx, Constraints { expr, iden })| {
let left_value = match &expr.left {
Operand::Identifier(id) => {
values_map[&id.to_string()]
},
Operand::Num(n) => {
n.parse::<u64>().unwrap()
}
};
let right_value = match &expr.right {
Operand::Identifier(id) => {
values_map[&id.to_string()]
},
Operand::Num(n) => {
n.parse::<u64>().unwrap()
}
};
let assigned_var = match iden {
Operand::Identifier(id) => id.to_string(),
_ => "".into(),
};
let eval_value = match &expr.op {
ast::Opcode::Mul => {
q_mul.push(1);
q_left.push(0);
q_right.push(0);
q_output.push(-1);
q_const.push(0);
left_value * right_value
},
ast::Opcode::Add => {
q_mul.push(0);
q_left.push(1);
q_right.push(1);
q_output.push(-1);
q_const.push(0);
left_value + right_value
},
};
a_values.push(left_value as i64);
b_values.push(right_value as i64);
c_values.push(eval_value as i64);
match values_map.get(&assigned_var) {
Some(value) => {
assert!(*value == eval_value,
"constraint {}: expecting {} equals {}\n{:?} = {:?}",
idx, value, left_value * right_value,
iden, expr,);
},
None => {
values_map.insert(assigned_var, eval_value);
}
}
});
println!("values {:?}", values_map);
println!("q_mul {:?}", q_mul);
println!("q_left {:?}", q_left);
println!("q_right {:?}", q_right);
println!("q_output {:?}", q_output);
println!("q_const {:?}", q_const);
println!("a_values {:?}", a_values);
println!("b_values {:?}", b_values);
println!("c_values {:?}", c_values);
let nroot = vec![1, 4, 16, 13];
let field = 17;
let a_poly = Polynomial::lagrange(&nroot, &a_values, Some(&field)).unwrap();
println!("{}", a_poly.pretty("x"));
}
}
fn main() -> Result<(), Box<dyn Error>>{
let args: Vec<String> = env::args().collect();
let content = fs::read_to_string(&args[1]).unwrap();
let mut lines = content.split("\n");
// first 3 lines declares the inputs/outputs/publics
let inputs = lines.next().ok_or("1st line must provide a list of inputs")?;
let outputs = lines.next().ok_or("2nd line must provide a list of outputs")?;
let publics = lines.next().ok_or("3rd line must provide a list of publics")?;
let inputs = if inputs.is_empty() {
Vec::new()
} else {
bsnark::DeclarationParser::new().parse(inputs).unwrap()
};
let outputs = if outputs.is_empty() {
Vec::new()
} else {
bsnark::DeclarationParser::new().parse(outputs).unwrap()
};
let publics = if publics.is_empty() {
Vec::new()
} else {
bsnark::DeclarationParser::new().parse(publics).unwrap()
};
let mut context = Context::new(&content, inputs, outputs, publics);
lines
.fold(&mut context, |ctx, line| {
if line.is_empty() {
return ctx;
}
let constraint = bsnark::ConstraintsParser::new().parse(line).unwrap();
println!("{:?}", constraint);
ctx.add_constraint(*constraint);
ctx
});
println!("{:?}", context);
// setup
//
// curve y^2 = x^3 + 3 (mod 101)
// G1 (1, 2)
// G2 (36, 31u) (complex number, u^2 = -2)
// toxic waste s = 2 (randomly generated)
//
// SRS = [G1, sG1, s^2 G1, s^3 G1, ...., s^(n+2) G1, G2, sG2]
// where n is the number of gates
//
// gates: QL a + QR b + QO c + QM a * b + QC = 0
// therefore, we have n = 4 (QLeft, QRight, QOutput, QMultiply) (QConstant is not counted)
let s = 2u64;
let mut srs: Vec<field::G1> = Vec::new();
for i in 0..=6 {
let mut g1 = field::G1::new(101, 1, 2);
g1.mul(s.pow(i));
srs.push(g1)
}
println!("{:?}", srs);
context.make_trace(vec![3, 4, 5]);
let a = vec![14, 6, 3, 3, 4, 7];
let a = a.iter().enumerate().fold(field::G1::new(101, 0, 0), |acc, (i, coeff)| {
let mut point = srs[i].clone();
point.mul(*coeff);
point.add(&acc);
point
});
println!("[a(s)]_1 = {}", a);
Ok(())
}