Browse Source

Add level up client request

onyinyang 9 months ago
parent
commit
1876897dcb
3 changed files with 618 additions and 85 deletions
  1. 479 2
      Cargo.lock
  2. 5 0
      Cargo.toml
  3. 134 83
      src/proto/level_up.rs

+ 479 - 2
Cargo.lock

@@ -2,6 +2,42 @@
 # It is not intended for manual editing.
 version = 4
 
+[[package]]
+name = "android-tzdata"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
+
+[[package]]
+name = "android_system_properties"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "autocfg"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
+
+[[package]]
+name = "base64"
+version = "0.22.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
+
+[[package]]
+name = "bincode"
+version = "1.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
+dependencies = [
+ "serde",
+]
+
 [[package]]
 name = "bitvec"
 version = "1.0.1"
@@ -23,39 +59,80 @@ dependencies = [
  "generic-array",
 ]
 
+[[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 = "cc"
+version = "1.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fcb57c740ae1daf453ae85f16e37396f672b039e00d9d866e07ddb24e328e3a"
+dependencies = [
+ "shlex",
+]
+
 [[package]]
 name = "cfg-if"
 version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
+[[package]]
+name = "chrono"
+version = "0.4.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c"
+dependencies = [
+ "android-tzdata",
+ "iana-time-zone",
+ "num-traits",
+ "serde",
+ "windows-link",
+]
+
 [[package]]
 name = "cmz"
 version = "0.1.0"
-source = "git+ssh://gogs@git-crysp.uwaterloo.ca/SigmaProtocol/cmz.git#f9759d4f0a10201d25ce05eff875b439f7f9d278"
+source = "git+ssh://gogs@git-crysp.uwaterloo.ca/SigmaProtocol/cmz.git#83f447d04b9dd9e4f1a0c10e48d30593fd635246"
 dependencies = [
  "cmzcred_derive",
  "curve25519-dalek",
  "ff",
+ "generic_static",
  "group",
+ "hex",
+ "lazy_static",
+ "rand_core",
+ "serde",
+ "serde_with",
+ "thiserror",
 ]
 
 [[package]]
 name = "cmzcred_derive"
 version = "0.1.0"
-source = "git+ssh://gogs@git-crysp.uwaterloo.ca/SigmaProtocol/cmz.git#f9759d4f0a10201d25ce05eff875b439f7f9d278"
+source = "git+ssh://gogs@git-crysp.uwaterloo.ca/SigmaProtocol/cmz.git#83f447d04b9dd9e4f1a0c10e48d30593fd635246"
 dependencies = [
  "darling",
  "quote",
  "syn",
 ]
 
+[[package]]
+name = "core-foundation-sys"
+version = "0.8.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
+
 [[package]]
 name = "cpufeatures"
 version = "0.2.17"
@@ -140,6 +217,16 @@ dependencies = [
  "syn",
 ]
 
+[[package]]
+name = "deranged"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28cfac68e08048ae1883171632c2aef3ebc555621ae56fbccce1cbf22dd7f058"
+dependencies = [
+ "powerfmt",
+ "serde",
+]
+
 [[package]]
 name = "digest"
 version = "0.10.7"
@@ -150,6 +237,12 @@ dependencies = [
  "crypto-common",
 ]
 
+[[package]]
+name = "equivalent"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
+
 [[package]]
 name = "ff"
 version = "0.13.1"
@@ -189,6 +282,15 @@ dependencies = [
  "version_check",
 ]
 
+[[package]]
+name = "generic_static"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28ccff179d8070317671db09aee6d20affc26e88c5394714553b04f509b43a60"
+dependencies = [
+ "once_cell",
+]
+
 [[package]]
 name = "getrandom"
 version = "0.2.15"
@@ -211,12 +313,95 @@ dependencies = [
  "subtle",
 ]
 
+[[package]]
+name = "hashbrown"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
+
+[[package]]
+name = "hashbrown"
+version = "0.15.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
+
+[[package]]
+name = "hex"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "iana-time-zone"
+version = "0.1.62"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b2fd658b06e56721792c5df4475705b6cda790e9298d19d2f8af083457bcd127"
+dependencies = [
+ "android_system_properties",
+ "core-foundation-sys",
+ "iana-time-zone-haiku",
+ "js-sys",
+ "log",
+ "wasm-bindgen",
+ "windows-core",
+]
+
+[[package]]
+name = "iana-time-zone-haiku"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
+dependencies = [
+ "cc",
+]
+
 [[package]]
 name = "ident_case"
 version = "1.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
 
+[[package]]
+name = "indexmap"
+version = "1.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
+dependencies = [
+ "autocfg",
+ "hashbrown 0.12.3",
+ "serde",
+]
+
+[[package]]
+name = "indexmap"
+version = "2.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058"
+dependencies = [
+ "equivalent",
+ "hashbrown 0.15.2",
+ "serde",
+]
+
+[[package]]
+name = "itoa"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
+
+[[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 = "lazy_static"
 version = "1.5.0"
@@ -229,20 +414,64 @@ version = "0.2.169"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
 
+[[package]]
+name = "log"
+version = "0.4.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
+
 [[package]]
 name = "lox-extensions"
 version = "0.1.0"
 dependencies = [
+ "bincode",
  "cmz",
  "curve25519-dalek",
+ "ff",
  "group",
  "lazy_static",
  "rand",
+ "rand_core",
  "serde",
+ "serde_with",
  "sha2",
  "subtle",
+ "thiserror",
 ]
 
+[[package]]
+name = "memchr"
+version = "2.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
+
+[[package]]
+name = "num-conv"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
+
+[[package]]
+name = "num-traits"
+version = "0.2.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.21.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
+
+[[package]]
+name = "powerfmt"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
+
 [[package]]
 name = "ppv-lite86"
 version = "0.2.20"
@@ -315,6 +544,18 @@ dependencies = [
  "semver",
 ]
 
+[[package]]
+name = "rustversion"
+version = "1.0.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2"
+
+[[package]]
+name = "ryu"
+version = "1.0.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
+
 [[package]]
 name = "semver"
 version = "1.0.25"
@@ -341,6 +582,48 @@ dependencies = [
  "syn",
 ]
 
+[[package]]
+name = "serde_json"
+version = "1.0.140"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
+dependencies = [
+ "itoa",
+ "memchr",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "serde_with"
+version = "3.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d6b6f7f2fcb69f747921f79f3926bd1e203fce4fef62c268dd3abfb6d86029aa"
+dependencies = [
+ "base64",
+ "chrono",
+ "hex",
+ "indexmap 1.9.3",
+ "indexmap 2.8.0",
+ "serde",
+ "serde_derive",
+ "serde_json",
+ "serde_with_macros",
+ "time",
+]
+
+[[package]]
+name = "serde_with_macros"
+version = "3.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8d00caa5193a3c8362ac2b73be6b9e768aa5a4b2f721d8f4b339600c3cb51f8e"
+dependencies = [
+ "darling",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
 [[package]]
 name = "sha2"
 version = "0.10.8"
@@ -352,6 +635,12 @@ dependencies = [
  "digest",
 ]
 
+[[package]]
+name = "shlex"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
+
 [[package]]
 name = "strsim"
 version = "0.11.1"
@@ -381,6 +670,57 @@ version = "1.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
 
+[[package]]
+name = "thiserror"
+version = "2.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[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 = "time"
+version = "0.3.41"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40"
+dependencies = [
+ "deranged",
+ "itoa",
+ "num-conv",
+ "powerfmt",
+ "serde",
+ "time-core",
+ "time-macros",
+]
+
+[[package]]
+name = "time-core"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c"
+
+[[package]]
+name = "time-macros"
+version = "0.2.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49"
+dependencies = [
+ "num-conv",
+ "time-core",
+]
+
 [[package]]
 name = "typenum"
 version = "1.17.0"
@@ -405,6 +745,143 @@ 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.100"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
+dependencies = [
+ "cfg-if",
+ "once_cell",
+ "rustversion",
+ "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-core"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-link"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38"
+
+[[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 = "wyz"
 version = "0.5.1"

+ 5 - 0
Cargo.toml

@@ -8,7 +8,12 @@ curve25519-dalek = {version = "4.1.3", default-features = false, features = ["se
 lazy_static = "1.5.0"
 rand = {version = "0.8.0", features = ["std_rng"] }
 serde = "1.0.217"
+serde_with = "3"
 sha2 = "0.10.8"
 subtle = "2.5"
 cmz = {git = "ssh://gogs@git-crysp.uwaterloo.ca/SigmaProtocol/cmz.git"}
 group = "0.13"
+ff = "0.13.1"
+bincode = "1"
+rand_core = "0.6"
+thiserror = "2.0.12"

+ 134 - 83
src/proto/level_up.rs

@@ -38,10 +38,14 @@ and a new Lox credential to be issued:
 
 */
 
-use phf::{Map, phf_map};
-use super::super::cmz::{IssueType, ShowType};
-use super::super::lox_creds;
+use super::super::scalar_u32;
+use super::errors::CredentialError;
+use crate::lox_creds::{BucketReachability, Lox};
+use cmz::*;
 use curve25519_dalek::ristretto::RistrettoPoint as G;
+use ff::PrimeField;
+use rand_core::RngCore;
+use sha2::Sha512;
 
 /// The maximum trust level in the system.  A user can run this level
 /// upgrade protocol when they're already at the max level; they will
@@ -49,105 +53,152 @@ use curve25519_dalek::ristretto::RistrettoPoint as G;
 /// field to today's date, but will remain in the max level.
 pub const MAX_LEVEL: usize = 4;
 
-/// DAYS_AGO\[i\] for i >= 1 is the minimum number of days a user
+/// LEVEL_INTERVAL\[i\] for i >= 1 is the minimum number of days a user
 /// must be at trust level i before advancing to level i+1 (or as above,
 /// remain at level i if i == MAX_LEVEL).  Note that the
-/// DAYS_AGO\[0\] entry is a dummy; the trust_promotion protocol
+/// LEVEL_INTERVAL\[0\] entry is a dummy; the trust_promotion protocol
 /// is used instead of this one to move from level 0 to level 1.
-pub const DAYS_AGO: [u32; MAX_LEVEL + 1] = [0, 14, 28, 56, 84];
+pub const LEVEL_INTERVAL: [u32; MAX_LEVEL + 1] = [0, 14, 28, 56, 84];
 
 /// LEVEL_INVITATIONS\[i\] for i >= 1 is the number of invitations a
 /// user will be eligible to issue upon advancing from level i to level
 /// i+1.  Again the LEVEL_INVITATIONS\[0\] entry is a dummy, as for
-/// DAYS_AGO.
+/// LEVEL_INTERVAL.
 pub const LEVEL_INVITATIONS: [u32; MAX_LEVEL + 1] = [0, 2, 4, 6, 8];
 
 /// MAX_BLOCKAGES\[i\] for i >= 1 is the maximum number of bucket
 /// blockages this credential is allowed to have recorded in order to
 /// advance from level i to level i+1.  Again the LEVEL_INVITATIONS\[0\]
-/// entry is a dummy, as for DAYS_AGO.
+/// entry is a dummy, as for LEVEL_INTERVAL.
 // If you change this to have a number greater than 7, you need to add
 // one or more bits to the ZKP.
 pub const MAX_BLOCKAGES: [u32; MAX_LEVEL + 1] = [0, 4, 3, 2, 2];
 
+CMZProtocol! { level_up<credential_expiry, eligibility_max_age, invitations, max_blockage>,
+    [ L: Lox { id: R, bucket: H, trust_level: R, level_since: H, invites_remaining: H, blockages: H },
+    B: BucketReachability { date: R, bucket: H } ],
+    N: Lox {id: J, bucket: H, trust_level: R, level_since: S, invites_remaining: I, blockages: H },
+    credential_expiry <= L.level_since,
+    L.level_since <= eligibility_max_age,
+    0 <= L.blockages,
+    L.blockages <= max_blockage,
+    B.bucket = L.bucket,
+    N.bucket = L.bucket,
+    N.trust_level = L.trust_level+1,
+    N.invites_remaining = invitations,
+    N.blockages = L.blockages,
+}
 
-static LOX_LEVEL_UP_SHOW: Map<&str, ShowType> = phf_map! {
-    "id" => ShowType::Reveal,
-    "bucket" => ShowType::Hide,
-    "trust_level" => ShowType::Reveal,
-    "level_since" => ShowType::Hide,
-    "invites_remaining" => ShowType::Hide,
-    "blockages" => ShowType::Hide,
-};
-
-static REACHABILITY_SHOW: Map<&str, ShowType> = phf_map! {
-    "date" => ShowType::Reveal,
-    "bucket" => ShowType::Hide,
-};
-
-static LOX_LEVEL_UP_ISSUE: Map<&str, IssueType> = phf_map! {
-    "id" => IssueType::Joint,
-    "bucket" => IssueType::Hide,
-    "trust_level" => IssueType::Reveal,
-    "level_since" => IssueType::Server,
-    "invites_remaining" => IssueType::Implicit, // determined by trust_level
-    "blockages" => IssueType::Hide,
-};
-
-let level_up = CMZ.Protocol(
-         vec![("L", lox_creds::Lox::attrs(), LOX_LEVEL_UP_SHOW),
-             ("BR", Reachability::attrs(), REACHABILITY_SHOW)],
-         vec![("NEW", Lox::attrs(), LOX_LEVEL_UP_ISSUE)],
-         statement,
-         request_message
-);
-
-let statement = Statement! {
-    today-(DAYS_AGO[level]+511) <= L.level_since <= today-DAYS_AGO[level],
-    0 <= L.blockages <= MAX_BLOCKAGES[level+1],
-    BR.bucket = L.bucket,
-    NEW.bucket = L.bucket,
-    NEW.blockages = L.blockages,
-};
-
-pub fn request(lox_credential: lox_creds::Lox, reachability_credential: lox_cred::Bucket,
-pubkeys: IssuerPubKeys) -> Result<(Vec<u8>, State), Error> {
-
-    // TODO: Check everything required for the lox_credential to run
-    // this protocol
-    let new_lox_credential = lox_creds::Lox::default();
+pub fn request(
+    L: Lox,
+    B: BucketReachability,
+    pubkeys: CMZPubkey<G>,
+    today: u32,
+) -> Result<(level_up::Request, level_up::ClientState), CredentialError> {
     let mut rng = rand::thread_rng();
-    new_lox_credential.id = Some(<G as Group>::Scalar::random(&mut rng));
-    new_lox_credential.bucket = Some(lox_credential.bucket);
-    new_lox_credential.trust_level = Some((lox_credential.trust_level as usize + 1).into());
-    new_lox_credential.invites_remaining = Some(LEVEL_INVITATIONS[trust_level as usize].into())
-    new_lox_credential.blockages = Some(lox_credential.blockages);
-
-    // TODO: Allocate pubkeys somehow
-    match level_up.show_issue(
-        vec![&lox_credential, &reachability_credential],
-        vec![&mut new_lox_credential]) {
-        Ok(request_message, state) => Ok(request_message, state),
-        Err(e) => Error(e),
+    cmz_group_init(G::hash_from_bytes::<Sha512>(b"CMZ Generator A"));
+
+    // Ensure the credential can be correctly shown: it must be the case
+    // that level_since + LEVEL_INTERVAL[level] <= today.
+    let level_since: u32 = match scalar_u32(&L.level_since.unwrap()) {
+        Some(v) => v,
+        None => {
+            return Err(CredentialError::InvalidField(
+                String::from("level_since"),
+                String::from("could not be converted to u32"),
+            ))
+        }
+    };
+    // The trust level has to be at least 1
+    let trust_level: u32 = match scalar_u32(&L.trust_level.unwrap()) {
+        Some(v) => v,
+        None => {
+            return Err(CredentialError::InvalidField(
+                String::from("trust_level"),
+                String::from("could not be converted to u32"),
+            ))
+        }
+    };
+    if trust_level < 1 || (trust_level as usize) > MAX_LEVEL {
+        return Err(CredentialError::InvalidField(
+            String::from("trust_level"),
+            format!("level {:?} not in range", trust_level),
+        ));
     }
-}
-
-impl BridgeAuth {
-
-    pub fn handle_level_up(&mut self, req: Request) -> Result<Response,
-ProofError> {
-
-    let public_verify = TODO;
-    level_up.handle(
-        vec![&mut req.lox_credential, &mut req.reachability_credential],
-        vec![&mut req.new_lox_credential],
-        public_verify) 
+    // The trust level has to be no higher than the highest level
+    let level_interval: u32 = match LEVEL_INTERVAL.get(trust_level as usize) {
+        Some(&v) => v,
+        None => {
+            return Err(CredentialError::InvalidField(
+                String::from("trust_level"),
+                format!("level {:?} not in range", trust_level),
+            ))
+        }
+    };
+    if level_since + level_interval > today {
+        return Err(CredentialError::TimeThresholdNotMet(
+            level_since + level_interval - today,
+        ));
     }
-}
-
-pub fn handle_response(state: State, resp: Response) -> Result<Vec<Credential>, ProofError> {
-    match cmz_finalize(client_state, response_message) {
-        Ok(Vec<Credential>) => Ok(Vec<Credential>),
-        Err(e) => ProofError(e),
+    // The credential can't be _too_ old
+    let diffdays = today - (level_since + level_interval);
+    if diffdays > 511 {
+        return Err(CredentialError::CredentialExpired);
+    }
+    // The current number of blockages
+    let blockages = match scalar_u32(&L.blockages.unwrap()) {
+        Some(v) => v,
+        None => {
+            return Err(CredentialError::InvalidField(
+                String::from("blockages"),
+                String::from("could not be converted to u32"),
+            ))
+        }
+    };
+    if blockages > MAX_BLOCKAGES[trust_level as usize] {
+        return Err(CredentialError::ExceededBlockagesThreshold);
+    }
+    // The buckets in the Lox and Bucket Reachability credentials have
+    // to match
+    if L.bucket != B.bucket {
+        return Err(CredentialError::CredentialMismatch);
+    }
+    // The Bucket Reachability credential has to be dated today
+    let reach_date: u32 = match scalar_u32(&B.date.unwrap()) {
+        Some(v) => v,
+        None => {
+            return Err(CredentialError::InvalidField(
+                String::from("date"),
+                String::from("could not be converted to u32"),
+            ))
         }
+    };
+    if reach_date != today {
+        return Err(CredentialError::InvalidField(
+            String::from("date"),
+            String::from("reachability credential must be generated today"),
+        ));
+    }
+    // The new trust level
+    let new_level = if (trust_level as usize) < MAX_LEVEL {
+        trust_level + 1
+    } else {
+        trust_level
+    };
+
+    let credential_expiry = today - LEVEL_INTERVAL[trust_level as usize] + 511;
+    let eligibility_max_age = today - LEVEL_INTERVAL[trust_level as usize];
+
+    let mut N = Lox::using_pubkey(&pubkeys);
+    let params = level_up::Params {
+        credential_expiry: level_up::Scalar::from_u128(credential_expiry.into()),
+        eligibility_max_age: level_up::Scalar::from_u128(eligibility_max_age.into()),
+        invitations: level_up::Scalar::from_u128(LEVEL_INVITATIONS[new_level as usize].into()),
+        max_blockage: level_up::Scalar::from_u128(MAX_BLOCKAGES[new_level as usize].into()),
+    };
+
+    match level_up::prepare(&mut rng, &L, &B, N, &params) {
+        Ok(req_state) => Ok(req_state),
+        Err(e) => Err(CredentialError::CMZError(e)),
+    }
 }