Browse Source

wip, working decoding

Samir Menon 2 years ago
parent
commit
a387a2bce9
9 changed files with 1168 additions and 76 deletions
  1. 677 1
      Cargo.lock
  2. 2 0
      Cargo.toml
  3. 19 0
      src/arith.rs
  4. 193 25
      src/client.rs
  5. 38 24
      src/discrete_gaussian.rs
  6. 68 11
      src/main.rs
  7. 27 4
      src/params.rs
  8. 19 8
      src/poly.rs
  9. 125 3
      src/util.rs

+ 677 - 1
Cargo.lock

@@ -19,6 +19,12 @@ version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
 
+[[package]]
+name = "base64"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
+
 [[package]]
 name = "bitflags"
 version = "1.3.2"
@@ -43,6 +49,12 @@ version = "3.9.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899"
 
+[[package]]
+name = "bytes"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8"
+
 [[package]]
 name = "cast"
 version = "0.2.7"
@@ -52,6 +64,12 @@ dependencies = [
  "rustc_version",
 ]
 
+[[package]]
+name = "cc"
+version = "1.0.73"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
+
 [[package]]
 name = "cfg-if"
 version = "1.0.0"
@@ -69,6 +87,22 @@ dependencies = [
  "unicode-width",
 ]
 
+[[package]]
+name = "core-foundation"
+version = "0.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
+[[package]]
+name = "core-foundation-sys"
+version = "0.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
+
 [[package]]
 name = "criterion"
 version = "0.3.5"
@@ -177,6 +211,103 @@ version = "1.6.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
 
+[[package]]
+name = "encoding_rs"
+version = "0.8.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7896dc8abb250ffdda33912550faa54c88ec8b998dec0b2c55ab224921ce11df"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "fastrand"
+version = "1.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf"
+dependencies = [
+ "instant",
+]
+
+[[package]]
+name = "fnv"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
+
+[[package]]
+name = "foreign-types"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
+dependencies = [
+ "foreign-types-shared",
+]
+
+[[package]]
+name = "foreign-types-shared"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
+
+[[package]]
+name = "form_urlencoded"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191"
+dependencies = [
+ "matches",
+ "percent-encoding",
+]
+
+[[package]]
+name = "futures-channel"
+version = "0.3.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010"
+dependencies = [
+ "futures-core",
+]
+
+[[package]]
+name = "futures-core"
+version = "0.3.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3"
+
+[[package]]
+name = "futures-io"
+version = "0.3.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b"
+
+[[package]]
+name = "futures-sink"
+version = "0.3.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868"
+
+[[package]]
+name = "futures-task"
+version = "0.3.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a"
+
+[[package]]
+name = "futures-util"
+version = "0.3.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a"
+dependencies = [
+ "futures-core",
+ "futures-io",
+ "futures-task",
+ "memchr",
+ "pin-project-lite",
+ "pin-utils",
+ "slab",
+]
+
 [[package]]
 name = "getrandom"
 version = "0.2.4"
@@ -185,7 +316,26 @@ checksum = "418d37c8b1d42553c93648be529cb70f920d3baf8ef469b74b9638df426e0b4c"
 dependencies = [
  "cfg-if",
  "libc",
- "wasi",
+ "wasi 0.10.2+wasi-snapshot-preview1",
+]
+
+[[package]]
+name = "h2"
+version = "0.3.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "62eeb471aa3e3c9197aa4bfeabfe02982f6dc96f750486c0bb0009ac58b26d2b"
+dependencies = [
+ "bytes",
+ "fnv",
+ "futures-core",
+ "futures-sink",
+ "futures-util",
+ "http",
+ "indexmap",
+ "slab",
+ "tokio",
+ "tokio-util",
+ "tracing",
 ]
 
 [[package]]
@@ -194,6 +344,12 @@ version = "1.8.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
 
+[[package]]
+name = "hashbrown"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
+
 [[package]]
 name = "hermit-abi"
 version = "0.1.19"
@@ -203,6 +359,113 @@ dependencies = [
  "libc",
 ]
 
+[[package]]
+name = "http"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "31f4c6746584866f0feabcc69893c5b51beef3831656a968ed7ae254cdc4fd03"
+dependencies = [
+ "bytes",
+ "fnv",
+ "itoa 1.0.1",
+]
+
+[[package]]
+name = "http-body"
+version = "0.4.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ff4f84919677303da5f147645dbea6b1881f368d03ac84e1dc09031ebd7b2c6"
+dependencies = [
+ "bytes",
+ "http",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "httparse"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9100414882e15fb7feccb4897e5f0ff0ff1ca7d1a86a23208ada4d7a18e6c6c4"
+
+[[package]]
+name = "httpdate"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421"
+
+[[package]]
+name = "hyper"
+version = "0.14.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b26ae0a80afebe130861d90abf98e3814a4f28a4c6ffeb5ab8ebb2be311e0ef2"
+dependencies = [
+ "bytes",
+ "futures-channel",
+ "futures-core",
+ "futures-util",
+ "h2",
+ "http",
+ "http-body",
+ "httparse",
+ "httpdate",
+ "itoa 1.0.1",
+ "pin-project-lite",
+ "socket2",
+ "tokio",
+ "tower-service",
+ "tracing",
+ "want",
+]
+
+[[package]]
+name = "hyper-tls"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905"
+dependencies = [
+ "bytes",
+ "hyper",
+ "native-tls",
+ "tokio",
+ "tokio-native-tls",
+]
+
+[[package]]
+name = "idna"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8"
+dependencies = [
+ "matches",
+ "unicode-bidi",
+ "unicode-normalization",
+]
+
+[[package]]
+name = "indexmap"
+version = "1.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223"
+dependencies = [
+ "autocfg",
+ "hashbrown",
+]
+
+[[package]]
+name = "instant"
+version = "0.1.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "ipnet"
+version = "2.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "35e70ee094dc02fd9c13fdad4940090f22dbd6ac7c9e7094a46cf0232a50bc7c"
+
 [[package]]
 name = "itertools"
 version = "0.10.3"
@@ -254,6 +517,12 @@ dependencies = [
  "cfg-if",
 ]
 
+[[package]]
+name = "matches"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
+
 [[package]]
 name = "memchr"
 version = "2.4.1"
@@ -269,6 +538,62 @@ dependencies = [
  "autocfg",
 ]
 
+[[package]]
+name = "mime"
+version = "0.3.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d"
+
+[[package]]
+name = "mio"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "52da4364ffb0e4fe33a9841a98a3f3014fb964045ce4f7a45a398243c8d6b0c9"
+dependencies = [
+ "libc",
+ "log",
+ "miow",
+ "ntapi",
+ "wasi 0.11.0+wasi-snapshot-preview1",
+ "winapi",
+]
+
+[[package]]
+name = "miow"
+version = "0.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "native-tls"
+version = "0.2.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09bf6f32a3afefd0b587ee42ed19acd945c6d1f3b5424040f50b2f24ab16be77"
+dependencies = [
+ "lazy_static",
+ "libc",
+ "log",
+ "openssl",
+ "openssl-probe",
+ "openssl-sys",
+ "schannel",
+ "security-framework",
+ "security-framework-sys",
+ "tempfile",
+]
+
+[[package]]
+name = "ntapi"
+version = "0.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c28774a7fd2fbb4f0babd8237ce554b73af68021b5f695a3cebd6c59bac0980f"
+dependencies = [
+ "winapi",
+]
+
 [[package]]
 name = "num-traits"
 version = "0.2.14"
@@ -288,12 +613,75 @@ dependencies = [
  "libc",
 ]
 
+[[package]]
+name = "once_cell"
+version = "1.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
+
 [[package]]
 name = "oorandom"
 version = "11.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575"
 
+[[package]]
+name = "openssl"
+version = "0.10.38"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c7ae222234c30df141154f159066c5093ff73b63204dcda7121eb082fc56a95"
+dependencies = [
+ "bitflags",
+ "cfg-if",
+ "foreign-types",
+ "libc",
+ "once_cell",
+ "openssl-sys",
+]
+
+[[package]]
+name = "openssl-probe"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
+
+[[package]]
+name = "openssl-sys"
+version = "0.9.72"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7e46109c383602735fa0a2e48dd2b7c892b048e1bf69e5c3b1d804b7d9c203cb"
+dependencies = [
+ "autocfg",
+ "cc",
+ "libc",
+ "pkg-config",
+ "vcpkg",
+]
+
+[[package]]
+name = "percent-encoding"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
+
+[[package]]
+name = "pin-project-lite"
+version = "0.2.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c"
+
+[[package]]
+name = "pin-utils"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
+
+[[package]]
+name = "pkg-config"
+version = "0.3.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe"
+
 [[package]]
 name = "plotters"
 version = "0.3.1"
@@ -401,6 +789,15 @@ dependencies = [
  "num_cpus",
 ]
 
+[[package]]
+name = "redox_syscall"
+version = "0.2.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ae183fc1b06c149f0c1793e1eb447c8b04bfe46d48e9e48bfb8d2d7ed64ecf0"
+dependencies = [
+ "bitflags",
+]
+
 [[package]]
 name = "regex"
 version = "1.5.4"
@@ -422,6 +819,51 @@ version = "0.6.25"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
 
+[[package]]
+name = "remove_dir_all"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "reqwest"
+version = "0.11.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "46a1f7aa4f35e5e8b4160449f51afc758f0ce6454315a9fa7d0d113e958c41eb"
+dependencies = [
+ "base64",
+ "bytes",
+ "encoding_rs",
+ "futures-core",
+ "futures-util",
+ "h2",
+ "http",
+ "http-body",
+ "hyper",
+ "hyper-tls",
+ "ipnet",
+ "js-sys",
+ "lazy_static",
+ "log",
+ "mime",
+ "native-tls",
+ "percent-encoding",
+ "pin-project-lite",
+ "serde",
+ "serde_json",
+ "serde_urlencoded",
+ "tokio",
+ "tokio-native-tls",
+ "url",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "web-sys",
+ "winreg",
+]
+
 [[package]]
 name = "rustc_version"
 version = "0.4.0"
@@ -446,12 +888,45 @@ dependencies = [
  "winapi-util",
 ]
 
+[[package]]
+name = "schannel"
+version = "0.1.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75"
+dependencies = [
+ "lazy_static",
+ "winapi",
+]
+
 [[package]]
 name = "scopeguard"
 version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
 
+[[package]]
+name = "security-framework"
+version = "2.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2dc14f172faf8a0194a3aded622712b0de276821addc574fa54fc0a1167e10dc"
+dependencies = [
+ "bitflags",
+ "core-foundation",
+ "core-foundation-sys",
+ "libc",
+ "security-framework-sys",
+]
+
+[[package]]
+name = "security-framework-sys"
+version = "2.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
 [[package]]
 name = "semver"
 version = "1.0.6"
@@ -496,12 +971,42 @@ dependencies = [
  "serde",
 ]
 
+[[package]]
+name = "serde_urlencoded"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
+dependencies = [
+ "form_urlencoded",
+ "itoa 1.0.1",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "slab"
+version = "0.4.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5"
+
+[[package]]
+name = "socket2"
+version = "0.4.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0"
+dependencies = [
+ "libc",
+ "winapi",
+]
+
 [[package]]
 name = "spiral-rs"
 version = "0.1.0"
 dependencies = [
  "criterion",
  "rand",
+ "reqwest",
+ "serde_json",
 ]
 
 [[package]]
@@ -515,6 +1020,20 @@ dependencies = [
  "unicode-xid",
 ]
 
+[[package]]
+name = "tempfile"
+version = "3.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4"
+dependencies = [
+ "cfg-if",
+ "fastrand",
+ "libc",
+ "redox_syscall",
+ "remove_dir_all",
+ "winapi",
+]
+
 [[package]]
 name = "textwrap"
 version = "0.11.0"
@@ -534,6 +1053,108 @@ dependencies = [
  "serde_json",
 ]
 
+[[package]]
+name = "tinyvec"
+version = "1.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2"
+dependencies = [
+ "tinyvec_macros",
+]
+
+[[package]]
+name = "tinyvec_macros"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
+
+[[package]]
+name = "tokio"
+version = "1.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2af73ac49756f3f7c01172e34a23e5d0216f6c32333757c2c61feb2bbff5a5ee"
+dependencies = [
+ "bytes",
+ "libc",
+ "memchr",
+ "mio",
+ "num_cpus",
+ "pin-project-lite",
+ "socket2",
+ "winapi",
+]
+
+[[package]]
+name = "tokio-native-tls"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b"
+dependencies = [
+ "native-tls",
+ "tokio",
+]
+
+[[package]]
+name = "tokio-util"
+version = "0.6.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e99e1983e5d376cd8eb4b66604d2e99e79f5bd988c3055891dcd8c9e2604cc0"
+dependencies = [
+ "bytes",
+ "futures-core",
+ "futures-sink",
+ "log",
+ "pin-project-lite",
+ "tokio",
+]
+
+[[package]]
+name = "tower-service"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6"
+
+[[package]]
+name = "tracing"
+version = "0.1.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4a1bdf54a7c28a2bbf701e1d2233f6c77f473486b94bee4f9678da5a148dca7f"
+dependencies = [
+ "cfg-if",
+ "pin-project-lite",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-core"
+version = "0.1.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aa31669fa42c09c34d94d8165dd2012e8ff3c66aca50f3bb226b68f216f2706c"
+dependencies = [
+ "lazy_static",
+]
+
+[[package]]
+name = "try-lock"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642"
+
+[[package]]
+name = "unicode-bidi"
+version = "0.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f"
+
+[[package]]
+name = "unicode-normalization"
+version = "0.1.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9"
+dependencies = [
+ "tinyvec",
+]
+
 [[package]]
 name = "unicode-width"
 version = "0.1.9"
@@ -546,6 +1167,24 @@ version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
 
+[[package]]
+name = "url"
+version = "2.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c"
+dependencies = [
+ "form_urlencoded",
+ "idna",
+ "matches",
+ "percent-encoding",
+]
+
+[[package]]
+name = "vcpkg"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
+
 [[package]]
 name = "walkdir"
 version = "2.3.2"
@@ -557,12 +1196,28 @@ dependencies = [
  "winapi-util",
 ]
 
+[[package]]
+name = "want"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0"
+dependencies = [
+ "log",
+ "try-lock",
+]
+
 [[package]]
 name = "wasi"
 version = "0.10.2+wasi-snapshot-preview1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
 
+[[package]]
+name = "wasi"
+version = "0.11.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
+
 [[package]]
 name = "wasm-bindgen"
 version = "0.2.79"
@@ -588,6 +1243,18 @@ dependencies = [
  "wasm-bindgen-shared",
 ]
 
+[[package]]
+name = "wasm-bindgen-futures"
+version = "0.4.29"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2eb6ec270a31b1d3c7e266b999739109abce8b6c87e4b31fcfcd788b65267395"
+dependencies = [
+ "cfg-if",
+ "js-sys",
+ "wasm-bindgen",
+ "web-sys",
+]
+
 [[package]]
 name = "wasm-bindgen-macro"
 version = "0.2.79"
@@ -657,3 +1324,12 @@ name = "winapi-x86_64-pc-windows-gnu"
 version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
+[[package]]
+name = "winreg"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d"
+dependencies = [
+ "winapi",
+]

+ 2 - 0
Cargo.toml

@@ -5,6 +5,8 @@ edition = "2021"
 
 [dependencies]
 rand = "0.8.5"
+reqwest = { version = "0.11", features = ["blocking"] }
+serde_json = "1.0"
 
 [dev-dependencies]
 criterion = "0.3"

+ 19 - 0
src/arith.rs

@@ -9,6 +9,10 @@ pub const fn log2(a: u64) -> u64 {
     std::mem::size_of::<u64>() as u64 * 8 - a.leading_zeros() as u64 - 1
 }
 
+pub fn log2_ceil(a: usize) -> usize {
+    f64::ceil(f64::log2(a as f64)) as usize
+}
+
 pub fn multiply_modular(params: &Params, a: u64, b: u64, c: usize) -> u64 {
     (a * b) % params.moduli[c]
 }
@@ -79,6 +83,21 @@ pub fn div2_uint_mod(operand: u64, modulus: u64) -> u64 {
     }
 }
 
+pub fn recenter(val: u64, from_modulus: u64, to_modulus: u64) -> u64 {
+    assert!(from_modulus >= to_modulus);
+
+    let from_modulus_i64 = from_modulus as i64;
+    let to_modulus_i64 = to_modulus as i64;
+
+    let mut a_val = val as i64;
+    if val >= from_modulus/2 {
+        a_val -= from_modulus_i64;
+    }
+    a_val = a_val + (from_modulus_i64/to_modulus_i64)*to_modulus_i64 + 2*to_modulus_i64;
+    a_val %= to_modulus_i64;
+    a_val as u64
+}
+
 #[cfg(test)]
 mod test {
     use super::*;

+ 193 - 25
src/client.rs

@@ -1,6 +1,16 @@
-use std::collections::HashMap;
+use crate::{poly::*, params::*, discrete_gaussian::*, gadget::*, arith::*, util::*, number_theory::*};
 
-use crate::{poly::*, params::*, discrete_gaussian::*, gadget::*, arith::*};
+fn serialize_polymatrix(vec: &mut Vec<u8>, a: &PolyMatrixRaw) {
+    for i in 0..a.rows * a.cols * a.params.poly_len {
+        vec.extend_from_slice(&u64::to_ne_bytes(a.data[i]));
+    }
+}
+
+fn serialize_vec_polymatrix(vec: &mut Vec<u8>, a: &Vec<PolyMatrixRaw>) {
+    for i in 0..a.len() {
+        serialize_polymatrix(vec, &a[i]);
+    }
+}
 
 pub struct PublicParameters<'a> {
     v_packing: Vec<PolyMatrixNTT<'a>>,            // Ws
@@ -10,7 +20,7 @@ pub struct PublicParameters<'a> {
 }
 
 impl<'a> PublicParameters<'a> {
-    fn init(params: &'a Params) -> Self {
+    pub fn init(params: &'a Params) -> Self {
         PublicParameters { 
             v_packing: Vec::new(), 
             v_expansion_left: Vec::new(), 
@@ -18,11 +28,41 @@ impl<'a> PublicParameters<'a> {
             conversion: PolyMatrixNTT::zero(params, 2, 2 * params.m_conv()) 
         }
     }
+
+    pub fn to_raw(&self) -> Vec<Vec<PolyMatrixRaw>> {
+        vec![
+            self.v_packing.iter().map(from_ntt_alloc).collect(),
+            self.v_expansion_left.iter().map(from_ntt_alloc).collect(),
+            self.v_expansion_right.iter().map(from_ntt_alloc).collect(),
+            vec![from_ntt_alloc(&self.conversion)]
+        ]
+    }
+
+    pub fn serialize(&self) -> Vec<u8> {
+        let mut data = Vec::new();
+        for v in self.to_raw().iter() {
+            println!("{} bytes", data.len());
+            serialize_vec_polymatrix(&mut data, v);
+        }
+        println!("{} bytes", data.len());
+        data
+    }
 }
 
 pub struct Query<'a> {
-    ct: PolyMatrixNTT<'a>,
-    v_ct: Vec<PolyMatrixNTT<'a>>,
+    ct: Option<PolyMatrixRaw<'a>>,
+    // v_ct: Option<Vec<PolyMatrixRaw<'a>>>,
+}
+
+impl<'a> Query<'a> {
+    pub fn serialize(&self) -> Vec<u8> {
+        let mut data = Vec::new();
+        if self.ct.is_some() {
+            let ct = self.ct.as_ref().unwrap();
+            serialize_polymatrix(&mut data, &ct);
+        }
+        data
+    }
 }
 
 pub struct Client<'a> {
@@ -32,6 +72,8 @@ pub struct Client<'a> {
     sk_gsw_full: PolyMatrixRaw<'a>,
     sk_reg_full: PolyMatrixRaw<'a>,
     dg: DiscreteGaussian,
+    g: usize,
+    stop_round: usize,
 }
 
 fn matrix_with_identity<'a> (p: &PolyMatrixRaw<'a>) -> PolyMatrixRaw<'a> {
@@ -42,6 +84,24 @@ fn matrix_with_identity<'a> (p: &PolyMatrixRaw<'a>) -> PolyMatrixRaw<'a> {
     r
 }
 
+fn params_with_moduli(params: &Params, moduli: &Vec<u64>) -> Params {
+    Params::init(
+        params.poly_len, 
+        moduli, 
+        params.noise_width,
+        params.n,
+        params.pt_modulus,
+        params.q2_bits,
+        params.t_conv,
+        params.t_exp_left,
+        params.t_exp_right,
+        params.t_gsw,
+        params.expand_queries,
+        params.db_dim_1,
+        params.db_dim_2,
+    )
+}
+
 impl<'a> Client<'a> {
     pub fn init(params: &'a Params) -> Self {
         let sk_gsw_dims = params.get_sk_gsw();
@@ -51,6 +111,12 @@ impl<'a> Client<'a> {
         let sk_gsw_full = matrix_with_identity(&sk_gsw);
         let sk_reg_full = matrix_with_identity(&sk_reg);
         let dg = DiscreteGaussian::init(params);
+
+        let further_dims = params.db_dim_2;
+        let num_expanded = 1usize << params.db_dim_1;
+        let num_bits_to_gen = params.t_gsw * further_dims + num_expanded;
+        let g = log2_ceil(num_bits_to_gen);
+        let stop_round = log2_ceil(params.t_gsw * further_dims);
         Self {
             params,
             sk_gsw,
@@ -58,6 +124,8 @@ impl<'a> Client<'a> {
             sk_gsw_full,
             sk_reg_full,
             dg,
+            g,
+            stop_round,
         }
     }
 
@@ -97,14 +165,14 @@ impl<'a> Client<'a> {
         p
     }
 
-    fn encrypt_matrix_gsw(&mut self, ag: PolyMatrixNTT<'a>) -> PolyMatrixNTT<'a> {
+    fn encrypt_matrix_gsw(&mut self, ag: &PolyMatrixNTT<'a>) -> PolyMatrixNTT<'a> {
         let mx = ag.cols;
         let p = self.get_fresh_gsw_public_key(mx);
         let res = &(p.ntt()) + &(ag.pad_top(1));
         res
     }
     
-    fn encrypt_matrix_reg(&mut self, a: PolyMatrixNTT<'a>) -> PolyMatrixNTT<'a> {
+    fn encrypt_matrix_reg(&mut self, a: &PolyMatrixNTT<'a>) -> PolyMatrixNTT<'a> {
         let m = a.cols;
         let p = self.get_fresh_reg_public_key(m);
         &p + &a.pad_top(1)
@@ -120,7 +188,7 @@ impl<'a> Client<'a> {
             let t = (params.poly_len / (1 << i)) + 1;
             let tau_sk_reg = automorph_alloc(&self.sk_reg, t);
             let prod = &tau_sk_reg.ntt() * &g_exp_ntt;
-            let w_exp_i = self.encrypt_matrix_reg(prod);
+            let w_exp_i = self.encrypt_matrix_reg(&prod);
             res.push(w_exp_i);
         }
         res
@@ -144,19 +212,16 @@ impl<'a> Client<'a> {
             let scaled = scalar_multiply_alloc(&sk_reg_ntt, &gadget_conv_ntt);
             let mut ag = PolyMatrixNTT::zero(params, params.n, m_conv);
             ag.copy_into(&scaled, i, 0);
-            let w = self.encrypt_matrix_gsw(ag);
+            let w = self.encrypt_matrix_gsw(&ag);
             pp.v_packing.push(w);
         }
 
         if params.expand_queries {
             // Params for expansion
-            let further_dims = 1usize << params.db_dim_2;
-            let num_expanded = 1usize << params.db_dim_1;
-            let num_bits_to_gen = params.t_gsw * further_dims + num_expanded;
-            let g = log2(num_bits_to_gen as u64) as usize;
-            let stop_round = log2((params.t_gsw * further_dims) as u64) as usize;
-            pp.v_expansion_left = self.generate_expansion_params(g, params.t_exp_left);
-            pp.v_expansion_right = self.generate_expansion_params(stop_round + 1, params.t_exp_right);
+            
+            pp.v_expansion_left = self.generate_expansion_params(self.g, params.t_exp_left);
+            println!("dims exp left {} x {}", pp.v_expansion_left[0].rows, pp.v_expansion_left[0].cols);
+            pp.v_expansion_right = self.generate_expansion_params(self.stop_round + 1, params.t_exp_right);
 
             // Params for converison
             let g_conv = build_gadget(params, 2, 2 * m_conv);
@@ -166,7 +231,7 @@ impl<'a> Client<'a> {
                 if i % 2 == 0 {
                     let val = g_conv.get_poly(0, i)[0];
                     let sigma = &sk_reg_squared_ntt * &single_poly(params, val).ntt();
-                    let ct = self.encrypt_matrix_reg(sigma);
+                    let ct = self.encrypt_matrix_reg(&sigma);
                     pp.conversion.copy_into(&ct, 0, i);
                 }
             }
@@ -175,14 +240,117 @@ impl<'a> Client<'a> {
         pp
     }
 
-    // fn generate_query(&self) -> Query<'a> {
-    //     let params = self.params;
-    //     let mut query = Query { ct: PolyMatrixNTT::zero(params, 1, 1), v_ct: Vec::new() }
-    //     if params.expand_queries {
-            
-    //     } else {
+    pub fn generate_query(&mut self, idx_target: usize) -> Query<'a> {
+        let params = self.params;
+        let further_dims = params.db_dim_2;
+        let idx_dim0= idx_target / (1 << further_dims);
+        let idx_further  = idx_target % (1 << further_dims);
+        let scale_k = params.modulus / params.pt_modulus;
+        let bits_per = get_bits_per(params, params.t_gsw);
+
+        let mut query = Query { ct: None };
+        if params.expand_queries {
+            // pack query into single ciphertext
+            let mut sigma = PolyMatrixRaw::zero(params, 1, 1);
+            sigma.data[2*idx_dim0] = scale_k;
+            for i in 0..further_dims as u64 {
+                let bit: u64 = ((idx_further as u64) & (1 << i)) >> i;
+                for j in 0..params.t_gsw {
+                    let val = (1u64 << (bits_per * j)) * bit;
+                    let idx = (i as usize) * params.t_gsw + (j as usize);
+                    sigma.data[2*idx + 1] = val;
+                }
+            }
+            let inv_2_g_first = invert_uint_mod(1 << self.g, params.modulus).unwrap();
+            let inv_2_g_rest = invert_uint_mod(1 << (self.stop_round+1), params.modulus).unwrap();
 
-    //     }
-    // }
+            for i in 0..params.poly_len/2 {
+                sigma.data[2*i]   = multiply_uint_mod(sigma.data[2*i], inv_2_g_first, params.modulus);
+                sigma.data[2*i+1] = multiply_uint_mod(sigma.data[2*i+1], inv_2_g_rest, params.modulus);
+            }
+
+            query.ct = Some(from_ntt_alloc(&self.encrypt_matrix_reg(&to_ntt_alloc(&sigma))));
+        } else {
+            assert!(false);
+        }
+        query
+    }
     
+    pub fn decode_response(&self, data: &[u8]) -> Vec<u8> {
+        /*
+            0. NTT over q2 the secret key
+
+            1. read first row in q2_bit chunks
+            2. read rest in q1_bit chunks
+            3. NTT over q2 the first row
+            4. Multiply the results of (0) and (3)
+            5. Divide and round correctly
+        */
+        let params = self.params;
+        let p = params.pt_modulus;
+        let p_bits = log2_ceil(params.pt_modulus as usize);
+        let q1 = 4 * params.pt_modulus;
+        let q1_bits = log2_ceil(q1 as usize);
+        let q2 = Q2_VALUES[params.q2_bits as usize];
+        let q2_bits = params.q2_bits as usize;
+
+        let q2_params = params_with_moduli(params, &vec![q2]);
+
+        // this only needs to be done during keygen
+        let mut sk_gsw_q2 = PolyMatrixRaw::zero(&q2_params, params.n, 1);
+        for i in 0..params.poly_len * params.n {
+            sk_gsw_q2.data[i] = recenter(self.sk_gsw.data[i], params.modulus, q2);
+        }
+        let mut sk_gsw_q2_ntt = PolyMatrixNTT::zero(&q2_params, params.n, 1);
+        to_ntt(&mut sk_gsw_q2_ntt, &sk_gsw_q2);
+
+        // this must be done during decoding
+        let mut first_row = PolyMatrixRaw::zero(&q2_params, 1, params.n);
+        let mut rest_rows = PolyMatrixRaw::zero(&params, params.n, params.n);
+        let mut bit_offs = 0;
+        for i in 0..params.n * params.poly_len {
+            first_row.data[i] = read_arbitrary_bits(data, bit_offs, q2_bits);
+            bit_offs += q2_bits;
+        }
+        for i in 0..params.n * params.n * params.poly_len {
+            rest_rows.data[i] = read_arbitrary_bits(data, bit_offs, q1_bits);
+            bit_offs += q1_bits;
+        }
+
+        let mut first_row_q2 = PolyMatrixNTT::zero(&q2_params, 1, params.n);
+        to_ntt(&mut first_row_q2, &first_row);
+
+        let sk_prod = (&sk_gsw_q2_ntt * &first_row_q2).raw();
+
+        let q1_i64 = q1 as i64;
+        let q2_i64 = q2 as i64;
+        let p_i128 = p as i128;
+        let mut result = PolyMatrixRaw::zero(&params, params.n, params.n);
+        for i in 0..result.rows * result.cols * params.poly_len {
+            let mut val_first = sk_prod.data[i] as i64;
+            if val_first >= q2_i64/2 {
+                val_first -= q2_i64;
+            }
+            let mut val_rest = rest_rows.data[i] as i64;
+            if val_rest >= q1_i64/2 {
+                val_rest -= q1_i64;
+            }
+
+            let denom = (q2 * (q1 / p)) as i64;
+
+            let mut r = val_first * q1_i64;
+            r += val_rest * q2_i64;
+
+            // divide r by q2, rounding
+            let sign: i64 = if r >= 0 { 1 } else { -1 };
+            let mut res = ((r + sign*(denom/2)) as i128) / (denom as i128);
+            res = (res + (denom as i128/p_i128)*(p_i128) + 2*(p_i128)) % (p_i128);
+            result.data[i] = res as u64;
+
+            // println!("{:?}, {:?} -> {:?}", val_first, val_rest, res as u64);
+        }
+        println!("{:?}", result.data);
+        
+        result.to_vec(p_bits)
+    }
 }

+ 38 - 24
src/discrete_gaussian.rs

@@ -1,5 +1,6 @@
-use rand::{thread_rng, Rng, rngs::ThreadRng};
-use rand::distributions::OpenClosed01;
+use rand::prelude::Distribution;
+use rand::{thread_rng, rngs::ThreadRng};
+use rand::distributions::WeightedIndex;
 
 use crate::params::*;
 use crate::poly::*;
@@ -8,45 +9,33 @@ use std::f64::consts::PI;
 pub const NUM_WIDTHS: usize = 8;
 
 pub struct DiscreteGaussian {
-    max_val: i64,
-    table: Vec<f64>,
+    choices: Vec<i64>,
+    dist: WeightedIndex<f64>,
     rng: ThreadRng
 }
 
 impl DiscreteGaussian {
     pub fn init(params: &Params) -> Self {
         let max_val = (params.noise_width * (NUM_WIDTHS as f64)).ceil() as i64;
+        let mut choices = Vec::new();
         let mut table = vec![0f64; 0];
-        let mut sum_p = 0f64;
-        table.push(0f64);
         for i in -max_val..max_val+1 {
             let p_val = f64::exp(-PI * f64::powi(i as f64, 2) / f64::powi(params.noise_width, 2));
+            choices.push(i);
             table.push(p_val);
-            sum_p += p_val;
         }
-        for i in 0..table.len() {
-            table[i] /= sum_p;
-        }
-        table.push(1.0);
-    
+        let dist = WeightedIndex::new(&table).unwrap();
+
         Self {
-            max_val,
-            table,
+            choices,
+            dist,
             rng: thread_rng()
         }
     }
 
-    // FIXME: this is not necessarily constant-time w/ optimization
+    // FIXME: not constant-time
     pub fn sample(&mut self) -> i64 {
-        let val: f64 = self.rng.sample(OpenClosed01);
-        let mut found = 0i64;
-        for i in 0..self.table.len()-1 {
-           let bit1: i64 = (val <= self.table[i]) as i64;
-           let bit2: i64 = (val > self.table[i+1]) as i64;
-            found += bit1 * bit2 * (i as i64);
-        }
-        found -= self.max_val;
-        found
+        self.choices[self.dist.sample(&mut self.rng)]
     }
 
     pub fn sample_matrix(&mut self, p: &mut PolyMatrixRaw) {
@@ -63,4 +52,29 @@ impl DiscreteGaussian {
             }
         }
     }
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    use crate::util::*;
+
+    #[test]
+    fn dg_seems_okay() {
+        let params = get_test_params();
+        let mut dg = DiscreteGaussian::init(&params);
+        let mut v = Vec::new();
+        let trials = 10000;
+        let mut sum = 0;
+        for _ in 0..trials {
+            let val = dg.sample();
+            v.push(val);
+            // println!("{}", val);
+            sum += val;
+        }
+        let mean = sum as f64 / trials as f64;
+        let std_dev = params.noise_width / f64::sqrt(2f64 * std::f64::consts::PI);
+        let std_dev_of_mean = std_dev / f64::sqrt(trials as f64);
+        assert!(f64::abs(mean) < std_dev_of_mean * 5f64);
+    }
 }

+ 68 - 11
src/main.rs

@@ -1,15 +1,72 @@
-use spiral_rs::poly::*;
+use serde_json::Value;
 use spiral_rs::util::*;
-use spiral_rs::*;
+use spiral_rs::client::*;
+use std::env;
+
+fn send_api_req_text(path: &str, data: Vec<u8>) -> Option<String> {
+    let client = reqwest::blocking::Client::builder()
+        .timeout(None)
+        .build().unwrap();
+    client.post(format!("https://spiralwiki.com:8088{}", path))
+        .body(data)
+        .send()
+        .ok()?
+        .text()
+        .ok()
+}
+
+fn send_api_req_vec(path: &str, data: Vec<u8>) -> Option<Vec<u8>> {
+    let client = reqwest::blocking::Client::builder()
+        .timeout(None)
+        .build().unwrap();
+    Some(client.post(format!("https://spiralwiki.com:8088{}", path))
+        .body(data)
+        .send()
+        .ok()?
+        .bytes()
+        .ok()?
+        .to_vec())
+}
 
 fn main() {
-    println!("Hello, world!");
-    let params = get_test_params();
-    let m1 = poly::PolyMatrixNTT::zero(&params, 2, 1);
-    println!("{}", m1.is_ntt());
-    let m2 = poly::PolyMatrixNTT::zero(&params, 3, 2);
-    let mut m3 = poly::PolyMatrixNTT::zero(&params, 3, 1);
-    println!("{}", m1.is_ntt());
-    multiply(&mut m3, &m2, &m1);
-    println!("{}", m3.is_ntt());
+    let cfg = r#"
+        {'n': 2,
+        'nu_1': 9,
+        'nu_2': 6,
+        'p': 256,
+        'q_prime_bits': 20,
+        's_e': 87.62938774292914,
+        't_GSW': 8,
+        't_conv': 4,
+        't_exp': 8,
+        't_exp_right': 56}
+    "#;
+    let cfg = cfg.replace("'", "\"");
+    let params = params_from_json(&cfg);
+
+    let args: Vec<String> = env::args().collect();
+    let idx_target: usize = (&args[1]).parse().unwrap();
+
+    println!("initializing client");
+    let mut c = Client::init(&params);
+    println!("generating public parameters");
+    let pub_params = c.generate_keys();
+    let pub_params_buf = pub_params.serialize();
+    println!("pub_params size {}", pub_params_buf.len());
+    let query = c.generate_query(idx_target);
+    let mut query_buf = query.serialize();
+    println!("initial query size {}", query_buf.len());
+
+    let setup_resp_str = send_api_req_text("/setup", pub_params_buf).unwrap();
+    println!("{}", setup_resp_str);
+    let resp_json: Value = serde_json::from_str(&setup_resp_str).unwrap();
+    let id = resp_json["id"].as_str().unwrap();
+    let mut full_query_buf = id.as_bytes().to_vec();
+    println!("id size {}", full_query_buf.len());
+    full_query_buf.append(&mut query_buf);
+    let query_resp = send_api_req_vec("/query", full_query_buf).unwrap();
+    println!("query_resp len {}", query_resp.len());
+
+    let _result = c.decode_response(query_resp.as_slice());
+    // println!("{:x?}", result);
 }

+ 27 - 4
src/params.rs

@@ -1,5 +1,11 @@
 use crate::{arith::*, ntt::*, number_theory::*};
 
+pub static Q2_VALUES: [u64; 37] = [
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12289, 12289, 61441, 65537, 65537, 520193, 786433, 786433, 3604481, 7340033, 16515073, 33292289, 67043329, 132120577, 268369921, 469762049, 1073479681, 2013265921, 4293918721, 8588886017, 17175674881, 34359214081, 68718428161
+];
+
+#[derive(Debug)]
+#[derive(PartialEq)]
 pub struct Params {    
     pub poly_len: usize,
     pub poly_len_log2: usize,
@@ -10,11 +16,11 @@ pub struct Params {
     pub moduli: Vec<u64>,
     pub modulus: u64,
     pub modulus_log2: u64,
-
     pub noise_width: f64,
 
     pub n: usize,
-
+    pub pt_modulus: u64,
+    pub q2_bits: u64,
     pub t_conv: usize,
     pub t_exp_left: usize,
     pub t_exp_right: usize,
@@ -47,7 +53,12 @@ impl Params {
     }
 
     pub fn m_conv(&self) -> usize {
-        2 * self.t_conv
+        self.t_conv
+    }
+
+    pub fn crt_compose_1(&self, x: u64) -> u64 {
+        assert_eq!(self.crt_count, 1);
+        x
     }
 
     pub fn crt_compose_2(&self, x: u64, y: u64) -> u64 {
@@ -62,11 +73,21 @@ impl Params {
         (val % (self.modulus as u128)) as u64 // FIXME: use barrett
     }
 
+    pub fn crt_compose(&self, a: &[u64], idx: usize) -> u64 {
+        if self.crt_count == 1 {
+            self.crt_compose_1(a[idx])
+        } else {
+            self.crt_compose_2(a[idx], a[idx + self.poly_len])
+        }
+    }
+
     pub fn init(
         poly_len: usize,
         moduli: &Vec<u64>,
         noise_width: f64,
         n: usize,
+        pt_modulus: u64,
+        q2_bits: u64,
         t_conv: usize,
         t_exp_left: usize,
         t_exp_right: usize,
@@ -83,7 +104,7 @@ impl Params {
         for m in moduli {
             modulus *= m;
         }
-        let modulus_log2 = log2(modulus);
+        let modulus_log2 = log2_ceil(modulus as usize) as u64;
         Self {
             poly_len,
             poly_len_log2,
@@ -95,6 +116,8 @@ impl Params {
             modulus_log2,
             noise_width,
             n,
+            pt_modulus,
+            q2_bits,
             t_conv,
             t_exp_left,
             t_exp_right,

+ 19 - 8
src/poly.rs

@@ -39,8 +39,8 @@ pub trait PolyMatrix<'a> {
     fn copy_into(&mut self, p: &Self, target_row: usize, target_col: usize) {
         assert!(target_row < self.get_rows());
         assert!(target_col < self.get_cols());
-        assert!(target_row + p.get_rows() < self.get_rows());
-        assert!(target_col + p.get_cols() < self.get_cols());
+        assert!(target_row + p.get_rows() <= self.get_rows());
+        assert!(target_col + p.get_cols() <= self.get_cols());
         for r in 0..p.get_rows() {
             for c in 0..p.get_cols() {
                 let pol_src = p.get_poly(r, c);
@@ -145,6 +145,20 @@ impl<'a> PolyMatrixRaw<'a> {
     pub fn ntt(&self) -> PolyMatrixNTT<'a> {
         to_ntt_alloc(&self)
     }
+
+    pub fn to_vec(&self, modulus_bits: usize) -> Vec<u8> {
+        let params = self.params;
+        let sz_bits = self.rows * self.cols * params.poly_len * modulus_bits;
+        let sz_bytes = f64::ceil((sz_bits as f64) / 8f64) as usize;
+        let sz_bytes_roundup_16 = ((sz_bytes + 15) / 16) * 16;
+        let mut data = vec![0u8; sz_bytes_roundup_16];
+        let mut bit_offs = 0;
+        for i in 0..self.rows * self.cols * params.poly_len {
+            write_arbitrary_bits(data.as_mut_slice(), self.data[i], bit_offs, modulus_bits);
+            bit_offs += modulus_bits;
+        }
+        data
+    }
 }
 
 impl<'a> PolyMatrix<'a> for PolyMatrixNTT<'a> {
@@ -237,11 +251,8 @@ pub fn add_poly(params: &Params, res: &mut [u64], a: &[u64], b: &[u64]) {
 }
 
 pub fn invert_poly(params: &Params, res: &mut [u64], a: &[u64]) {
-    for c in 0..params.crt_count {
-        for i in 0..params.poly_len {
-            let idx = c * params.poly_len + i;
-            res[idx] = invert_modular(params, a[idx], c);
-        }
+    for i in 0..params.poly_len {
+        res[i] = params.modulus - a[i];
     }
 }
 
@@ -455,7 +466,7 @@ pub fn from_ntt(a: &mut PolyMatrixRaw, b: &PolyMatrixNTT) {
                 scratch[0..pol_src.len()].copy_from_slice(pol_src);
                 ntt_inverse(params, scratch);
                 for z in 0..params.poly_len {
-                    pol_dst[z] = params.crt_compose_2(scratch[z], scratch[params.poly_len + z]);
+                    pol_dst[z] = params.crt_compose(scratch, z);
                 }
             }
         }

+ 125 - 3
src/util.rs

@@ -1,4 +1,5 @@
 use crate::params::*;
+use serde_json::{Value};
 
 pub fn calc_index(indices: &[usize], lengths: &[usize]) -> usize {
     let mut idx = 0usize;
@@ -16,12 +17,133 @@ pub fn get_test_params() -> Params {
         &vec![268369921u64, 249561089u64], 
         6.4,
         2,
+        256,
+        20,
+        4,
+        8,
         56,
-        56,
-        56,
-        56,
+        8,
         true,
         9,
         6,
     )
+}
+
+pub fn params_from_json(cfg: &str) -> Params {
+    let v: Value = serde_json::from_str(cfg).unwrap();
+    let n = v["n"].as_u64().unwrap() as usize;
+    let db_dim_1 = v["nu_1"].as_u64().unwrap() as usize;
+    let db_dim_2 = v["nu_2"].as_u64().unwrap() as usize;
+    let p = v["p"].as_u64().unwrap();
+    let q2_bits = v["q_prime_bits"].as_u64().unwrap();
+    let t_gsw = v["t_GSW"].as_u64().unwrap() as usize;
+    let t_conv = v["t_conv"].as_u64().unwrap() as usize;
+    let t_exp_left = v["t_exp"].as_u64().unwrap() as usize;
+    let t_exp_right = v["t_exp_right"].as_u64().unwrap() as usize;
+    let do_expansion = v.get("kinda_direct_upload").is_none();
+    Params::init(
+        2048, 
+        &vec![268369921u64, 249561089u64], 
+        6.4,
+        n,
+        p,
+        q2_bits,
+        t_conv,
+        t_exp_left,
+        t_exp_right,
+        t_gsw,
+        do_expansion,
+        db_dim_1,
+        db_dim_2,
+    )
+}
+
+pub fn read_arbitrary_bits(data: &[u8], bit_offs: usize, num_bits: usize) -> u64 {
+    let word_off = bit_offs / 64;
+    let bit_off_within_word = bit_offs % 64;
+    if (bit_off_within_word + num_bits) <= 64 {
+        let idx = word_off * 8;
+        let val = u64::from_ne_bytes(data[idx..idx + 8].try_into().unwrap());
+        (val >> bit_off_within_word) & ((1u64 << num_bits) - 1)
+    } else {
+        let idx = word_off * 8;
+        let val = u128::from_ne_bytes(data[idx..idx + 16].try_into().unwrap());
+        ((val >> bit_off_within_word) & ((1u128 << num_bits) - 1)) as u64
+    }
+}
+
+pub fn write_arbitrary_bits(data: &mut [u8], mut val: u64, bit_offs: usize, num_bits: usize) {
+    let word_off = bit_offs / 64;
+    let bit_off_within_word = bit_offs % 64;
+    val = val & ((1u64 << num_bits) - 1);
+    if (bit_off_within_word + num_bits) <= 64 {
+        let idx = word_off * 8;
+        let mut cur_val = u64::from_ne_bytes(data[idx..idx + 8].try_into().unwrap());
+        cur_val &= !(((1u64 << num_bits) - 1) << bit_off_within_word);
+        cur_val |= val << bit_off_within_word;
+        data[idx..idx + 8].copy_from_slice(&u64::to_ne_bytes(cur_val));
+    } else {
+        let idx = word_off * 8;
+        let mut cur_val = u128::from_ne_bytes(data[idx..idx + 16].try_into().unwrap());
+        let mask = !(((1u128 << num_bits) - 1) << bit_off_within_word);
+        cur_val &= mask;
+        cur_val |= (val as u128) << bit_off_within_word;
+        data[idx..idx + 16].copy_from_slice(&u128::to_ne_bytes(cur_val));
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+
+    #[test]
+    fn params_from_json_correct() {
+        let cfg = r#"
+            {'n': 2,
+            'nu_1': 9,
+            'nu_2': 6,
+            'p': 256,
+            'q_prime_bits': 20,
+            's_e': 87.62938774292914,
+            't_GSW': 8,
+            't_conv': 4,
+            't_exp': 8,
+            't_exp_right': 56}
+        "#;
+        let cfg = cfg.replace("'", "\"");
+        let b = params_from_json(&cfg);
+        let c = Params::init(
+            2048, 
+            &vec![268369921u64, 249561089u64], 
+            6.4,
+            2,
+            256,
+            20,
+            4,
+            8,
+            56,
+            8,
+            true,
+            9,
+            6,
+        );
+        assert_eq!(b, c);
+    }
+
+    #[test]
+    fn test_read_write_arbitrary_bits() {
+        let mut data = vec![0u8; 1024];
+        let num_bits = 5;
+        let mut bit_offs = 0;
+        for i in 0..1000 {
+            write_arbitrary_bits(data.as_mut_slice(), i % 32, bit_offs, num_bits);
+            bit_offs += num_bits;
+        }
+        bit_offs = 0;
+        for i in 0..1000 {
+            let val = read_arbitrary_bits(data.as_slice(), bit_offs, num_bits);
+            assert_eq!(val, i % 32);
+            bit_offs += num_bits;
+        }
+    }
 }