diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml new file mode 100644 index 00000000..b8d2cc7b --- /dev/null +++ b/.github/actions/setup/action.yml @@ -0,0 +1,46 @@ +name: 'Setup' +inputs: + rust-version: + description: 'The version of Rust to use in cache keys' + required: true + protoc-version: + description: 'The version of protoc to use in cache keys' + default: '28.2' + required: false +runs: + using: 'composite' + steps: + - name: Cache cargo registry + uses: actions/cache@v4 + with: + path: ~/.cargo/registry + key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}-${{ inputs.rust-version }} + - name: Cache cargo index + uses: actions/cache@v4 + with: + path: ~/.cargo/git + key: ${{ runner.os }}-cargo-index-${{ hashFiles('**/Cargo.lock') }}-${{ inputs.rust-version }} + - name: Cache cargo target + uses: actions/cache@v4 + with: + path: target + key: ${{ runner.os }}-cargo-target-${{ hashFiles('**/Cargo.lock') }}-${{ inputs.rust-version }} + - name: Create protoc directory + run: mkdir -p ~/protoc + shell: bash + - name: Cache protoc + id: cache-protoc + uses: actions/cache@v4 + with: + path: ~/protoc + key: ${{ runner.os }}-protoc-${{ inputs.protoc-version }} + - name: Install protoc + if: steps.cache-protoc.outputs.cache-hit != 'true' + run: | + curl -L -o protoc.zip https://github.com/protocolbuffers/protobuf/releases/download/v${{ inputs.protoc-version }}/protoc-${{ inputs.protoc-version }}-linux-x86_64.zip + unzip protoc.zip -d ~/protoc + rm protoc.zip + shell: bash + - name: Add protoc to PATH + run: echo "$HOME/protoc/bin" >> $GITHUB_PATH + shell: bash diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml new file mode 100644 index 00000000..d285054c --- /dev/null +++ b/.github/workflows/coverage.yml @@ -0,0 +1,33 @@ +name: Coverage + +on: + push: + branches: [ "main" ] + pull_request: + +env: + CARGO_TERM_COLOR: always + +jobs: + All: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Get Rust version + id: rust-version + run: echo "rust_version=$(rustc --version)" >> "$GITHUB_OUTPUT" + - name: Run setup + uses: ./.github/actions/setup + with: + rust-version: ${{ steps.rust-version.outputs.rust_version}} + - name: Install cargo-llvm-cov + uses: taiki-e/install-action@cargo-llvm-cov + - name: Generate coverage report + run: cargo llvm-cov --all-features --workspace --lcov --output-path lcov.info + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v4 + with: + files: lcov.info + fail_ci_if_error: true + token: ${{ secrets.CODECOV_TOKEN }} diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 00000000..270b132d --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,24 @@ +name: Publish + +on: + push: + branches: [ "main" ] + +jobs: + All: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Get Rust version + id: rust-version + run: echo "rust_version=$(rustc --version)" >> "$GITHUB_OUTPUT" + - name: Run setup + uses: ./.github/actions/setup + with: + rust-version: ${{ steps.rust-version.outputs.rust_version}} + - name: Publish types + run: cargo publish --manifest-path types/Cargo.toml + continue-on-error: true + env: + CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 00000000..1a3c57a4 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,77 @@ +name: Tests + +on: + push: + branches: [ "main" ] + pull_request: + +env: + CARGO_TERM_COLOR: always + UDEPS_VERSION: 0.1.50 + +jobs: + All: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Get Rust version + id: rust-version + run: echo "rust_version=$(rustc --version)" >> "$GITHUB_OUTPUT" + - name: Run setup + uses: ./.github/actions/setup + with: + rust-version: ${{ steps.rust-version.outputs.rust_version}} + - name: Lint + run: cargo clippy --all-targets --all-features -- -D warnings + - name: Fmt + run: cargo fmt --all -- --check + - name: Check docs + run: cargo doc --no-deps --document-private-items + env: + RUSTDOCFLAGS: "-D warnings" + - name: Run tests + run: cargo test --verbose + + Dependencies: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Install nightly Rust toolchain + run: rustup toolchain install nightly + - name: Get Rust version + id: rust-version + run: echo "rust_version=$(rustc +nightly --version)" >> "$GITHUB_OUTPUT" + - name: Run setup + uses: ./.github/actions/setup + with: + rust-version: ${{ steps.rust-version.outputs.rust_version}} + - name: Cache cargo-udeps + id: cargo-udeps-cache + uses: actions/cache@v4 + with: + path: ~/.cargo/bin/cargo-udeps + key: ${{ runner.os }}-${{ env.UDEPS_VERSION }}-cargo-udeps-${{ steps.rust-version.outputs.rust_version }} + - name: Install cargo-udeps + if: steps.cargo-udeps-cache.outputs.cache-hit != 'true' + run: cargo +nightly install cargo-udeps --version ${{ env.UDEPS_VERSION }} + - name: Check for unused dependencies + run: cargo +nightly udeps --all-targets + + WASM: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Get Rust version + id: rust-version + run: echo "rust_version=$(rustc --version)" >> "$GITHUB_OUTPUT" + - name: Run setup + uses: ./.github/actions/setup + with: + rust-version: ${{ steps.rust-version.outputs.rust_version}} + - name: Add WASM target + run: rustup target add wasm32-unknown-unknown + - name: Build types + run: cargo build --target wasm32-unknown-unknown --release --manifest-path types/Cargo.toml && du -h target/wasm32-unknown-unknown/release/alto_types.wasm diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..03bb25b2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*.swp +*.DS_Store +/target +*.vscode \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 00000000..94864f01 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,1250 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "alto-types" +version = "0.0.1" +dependencies = [ + "bytes", + "commonware-cryptography", + "commonware-utils", + "getrandom 0.2.15", + "rand", + "thiserror 2.0.12", +] + +[[package]] +name = "anyhow" +version = "1.0.97" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[package]] +name = "bitflags" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "blst" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47c79a94619fade3c0b887670333513a67ac28a6a7e653eb260bf0d4103db38d" +dependencies = [ + "cc", + "glob", + "threadpool", + "zeroize", +] + +[[package]] +name = "bumpalo" +version = "3.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" + +[[package]] +name = "cc" +version = "1.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c" +dependencies = [ + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "commonware-cryptography" +version = "0.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b84d40bcad0d5851ccb1358bb204556717db7316ce5ebc3a0c22e80df20ed5a" +dependencies = [ + "blst", + "bytes", + "commonware-utils", + "ed25519-consensus", + "getrandom 0.2.15", + "p256", + "prost-build", + "rand", + "rayon", + "sha2 0.10.8", + "thiserror 2.0.12", + "zeroize", +] + +[[package]] +name = "commonware-utils" +version = "0.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa92ca35aa551d03ed702c694913afb5ff67fde88aaad2ffc175a411ab2c1d" +dependencies = [ + "bytes", + "futures", + "prost", + "thiserror 2.0.12", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "curve25519-dalek-ng" +version = "4.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c359b7249347e46fb28804470d071c921156ad62b3eef5d34e2ba867533dec8" +dependencies = [ + "byteorder", + "digest 0.9.0", + "rand_core", + "subtle-ng", + "zeroize", +] + +[[package]] +name = "der" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" +dependencies = [ + "const-oid", + "pem-rfc7468", + "zeroize", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer 0.10.4", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest 0.10.7", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + +[[package]] +name = "ed25519-consensus" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c8465edc8ee7436ffea81d21a019b16676ee3db267aa8d5a8d729581ecf998b" +dependencies = [ + "curve25519-dalek-ng", + "hex", + "rand_core", + "serde", + "sha2 0.9.9", + "thiserror 1.0.69", + "zeroize", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest 0.10.7", + "ff", + "generic-array", + "group", + "pem-rfc7468", + "pkcs8", + "rand_core", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "rand_core", + "subtle", +] + +[[package]] +name = "fixedbitset" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" + +[[package]] +name = "futures" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-executor" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[package]] +name = "futures-macro" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.13.3+wasi-0.2.2", + "windows-targets", +] + +[[package]] +name = "glob" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core", + "subtle", +] + +[[package]] +name = "hashbrown" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "indexmap" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + +[[package]] +name = "js-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "libc" +version = "0.2.170" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "875b3680cb2f8f71bdcf9a30f38d48282f5d3c95cbf9b3fa57269bb5d5c06828" + +[[package]] +name = "linux-raw-sys" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db9c683daf087dc577b7506e9695b3d556a9f3849903fa28186283afd6809e9" + +[[package]] +name = "log" +version = "0.4.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "multimap" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03" + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "once_cell" +version = "1.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e" + +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "p256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2 0.10.8", +] + +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + +[[package]] +name = "petgraph" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772" +dependencies = [ + "fixedbitset", + "indexmap", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "prettyplease" +version = "0.2.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1ccf34da56fc294e7d4ccf69a85992b7dfb826b7cf57bac6a70bba3494cc08a" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve", +] + +[[package]] +name = "proc-macro2" +version = "1.0.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "prost" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-build" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be769465445e8c1474e9c5dac2018218498557af32d9ed057325ec9a41ae81bf" +dependencies = [ + "heck", + "itertools", + "log", + "multimap", + "once_cell", + "petgraph", + "prettyplease", + "prost", + "prost-types", + "regex", + "syn", + "tempfile", +] + +[[package]] +name = "prost-derive" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "prost-types" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52c2c1bf36ddb1a1c396b3601a3cec27c2462e45f07c386894ec3ccf5332bd16" +dependencies = [ + "prost", +] + +[[package]] +name = "quote" +version = "1.0.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1f1914ce909e1658d9907913b4b91947430c7d9be598b15a1912935b8c04801" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.15", +] + +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[package]] +name = "rustix" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dade4812df5c384711475be5fcd8c162555352945401aed22a35bffeab61f657" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "serde" +version = "1.0.218" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8dfc9d19bdbf6d17e22319da49161d5d0108e4188e8b680aef6299eed22df60" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.218" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f09503e191f4e797cb8aac08e9a4a4695c5edf6a2e70e376d961ddd5c969f82b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest 0.10.7", + "rand_core", +] + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "subtle-ng" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "734676eb262c623cec13c3155096e08d1f8f29adce39ba17948b18dad1e54142" + +[[package]] +name = "syn" +version = "2.0.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e02e925281e18ffd9d640e234264753c43edc62d64b2d4cf898f1bc5e75f3fc2" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tempfile" +version = "3.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c317e0a526ee6120d8dabad239c8dadca62b24b6f168914bbbc8e2fb1f0e567" +dependencies = [ + "cfg-if", + "fastrand", + "getrandom 0.3.1", + "once_cell", + "rustix", + "windows-sys", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +dependencies = [ + "thiserror-impl 2.0.12", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "threadpool" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" +dependencies = [ + "num_cpus", +] + +[[package]] +name = "typenum" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasi" +version = "0.13.3+wasi-0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" +dependencies = [ + "wit-bindgen-rt", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +dependencies = [ + "cfg-if", + "once_cell", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "wit-bindgen-rt" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" +dependencies = [ + "bitflags", +] + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 00000000..bf083af5 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,47 @@ +[workspace] +members = [ + "types", +] +resolver = "2" + +[workspace.dependencies] +alto-types = { version = "0.0.1", path = "types" } +commonware-consensus = { version = "0.0.14" } +commonware-cryptography = { version = "0.0.25" } +commonware-macros = { version = "0.0.16" } +commonware-p2p = { version = "0.0.36" } +commonware-resolver = { version = "0.0.5" } +commonware-runtime = { version = "0.0.22" } +commonware-storage = { version = "0.0.17" } +commonware-stream = { version = "0.0.14" } +commonware-utils = { version = "0.0.17" } +thiserror = "2.0.12" +bytes = "1.7.1" +rand = "0.8.5" +prost = "0.13.5" +prost-build = "0.13.5" +futures = "0.3.31" +futures-util = "0.3.31" +tracing = "0.1.41" +tracing-subscriber = "0.3.19" +governor = "0.6.3" +prometheus-client = "0.22.3" + +[profile.bench] +# Because we enable overflow checks in "release," we should benchmark with them. +overflow-checks = true + +[profile.dev] +# Although overflow checks are enabled by default in "dev", we explicitly +# enable them here for clarity. +overflow-checks = true + +[profile.release] +# To guard against unexpected behavior in production, we enable overflow checks in +# "release" although they incur some performance penalty. +overflow-checks = true + +[profile.test] +# Although overflow checks are enabled by default in "test", we explicitly +# enable them here for clarity. +overflow-checks = true diff --git a/LICENSE-APACHE b/LICENSE-APACHE new file mode 100644 index 00000000..e5268c58 --- /dev/null +++ b/LICENSE-APACHE @@ -0,0 +1,178 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + Copyright (c) 2025 Commonware, Inc. + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS \ No newline at end of file diff --git a/LICENSE-MIT b/LICENSE-MIT new file mode 100644 index 00000000..21092130 --- /dev/null +++ b/LICENSE-MIT @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Commonware, Inc. + +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. \ No newline at end of file diff --git a/README.md b/README.md index 1510c1ab..76e3ee11 100644 --- a/README.md +++ b/README.md @@ -1 +1,17 @@ # alto + +[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE-MIT) +[![License: Apache 2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](./LICENSE-APACHE) +[![codecov](https://codecov.io/gh/commonwarexyz/alto/graph/badge.svg?token=Y2A6Q5G25W)](https://codecov.io/gh/commonwarexyz/alto) + +## Components + +* [types](./types/README.md): Common types used throughout `alto`. + +## Licensing + +This repository is dual-licensed under both the [Apache 2.0](./LICENSE-APACHE) and [MIT](./LICENSE-MIT) licenses. You may choose either license when employing this code. + +## Support + +If you have any questions about `alto`, we encourage you to post in [GitHub Discussions](https://github.com/commonwarexyz/monorepo/discussions). We're happy to help! \ No newline at end of file diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 00000000..57ebe304 --- /dev/null +++ b/codecov.yml @@ -0,0 +1,18 @@ +comment: + layout: "header, diff, files, footer" + behavior: new + require_changes: false + require_head: false + require_base: false + hide_project_coverage: false + +coverage: + status: + patch: + default: + threshold: 0.25% + only_pulls: true + project: + default: + threshold: 0.25% + only_pulls: true diff --git a/types/Cargo.toml b/types/Cargo.toml new file mode 100644 index 00000000..d2419c64 --- /dev/null +++ b/types/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "alto-types" +version = "0.0.1" +publish = true +edition = "2021" +license = "MIT OR Apache-2.0" +description = "Common types used throughout alto." +readme = "README.md" +homepage = "https://alto.commonware.xyz" +repository = "https://github.com/commonwarexyz/alto/tree/main/types" +documentation = "https://docs.rs/alto-types" + +[lib] +crate-type = ["rlib", "cdylib"] + +[dependencies] +commonware-cryptography = { workspace = true } +commonware-utils = { workspace = true } +bytes = { workspace = true } +rand = { workspace = true } +thiserror = { workspace = true } + +# Enable "js" feature when WASM is target +[target.'cfg(target_arch = "wasm32")'.dependencies.getrandom] +version = "0.2.15" +features = ["js"] diff --git a/types/README.md b/types/README.md new file mode 100644 index 00000000..94eae99a --- /dev/null +++ b/types/README.md @@ -0,0 +1,10 @@ +# alto-types + +[![Crates.io](https://img.shields.io/crates/v/alto-types.svg)](https://crates.io/crates/alto-types) +[![Docs.rs](https://docs.rs/alto-types/badge.svg)](https://docs.rs/alto-types) + +Common types used throughout `alto`. + +## Status + +`alto-types` is **ALPHA** software and is not yet recommended for production use. Developers should expect breaking changes and occasional instability. \ No newline at end of file diff --git a/types/src/block.rs b/types/src/block.rs new file mode 100644 index 00000000..f86afe30 --- /dev/null +++ b/types/src/block.rs @@ -0,0 +1,139 @@ +use crate::{Finalization, Notarization}; +use bytes::{Buf, BufMut}; +use commonware_cryptography::{bls12381::PublicKey, sha256::Digest, Hasher, Sha256}; +use commonware_utils::{Array, SizedSerialize}; + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Block { + /// The parent block's digest. + pub parent: Digest, + + /// The height of the block in the blockchain. + pub height: u64, + + /// The timestamp of the block (in milliseconds since the Unix epoch). + pub timestamp: u64, + + /// Pre-computed digest of the block. + digest: Digest, +} + +impl Block { + fn compute_digest(parent: &Digest, height: u64, timestamp: u64) -> Digest { + let mut hasher = Sha256::new(); + hasher.update(parent); + hasher.update(&height.to_be_bytes()); + hasher.update(×tamp.to_be_bytes()); + hasher.finalize() + } + + pub fn new(parent: Digest, height: u64, timestamp: u64) -> Self { + let digest = Self::compute_digest(&parent, height, timestamp); + Self { + parent, + height, + timestamp, + digest, + } + } + + pub fn serialize(&self) -> Vec { + let mut bytes = Vec::with_capacity(Self::SERIALIZED_LEN); + bytes.extend_from_slice(&self.parent); + bytes.put_u64(self.height); + bytes.put_u64(self.timestamp); + bytes + } + + pub fn deserialize(mut bytes: &[u8]) -> Option { + // Parse the block + if bytes.len() != Self::SERIALIZED_LEN { + return None; + } + let parent = Digest::read_from(&mut bytes).ok()?; + let height = bytes.get_u64(); + let timestamp = bytes.get_u64(); + + // Return block + let digest = Self::compute_digest(&parent, height, timestamp); + Some(Self { + parent, + height, + timestamp, + digest, + }) + } + + pub fn digest(&self) -> Digest { + self.digest.clone() + } +} + +impl SizedSerialize for Block { + const SERIALIZED_LEN: usize = + Digest::SERIALIZED_LEN + u64::SERIALIZED_LEN + u64::SERIALIZED_LEN; +} + +pub struct Notarized { + pub proof: Notarization, + pub block: Block, +} + +impl Notarized { + pub fn new(proof: Notarization, block: Block) -> Self { + Self { proof, block } + } + + pub fn serialize(&self) -> Vec { + let block = self.block.serialize(); + let mut bytes = Vec::with_capacity(Notarization::SERIALIZED_LEN + block.len()); + bytes.extend_from_slice(&self.proof.serialize()); + bytes.extend_from_slice(&block); + bytes + } + + pub fn deserialize(public: Option<&PublicKey>, bytes: &[u8]) -> Option { + // Deserialize the proof and block + let (proof, block) = bytes.split_at_checked(Notarization::SERIALIZED_LEN)?; + let proof = Notarization::deserialize(public, proof)?; + let block = Block::deserialize(block)?; + + // Ensure the proof is for the block + if proof.payload != block.digest() { + return None; + } + Some(Self { proof, block }) + } +} + +pub struct Finalized { + pub proof: Finalization, + pub block: Block, +} + +impl Finalized { + pub fn new(proof: Finalization, block: Block) -> Self { + Self { proof, block } + } + + pub fn serialize(&self) -> Vec { + let block = self.block.serialize(); + let mut bytes = Vec::with_capacity(Finalization::SERIALIZED_LEN + block.len()); + bytes.extend_from_slice(&self.proof.serialize()); + bytes.extend_from_slice(&block); + bytes + } + + pub fn deserialize(public: Option<&PublicKey>, bytes: &[u8]) -> Option { + // Deserialize the proof and block + let (proof, block) = bytes.split_at_checked(Finalization::SERIALIZED_LEN)?; + let proof = Finalization::deserialize(public, proof)?; + let block = Block::deserialize(block)?; + + // Ensure the proof is for the block + if proof.payload != block.digest() { + return None; + } + Some(Self { proof, block }) + } +} diff --git a/types/src/consensus.rs b/types/src/consensus.rs new file mode 100644 index 00000000..ca2b357b --- /dev/null +++ b/types/src/consensus.rs @@ -0,0 +1,297 @@ +use bytes::{Buf, BufMut}; +use commonware_cryptography::sha256::Digest; +use commonware_cryptography::{bls12381, Bls12381, Scheme}; +use commonware_utils::{hex, Array, SizedSerialize}; + +// We don't use functions here to guard against silent changes. +pub const NAMESPACE: &[u8] = b"_ALTO"; +pub const SEED_NAMESPACE: &[u8] = b"_ALTO_SEED"; +pub const NOTARIZE_NAMESPACE: &[u8] = b"_ALTO_NOTARIZE"; +pub const NULLIFY_NAMESPACE: &[u8] = b"_ALTO_NULLIFY"; +pub const FINALIZE_NAMESPACE: &[u8] = b"_ALTO_FINALIZE"; + +// We hardcode the keys here to guard against silent changes. +#[repr(u8)] +pub enum Kind { + Seed = 0, + Notarization = 1, + Nullification = 2, + Finalization = 3, +} + +impl Kind { + pub fn from_u8(value: u8) -> Option { + match value { + 0 => Some(Self::Seed), + 1 => Some(Self::Notarization), + 2 => Some(Self::Nullification), + 3 => Some(Self::Finalization), + _ => None, + } + } + + pub fn to_hex(&self) -> String { + match self { + Self::Seed => hex(&[0]), + Self::Notarization => hex(&[1]), + Self::Nullification => hex(&[2]), + Self::Finalization => hex(&[3]), + } + } +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Seed { + pub view: u64, + pub signature: bls12381::Signature, +} + +impl Seed { + pub fn payload(view: u64) -> Vec { + let mut bytes = Vec::with_capacity(u64::SERIALIZED_LEN); + bytes.put_u64(view); + bytes + } + + fn pack(view: u64, signature: &bls12381::Signature) -> Vec { + let mut bytes = Vec::with_capacity(Self::SERIALIZED_LEN); + bytes.put_u64(view); + bytes.extend_from_slice(signature); + bytes + } + + pub fn new(view: u64, signature: bls12381::Signature) -> Self { + Self { view, signature } + } + + pub fn serialize(&self) -> Vec { + Self::pack(self.view, &self.signature) + } + + pub fn deserialize(public: Option<&bls12381::PublicKey>, mut bytes: &[u8]) -> Option { + // Check if the length is correct + if bytes.len() != Self::SERIALIZED_LEN { + return None; + } + + // Deserialize the block proof + let view = bytes.get_u64(); + let signature = bls12381::Signature::read_from(&mut bytes).ok()?; + + // Verify the signature + if let Some(public) = public { + let message = Self::payload(view); + if !Bls12381::verify(Some(SEED_NAMESPACE), &message, public, &signature) { + return None; + } + } + Some(Self { view, signature }) + } +} + +impl SizedSerialize for Seed { + const SERIALIZED_LEN: usize = u64::SERIALIZED_LEN + bls12381::Signature::SERIALIZED_LEN; +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Notarization { + pub view: u64, + pub parent: u64, + pub payload: Digest, + pub signature: bls12381::Signature, +} + +impl Notarization { + pub fn payload(view: u64, parent: u64, payload: &Digest) -> Vec { + let mut bytes = + Vec::with_capacity(u64::SERIALIZED_LEN + u64::SERIALIZED_LEN + Digest::SERIALIZED_LEN); + bytes.put_u64(view); + bytes.put_u64(parent); + bytes.extend_from_slice(payload); + bytes + } + + fn pack(view: u64, parent: u64, payload: &Digest, signature: &bls12381::Signature) -> Vec { + let mut bytes = Vec::with_capacity(Self::SERIALIZED_LEN); + bytes.put_u64(view); + bytes.put_u64(parent); + bytes.extend_from_slice(payload); + bytes.extend_from_slice(signature); + bytes + } + + pub fn new(view: u64, parent: u64, payload: Digest, signature: bls12381::Signature) -> Self { + Self { + view, + parent, + payload, + signature, + } + } + + pub fn serialize(&self) -> Vec { + Self::pack(self.view, self.parent, &self.payload, &self.signature) + } + + pub fn deserialize(public: Option<&bls12381::PublicKey>, mut bytes: &[u8]) -> Option { + // Check if the length is correct + if bytes.len() != Self::SERIALIZED_LEN { + return None; + } + + // Deserialize the block proof + let view = bytes.get_u64(); + let parent = bytes.get_u64(); + let payload = Digest::read_from(&mut bytes).ok()?; + let signature = bls12381::Signature::read_from(&mut bytes).ok()?; + + // Verify the signature + if let Some(public) = public { + let message = Self::payload(view, parent, &payload); + if !Bls12381::verify(Some(NOTARIZE_NAMESPACE), &message, public, &signature) { + return None; + } + } + Some(Self { + view, + parent, + payload, + signature, + }) + } +} + +impl SizedSerialize for Notarization { + const SERIALIZED_LEN: usize = u64::SERIALIZED_LEN + + u64::SERIALIZED_LEN + + Digest::SERIALIZED_LEN + + bls12381::Signature::SERIALIZED_LEN; +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Nullification { + pub view: u64, + pub signature: bls12381::Signature, +} + +impl Nullification { + pub fn payload(view: u64) -> Vec { + let mut bytes = Vec::with_capacity(u64::SERIALIZED_LEN); + bytes.put_u64(view); + bytes + } + + fn pack(view: u64, signature: &bls12381::Signature) -> Vec { + let mut bytes = Vec::with_capacity(Self::SERIALIZED_LEN); + bytes.put_u64(view); + bytes.extend_from_slice(signature); + bytes + } + + pub fn new(view: u64, signature: bls12381::Signature) -> Self { + Self { view, signature } + } + + pub fn serialize(&self) -> Vec { + Self::pack(self.view, &self.signature) + } + + pub fn deserialize(public: Option<&bls12381::PublicKey>, mut bytes: &[u8]) -> Option { + // Check if the length is correct + if bytes.len() != Self::SERIALIZED_LEN { + return None; + } + + // Deserialize the block proof + let view = bytes.get_u64(); + let signature = bls12381::Signature::read_from(&mut bytes).ok()?; + + // Verify the signature + if let Some(public) = public { + let message = Self::payload(view); + if !Bls12381::verify(Some(NULLIFY_NAMESPACE), &message, public, &signature) { + return None; + } + } + Some(Self { view, signature }) + } +} + +impl SizedSerialize for Nullification { + const SERIALIZED_LEN: usize = u64::SERIALIZED_LEN + bls12381::Signature::SERIALIZED_LEN; +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Finalization { + pub view: u64, + pub parent: u64, + pub payload: Digest, + pub signature: bls12381::Signature, +} + +impl Finalization { + pub fn payload(view: u64, parent: u64, payload: &Digest) -> Vec { + let mut bytes = + Vec::with_capacity(u64::SERIALIZED_LEN + u64::SERIALIZED_LEN + Digest::SERIALIZED_LEN); + bytes.put_u64(view); + bytes.put_u64(parent); + bytes.extend_from_slice(payload); + bytes + } + + fn pack(view: u64, parent: u64, payload: &Digest, signature: &bls12381::Signature) -> Vec { + let mut bytes = Vec::with_capacity(Self::SERIALIZED_LEN); + bytes.put_u64(view); + bytes.put_u64(parent); + bytes.extend_from_slice(payload); + bytes.extend_from_slice(signature); + bytes + } + + pub fn new(view: u64, parent: u64, payload: Digest, signature: bls12381::Signature) -> Self { + Self { + view, + parent, + payload, + signature, + } + } + + pub fn serialize(&self) -> Vec { + Self::pack(self.view, self.parent, &self.payload, &self.signature) + } + + pub fn deserialize(public: Option<&bls12381::PublicKey>, mut bytes: &[u8]) -> Option { + // Check if the length is correct + if bytes.len() != Self::SERIALIZED_LEN { + return None; + } + + // Deserialize the block proof + let view = bytes.get_u64(); + let parent = bytes.get_u64(); + let payload = Digest::read_from(&mut bytes).ok()?; + let signature = bls12381::Signature::read_from(&mut bytes).ok()?; + + // Verify the signature + if let Some(public) = public { + let message = Self::payload(view, parent, &payload); + if !Bls12381::verify(Some(FINALIZE_NAMESPACE), &message, public, &signature) { + return None; + } + } + Some(Self { + view, + parent, + payload, + signature, + }) + } +} + +impl SizedSerialize for Finalization { + const SERIALIZED_LEN: usize = u64::SERIALIZED_LEN + + u64::SERIALIZED_LEN + + Digest::SERIALIZED_LEN + + bls12381::Signature::SERIALIZED_LEN; +} diff --git a/types/src/lib.rs b/types/src/lib.rs new file mode 100644 index 00000000..eb6d33ca --- /dev/null +++ b/types/src/lib.rs @@ -0,0 +1,203 @@ +//! Common types used throughout `alto`. + +mod block; +pub use block::{Block, Finalized, Notarized}; +mod consensus; +pub use consensus::{ + Finalization, Kind, Notarization, Nullification, Seed, FINALIZE_NAMESPACE, NAMESPACE, + NOTARIZE_NAMESPACE, NULLIFY_NAMESPACE, SEED_NAMESPACE, +}; + +#[cfg(test)] +mod tests { + use super::*; + use commonware_cryptography::{hash, Bls12381, Scheme}; + use rand::{rngs::StdRng, SeedableRng}; + + #[test] + fn test_seed() { + // Create network key + let mut rng = StdRng::seed_from_u64(0); + let mut network = Bls12381::new(&mut rng); + + // Create seed + let view = 0; + let seed_payload = Seed::payload(view); + let seed_signature = network.sign(Some(SEED_NAMESPACE), &seed_payload); + let seed = Seed::new(view, seed_signature); + + // Check seed serialization + let serialized = seed.serialize(); + let deserialized = Seed::deserialize(Some(&network.public_key()), &serialized).unwrap(); + assert_eq!(seed.view, deserialized.view); + } + + #[test] + fn test_seed_manipulated() { + // Create network key + let mut rng = StdRng::seed_from_u64(0); + let mut network = Bls12381::new(&mut rng); + + // Create seed + let view = 0; + let seed_payload = Seed::payload(view); + let seed_signature = network.sign(Some(SEED_NAMESPACE), &seed_payload); + let mut seed = Seed::new(view, seed_signature); + + // Modify contents + seed.view = 1; + + // Serialize seed + let serialized = seed.serialize(); + + // Deserialize seed + assert!(Seed::deserialize(Some(&network.public_key()), &serialized).is_none()); + + // Deserialize seed with no public key + assert!(Seed::deserialize(None, &serialized).is_some()); + } + + #[test] + fn test_nullification() { + // Create network key + let mut rng = StdRng::seed_from_u64(0); + let mut network = Bls12381::new(&mut rng); + + // Create nullification + let view = 0; + let nullify_payload = Nullification::payload(view); + let nullify_signature = network.sign(Some(NULLIFY_NAMESPACE), &nullify_payload); + let nullification = Nullification::new(view, nullify_signature); + + // Check nullification serialization + let serialized = nullification.serialize(); + let deserialized = + Nullification::deserialize(Some(&network.public_key()), &serialized).unwrap(); + assert_eq!(nullification.view, deserialized.view); + } + + #[test] + fn test_nullification_manipulated() { + // Create network key + let mut rng = StdRng::seed_from_u64(0); + let mut network = Bls12381::new(&mut rng); + + // Create nullification + let view = 0; + let nullify_payload = Nullification::payload(view); + let nullify_signature = network.sign(Some(NULLIFY_NAMESPACE), &nullify_payload); + let mut nullification = Nullification::new(view, nullify_signature); + + // Modify contents + nullification.view = 1; + + // Serialize nullification + let serialized = nullification.serialize(); + + // Deserialize nullification + assert!(Nullification::deserialize(Some(&network.public_key()), &serialized).is_none()); + + // Deserialize nullification with no public key + assert!(Nullification::deserialize(None, &serialized).is_some()); + } + + #[test] + fn test_notarization_finalization() { + // Create network key + let mut rng = StdRng::seed_from_u64(0); + let mut network = Bls12381::new(&mut rng); + + // Create block + let parent_digest = hash(&[0; 32]); + let height = 0; + let timestamp = 1; + let block = Block::new(parent_digest, height, timestamp); + let block_digest = block.digest(); + + // Check block serialization + let serialized = block.serialize(); + let deserialized = Block::deserialize(&serialized).unwrap(); + assert_eq!(block_digest, deserialized.digest()); + assert_eq!(block.parent, deserialized.parent); + assert_eq!(block.height, deserialized.height); + assert_eq!(block.timestamp, deserialized.timestamp); + + // Create notarization + let view = 0; + let parent_view = 0; + let block_payload = Notarization::payload(view, parent_view, &block_digest); + let block_signature = network.sign(Some(NOTARIZE_NAMESPACE), &block_payload); + let notarization = Notarization::new(view, parent_view, block_digest, block_signature); + + // Check notarization serialization + let serialized = notarization.serialize(); + let deserialized = + Notarization::deserialize(Some(&network.public_key()), &serialized).unwrap(); + assert_eq!(notarization.view, deserialized.view); + assert_eq!(notarization.parent, deserialized.parent); + assert_eq!(notarization.payload, deserialized.payload); + + // Create finalization + let finalize_payload = Finalization::payload(view, parent_view, ¬arization.payload); + let finalize_signature = network.sign(Some(FINALIZE_NAMESPACE), &finalize_payload); + let finalization = + Finalization::new(view, parent_view, notarization.payload, finalize_signature); + + // Check finalization serialization + let serialized = finalization.serialize(); + let deserialized = + Finalization::deserialize(Some(&network.public_key()), &serialized).unwrap(); + assert_eq!(finalization.view, deserialized.view); + assert_eq!(finalization.parent, deserialized.parent); + assert_eq!(finalization.payload, deserialized.payload); + } + + #[test] + fn test_notarization_finalization_manipulated() { + // Create network key + let mut rng = StdRng::seed_from_u64(0); + let mut network = Bls12381::new(&mut rng); + + // Create block + let parent_digest = hash(&[0; 32]); + let height = 0; + let timestamp = 1; + let block = Block::new(parent_digest, height, timestamp); + + // Create notarization + let view = 0; + let parent_view = 0; + let block_payload = Notarization::payload(view, parent_view, &block.digest()); + let block_signature = network.sign(Some(NOTARIZE_NAMESPACE), &block_payload); + + // Create incorrect notarization proof + let notarization = + Notarization::new(view + 1, parent_view, block.digest(), block_signature); + + // Check notarization serialization + let serialized = notarization.serialize(); + let result = Notarization::deserialize(Some(&network.public_key()), &serialized); + assert!(result.is_none()); + + // Check notarization serialization with no public key + let result = Notarization::deserialize(None, &serialized); + assert!(result.is_some()); + + // Create finalization + let finalize_payload = Finalization::payload(view, parent_view, &block.digest()); + let finalize_signature = network.sign(Some(FINALIZE_NAMESPACE), &finalize_payload); + + // Create incorrect finalization proof + let finalization = + Finalization::new(view + 1, parent_view, block.digest(), finalize_signature); + + // Check finalization serialization + let serialized = finalization.serialize(); + let result = Finalization::deserialize(Some(&network.public_key()), &serialized); + assert!(result.is_none()); + + // Check finalization serialization with no public key + let result = Finalization::deserialize(None, &serialized); + assert!(result.is_some()); + } +}