From f0b13a630db1810238bff3f3025e6b7e28c7b686 Mon Sep 17 00:00:00 2001 From: HAOYUatHZ <37070449+HAOYUatHZ@users.noreply.github.com> Date: Sun, 27 Jun 2021 14:47:22 +0800 Subject: [PATCH] feat: add order signature verification (#203) --- Cargo.lock | 350 ++++++++++++++++++++++++- Cargo.toml | 6 +- src/lib.rs | 1 + src/matchengine/asset/asset_manager.rs | 48 +++- src/matchengine/controller.rs | 4 +- src/matchengine/market/order.rs | 34 +++ src/matchengine/server.rs | 11 +- src/matchengine/user_manager.rs | 14 +- src/primitives.rs | 127 +++++++++ 9 files changed, 578 insertions(+), 17 deletions(-) create mode 100644 src/primitives.rs diff --git a/Cargo.lock b/Cargo.lock index 8b354c1e..8e42f161 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -313,6 +313,12 @@ dependencies = [ "num-traits 0.2.14", ] +[[package]] +name = "autocfg" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" + [[package]] name = "autocfg" version = "1.0.1" @@ -345,6 +351,26 @@ dependencies = [ "serde_urlencoded", ] +[[package]] +name = "babyjubjub-rs" +version = "0.0.8" +source = "git+https://github.com/lispc/babyjubjub-rs#d5b8e3da8d136f8394904423edaa8658d6cf37d0" +dependencies = [ + "arrayref", + "blake", + "ff_ce", + "generic-array 0.13.3", + "lazy_static", + "num", + "num-bigint 0.2.6", + "num-traits 0.2.14", + "poseidon-rs", + "rand 0.4.6", + "rand 0.6.5", + "rustc-hex", + "tiny-keccak", +] + [[package]] name = "base-x" version = "0.2.8" @@ -375,13 +401,23 @@ dependencies = [ "wyz", ] +[[package]] +name = "blake" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f76cff23583935d01f1d259e546bf988450648a644da066de24717fdd015aa81" +dependencies = [ + "gcc", + "libc", +] + [[package]] name = "block-buffer" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" dependencies = [ - "generic-array", + "generic-array 0.14.4", ] [[package]] @@ -463,6 +499,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "cloudabi" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +dependencies = [ + "bitflags", +] + [[package]] name = "cmake" version = "0.1.45" @@ -555,18 +600,24 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7e9d99fa91428effe99c5c6d4634cdeba32b8cf784fc428a2a687f61a952c49" dependencies = [ - "autocfg", + "autocfg 1.0.1", "cfg-if", "lazy_static", ] +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + [[package]] name = "crypto-mac" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4857fd85a0c34b3c3297875b747c1e02e06b6a0ea32dd892d8192b9ce0813ea6" dependencies = [ - "generic-array", + "generic-array 0.14.4", "subtle", ] @@ -598,7 +649,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" dependencies = [ - "generic-array", + "generic-array 0.14.4", ] [[package]] @@ -609,11 +660,13 @@ dependencies = [ "actix-web", "anyhow", "arrayref", + "babyjubjub-rs", "bytes", "chrono", "config", "crossbeam-channel", "dotenv", + "ff_ce", "futures", "futures-channel", "futures-core", @@ -625,7 +678,9 @@ dependencies = [ "lazy_static", "log", "nix", + "num-bigint 0.2.6", "num_enum", + "poseidon-rs", "prost", "prost-types", "qstring", @@ -681,6 +736,32 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" +[[package]] +name = "ff_ce" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d3a682c12d0cc98a32ab7540401a5ea1ed21d11571eea11d5829cd721f85ff0" +dependencies = [ + "byteorder", + "ff_derive_ce", + "hex", + "rand 0.4.6", +] + +[[package]] +name = "ff_derive_ce" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50c052fa6d4c2f12305ec364bfb8ef884836f3f61ea015b202372ff996d1ac4b" +dependencies = [ + "num-bigint 0.2.6", + "num-integer", + "num-traits 0.2.14", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "fixedbitset" version = "0.2.0" @@ -715,6 +796,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" + [[package]] name = "funty" version = "1.1.0" @@ -813,6 +900,21 @@ dependencies = [ "slab", ] +[[package]] +name = "gcc" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" + +[[package]] +name = "generic-array" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f797e67af32588215eaaab8327027ee8e71b9dd0b2b26996aedf20c030fce309" +dependencies = [ + "typenum", +] + [[package]] name = "generic-array" version = "0.14.4" @@ -1006,7 +1108,7 @@ version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "824845a0bf897a9042383849b02c1bc219c2383772efcd5c6f9766fa4b81aef3" dependencies = [ - "autocfg", + "autocfg 1.0.1", "hashbrown", ] @@ -1186,7 +1288,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" dependencies = [ "adler", - "autocfg", + "autocfg 1.0.1", ] [[package]] @@ -1263,24 +1365,83 @@ dependencies = [ "winapi", ] +[[package]] +name = "num" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8536030f9fea7127f841b45bb6243b27255787fb4eb83958aa1ef9d2fdc0c36" +dependencies = [ + "num-bigint 0.2.6", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits 0.2.14", +] + +[[package]] +name = "num-bigint" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" +dependencies = [ + "autocfg 1.0.1", + "num-integer", + "num-traits 0.2.14", + "rand 0.5.6", +] + [[package]] name = "num-bigint" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d0a3d5e207573f948a9e5376662aa743a2ea13f7c50a554d7af443a73fbfeba" dependencies = [ - "autocfg", + "autocfg 1.0.1", "num-integer", "num-traits 0.2.14", ] +[[package]] +name = "num-complex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6b19411a9719e753aff12e5187b74d60d3dc449ec3f4dc21e3989c3f554bc95" +dependencies = [ + "autocfg 1.0.1", + "num-traits 0.2.14", +] + [[package]] name = "num-integer" version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" dependencies = [ - "autocfg", + "autocfg 1.0.1", + "num-traits 0.2.14", +] + +[[package]] +name = "num-iter" +version = "0.1.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2021c8337a54d21aca0d59a92577a029af9431cb59b909b03252b9c164fad59" +dependencies = [ + "autocfg 1.0.1", + "num-integer", + "num-traits 0.2.14", +] + +[[package]] +name = "num-rational" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c000134b5dbf44adc5cb772486d335293351644b801551abe8f75c84cfa4aef" +dependencies = [ + "autocfg 1.0.1", + "num-bigint 0.2.6", + "num-integer", "num-traits 0.2.14", ] @@ -1299,7 +1460,7 @@ version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" dependencies = [ - "autocfg", + "autocfg 1.0.1", ] [[package]] @@ -1443,6 +1604,17 @@ version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" +[[package]] +name = "poseidon-rs" +version = "0.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c76e4996e3d9572d8b5cd56f495dda3fb748fd4cd6bdca754270b8b66a9a2dd3" +dependencies = [ + "ff_ce", + "rand 0.4.6", + "serde_json", +] + [[package]] name = "postgres" version = "0.19.0" @@ -1597,6 +1769,51 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "941ba9d78d8e2f7ce474c015eea4d9c6d25b6a3327f9832ee29a4de27f91bbb8" +[[package]] +name = "rand" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" +dependencies = [ + "fuchsia-cprng", + "libc", + "rand_core 0.3.1", + "rdrand", + "winapi", +] + +[[package]] +name = "rand" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c618c47cd3ebd209790115ab837de41425723956ad3ce2e6a7f09890947cacb9" +dependencies = [ + "cloudabi", + "fuchsia-cprng", + "libc", + "rand_core 0.3.1", + "winapi", +] + +[[package]] +name = "rand" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" +dependencies = [ + "autocfg 0.1.7", + "libc", + "rand_chacha 0.1.1", + "rand_core 0.4.2", + "rand_hc 0.1.0", + "rand_isaac", + "rand_jitter", + "rand_os", + "rand_pcg", + "rand_xorshift", + "winapi", +] + [[package]] name = "rand" version = "0.7.3" @@ -1622,6 +1839,16 @@ dependencies = [ "rand_hc 0.3.0", ] +[[package]] +name = "rand_chacha" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" +dependencies = [ + "autocfg 0.1.7", + "rand_core 0.3.1", +] + [[package]] name = "rand_chacha" version = "0.2.2" @@ -1642,6 +1869,21 @@ dependencies = [ "rand_core 0.6.2", ] +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +dependencies = [ + "rand_core 0.4.2", +] + +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" + [[package]] name = "rand_core" version = "0.5.1" @@ -1660,6 +1902,15 @@ dependencies = [ "getrandom 0.2.2", ] +[[package]] +name = "rand_hc" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" +dependencies = [ + "rand_core 0.3.1", +] + [[package]] name = "rand_hc" version = "0.2.0" @@ -1678,6 +1929,59 @@ dependencies = [ "rand_core 0.6.2", ] +[[package]] +name = "rand_isaac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rand_jitter" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" +dependencies = [ + "libc", + "rand_core 0.4.2", + "winapi", +] + +[[package]] +name = "rand_os" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" +dependencies = [ + "cloudabi", + "fuchsia-cprng", + "libc", + "rand_core 0.4.2", + "rdrand", + "winapi", +] + +[[package]] +name = "rand_pcg" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" +dependencies = [ + "autocfg 0.1.7", + "rand_core 0.4.2", +] + +[[package]] +name = "rand_xorshift" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" +dependencies = [ + "rand_core 0.3.1", +] + [[package]] name = "rdkafka" version = "0.25.0" @@ -1708,6 +2012,15 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +dependencies = [ + "rand_core 0.3.1", +] + [[package]] name = "redox_syscall" version = "0.1.57" @@ -1804,6 +2117,12 @@ dependencies = [ "rust_decimal", ] +[[package]] +name = "rustc-hex" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ceb8ce7a5e520de349e1fa172baeba4a9e8d5ef06c47471863530bc4972ee1e" + [[package]] name = "rustc_version" version = "0.2.3" @@ -2082,7 +2401,7 @@ dependencies = [ "log", "md-5", "memchr", - "num-bigint", + "num-bigint 0.3.2", "once_cell", "parking_lot", "percent-encoding", @@ -2336,6 +2655,15 @@ dependencies = [ "syn", ] +[[package]] +name = "tiny-keccak" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d8a021c69bb74a44ccedb824a046447e2c84a01df9e5c20779750acb38e11b2" +dependencies = [ + "crunchy", +] + [[package]] name = "tinyvec" version = "1.1.1" @@ -2357,7 +2685,7 @@ version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a38d31d7831c6ed7aad00aa4c12d9375fd225a6dd77da1d25b707346319a975" dependencies = [ - "autocfg", + "autocfg 1.0.1", "bytes", "libc", "memchr", diff --git a/Cargo.toml b/Cargo.toml index 78855c7a..184a1969 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,11 +9,13 @@ actix-rt = "2.1.0" actix-web = "4.0.0-beta.4" anyhow = "1.0.38" arrayref = "0.3.6" +babyjubjub-rs = { git = "https://github.com/lispc/babyjubjub-rs", features = [ "aarch64" ], default-features = false } bytes = "1.0.1" chrono = { version = "0.4.19", features = [ "serde" ] } config_rs = { package = "config", version = "0.10.1" } crossbeam-channel = "0.5.0" dotenv = "0.15.0" +ff = { package = "ff_ce", version = "0.11", features = [ "derive" ] } futures = "0.3.13" futures-channel = "0.3.13" futures-core = { version = "0.3.13", default-features = false } @@ -25,7 +27,9 @@ itertools = "0.10.0" lazy_static = "1.4.0" log = "0.4.14" nix = "0.20.0" +num-bigint = { version = "0.2.2", features = [ "rand" ] } num_enum = "0.5.1" +poseidon-rs = { version = "0.0.8" } prost = "0.7.0" prost-types = "0.7.0" qstring = "0.7.2" @@ -61,6 +65,6 @@ path = "src/bin/matchengine.rs" [features] windows_build = [ "rdkafka/dynamic_linking" ] emit_state_diff = [ ] -default = ["emit_state_diff" ] +default = [ "emit_state_diff" ] #default = ["windows_build"] #default = ["windows_build", "emit_state_diff"] diff --git a/src/lib.rs b/src/lib.rs index 2029be28..e4637e8e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,6 +10,7 @@ pub mod storage; pub use storage::{database, models, sqlxextend}; pub mod config; pub mod message; +pub mod primitives; pub mod restapi; pub mod types; pub mod utils; diff --git a/src/matchengine/asset/asset_manager.rs b/src/matchengine/asset/asset_manager.rs index 5948dea4..a1cce5bd 100644 --- a/src/matchengine/asset/asset_manager.rs +++ b/src/matchengine/asset/asset_manager.rs @@ -1,12 +1,17 @@ use crate::config; -use anyhow::Result; +use crate::market::OrderCommitment; +use crate::matchengine::rpc::*; +use crate::primitives::*; +use anyhow::{bail, Result}; use serde::{Deserialize, Serialize}; use std::collections::HashMap; +use std::str::FromStr; #[derive(Serialize, Deserialize, Debug, PartialEq, Clone, Eq, Hash)] pub struct AssetInfo { pub prec_save: u32, pub prec_show: u32, + pub inner_id: u32, } #[derive(Clone)] @@ -24,6 +29,7 @@ impl AssetManager { AssetInfo { prec_save: item.prec_save, prec_show: item.prec_show, + inner_id: item.rollup_token_id as u32, }, ); } @@ -38,6 +44,7 @@ impl AssetManager { AssetInfo { prec_save: item.prec_save, prec_show: item.prec_show, + inner_id: item.rollup_token_id as u32, }, ); if ret.is_some() { @@ -60,4 +67,43 @@ impl AssetManager { pub fn asset_prec_show(&self, id: &str) -> u32 { self.asset_get(id).unwrap().prec_show } + + pub fn commit_order(&self, o: &OrderPutRequest) -> Result { + let assets: Vec<&str> = o.market.split('_').collect(); + if assets.len() != 2 { + bail!("market error"); + } + let base_token = match self.asset_get(assets[0]) { + Some(token) => token, + None => bail!("market base_token error"), + }; + let quote_token = match self.asset_get(assets[1]) { + Some(token) => token, + None => bail!("market quote_token error"), + }; + let amount = match rust_decimal::Decimal::from_str(&o.amount) { + Ok(d) => d, + _ => bail!("amount error"), + }; + let price = match rust_decimal::Decimal::from_str(&o.price) { + Ok(d) => d, + _ => bail!("price error"), + }; + + match OrderSide::from_i32(o.order_side) { + Some(OrderSide::Ask) => Ok(OrderCommitment { + token_buy: u32_to_fr(quote_token.inner_id), + token_sell: u32_to_fr(base_token.inner_id), + total_buy: decimal_to_fr(&(amount * price), quote_token.prec_save), + total_sell: decimal_to_fr(&amount, base_token.prec_save), + }), + Some(OrderSide::Bid) => Ok(OrderCommitment { + token_buy: u32_to_fr(base_token.inner_id), + token_sell: u32_to_fr(quote_token.inner_id), + total_buy: decimal_to_fr(&amount, base_token.prec_save), + total_sell: decimal_to_fr(&(amount * price), quote_token.prec_save), + }), + None => bail!("market error"), + } + } } diff --git a/src/matchengine/controller.rs b/src/matchengine/controller.rs index 6f43c0c8..56d9d496 100644 --- a/src/matchengine/controller.rs +++ b/src/matchengine/controller.rs @@ -13,7 +13,7 @@ use crate::types::{ConnectionType, DbType, SimpleResult}; use crate::user_manager::{self, UserManager}; use crate::utils::{self, FTimestamp}; -use anyhow::anyhow; +use anyhow::{anyhow, bail}; use rust_decimal::prelude::Zero; use rust_decimal::Decimal; use serde::Serialize; @@ -725,7 +725,7 @@ impl Controller { OPERATION_REGISTER_USER => { self.register_user(false, serde_json::from_str(params)?)?; } - _ => return Err(anyhow!("invalid operation {}", method)), + _ => bail!("invalid operation {}", method), } Ok(()) } diff --git a/src/matchengine/market/order.rs b/src/matchengine/market/order.rs index ff9e2687..31340795 100644 --- a/src/matchengine/market/order.rs +++ b/src/matchengine/market/order.rs @@ -1,3 +1,4 @@ +use crate::primitives::*; use crate::types::{OrderSide, OrderType}; use crate::utils::InternedString; use rust_decimal::Decimal; @@ -175,3 +176,36 @@ pub struct OrderInput { pub post_only: bool, pub signature: [u8; 64], } + +pub struct OrderCommitment { + // order_id + // account_id + // nonce + pub token_sell: Fr, + pub token_buy: Fr, + pub total_sell: Fr, + pub total_buy: Fr, +} + +impl OrderCommitment { + pub fn hash(&self) -> BigInt { + // consistent with https://github.com/Fluidex/circuits/blob/d6e06e964b9d492f1fa5513bcc2295e7081c540d/helper.ts/state-utils.ts#L38 + // TxType::PlaceOrder + let magic_head = u32_to_fr(4); + let data = hash(&[ + magic_head, + // TODO: sign nonce or order_id + //u32_to_fr(self.order_id), + self.token_sell, + self.token_buy, + self.total_sell, + self.total_buy, + ]); + //data = hash([data, accountID, nonce]); + // nonce and orderID seems redundant? + + // account_id is not needed if the hash is signed later? + //data = hash(&[data, u32_to_fr(self.account_id)]); + fr_to_bigint(&data) + } +} diff --git a/src/matchengine/server.rs b/src/matchengine/server.rs index 21042114..60b93a6a 100644 --- a/src/matchengine/server.rs +++ b/src/matchengine/server.rs @@ -190,10 +190,19 @@ impl super::rpc::matchengine_server::Matchengine for GrpcHandler { if self.settings.check_eddsa_signatue == OrderSignatrueCheck::Needed || self.settings.check_eddsa_signatue == OrderSignatrueCheck::Auto && !req.signature.is_empty() { - // TODO: // check order signature here // order signature checking is not 'write' op, so it need not to be moved into the main thread // it is better to finish it here + let stub = self.stub.read().await; + let order = stub + .balance_manager + .asset_manager + .commit_order(&req) + .map_err(|_| Status::invalid_argument("invalid order params"))?; + let msg = order.hash(); + if !stub.user_manager.verify_signature(req.user_id, msg, &req.signature) { + return Err(Status::invalid_argument("invalid signature")); + } } let ControllerDispatch(act, rt) = ControllerDispatch::new(move |ctrl: &mut Controller| Box::pin(async move { ctrl.order_put(true, req) })); diff --git a/src/matchengine/user_manager.rs b/src/matchengine/user_manager.rs index d9089f74..dc6fa674 100644 --- a/src/matchengine/user_manager.rs +++ b/src/matchengine/user_manager.rs @@ -1,4 +1,5 @@ -pub use crate::models::AccountDesc; +use crate::models::AccountDesc; +use crate::primitives::*; use crate::types::ConnectionType; use serde::{Deserialize, Serialize}; use std::collections::HashMap; @@ -36,6 +37,17 @@ impl UserManager { } Ok(()) } + + pub fn verify_signature(&self, user_id: u32, msg: BigInt, signature: &str) -> bool { + match self.users.get(&user_id) { + None => false, + Some(user) => { + let pubkey = str_to_pubkey(&user.l2_pubkey).map_err(|_| false).unwrap(); + let signature = str_to_signature(signature).map_err(|_| false).unwrap(); + babyjubjub_rs::verify(pubkey, signature, msg) + } + } + } } impl Default for UserManager { diff --git a/src/primitives.rs b/src/primitives.rs new file mode 100644 index 00000000..d041d8ec --- /dev/null +++ b/src/primitives.rs @@ -0,0 +1,127 @@ +use anyhow::{anyhow, Result}; +use lazy_static::lazy_static; +use rust_decimal::prelude::ToPrimitive; +use std::convert::TryInto; +use std::str::FromStr; + +pub use babyjubjub_rs::{Point, Signature}; +pub use ff::{from_hex, to_hex}; +pub use ff::{Field, PrimeField, PrimeFieldRepr}; +pub use num_bigint::BigInt; +pub use poseidon_rs::Fr; +pub use rust_decimal::Decimal; + +lazy_static! { + //pub static ref POSEIDON_PARAMS: poseidon_rs::Constants = poseidon_rs::load_constants(); + pub static ref POSEIDON_HASHER: poseidon_rs::Poseidon = poseidon_rs::Poseidon::new(); +} + +pub fn hash(inputs: &[Fr]) -> Fr { + (&POSEIDON_HASHER).hash(inputs.to_vec()).unwrap() +} + +// TODO: these functions needed to be rewrite... + +pub fn u32_to_fr(x: u32) -> Fr { + Fr::from_str(&format!("{}", x)).unwrap() +} + +pub fn u64_to_fr(x: u64) -> Fr { + Fr::from_repr(poseidon_rs::FrRepr::from(x)).unwrap() +} + +pub fn bigint_to_fr(x: BigInt) -> Fr { + let mut s = x.to_str_radix(16); + if s.len() % 2 != 0 { + // convert "f" to "0f" + s.insert(0, '0'); + } + from_hex(&s).unwrap() +} + +pub fn str_to_fr(x: &str) -> Fr { + if x.starts_with("0x") { + vec_to_fr(&hex::decode(x.trim_start_matches("0x")).unwrap()).unwrap() + } else { + let i = BigInt::from_str(x).unwrap(); + bigint_to_fr(i) + } +} + +pub fn vec_to_fr(arr: &[u8]) -> Result { + if arr.len() > 32 { + anyhow::bail!("invalid vec len for fr"); + } + let mut repr = ::Repr::default(); + + // prepad 0 + let mut buf = arr.to_vec(); + let required_length = repr.as_ref().len() * 8; + buf.reverse(); + buf.resize(required_length, 0); + buf.reverse(); + + repr.read_be(&buf[..])?; + Ok(Fr::from_repr(repr)?) +} + +pub fn fr_to_u32(f: &Fr) -> u32 { + fr_to_string(f).parse::().unwrap() +} + +pub fn fr_to_i64(f: &Fr) -> i64 { + fr_to_string(f).parse::().unwrap() +} + +pub fn fr_to_bigint(elem: &Fr) -> BigInt { + BigInt::parse_bytes(to_hex(elem).as_bytes(), 16).unwrap() +} + +pub fn fr_to_string(elem: &Fr) -> String { + fr_to_bigint(&elem).to_str_radix(10) +} + +pub fn fr_to_decimal(f: &Fr, scale: u32) -> Decimal { + Decimal::new(fr_to_i64(f), scale) +} + +// big endian +pub fn fr_to_vec(f: &Fr) -> Vec { + let repr = f.into_repr(); + let required_length = repr.as_ref().len() * 8; + let mut buf: Vec = Vec::with_capacity(required_length); + repr.write_be(&mut buf).unwrap(); + buf +} + +pub fn fr_to_bool(f: &Fr) -> Result { + if f.is_zero() { + Ok(false) + } else if f == &Fr::one() { + Ok(true) + } else { + Err(anyhow!("invalid fr")) + } +} + +pub fn str_to_pubkey(pubkey: &str) -> Result { + let pubkey_packed = hex::decode(pubkey)?; + babyjubjub_rs::decompress_point(pubkey_packed.try_into().unwrap()).map_err(|e| anyhow!(e)) +} + +pub fn str_to_signature(signature: &str) -> Result { + let sig_packed_vec = hex::decode(signature)?; + babyjubjub_rs::decompress_signature(&sig_packed_vec.try_into().unwrap()).map_err(|e| anyhow!(e)) +} + +pub fn decimal_to_u64(num: &Decimal, prec: u32) -> u64 { + let prec_mul = Decimal::new(10, 0).powi(prec as u64); + let adjusted = num * prec_mul; + adjusted.floor().to_u64().unwrap() +} + +pub fn decimal_to_fr(num: &Decimal, prec: u32) -> Fr { + // TODO: is u64 enough? + u64_to_fr(decimal_to_u64(num, prec)) + // Float864::from_decimal(num, prec).unwrap().to_fr() +}