diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3299c95440f30ff9e94d7f0efa38904a2734dab9..15af260b6b731d128f00abb1811edcf04e9da76c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,13 +31,8 @@ jobs: sudo apt update --yes sudo apt upgrade --yes sudo apt install protobuf-compiler --yes - - name: Install Nushell - run: | - # looks like the following PATH export does not work and `NU` still needs to be set for some reason to invoke `make`... - echo "PATH=\"$(make print-NU_DEST):$PATH\"" >> $GITHUB_ENV - make install-nu - name: Show configuration - run: make NU="$(make print-NU_DEST)/nu" show + run: make show - name: Run tests run: | - make NU="$(make print-NU_DEST)/nu" check clippy test example + make check clippy test diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index daa0125bc0891e723f0a60958d68002af8641c86..a1720e8ab1ef72320bdbbe20c7629b1af6456b03 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -28,9 +28,7 @@ test: - apt update --yes - apt upgrade --yes - apt install protobuf-compiler --yes - - export PATH="$(make print-NU_DEST):$PATH" - - make install-nu - make show script: - - make check clippy test example + - make check clippy test diff --git a/Cargo.toml b/Cargo.toml index b2797fda681e9ce44274aa1b1eaa0c9c5f00bbb5..5d4cd0d9a7a30fba5b5f0f817fb66c15d6b01752 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,7 +31,6 @@ dragoonfri = { version = "0.1.0", optional = true} members = [ "benchmarks", "bins/rank", - "bins/saclin", ] [dev-dependencies] @@ -66,4 +65,4 @@ required-features = ["fri"] [[example]] name = "fec" -required-features = ["fri"] \ No newline at end of file +required-features = ["fri"] diff --git a/Makefile b/Makefile index bdc911171d3e5f7c70f357fda95fb8ad75d632d7..c9913f0524fcb969ec26ab2240e693c5a232715d 100644 --- a/Makefile +++ b/Makefile @@ -1,12 +1,4 @@ -NU="nu" -NU_FLAGS="--no-config-file" - -NU_ARCH="x86_64-unknown-linux-musl" -NU_VERSION="0.101.0" -NU_BUILD="nu-${NU_VERSION}-${NU_ARCH}" -NU_DEST="/tmp/" - -DEFAULT_GOAL: fmt-check check clippy test-rs +DEFAULT_GOAL: fmt-check check clippy test .PHONY: fmt-check fmt-check: @@ -16,16 +8,8 @@ fmt-check: fmt: cargo fmt --all -.PHONY: install-nu -install-nu: - mkdir -p "${NU_DEST}" - curl -fLo "${NU_DEST}/nu.tar.gz" "https://github.com/nushell/nushell/releases/download/${NU_VERSION}/${NU_BUILD}.tar.gz" - tar xvf "${NU_DEST}/nu.tar.gz" --directory "${NU_DEST}" - cp "${NU_DEST}/${NU_BUILD}/nu" "${NU_DEST}/nu" - .PHONY: check check: - ${NU} ${NU_FLAGS} scripts/check-nushell-files.nu cargo check --workspace --all-targets cargo check --workspace --all-targets --features kzg cargo check --workspace --all-targets --features aplonk @@ -35,23 +19,11 @@ check: clippy: cargo clippy --workspace --all-targets --all-features -- -D warnings -.PHONY: test-rs -test-rs: +.PHONY: test +test: cargo test --workspace --verbose --all-features cargo test --examples --verbose -.PHONY: test-nu -test-nu: - ${NU} ${NU_FLAGS} bins/saclin/tests/cli.nu - ${NU} ${NU_FLAGS} bins/saclin/tests/binary.nu - -.PHONY: test -test: test-rs test-nu - -.PHONY: example -example: - ${NU} ${NU_FLAGS} bins/saclin/examples/cli.nu - .PHONY: show show: @rustup --version 2> /dev/null @@ -59,7 +31,6 @@ show: @rustc --version @cargo --version @cargo clippy --version - @${NU} ${NU_FLAGS} --commands "version" .PHONY: doc doc: diff --git a/README.md b/README.md index d29178c066e4871de0f7c31691636fdb43df3092..f309ec76b27e1cbb3155b454681deda482dfbc26 100644 --- a/README.md +++ b/README.md @@ -15,23 +15,7 @@ make ``` or ```shell -make check clippy test-rs -``` - -### some extra tests -this project defines some tests written in [Nushell](https://www.nushell.sh/) to test an -[implementation of Komodo in a CLI application](bins/saclin/). - -If you have [Nushell installed](https://www.nushell.sh/book/installation.html), you can run these -with the following command: -```shell -make test-nu -``` - -## examples -A [CLI example](bins/saclin/examples/cli.nu) is also provided and can be run with -```shell -make example +make check clippy test ``` Other examples that showcase the Komodo API are available in [`examples/`](examples/). diff --git a/bins/saclin/Cargo.toml b/bins/saclin/Cargo.toml deleted file mode 100644 index bd89b21402b51c7643099af5be0f6bbd24d18c32..0000000000000000000000000000000000000000 --- a/bins/saclin/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "saclin" -version = "1.0.1" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -anyhow = "1.0.81" -ark-bls12-381 = "0.4.0" -ark-ec = "0.4.2" -ark-ff = "0.4.2" -ark-poly = "0.4.2" -ark-serialize = "0.4.2" -ark-std = "0.4.0" -komodo = { path = "../../", features = ["fs"] } -rand = "0.8.5" -tracing = "0.1.40" -tracing-subscriber = "0.3.17" diff --git a/bins/saclin/README.md b/bins/saclin/README.md deleted file mode 100644 index 53cd160d0986cccac8133a5c39d18008659df5ce..0000000000000000000000000000000000000000 --- a/bins/saclin/README.md +++ /dev/null @@ -1 +0,0 @@ -## CLI app using Semi-AVID diff --git a/bins/saclin/binary.nu b/bins/saclin/binary.nu deleted file mode 100644 index 2f30ec71138b5209f0a6ee93369d052daeaf10e4..0000000000000000000000000000000000000000 --- a/bins/saclin/binary.nu +++ /dev/null @@ -1,10 +0,0 @@ -export def "bytes from_int" []: [int -> binary, list<int> -> binary] { - each { into binary --compact } | bytes collect -} - -export def "bytes to_int" []: binary -> list<int> { - let bytes = $in - seq 1 ($bytes | bytes length) | each {|i| - $bytes | bytes at ($i - 1)..($i) | get 0 - } -} diff --git a/bins/saclin/examples/cli.nu b/bins/saclin/examples/cli.nu deleted file mode 100755 index bdc31972a656753bde19c349107168a6db8570e7..0000000000000000000000000000000000000000 --- a/bins/saclin/examples/cli.nu +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/env nu -use .. [ - "saclin build", - "saclin setup", - "saclin prove", - "saclin verify", - "saclin reconstruct", - "saclin ls", -] -use ../binary.nu [ "bytes from_int" ] - -use std assert - -const BYTES = "assets/dragoon_32x32.png" -const FEC_PARAMS = { k: 3, n: 5 } - -const BLOCKS_TO_VERIFY = [0, 1] -const BLOCKS_TO_RECONSTRUCT = [0, 2, 3] - -def main [] { - saclin build - - saclin setup (open $BYTES | into binary | bytes length) - saclin prove $BYTES --fec-params $FEC_PARAMS - - let blocks = saclin ls - - saclin verify ...($BLOCKS_TO_VERIFY | each {|i| $blocks | get $i }) - - let actual = saclin reconstruct ...($BLOCKS_TO_RECONSTRUCT | each {|i| $blocks | get $i }) - let expected = open $BYTES | bytes from_int - assert equal $actual $expected - - print "reconstruction was successful" -} diff --git a/bins/saclin/mod.nu b/bins/saclin/mod.nu deleted file mode 100644 index 2080cb25c8787ceb3321f3f9e4baba6d3345816a..0000000000000000000000000000000000000000 --- a/bins/saclin/mod.nu +++ /dev/null @@ -1,381 +0,0 @@ -# Welcome to SACLIN (**S**emi-**A**VID **CLI** in **N**ushell), a tool to encode and prove data. -# -# please run `saclin --help` or `saclin <tab>` to have a look at more information - -module binary.nu - -use binary ["bytes from_int"] - -const BIN = "./target/release/saclin" -const DEFAULT_LOG_LEVEL = "INFO" - -def home-dir []: nothing -> path { - $env.SACLIN_HOME? | default ( - $env.XDG_DATA_HOME? | default "~/.local/share" | path join "saclin" - ) | path expand -} - -def block-dir []: nothing -> path { - home-dir | path join "blocks" -} - -def "nu-complete log-levels" []: nothing -> list<string> { - [ - "TRACE" - "DEBUG", - "INFO", - "WARN", - "ERROR", - ] -} - -def "nu-complete encoding-methods" []: nothing -> list<string> { - [ - "vandermonde" - "random", - ] -} - -def run-saclin [ - --input: path = "", - --nb-bytes: int = 0, - -k: int = 0, - -n: int = 0, - --generate-powers, - --reconstruct, - --verify, - --combine, - --inspect, - --encoding-method: string = "", - --log-level: string, - ...block_hashes: string, -]: nothing -> any { - let home_dir = home-dir - if not ($home_dir | is-empty) { - mkdir $home_dir - } - let block_dir = block-dir - if not ($block_dir | is-empty) { - mkdir $block_dir - } - - with-env {RUST_LOG: $log_level} { - let res = do { - ^$BIN ...([ - $input - $k - $n - ($generate_powers | into string) - $home_dir - ($reconstruct | into string) - ($verify | into string) - ($combine | into string) - ($inspect | into string) - $nb_bytes - $encoding_method - ] | append $block_hashes) - } | complete - - print --no-newline $res.stdout - if $res.exit_code != 0 { - error make --unspanned { msg: $"($res.stderr) \(($res.exit_code)\)" } - } - $res.stderr | from json - } -} - -def list-blocks []: nothing -> list<string> { - try { - ls (block-dir) | get name | path parse | get stem - } catch { - [] - } -} - -# build SACLIN from source, updating the application -export def "saclin build" []: nothing -> nothing { - ^cargo build --release --manifest-path bins/saclin/Cargo.toml -} - -# create a random trusted setup for a given amount of data -# -# # Examples -# ```nushell -# # create a trusted setup well suited for a file called `my_target_file.txt` -# saclin setup (open my_target_file.txt | into binary | bytes length) -# ``` -# --- -# ```nushell -# # create a trusted setup for 50k bytes and make sure the setup has been created -# saclin setup 50_000 -# use std assert; assert ("~/.local/share/saclin/powers" | path exists) -export def "saclin setup" [ - nb_bytes: int, # the size of the biggest expected data during the lifetime of the application - --log-level: string@"nu-complete log-levels" = $DEFAULT_LOG_LEVEL # change the log level -]: nothing -> nothing { - ( - run-saclin - --log-level $log_level - --nb-bytes $nb_bytes - --generate-powers - ) -} - -# encode and _prove_ a bunch of input bytes -# -# # Examples -# ```nushell -# # encode and prove `assets/dragoon_32x32.png` with a _3 x 5_ Vandermonde encoding -# saclin prove assets/dragoon_32x32.png --fec-params {k: 3, n: 5} --encoding-method vandermonde -# ``` -# ``` -# ─┬──────────────────────────────────────────────────────────────── -# 0│44614daf1f5ebb86f1c69293b82c7795a5a35b4d12718b551648223441028e3 -# 1│8be575889246fbc49f4c748ac2dc1cd8a4ef71d16e91c9343660a5f79f086 -# 2│6de9fd5fdfe8c08b3132e0d527b14a2a4e4be9a543af1f13d2c397bd113846e4 -# 3│f1c34065cbfc3267f9d41558a465ba6335fd45229ff2eae5b34a8f30467562 -# 4│7aa698f338605462205c5ff46b5463720d073de92a19f897cc4ae6c286ab87 -# ─┴──────────────────────────────────────────────────────────────── -# ``` -export def "saclin prove" [ - input: path, # the path to the input file to encode and prove - --fec-params: record<k: int, n: int>, # the parameters of the encoding - --encoding-method: string@"nu-complete encoding-methods" = "random", # the encoding method, e.g. _random_ or _vandermonde_ - --log-level: string@"nu-complete log-levels" = $DEFAULT_LOG_LEVEL # change the log level -]: nothing -> list<string> { - # NOTE: the next two runtime checks on the type of `--fec-params` might be - # a bug on the Nushell side - if $fec_params == null { - error make --unspanned { - msg: "`saclin prove` requires `--fec-params` to be given" - } - } - - let type = $fec_params | describe --detailed | update columns { sort } - let expected = { type: record, columns: { k: int, n: int } } - if $type != $expected { - error make { - msg: $"(ansi red_bold)invalid `--fec-params`(ansi reset)", - label: { - text: $"expected ($expected) got ($type)", - span: (metadata $fec_params).span, - } - } - } - - ( - run-saclin - --log-level $log_level - --input $input - -k $fec_params.k - -n $fec_params.n - --encoding-method $encoding_method - ) -} - -# verify the integrity of any number of blocks -# -# # Examples -# ```nushell -# # verify the integrity of two blocks (note the use of the spread operator introduced in Nushell 0.89.0) -# # > **Note** -# # > file: `assets/dragoon_32x32.png` -# # > parameters: k = 3 and n = 5 -# # > method: vandermonde -# saclin verify ...[ -# 44614daf1f5ebb86f1c69293b82c7795a5a35b4d12718b551648223441028e3, -# 7aa698f338605462205c5ff46b5463720d073de92a19f897cc4ae6c286ab87, -# ] -# ``` -# ``` -# #┬─────────────────────────────block─────────────────────────────┬status -# 0│44614daf1f5ebb86f1c69293b82c7795a5a35b4d12718b551648223441028e3│true -# 1│7aa698f338605462205c5ff46b5463720d073de92a19f897cc4ae6c286ab87 │true -# ─┴───────────────────────────────────────────────────────────────┴────── -# ``` -export def "saclin verify" [ - ...blocks: string@"list-blocks", # the list of blocks to verify - --log-level: string@"nu-complete log-levels" = $DEFAULT_LOG_LEVEL # change the log level -]: nothing -> table<block: string, status: int> { - run-saclin --log-level $log_level --verify ...$blocks -} - -# reconstruct the original data from a subset of blocks -# -# `saclin reconstruct` might throw an error in some cases -# - when there are too few blocks -# - when the blocks are linearly dependant, and thus the decoding cannot be applied -# - when the blocks belong to different data -# -# # Examples -# ```nushell -# # applying a valid reconstruction -# # > **Note** -# # > file: `assets/dragoon_32x32.png` -# # > parameters: k = 3 and n = 5 -# # > method: vandermonde -# let bytes = saclin reconstruct ...[ -# 44614daf1f5ebb86f1c69293b82c7795a5a35b4d12718b551648223441028e3, -# 7aa698f338605462205c5ff46b5463720d073de92a19f897cc4ae6c286ab87, -# 8be575889246fbc49f4c748ac2dc1cd8a4ef71d16e91c9343660a5f79f086, -# ] -# $bytes | bytes at 0..10 -# ``` -# ``` -# Length: 10 (0xa) bytes | printable whitespace ascii_other non_ascii -# 00000000: 89 50 4e 47 0d 0a 1a 0a 00 00 ×PNG__•_00 -# ``` -# --- -# ```nushell -# # giving too few blocks -# # > **Note** -# # > file: `assets/dragoon_32x32.png` -# # > parameters: k = 3 and n = 5 -# # > method: vandermonde -# saclin reconstruct ...[ -# 44614daf1f5ebb86f1c69293b82c7795a5a35b4d12718b551648223441028e3, -# 7aa698f338605462205c5ff46b5463720d073de92a19f897cc4ae6c286ab87, -# ] -# ``` -# ``` -# Error: × could not decode: Expected at least 3, got 2 (1) -# ``` -# --- -# ```nushell -# # after combining _44614d_ and _6de9fd_ (see [`saclin combine`]), try to decode with linear dependencies -# # > **Note** -# # > file: `assets/dragoon_32x32.png` -# # > parameters: k = 3 and n = 5 -# # > method: vandermonde -# # > recoding: _44614d_ <+> _6de9fd_ => _86cdd1_ -# saclin reconstruct ...[ -# 44614daf1f5ebb86f1c69293b82c7795a5a35b4d12718b551648223441028e3, -# 6de9fd5fdfe8c08b3132e0d527b14a2a4e4be9a543af1f13d2c397bd113846e4, -# 86cdd1b7ed79618696ab82d848833cbe448719a513b850207936e4dce6294, -# ] -# ``` -# ``` -# Error: × could not decode: Matrix is not invertible at row 2 (1) -# ``` -export def "saclin reconstruct" [ - ...blocks: string@"list-blocks", # the blocks that should be used to reconstruct the original data - --log-level: string@"nu-complete log-levels" = $DEFAULT_LOG_LEVEL # change the log level -]: nothing -> binary { - run-saclin --log-level $log_level --reconstruct ...$blocks | bytes from_int -} - -# combine two blocks by computing a random linear combination -# -# # Examples -# # > **Note** -# # > file: `assets/dragoon_133x133.png` -# # > parameters: k = 7 and n = 23 -# # > method: random -# ```nushell -# saclin combine ...[ -# 1b112a11cd89dad619aadc18cb2c15c315453e177f1117c79d4ae4e219922, -# 31c9bfe2845cc430d666413d8b8b51aee0d010aa89275a8c7d9d9ca1c9e05c, -# ] -# ``` -# ``` -# b785bf5b93d7811792db7234d1b1ee7347398cee617243612d3225fa245545 -# ``` -# --- -# ```nushell -# # not giving exactly 2 blocks -# # > **Note** -# # > file: `assets/dragoon_133x133.png` -# # > parameters: k = 7 and n = 23 -# # > method: random -# saclin combine ...[ -# c22fe3c72cbc52fc55b46a3f9783f5c9a1e5fb59875f736332cf1b970b8, -# 1b112a11cd89dad619aadc18cb2c15c315453e177f1117c79d4ae4e219922, -# f3f423df47cd7538accd38abe9ad6670b894243647af98fbfa9776e9cf7ff8e, -# ] -# ``` -# ``` -# Error: × expected exactly 2 blocks, found 3 (1) -# ``` -export def "saclin combine" [ - ...blocks: string@"list-blocks", # the blocks to combine, should contain two hashes - --log-level: string@"nu-complete log-levels" = $DEFAULT_LOG_LEVEL # change the log level -]: nothing -> string { - run-saclin --log-level $log_level --combine ...$blocks | get 0 -} - -# open one or more blocks and inspect their content -# -# # Examples -# ```nushell -# # inspect a single block -# # # > **Note** -# # # > file: `assets/dragoon_133x133.png` -# # # > parameters: k = 7 and n = 23 -# # # > method: random -# # # > -# # # > `$.commits` and `$shard.bytes` have been truncated for readability -# saclin inspect 374f23fd1f25ae4050c414bc169550bdd10f49f775e2af71d2aee8a87dc -# | into record -# | update commits { parse --regex '\((?<f>\d{7})\d+, (?<s>\d{7})\d+\)' } -# | update shard.bytes { length } -# ``` -# ``` -# ───────┬────────────────────────────────────────────────────────────────────── -# │─────┬──────────────────────────────────────────────────────────────── -# shard │k │7 -# │ │─┬─────────────────────────────────────── -# │comb │0│79293070128283035155183921571762200246 -# │ │1│251822311562506197186167674369775071480 -# │ │2│271375591445361086306725794586025747695 -# │ │3│170387538935153872006296956270886059735 -# │ │4│67758248758369211569040944574905941217 -# │ │5│245908698054074962369032280439731463970 -# │ │6│323120636634748190275497410128071523309 -# │ │─┴─────────────────────────────────────── -# │bytes│89 -# │hash │d116d9e2bdb0e03fb2bdd6e716a929198f1012ae62a83e773eb2c21917f4b12c -# │size │19102 -# │─────┴──────────────────────────────────────────────────────────────── -# │#┬───f───┬───s─── -# commits│0│3258872│1117914 -# │1│1336159│2841207 -# │2│3908964│4603563 -# │3│3956175│1154567 -# │4│2056568│3904956 -# │5│2957425│2772456 -# │6│2395336│2282274 -# │─┴───────┴─────── -# m │89 -# ───────┴────────────────────────────────────────────────────────────────────── -# ``` -export def "saclin inspect" [ - ...blocks: string@"list-blocks", # the blocks to inspect - --log-level: string@"nu-complete log-levels" = $DEFAULT_LOG_LEVEL # change the log level -]: nothing -> table<shard: record<k: int, comb: list<any>, bytes: list<string>, hash: string, size: int>, commits: list<string>, m: int> { - run-saclin --log-level $log_level --inspect ...$blocks -} - -# list all the blocks that are currently in the store -export def "saclin ls" []: nothing -> list<string> { - list-blocks -} - -# clean the SACLIN home from all blocks and trusted setup -export def "saclin clean" []: nothing -> nothing { - rm --force --recursive (home-dir) -} - -def pretty-code []: string -> string { - $"`(ansi default_dimmed)($in)(ansi reset)`" -} - -# the main entry point of SACLIN, will only print some help -export def main []: nothing -> nothing { - let help = [ - $"the location of the files generated by SACLIN can be configured via ("$env.SACLIN_HOME" | pretty-code) which will default to", - $"- ("$env.XDG_DATA_HOME/saclin" | pretty-code) if ("$env.XDG_DATA_HOME" | pretty-code) is set", - $"- ("~/.local/share/saclin/" | pretty-code) otherwise" - ] - - print ($help | str join "\n") -} diff --git a/bins/saclin/src/main.rs b/bins/saclin/src/main.rs deleted file mode 100644 index 2f6b1ff2872a49719c9d2a8aa98518893840595c..0000000000000000000000000000000000000000 --- a/bins/saclin/src/main.rs +++ /dev/null @@ -1,341 +0,0 @@ -use std::path::{Path, PathBuf}; -use std::process::exit; - -use ark_bls12_381::{Fr, G1Projective}; -use ark_ec::CurveGroup; -use ark_ff::PrimeField; -use ark_poly::{univariate::DensePolynomial, DenseUVPolynomial}; -use ark_serialize::{CanonicalDeserialize, Compress, Validate}; -use ark_std::ops::Div; - -use anyhow::Result; -use ark_std::rand::RngCore; -use tracing::{info, warn}; - -use komodo::{ - algebra::linalg::Matrix, - error::KomodoError, - fec::{self, decode, Shard}, - fs, - semi_avid::{build, prove, recode, verify, Block}, - zk::{self, Powers}, -}; - -const COMPRESS: Compress = Compress::Yes; -const VALIDATE: Validate = Validate::Yes; - -#[allow(clippy::type_complexity)] -fn parse_args() -> ( - Vec<u8>, - usize, - usize, - bool, - String, - bool, - bool, - bool, - bool, - usize, - String, - Vec<String>, -) { - let bytes_path = std::env::args() - .nth(1) - .expect("expected path to bytes as first positional argument"); - let bytes = if bytes_path.is_empty() { - vec![] - } else { - std::fs::read(bytes_path).unwrap() - }; - let k: usize = std::env::args() - .nth(2) - .expect("expected k as second positional argument") - .parse() - .expect("could not parse k as an int"); - let n: usize = std::env::args() - .nth(3) - .expect("expected n as third positional argument") - .parse() - .expect("could not parse n as an int"); - let do_generate_powers: bool = std::env::args() - .nth(4) - .expect("expected do_generate_powers as fourth positional argument") - .parse() - .expect("could not parse do_generate_powers as a bool"); - let home_dir = std::env::args() - .nth(5) - .expect("expected home_dir as fifth positional argument"); - let do_reconstruct_data: bool = std::env::args() - .nth(6) - .expect("expected do_reconstruct_data as sixth positional argument") - .parse() - .expect("could not parse do_reconstruct_data as a bool"); - let do_verify_blocks: bool = std::env::args() - .nth(7) - .expect("expected do_verify_blocks as seventh positional argument") - .parse() - .expect("could not parse do_verify_blocks as a bool"); - let do_combine_blocks: bool = std::env::args() - .nth(8) - .expect("expected do_combine_blocks as eigth positional argument") - .parse() - .expect("could not parse do_combine_blocks as a bool"); - let do_inspect_blocks: bool = std::env::args() - .nth(9) - .expect("expected do_inspect_blocks as ninth positional argument") - .parse() - .expect("could not parse do_inspect_blocks as a bool"); - let nb_bytes: usize = std::env::args() - .nth(10) - .expect("expected nb_bytes as 10th positional argument") - .parse() - .expect("could not parse nb_bytes as a usize"); - let encoding_method = std::env::args() - .nth(11) - .expect("expected encoding_method as 11th positional argument"); - let block_hashes = std::env::args().skip(12).collect::<Vec<_>>(); - - ( - bytes, - k, - n, - do_generate_powers, - home_dir, - do_reconstruct_data, - do_verify_blocks, - do_combine_blocks, - do_inspect_blocks, - nb_bytes, - encoding_method, - block_hashes, - ) -} - -fn throw_error(code: i32, message: &str) { - eprint!("{}", message); - exit(code); -} - -fn generate_random_powers<F, G, P>( - n: usize, - powers_dir: &Path, - powers_filename: Option<&str>, - rng: &mut impl RngCore, -) -> Result<()> -where - F: PrimeField, - G: CurveGroup<ScalarField = F>, - P: DenseUVPolynomial<F>, - for<'a, 'b> &'a P: Div<&'b P, Output = P>, -{ - info!("generating new powers"); - let powers = zk::setup::<F, G>(zk::nb_elements_in_setup::<F>(n), rng)?; - - fs::dump(&powers, powers_dir, powers_filename, COMPRESS)?; - - Ok(()) -} - -fn verify_blocks<F, G, P>( - blocks: &[(String, Block<F, G>)], - powers: Powers<F, G>, -) -> Result<(), KomodoError> -where - F: PrimeField, - G: CurveGroup<ScalarField = F>, - P: DenseUVPolynomial<F>, - for<'a, 'b> &'a P: Div<&'b P, Output = P>, -{ - let res = blocks - .iter() - .map(|(f, b)| Ok((f, verify::<F, G, P>(b, &powers)?))) - .collect::<Result<Vec<(&String, bool)>, KomodoError>>()?; - - eprint!("["); - for (f, v) in res { - eprint!("{{block: {:?}, status: {}}}", f, v); - } - eprint!("]"); - Ok(()) -} - -fn main() { - tracing_subscriber::fmt::try_init().expect("cannot init logger"); - - let mut rng = rand::thread_rng(); - - let ( - bytes, - k, - n, - do_generate_powers, - home_dir, - do_reconstruct_data, - do_verify_blocks, - do_combine_blocks, - do_inspect_blocks, - nb_bytes, - encoding_method, - block_hashes, - ) = parse_args(); - - let home_dir = PathBuf::from(&home_dir); - let block_dir = home_dir.join("blocks/"); - let powers_dir = home_dir; - let powers_filename = "powers"; - let powers_file = powers_dir.join(powers_filename); - - if do_generate_powers { - generate_random_powers::<Fr, G1Projective, DensePolynomial<Fr>>( - nb_bytes, - &powers_dir, - Some(powers_filename), - &mut rng, - ) - .unwrap_or_else(|e| throw_error(1, &format!("could not generate powers: {}", e))); - - exit(0); - } - - if do_reconstruct_data { - let blocks: Vec<Shard<Fr>> = - fs::read_blocks::<Fr, G1Projective>(&block_hashes, &block_dir, COMPRESS, VALIDATE) - .unwrap_or_else(|e| { - throw_error(1, &format!("could not read blocks: {}", e)); - unreachable!() - }) - .iter() - .cloned() - .map(|b| b.1.shard) - .collect(); - eprintln!( - "{:?}", - decode::<Fr>(blocks).unwrap_or_else(|e| { - throw_error(1, &format!("could not decode: {}", e)); - unreachable!() - }) - ); - - exit(0); - } - - if do_combine_blocks { - let blocks = - fs::read_blocks::<Fr, G1Projective>(&block_hashes, &block_dir, COMPRESS, VALIDATE) - .unwrap_or_else(|e| { - throw_error(1, &format!("could not read blocks: {}", e)); - unreachable!() - }); - - let formatted_output = fs::dump_blocks( - &[recode( - &blocks.iter().map(|(_, b)| b).cloned().collect::<Vec<_>>(), - &mut rng, - ) - .unwrap_or_else(|e| { - throw_error(1, &format!("could not encode block: {}", e)); - unreachable!() - }) - .unwrap_or_else(|| { - throw_error(1, "could not recode block (list of blocks is likely empty)"); - unreachable!() - })], - &block_dir, - COMPRESS, - ) - .unwrap_or_else(|e| { - throw_error(1, &format!("could not dump block: {}", e)); - unreachable!() - }); - - eprint!("{}", formatted_output); - - exit(0); - } - - if do_inspect_blocks { - let blocks = - fs::read_blocks::<Fr, G1Projective>(&block_hashes, &block_dir, COMPRESS, VALIDATE) - .unwrap_or_else(|e| { - throw_error(1, &format!("could not read blocks: {}", e)); - unreachable!() - }); - eprint!("["); - for (_, block) in &blocks { - eprint!("{},", block); - } - eprintln!("]"); - - exit(0); - } - - info!("reading powers from file `{:?}`", powers_file); - let powers = if let Ok(serialized) = std::fs::read(&powers_file) { - info!("deserializing the powers from `{:?}`", powers_file); - Powers::<Fr, G1Projective>::deserialize_with_mode(&serialized[..], COMPRESS, VALIDATE) - .unwrap_or_else(|e| { - throw_error( - 1, - &format!("could not deserialize powers from {:?}: {}", powers_file, e), - ); - unreachable!() - }) - } else { - warn!("could not read powers from `{:?}`", powers_file); - info!("regenerating temporary powers"); - zk::setup::<Fr, G1Projective>(zk::nb_elements_in_setup::<Fr>(nb_bytes), &mut rng) - .unwrap_or_else(|e| { - throw_error(1, &format!("could not generate powers: {}", e)); - unreachable!() - }) - }; - - if do_verify_blocks { - verify_blocks::<Fr, G1Projective, DensePolynomial<Fr>>( - &fs::read_blocks::<Fr, G1Projective>(&block_hashes, &block_dir, COMPRESS, VALIDATE) - .unwrap_or_else(|e| { - throw_error(1, &format!("could not read blocks: {}", e)); - unreachable!() - }), - powers, - ) - .unwrap_or_else(|e| { - throw_error(1, &format!("Failed to verify blocks: {}", e)); - unreachable!() - }); - - exit(0); - } - - let encoding_mat = match encoding_method.as_str() { - "vandermonde" => { - let points: Vec<Fr> = (0..n) - .map(|i| Fr::from_le_bytes_mod_order(&i.to_le_bytes())) - .collect(); - Matrix::vandermonde_unchecked(&points, k) - } - "random" => Matrix::random(k, n, &mut rng), - m => { - throw_error(1, &format!("invalid encoding method: {}", m)); - unreachable!() - } - }; - - let shards = fec::encode::<Fr>(&bytes, &encoding_mat).unwrap_or_else(|e| { - throw_error(1, &format!("could not encode: {}", e)); - unreachable!() - }); - let proof = - prove::<Fr, G1Projective, DensePolynomial<Fr>>(&bytes, &powers, k).unwrap_or_else(|e| { - throw_error(1, &format!("could not prove: {}", e)); - unreachable!() - }); - let blocks = build::<Fr, G1Projective, DensePolynomial<Fr>>(&shards, &proof); - - let formatted_output = fs::dump_blocks(&blocks, &block_dir, COMPRESS).unwrap_or_else(|e| { - throw_error(1, &format!("could not dump blocks: {}", e)); - unreachable!() - }); - - eprint!("{}", formatted_output); -} diff --git a/bins/saclin/tests/binary.nu b/bins/saclin/tests/binary.nu deleted file mode 100644 index 0bd2669bfa9b33df7e6f95fc4b77d3d07c2e22cc..0000000000000000000000000000000000000000 --- a/bins/saclin/tests/binary.nu +++ /dev/null @@ -1,19 +0,0 @@ -use ../binary.nu [ "bytes from_int", "bytes to_int" ] - -use std assert - -def random-bytes [n: int]: nothing -> list<int> { - 0..$n | each { random int 0..255 } -} - -def main [] { - const hello_world_int = [ - 104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 33 - ] - - const expected = 0x[68 65 6C 6C 6F 20 77 6F 72 6C 64 21] - assert equal ($hello_world_int | bytes from_int) $expected - - let bytes = random-bytes 1_000 - assert equal ($bytes | bytes from_int | bytes to_int) $bytes -} diff --git a/bins/saclin/tests/cli.nu b/bins/saclin/tests/cli.nu deleted file mode 100644 index ac765c6f638dbaaa3499b9e48b2e72b60ba19463..0000000000000000000000000000000000000000 --- a/bins/saclin/tests/cli.nu +++ /dev/null @@ -1,171 +0,0 @@ -use .. [ - "saclin build", - "saclin setup", - "saclin prove", - "saclin verify", - "saclin reconstruct", - "saclin ls", - "saclin clean", -] -use ../binary.nu [ "bytes from_int" ] - -use std assert - -# a simple module to extend the `math` command -module math { - # `choose k n` is the list of all the possible $k$ indices chosen among $n$ indices - # - # see [_test_choose] below for some examples - export def choose [k: int, n: int]: nothing -> list<list<int>> { - if $k == 0 { - return [] - } else if $k == 1 { - return (seq 0 ($n - 1) | each {[ $in ]}) - } - - choose ($k - 1) $n - | each { |x| - let l = $x | last - if $l != ($n - 1) { - seq ($l + 1) ($n - 1) | each {|it| $x | append $it} - } - } - | flatten - } - - def _test_choose [] { - use std assert - - assert equal (choose 0 5) [] - assert equal (choose 1 5) [[0], [1], [2], [3], [4]] - assert equal (choose 2 5) [ - [0, 1], [0, 2], [0, 3], [0, 4], [1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4] - ] - assert equal (choose 3 5) [ - [0, 1, 2], - [0, 1, 3], - [0, 1, 4], - [0, 2, 3], - [0, 2, 4], - [0, 3, 4], - [1, 2, 3], - [1, 2, 4], - [1, 3, 4], - [2, 3, 4], - ] - assert equal (choose 4 5) [ - [0, 1, 2, 3], - [0, 1, 2, 4], - [0, 1, 3, 4], - [0, 2, 3, 4], - [1, 2, 3, 4], - ] - assert equal (choose 5 5) [[0, 1, 2, 3, 4]] - } - - # `perm n` is the list of all the possible permutations on $n$ elements - # - # see [_test_perm] below for some examples - export def perm [n: int]: nothing -> list<list<int>> { - if $n == 0 { - return [] - } else if $n == 1 { - return [[0]] - } - - perm ($n - 1) - | each {|x| - seq 0 ($x | length) | each {|i| $x | insert $i ($n - 1)} - } - | flatten - } - - def _test_perm [] { - use std assert - - assert equal (perm 0 | sort) [] - assert equal (perm 1 | sort) [[0]] - assert equal (perm 2 | sort) [[0, 1], [1, 0]] - assert equal (perm 3 | sort) [ - [0, 1, 2], [0, 2, 1], [1, 0, 2], [1, 2, 0], [2, 0, 1], [2, 1, 0] - ] - assert equal (perm 4 | sort) [ - [0, 1, 2, 3], - [0, 1, 3, 2], - [0, 2, 1, 3], - [0, 2, 3, 1], - [0, 3, 1, 2], - [0, 3, 2, 1], - [1, 0, 2, 3], - [1, 0, 3, 2], - [1, 2, 0, 3], - [1, 2, 3, 0], - [1, 3, 0, 2], - [1, 3, 2, 0], - [2, 0, 1, 3], - [2, 0, 3, 1], - [2, 1, 0, 3], - [2, 1, 3, 0], - [2, 3, 0, 1], - [2, 3, 1, 0], - [3, 0, 1, 2], - [3, 0, 2, 1], - [3, 1, 0, 2], - [3, 1, 2, 0], - [3, 2, 0, 1], - [3, 2, 1, 0], - ] - } -} - -use math - -const FILE = "assets/dragoon_32x32.png" -const FEC_PARAMS = {k: 3, n: 5} - -def test [blocks: list<int>, --fail] { - let actual = try { - saclin reconstruct ...(saclin ls) - } catch { - if not $fail { - error make --unspanned { msg: "woopsie" } - } else { - return - } - } - - let expected = open $FILE | bytes from_int - assert equal $actual $expected -} - -def main [] { - saclin build - - saclin clean - - saclin setup (open $FILE | into binary | bytes length) - saclin prove $FILE --fec-params $FEC_PARAMS - - saclin verify ...(saclin ls) - - let all_k_choose_n_permutations = seq 1 $FEC_PARAMS.n - | each {|ki| - let p = math perm $ki - math choose $ki $FEC_PARAMS.n - | each {|it| - { - blocks: ($p | each { each {|i| $it | get $i} }), - fail: ($ki < $FEC_PARAMS.k), - } - } - | flatten - } - | flatten - let total = $all_k_choose_n_permutations | length - $all_k_choose_n_permutations | enumerate | each {|it| - print $"[($it.index / $total * 100 | into int)%]: ($it.item.blocks | str join ', ') | ($it.item.fail)" - test $it.item.blocks --fail=$it.item.fail - } - - print "reconstruction was successful" -}