├── .github └── workflows │ ├── commitlint.yml │ ├── format-check.yml │ └── test.yml ├── .gitignore ├── Cargo.toml ├── README.md ├── Rocket.toml ├── examples └── gg18_sm_manager.rs ├── index.js ├── package.json ├── params.json ├── run_keygen_sign.js ├── scripts └── run_keygen_sign_node.js ├── sm.dockerfile ├── src ├── api.rs ├── common.rs ├── curv │ ├── arithmetic │ │ ├── mod.rs │ │ ├── num_bigint.rs │ │ └── traits.rs │ ├── cryptographic_primitives │ │ ├── commitments │ │ │ ├── hash_commitment.rs │ │ │ ├── mod.rs │ │ │ └── traits.rs │ │ ├── hashing │ │ │ ├── constants.rs │ │ │ ├── ext.rs │ │ │ ├── hash_sha256.rs │ │ │ ├── mod.rs │ │ │ └── traits.rs │ │ ├── mod.rs │ │ ├── proofs │ │ │ ├── mod.rs │ │ │ ├── sigma_correct_homomorphic_elgamal_enc.rs │ │ │ └── sigma_dlog.rs │ │ └── secret_sharing │ │ │ ├── feldman_vss.rs │ │ │ └── mod.rs │ ├── elliptic │ │ ├── curves │ │ │ ├── mod.rs │ │ │ ├── secp256_k1.rs │ │ │ └── traits.rs │ │ └── mod.rs │ └── mod.rs ├── errors.rs ├── gg_2018 │ ├── mod.rs │ ├── mta.rs │ ├── party_i.rs │ └── range_proofs.rs ├── lib.rs └── paillier │ ├── core.rs │ ├── encoding │ ├── integral.rs │ └── mod.rs │ ├── keygen.rs │ ├── mod.rs │ ├── serialize.rs │ ├── traits.rs │ └── zkproofs │ ├── correct_key_ni.rs │ ├── mod.rs │ └── wi_dlog_proof.rs ├── tests ├── common │ └── mod.rs ├── keygen.rs ├── mta.rs └── sign.rs └── webpack.config.js /.github/workflows/commitlint.yml: -------------------------------------------------------------------------------- 1 | name: Eigen Lint Commit Messages 2 | on: 3 | push: 4 | branches: [ main ] 5 | pull_request: 6 | branches: [ main ] 7 | 8 | jobs: 9 | commitlint: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v2 13 | with: 14 | fetch-depth: 0 15 | - uses: wagoid/commitlint-github-action@v4 16 | with: 17 | configFile: .commitlintrc.js 18 | firstParent: true -------------------------------------------------------------------------------- /.github/workflows/format-check.yml: -------------------------------------------------------------------------------- 1 | # This workflow will do a clean install of node dependencies, cache/restore them, build the source code and run tests across different versions of node 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions 3 | 4 | name: Eigen TSS WASM CI (format check) 5 | 6 | on: 7 | push: 8 | branches: [ main ] 9 | pull_request: 10 | branches: [ main ] 11 | 12 | jobs: 13 | check: 14 | name: Check 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@v2 18 | - uses: actions-rs/toolchain@v1 19 | with: 20 | profile: minimal 21 | toolchain: stable 22 | override: true 23 | - uses: actions-rs/cargo@v1 24 | with: 25 | command: check 26 | 27 | fmt: 28 | name: Rustfmt 29 | runs-on: ubuntu-latest 30 | steps: 31 | - uses: actions/checkout@v2 32 | - uses: actions-rs/toolchain@v1 33 | with: 34 | profile: minimal 35 | toolchain: stable 36 | override: true 37 | - run: rustup component add rustfmt 38 | - uses: actions-rs/cargo@v1 39 | with: 40 | command: fmt 41 | args: --all -- --check -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | # This workflow will do a clean install of node dependencies, cache/restore them, build the source code and run tests across different versions of node 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions 3 | 4 | name: Eigen TSS WASM CI 5 | 6 | on: 7 | push: 8 | branches: [ main ] 9 | pull_request: 10 | branches: [ main ] 11 | 12 | jobs: 13 | build-test: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | strategy: 18 | matrix: 19 | node-version: [16.x, 18.x] 20 | # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ 21 | 22 | steps: 23 | - uses: actions/checkout@v2 24 | - uses: actions-rs/toolchain@v1 25 | with: 26 | profile: minimal 27 | toolchain: stable 28 | override: true 29 | - name: Use Node.js ${{ matrix.node-version }} 30 | uses: actions/setup-node@v2 31 | with: 32 | node-version: ${{ matrix.node-version }} 33 | - name: Cache Node Dependencies 34 | id: cache 35 | uses: actions/cache@v2 36 | with: 37 | path: node_modules 38 | key: ${{runner.OS}}-npm-caches-${{ hashFiles('package-lock.json') }} 39 | - name: Install Dependencies 40 | run: npm install --legacy-peer-deps 41 | - name: Install wasm-pack 42 | run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh 43 | - name: Start test 44 | run: yarn test 45 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | .idea/ 3 | .DS_Store 4 | node_modules 5 | yarn-error.log 6 | package-lock.json 7 | pkg 8 | Cargo.lock 9 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tss-wasm" 3 | version = "0.0.1" 4 | edition = "2021" 5 | 6 | authors = ["Omer ", "Eigen Labs "] 7 | description = "WASM/HW-friendly lightweight client application for threshold ECDSA" 8 | homepage = "https://github.com/0xEigenLabs" 9 | repository = "https://github.com/0xEigenLabs/tss-wasm" 10 | license = "GPL-3.0-or-later" 11 | 12 | 13 | [lib] 14 | crate-type = ["cdylib", "lib"] 15 | 16 | [target.'cfg(not(target_arch = "wasm32"))'.dependencies] 17 | rand = "0.6.5" 18 | 19 | [target.'cfg(target_arch = "wasm32")'.dependencies] 20 | wasm-bindgen = { version = "0.2.51", features = ["serde-serialize"] } 21 | wasm-bindgen-futures = "0.4.1" 22 | rand = { version = "0.6.5", features = ["wasm-bindgen"] } 23 | 24 | [dependencies] 25 | #serde = "1.0" 26 | serde = { version = "1.0.101", features = ["derive"] } 27 | serde_derive = "1.0" 28 | serde_json = "1.0" 29 | 30 | num-bigint = { version = "0.2.2", features = ["serde", "rand"] } 31 | num-integer = "0.1" 32 | num-traits = "0.2.6" 33 | 34 | bit-vec = "0.5" 35 | cryptoxide = "0.1.1" 36 | zeroize = "1.0" 37 | 38 | libsecp256k1 = "0.3.2" 39 | reqwest = { version = "0.11.11", features = ["json"] } 40 | aes-gcm = "0.9.4" 41 | sha2 = "0.9" 42 | sha3 = "0.10.6" 43 | hex = "0.4" 44 | lazy_static = "1.4" 45 | hmac = "0.11" 46 | digest = "0.9" 47 | typenum = "1.13" 48 | generic-array = "0.14" 49 | js-sys = "0.3.59" 50 | tiny-keccak = { version = "2.0.1", features = ["keccak"] } 51 | log = "0.4.17" 52 | thiserror = "1.0" 53 | 54 | [dependencies.web-sys] 55 | version = "0.3.4" 56 | features = [ 57 | 'Headers', 58 | 'Request', 59 | 'RequestInit', 60 | 'RequestMode', 61 | 'Response', 62 | 'Window', 63 | ] 64 | 65 | [target.'cfg(target_arch = "wasm32")'.dev-dependencies] 66 | wasm-bindgen-test = "0.3" 67 | 68 | [target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies] 69 | criterion = "0.2" 70 | rocket = { version = "0.5.0-rc.1", default-features = false, features = [ 71 | "json", 72 | ] } 73 | uuid = { version = "0.8", features = ["v4"] } 74 | tokio = { version = "1", default-features = false, features = ["macros"] } 75 | rocket_cors = { git = "https://github.com/lawliet89/rocket_cors", branch = "master" } 76 | 77 | [[example]] 78 | name = "gg18_sm_manager" 79 | 80 | [[bench]] 81 | name = "keygen" 82 | path = "tests/keygen.rs" 83 | harness = false 84 | 85 | [[bench]] 86 | name = "sign" 87 | path = "tests/sign.rs" 88 | harness = false 89 | 90 | [features] 91 | default = [] 92 | bench = [] 93 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TSS WASM 2 | A portable lightweight client application for threshold ECDSA (based on [GG18](https://eprint.iacr.org/2019/114.pdf)), built on&for [multi-party-ecdsa](https://github.com/ZenGo-X/multi-party-ecdsa) : 3 | 1) Wasm/Web 4 | 2) HW friendly, like [TEE](https://github.com/0xEigenLabs/eigencc) 5 | 6 | # Npm publish 7 | 8 | * node: npm run build_node 9 | * web: npm run build 10 | 11 | ## Latest release 12 | 13 | web: @ieigen/tss-wasm@0.0.8 14 | 15 | nodejs: @ieigen/tss-wasm-node@0.0.7, node 18.0+ is required 16 | 17 | # Test 18 | 19 | ## Unit Test 20 | ``` 21 | npm run build 22 | npm run test 23 | ``` 24 | 25 | ## Function Test via NodeJS 26 | ``` 27 | cargo build --examples --release 28 | ./target/release/examples/gg18_sm_manager 29 | 30 | # open another console 31 | npm run build_node 32 | node scripts/run_keygen_sign_node.js 33 | ``` 34 | 35 | ## Function Test via Web 36 | 37 | ``` 38 | cargo build --examples --release 39 | ./target/release/examples/gg18_sm_manager 40 | 41 | # open another console 42 | npm run build 43 | export NODE_OPTIONS=--openssl-legacy-provider 44 | npm run webpack && npm run webpack-dev-server 45 | ``` 46 | 47 | Open `http://localhost:8080/` in browser, check out the output in `console`. 48 | 49 | # Compile SM server by Docker 50 | 51 | ``` 52 | docker build -t ieigen:tss-sm-server --build-arg "BUILDARCH=$(uname -m)" -f sm.dockerfile . 53 | docker run -d -p 8000:8000 -v $PWD/params.json:/tss-wasm/params.json ieigen:tss-sm-server 54 | ``` 55 | 56 | # licence 57 | GPL & Apache-2.0 58 | -------------------------------------------------------------------------------- /Rocket.toml: -------------------------------------------------------------------------------- 1 | [default.limits] 2 | forms = "64 kB" 3 | json = "1 MiB" 4 | msgpack = "2 MiB" 5 | "file/jpg" = "5 MiB" 6 | 7 | [default] 8 | key = "a default app-key" 9 | extra = false 10 | ident = "Rocket" 11 | 12 | [debug] 13 | address = "0.0.0.0" 14 | port = 8000 15 | workers = 1 16 | keep_alive = 0 17 | log_level = "normal" 18 | 19 | [release] 20 | address = "0.0.0.0" 21 | port = 8000 22 | workers = 12 23 | keep_alive = 5 24 | log_level = "critical" 25 | -------------------------------------------------------------------------------- /examples/gg18_sm_manager.rs: -------------------------------------------------------------------------------- 1 | // #[cfg(not(target_arch = "wasm32"))] 2 | // use rocket::fairing::{Fairing, Info, Kind}; 3 | #[cfg(not(target_arch = "wasm32"))] 4 | use rocket::serde::json::Json; 5 | #[cfg(not(target_arch = "wasm32"))] 6 | use rocket::{post, routes, State}; 7 | // #[cfg(not(target_arch = "wasm32"))] 8 | // use rocket::{Request, Response}; 9 | #[cfg(not(target_arch = "wasm32"))] 10 | use rocket_cors::{AllowedOrigins, CorsOptions}; 11 | #[cfg(not(target_arch = "wasm32"))] 12 | use std::collections::HashMap; 13 | #[cfg(not(target_arch = "wasm32"))] 14 | use std::fs; 15 | #[cfg(not(target_arch = "wasm32"))] 16 | use std::sync::RwLock; 17 | #[cfg(not(target_arch = "wasm32"))] 18 | use tss_wasm::common::{Entry, Index, Key, Params, PartySignup}; 19 | #[cfg(not(target_arch = "wasm32"))] 20 | use uuid::Uuid; 21 | 22 | #[cfg(not(target_arch = "wasm32"))] 23 | #[post("/get", format = "json", data = "")] 24 | fn get( 25 | db_mtx: &State>>, 26 | request: Json, 27 | ) -> Json> { 28 | let index: Index = request.0; 29 | let hm = db_mtx.read().unwrap(); 30 | match hm.get(&index.key) { 31 | Some(v) => { 32 | let entry = Entry { 33 | key: index.key, 34 | value: v.clone(), 35 | }; 36 | Json(Ok(entry)) 37 | } 38 | None => Json(Err(())), 39 | } 40 | } 41 | 42 | #[cfg(not(target_arch = "wasm32"))] 43 | #[post("/set", format = "json", data = "")] 44 | fn set(db_mtx: &State>>, request: Json) -> Json> { 45 | let entry: Entry = request.0; 46 | let mut hm = db_mtx.write().unwrap(); 47 | hm.insert(entry.key.clone(), entry.value); 48 | Json(Ok(())) 49 | } 50 | 51 | #[cfg(not(target_arch = "wasm32"))] 52 | #[post("/signupkeygen", format = "json")] 53 | fn signup_keygen(db_mtx: &State>>) -> Json> { 54 | let data = fs::read_to_string("params.json") 55 | .expect("Unable to read params, make sure config file is present in the same folder "); 56 | let params: Params = serde_json::from_str(&data).unwrap(); 57 | let parties = params.parties.parse::().unwrap(); 58 | 59 | let key = "signup-keygen".to_string(); 60 | 61 | let mut hm = db_mtx.write().unwrap(); 62 | let party_signup = { 63 | let value = hm.get(&key).unwrap(); 64 | let client_signup: PartySignup = serde_json::from_str(value).unwrap(); 65 | if client_signup.number < parties { 66 | PartySignup { 67 | number: client_signup.number + 1, 68 | uuid: client_signup.uuid, 69 | } 70 | } else { 71 | PartySignup { 72 | number: 1, 73 | uuid: Uuid::new_v4().to_string(), 74 | } 75 | } 76 | }; 77 | 78 | hm.insert(key, serde_json::to_string(&party_signup).unwrap()); 79 | Json(Ok(party_signup)) 80 | } 81 | 82 | #[cfg(not(target_arch = "wasm32"))] 83 | #[post("/signupsign", format = "json")] 84 | fn signup_sign(db_mtx: &State>>) -> Json> { 85 | //read parameters: 86 | let data = fs::read_to_string("params.json") 87 | .expect("Unable to read params, make sure config file is present in the same folder "); 88 | let params: Params = serde_json::from_str(&data).unwrap(); 89 | let threshold = params.threshold.parse::().unwrap(); 90 | let key = "signup-sign".to_string(); 91 | 92 | let mut hm = db_mtx.write().unwrap(); 93 | let party_signup = { 94 | let value = hm.get(&key).unwrap(); 95 | let client_signup: PartySignup = serde_json::from_str(value).unwrap(); 96 | if client_signup.number < threshold + 1 { 97 | PartySignup { 98 | number: client_signup.number + 1, 99 | uuid: client_signup.uuid, 100 | } 101 | } else { 102 | PartySignup { 103 | number: 1, 104 | uuid: Uuid::new_v4().to_string(), 105 | } 106 | } 107 | }; 108 | 109 | hm.insert(key, serde_json::to_string(&party_signup).unwrap()); 110 | Json(Ok(party_signup)) 111 | } 112 | 113 | #[cfg(not(target_arch = "wasm32"))] 114 | #[tokio::main] 115 | async fn main() { 116 | let db: HashMap = HashMap::new(); 117 | let db_mtx = RwLock::new(db); 118 | 119 | ///////////////////////////////////////////////////////////////// 120 | //////////////////////////init signups:////////////////////////// 121 | ///////////////////////////////////////////////////////////////// 122 | 123 | let keygen_key = "signup-keygen".to_string(); 124 | let sign_key = "signup-sign".to_string(); 125 | 126 | let uuid_keygen = Uuid::new_v4().to_string(); 127 | let uuid_sign = Uuid::new_v4().to_string(); 128 | 129 | let party1 = 0; 130 | let party_signup_keygen = PartySignup { 131 | number: party1, 132 | uuid: uuid_keygen, 133 | }; 134 | let party_signup_sign = PartySignup { 135 | number: party1, 136 | uuid: uuid_sign, 137 | }; 138 | { 139 | let mut hm = db_mtx.write().unwrap(); 140 | hm.insert( 141 | keygen_key, 142 | serde_json::to_string(&party_signup_keygen).unwrap(), 143 | ); 144 | hm.insert(sign_key, serde_json::to_string(&party_signup_sign).unwrap()); 145 | } 146 | 147 | let cors = CorsOptions::default() 148 | .allowed_origins(AllowedOrigins::all()) 149 | .allowed_methods( 150 | ["Get", "Post", "Patch"] 151 | .iter() 152 | .map(|s| std::str::FromStr::from_str(s).unwrap()) 153 | .collect(), 154 | ) 155 | .allow_credentials(true); 156 | 157 | ///////////////////////////////////////////////////////////////// 158 | rocket::build() 159 | .mount("/", routes![get, set, signup_keygen, signup_sign]) 160 | .attach(cors.to_cors().unwrap()) 161 | .manage(db_mtx) 162 | .launch() 163 | .await 164 | .unwrap(); 165 | } 166 | 167 | #[cfg(target_arch = "wasm32")] 168 | fn main() { 169 | panic!("Unimplemented") 170 | } 171 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | exports.gg18 = require("./pkg"); 2 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@ieigen/tss-wasm", 3 | "version": "0.0.9", 4 | "description": "TSS Wasm for ECDSA", 5 | "keywords": [ 6 | "tss", 7 | "wasm", 8 | "gg18", 9 | "mpc", 10 | "wallet", 11 | "blockchain" 12 | ], 13 | "scripts": { 14 | "build": "wasm-pack build --target web --release && ./node_modules/webpack/bin/webpack.js", 15 | "build_node": "wasm-pack build --target nodejs --release", 16 | "test": "wasm-pack test --node" 17 | }, 18 | "devDependencies": { 19 | "@wasm-tool/wasm-pack-plugin": "1.0.1", 20 | "html-webpack-plugin": "^3.2.0", 21 | "text-encoding": "^0.7.0", 22 | "webpack": "^4.29.4", 23 | "webpack-cli": "^3.1.1", 24 | "webpack-dev-server": "^3.1.0", 25 | "ethers": "^5.7.1" 26 | }, 27 | "author": "EigenLabs", 28 | "main": "index.js", 29 | "license": "Apache-2.0", 30 | "files": [ 31 | "pkg/*", 32 | "index.js" 33 | ] 34 | } 35 | -------------------------------------------------------------------------------- /params.json: -------------------------------------------------------------------------------- 1 | {"parties":"3", "threshold":"1"} 2 | -------------------------------------------------------------------------------- /run_keygen_sign.js: -------------------------------------------------------------------------------- 1 | const thsig = import("./pkg"); 2 | 3 | var items = [{ idx: 0 }, { idx: 1 }, { idx: 2 }]; 4 | var results = []; 5 | 6 | let t = 1; 7 | let n = 3; 8 | let addr = "http://127.0.0.1:8000" 9 | 10 | const delay_ms = ms => new Promise(resolve => setTimeout(resolve, ms)) 11 | 12 | async function keygen(m, arg, delay) { 13 | let context = await m.gg18_keygen_client_new_context(addr, t, n, delay); 14 | console.log("keygen new context: ", context); 15 | context = await m.gg18_keygen_client_round1(context, delay); 16 | console.log("keygen round1: ", context); 17 | context = await m.gg18_keygen_client_round2(context, delay); 18 | console.log("keygen round2: ", context); 19 | context = await m.gg18_keygen_client_round3(context, delay); 20 | console.log("keygen round3: ", context); 21 | context = await m.gg18_keygen_client_round4(context, delay); 22 | console.log("keygen round4: ", context); 23 | keygen_json = await m.gg18_keygen_client_round5(context, delay); 24 | console.log("keygen json: ", keygen_json); 25 | return keygen_json; 26 | } 27 | 28 | async function sign(m, arg, key_store, delay) { 29 | let context = await m.gg18_sign_client_new_context( 30 | addr, 31 | t, 32 | n, 33 | key_store, 34 | ethers.utils.keccak256(ethers.utils.toUtf8Bytes('Hello Eigen')).slice(2) 35 | ); 36 | console.log("sign new context: ", context); 37 | context = await m.gg18_sign_client_round0(context, delay); 38 | console.log("sign round0: ", context); 39 | context = await m.gg18_sign_client_round1(context, delay); 40 | console.log("sign round1: ", context); 41 | context = await m.gg18_sign_client_round2(context, delay); 42 | console.log("sign round2: ", context); 43 | context = await m.gg18_sign_client_round3(context, delay); 44 | console.log("sign round3: ", context); 45 | context = await m.gg18_sign_client_round4(context, delay); 46 | console.log("sign round4: ", context); 47 | context = await m.gg18_sign_client_round5(context, delay); 48 | console.log("sign round5: ", context); 49 | context = await m.gg18_sign_client_round6(context, delay); 50 | console.log("sign round6: ", context); 51 | context = await m.gg18_sign_client_round7(context, delay); 52 | console.log("sign round7: ", context); 53 | context = await m.gg18_sign_client_round8(context, delay); 54 | console.log("sign round8: ", context); 55 | sign_json = await m.gg18_sign_client_round9(context, delay); 56 | console.log("keygen json: ", sign_json); 57 | return sign_json; 58 | } 59 | 60 | /* 61 | async function main() { 62 | const gg18 = await thsig; 63 | await Promise.all( 64 | items.map( 65 | async (item) => { 66 | let delay = Math.max(Math.random() % 500, 100); 67 | res = await keygen(gg18, item, delay); 68 | console.log("Keysign done", item.idx, " ", res); 69 | results.push(res); 70 | } 71 | ) 72 | ) 73 | 74 | await Promise.all( 75 | items.map( 76 | async (item) => { 77 | if (item.idx < t+1) { 78 | let delay = Math.max(Math.random() % 500, 100); 79 | delay_ms(delay); 80 | console.log(item.idx, " ", results[item.idx]); 81 | res = await sign(gg18, item, results[item.idx], delay + 1); 82 | console.log("Sign result: ", res); 83 | } 84 | } 85 | ) 86 | ) 87 | } 88 | 89 | main().then(() => { 90 | console.log("Done"); 91 | }) 92 | */ 93 | thsig.then((m) => { 94 | items.forEach(async function (item) { 95 | let delay = Math.max(Math.random() % 500, 100); 96 | res = await keygen(m, item, delay); 97 | console.log(item.idx, " ", res); 98 | results.push(res); 99 | 100 | if (results.length == items.length) { 101 | console.log(results.length); 102 | items.forEach(async function (item) { 103 | if (item.idx < t + 1) { 104 | console.log(item.idx, " ", results[item.idx]); 105 | let delay = Math.max(Math.random() % 500, 100); 106 | res = await sign(m, item, results[item.idx], delay); 107 | console.log("Sign result: ", res); 108 | } 109 | }); 110 | } 111 | }); 112 | }); 113 | -------------------------------------------------------------------------------- /scripts/run_keygen_sign_node.js: -------------------------------------------------------------------------------- 1 | const gg18 = require('../pkg') 2 | const ethers = require('ethers') 3 | 4 | var items = [{ idx: 0 }, { idx: 1 }, { idx: 2 }] 5 | 6 | let t = 1 7 | let n = 3 8 | let addr = 'http://127.0.0.1:8000' 9 | 10 | const delay_ms = (ms) => new Promise((resolve) => setTimeout(resolve, ms)) 11 | const digest = ethers.utils.keccak256(ethers.utils.toUtf8Bytes('Hello Eigen')) 12 | 13 | async function keygen(m, delay) { 14 | let context = await m.gg18_keygen_client_new_context(addr, t, n, delay) 15 | console.log('keygen new context: ') 16 | context = await m.gg18_keygen_client_round1(context, delay) 17 | console.log('keygen round1:') 18 | context = await m.gg18_keygen_client_round2(context, delay) 19 | console.log('keygen round2: ') 20 | context = await m.gg18_keygen_client_round3(context, delay) 21 | console.log('keygen round3: ') 22 | context = await m.gg18_keygen_client_round4(context, delay) 23 | console.log('keygen round4: ') 24 | keygen_json = await m.gg18_keygen_client_round5(context, delay) 25 | console.log('keygen json: ', keygen_json) 26 | return keygen_json 27 | } 28 | 29 | async function sign(m, key_store, delay) { 30 | let context = await m.gg18_sign_client_new_context( 31 | addr, 32 | t, 33 | n, 34 | key_store, 35 | digest.slice(2) 36 | ) 37 | console.log('sign new context: ', context) 38 | context = await m.gg18_sign_client_round0(context, delay) 39 | console.log('sign round0: ') 40 | context = await m.gg18_sign_client_round1(context, delay) 41 | console.log('sign round1: ') 42 | context = await m.gg18_sign_client_round2(context, delay) 43 | console.log('sign round2: ') 44 | context = await m.gg18_sign_client_round3(context, delay) 45 | console.log('sign round3: ') 46 | context = await m.gg18_sign_client_round4(context, delay) 47 | console.log('sign round4: ') 48 | context = await m.gg18_sign_client_round5(context, delay) 49 | console.log('sign round5: ') 50 | context = await m.gg18_sign_client_round6(context, delay) 51 | console.log('sign round6: ') 52 | context = await m.gg18_sign_client_round7(context, delay) 53 | console.log('sign round7: ') 54 | context = await m.gg18_sign_client_round8(context, delay) 55 | console.log('sign round8: ') 56 | sign_json = await m.gg18_sign_client_round9(context, delay) 57 | console.log('keysign json: ', sign_json) 58 | return sign_json 59 | } 60 | 61 | async function main() { 62 | var results = await Promise.all( 63 | items.map(async (item) => { 64 | let delay = Math.max(Math.random() % 500, 100) 65 | res = await keygen(gg18, delay) 66 | return { idx: item.idx, res: res } 67 | }), 68 | ) 69 | 70 | console.log('sign items: ', results) 71 | await Promise.all( 72 | results.map(async (item) => { 73 | if (item.idx < t + 1) { 74 | let delay = Math.max(Math.random() % 500, 100) 75 | //select random signer 76 | res = JSON.parse(await sign(gg18, item.res, delay)) 77 | console.log('Sign result: ', res) 78 | // recover the address 79 | console.log("digest", digest); 80 | let address = ethers.utils.recoverAddress(digest, { 81 | r: "0x"+res[0], 82 | s: "0x"+res[1], 83 | v: res[2] 84 | }) 85 | console.log("recover address by etherjs", address) 86 | } 87 | }), 88 | ) 89 | } 90 | 91 | main().then(() => { 92 | console.log('Done') 93 | }) 94 | -------------------------------------------------------------------------------- /sm.dockerfile: -------------------------------------------------------------------------------- 1 | FROM rust:latest AS builder 2 | 3 | WORKDIR /tss-wasm 4 | COPY ./ . 5 | 6 | RUN apt-get update \ 7 | && apt-get install -y --no-install-recommends libssl-dev libc6-dev 8 | 9 | ## install wasm-pack 10 | RUN curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh 11 | 12 | ## compile sm server 13 | RUN cargo build --examples --release 14 | 15 | FROM debian:buster-slim 16 | # Import from builder. 17 | 18 | WORKDIR /tss-wasm 19 | 20 | # Copy our build 21 | ARG BUILDARCH 22 | COPY --from=builder /tss-wasm/target/release/examples/gg18_sm_manager ./ 23 | COPY --from=builder /tss-wasm/Rocket.toml ./ 24 | COPY --from=builder /usr/lib/$BUILDARCH-linux-gnu/libssl.so.1.1 /usr/lib/$BUILDARCH-linux-gnu/ 25 | COPY --from=builder /usr/lib/$BUILDARCH-linux-gnu/libcrypto.so.1.1 /usr/lib/$BUILDARCH-linux-gnu/ 26 | 27 | EXPOSE 8000:8000 28 | CMD ["/tss-wasm/gg18_sm_manager"] 29 | 30 | -------------------------------------------------------------------------------- /src/common.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | use crate::curv::elliptic::curves::traits::{ECPoint, ECScalar}; 4 | use crate::errors::TssError; 5 | #[cfg(target_arch = "wasm32")] 6 | use crate::log; 7 | 8 | use aes_gcm::aead::{Aead, NewAead}; 9 | use aes_gcm::{Aes256Gcm, Nonce}; 10 | use rand::{rngs::OsRng, RngCore}; 11 | 12 | use crate::curv::{ 13 | arithmetic::num_bigint::BigInt, 14 | arithmetic::traits::Converter, 15 | elliptic::curves::secp256_k1::{Secp256k1Point as Point, Secp256k1Scalar as Scalar}, 16 | }; 17 | 18 | use reqwest::Client; 19 | use serde::{Deserialize, Serialize}; 20 | use sha3::{Digest, Keccak256}; 21 | 22 | use crate::errors::Result; 23 | 24 | pub type Key = String; 25 | 26 | #[allow(dead_code)] 27 | pub const AES_KEY_BYTES_LEN: usize = 32; 28 | 29 | #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] 30 | pub struct AEAD { 31 | pub ciphertext: Vec, 32 | pub tag: Vec, 33 | } 34 | 35 | #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] 36 | pub struct PartySignup { 37 | pub number: u16, 38 | pub uuid: String, 39 | } 40 | 41 | #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] 42 | pub struct Index { 43 | pub key: Key, 44 | } 45 | 46 | #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] 47 | pub struct Entry { 48 | pub key: Key, 49 | pub value: String, 50 | } 51 | 52 | #[derive(Serialize, Deserialize)] 53 | pub struct Params { 54 | pub parties: String, 55 | pub threshold: String, 56 | } 57 | 58 | #[allow(dead_code)] 59 | pub fn aes_encrypt(key: &[u8], plaintext: &[u8]) -> Result { 60 | let aes_key = aes_gcm::Key::from_slice(key); 61 | let cipher = Aes256Gcm::new(aes_key); 62 | 63 | let mut nonce = [0u8; 12]; 64 | let mut rng = OsRng::new()?; 65 | rng.fill_bytes(&mut nonce); 66 | let nonce = Nonce::from_slice(&nonce); 67 | 68 | let ciphertext = cipher 69 | .encrypt(nonce, plaintext) 70 | .map_err(|_e| TssError::UnknownError { 71 | msg: ("encryption failure!").to_string(), 72 | line: (line!()), 73 | })?; 74 | Ok(AEAD { 75 | ciphertext: ciphertext, 76 | tag: nonce.to_vec(), 77 | }) 78 | } 79 | 80 | #[allow(dead_code)] 81 | pub fn aes_decrypt(key: &[u8], aead_pack: AEAD) -> Result> { 82 | let aes_key = aes_gcm::Key::from_slice(key); 83 | let nonce = Nonce::from_slice(&aead_pack.tag); 84 | let gcm = Aes256Gcm::new(aes_key); 85 | 86 | let out = gcm 87 | .decrypt(nonce, aead_pack.ciphertext.as_slice()) 88 | .map_err(|_e| TssError::UnknownError { 89 | msg: ("aes_decrypt").to_string(), 90 | line: (line!()), 91 | }); 92 | out 93 | } 94 | 95 | #[cfg(target_arch = "wasm32")] 96 | pub async fn sleep(ms: u32) { 97 | let promise = js_sys::Promise::new(&mut |resolve, _| { 98 | web_sys::window() 99 | .unwrap() 100 | .set_timeout_with_callback_and_timeout_and_arguments_0(&resolve, ms as i32) 101 | .unwrap(); 102 | }); 103 | wasm_bindgen_futures::JsFuture::from(promise).await; 104 | } 105 | 106 | #[cfg(not(target_arch = "wasm32"))] 107 | pub async fn sleep(ms: u32) { 108 | std::thread::sleep(core::time::Duration::from_millis(ms as u64)); 109 | } 110 | 111 | pub async fn postb(client: &Client, addr: &str, path: &str, body: T) -> Result 112 | where 113 | T: serde::ser::Serialize, 114 | { 115 | let url = format!("{}/{}", addr, path); 116 | let retries = 3; 117 | for _i in 1..retries { 118 | let res = client 119 | .post(url.clone()) 120 | .header("Content-Type", "application/json; charset=utf-8") 121 | .json(&body) 122 | .send() 123 | .await; 124 | if let Ok(res) = res { 125 | return Ok(res.text().await?); 126 | } 127 | } 128 | Err(TssError::UnknownError { 129 | msg: ("postb").to_string(), 130 | line: (line!()), 131 | }) 132 | } 133 | 134 | pub async fn broadcast( 135 | client: &Client, 136 | addr: &str, 137 | party_num: u16, 138 | round: &str, 139 | data: String, 140 | sender_uuid: String, 141 | ) -> Result<()> { 142 | let key = format!("{}-{}-{}", party_num, round, sender_uuid); 143 | let entry = Entry { key, value: data }; 144 | let res_body = postb(client, addr, "set", entry).await?; 145 | let u: std::result::Result<(), ()> = serde_json::from_str(&res_body)?; 146 | Ok(u.unwrap()) 147 | } 148 | 149 | pub async fn sendp2p( 150 | client: &Client, 151 | addr: &str, 152 | party_from: u16, 153 | party_to: u16, 154 | round: &str, 155 | data: String, 156 | sender_uuid: String, 157 | ) -> Result<()> { 158 | let key = format!("{}-{}-{}-{}", party_from, party_to, round, sender_uuid); 159 | 160 | let entry = Entry { key, value: data }; 161 | 162 | let res_body = postb(client, addr, "set", entry).await?; 163 | let u: std::result::Result<(), ()> = serde_json::from_str(&res_body)?; 164 | Ok(u.unwrap()) 165 | } 166 | 167 | pub async fn poll_for_broadcasts( 168 | client: &Client, 169 | addr: &str, 170 | party_num: u16, 171 | n: u16, 172 | round: &str, 173 | sender_uuid: String, 174 | delay: u32, 175 | ) -> Result> { 176 | let mut ans_vec = Vec::new(); 177 | for i in 1..=n { 178 | if i != party_num { 179 | let key = format!("{}-{}-{}", i, round, sender_uuid); 180 | let index = Index { key }; 181 | loop { 182 | sleep(delay).await; 183 | // add delay to allow the server to process request: 184 | let res_body = postb(client, addr, "get", index.clone()).await?; 185 | let answer: std::result::Result = serde_json::from_str(&res_body)?; 186 | if let Ok(answer) = answer { 187 | ans_vec.push(answer.value); 188 | println!("[{:?}] party {:?} => party {:?}", round, i, party_num); 189 | break; 190 | } 191 | } 192 | } 193 | } 194 | return Ok(ans_vec); 195 | } 196 | 197 | pub async fn poll_for_p2p( 198 | client: &Client, 199 | addr: &str, 200 | party_num: u16, 201 | n: u16, 202 | delay: u32, 203 | round: &str, 204 | sender_uuid: String, 205 | ) -> Result> { 206 | let mut ans_vec = Vec::new(); 207 | for i in 1..=n { 208 | if i != party_num { 209 | let key = format!("{}-{}-{}-{}", i, party_num, round, sender_uuid); 210 | let index = Index { key }; 211 | loop { 212 | // add delay to allow the server to process request: 213 | sleep(delay).await; 214 | let res_body = postb(client, addr, "get", index.clone()).await?; 215 | let answer: std::result::Result = serde_json::from_str(&res_body)?; 216 | if let Ok(answer) = answer { 217 | ans_vec.push(answer.value); 218 | println!("[{:?}] party {:?} => party {:?}", round, i, party_num); 219 | break; 220 | } 221 | } 222 | } 223 | } 224 | Ok(ans_vec) 225 | } 226 | 227 | pub fn check_sig(r: &Scalar, s: &Scalar, msg: &BigInt, pk: &Point) -> Result { 228 | let r_vec = BigInt::to_vec(&r.to_big_int()); 229 | let s_vec = BigInt::to_vec(&s.to_big_int()); 230 | 231 | let mut signature_a = [0u8; 64]; 232 | for i in 0..32 { 233 | signature_a[i] = r_vec[i]; 234 | } 235 | for i in 0..32 { 236 | signature_a[i + 32] = s_vec[i]; 237 | } 238 | 239 | let signature = secp256k1::Signature::parse(&signature_a); 240 | 241 | let msg_vec = BigInt::to_vec(msg); 242 | 243 | let message = secp256k1::Message::parse(&msg_vec.try_into().unwrap()); 244 | 245 | let pubkey_a = pk.get_element().serialize(); 246 | 247 | let pubkey = secp256k1::PublicKey::parse(&pubkey_a)?; 248 | 249 | #[cfg(target_arch = "wasm32")] 250 | crate::console_log!("pubkey: {:?}", pubkey); 251 | #[cfg(target_arch = "wasm32")] 252 | crate::console_log!( 253 | "address: {:?}", 254 | checksum(&hex::encode(public_key_address(&pubkey))) 255 | ); 256 | Ok(secp256k1::verify(&message, &signature, &pubkey)) 257 | } 258 | 259 | pub fn public_key_address(public_key: &secp256k1::PublicKey) -> [u8; 20] { 260 | let public_key = public_key.serialize(); 261 | debug_assert_eq!(public_key[0], 0x04); 262 | let hash = keccak256(&public_key[1..]); 263 | hash[12..32].try_into().unwrap() 264 | } 265 | 266 | pub fn keccak256(bytes: &[u8]) -> [u8; 32] { 267 | use tiny_keccak::{Hasher, Keccak}; 268 | let mut output = [0u8; 32]; 269 | let mut hasher = Keccak::v256(); 270 | hasher.update(bytes); 271 | hasher.finalize(&mut output); 272 | output 273 | } 274 | 275 | const PREFIX: &str = "0x"; 276 | 277 | pub fn checksum(address: &str) -> Result { 278 | let stripped = String::from(address.to_ascii_lowercase().trim_start_matches(PREFIX)); 279 | 280 | let mut hasher = Keccak256::new(); 281 | hasher.update(stripped.clone()); 282 | let hash_vec = hasher.finalize().to_vec(); 283 | let hash = hex::encode(hash_vec); 284 | 285 | let mut checksum = String::new(); 286 | 287 | if address.len() != stripped.len() { 288 | checksum.push_str(PREFIX); 289 | } 290 | 291 | for (pos, char) in hash.chars().enumerate() { 292 | if pos > 39 { 293 | break; 294 | } 295 | if u32::from_str_radix(&char.to_string()[..], 16)? > 7 { 296 | checksum.push_str(&stripped[pos..pos + 1].to_ascii_uppercase()); 297 | } else { 298 | checksum.push_str(&stripped[pos..pos + 1].to_ascii_lowercase()); 299 | } 300 | } 301 | 302 | Ok(checksum) 303 | } 304 | -------------------------------------------------------------------------------- /src/curv/arithmetic/mod.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Cryptography utilities 3 | 4 | Copyright 2018 by Kzen Networks 5 | 6 | This file is part of Cryptography utilities library 7 | (https://github.com/KZen-networks/cryptography-utils) 8 | 9 | Cryptography utilities is free software: you can redistribute 10 | it and/or modify it under the terms of the GNU General Public 11 | License as published by the Free Software Foundation, either 12 | version 3 of the License, or (at your option) any later version. 13 | 14 | @license GPL-3.0+ 15 | */ 16 | 17 | pub mod num_bigint; 18 | pub mod traits; 19 | -------------------------------------------------------------------------------- /src/curv/arithmetic/num_bigint.rs: -------------------------------------------------------------------------------- 1 | use super::traits::*; 2 | use num_bigint::BigUint; 3 | use num_integer::Integer; 4 | use rand::thread_rng; 5 | 6 | use num_bigint::BigInt as BN; 7 | use num_bigint::RandBigInt; 8 | use num_bigint::ToBigInt; 9 | use num_traits::cast::ToPrimitive; 10 | use num_traits::identities::Zero; 11 | use num_traits::Num; 12 | use num_traits::One; 13 | use std::ops::{BitAnd, BitOr, Shl}; 14 | 15 | impl Samplable for BigUint { 16 | fn sample_below(upper: &Self) -> Self { 17 | let mut rng = thread_rng(); 18 | rng.gen_biguint_below(upper) 19 | } 20 | 21 | fn sample(bitsize: usize) -> Self { 22 | let mut rng = thread_rng(); 23 | rng.gen_biguint(bitsize) 24 | } 25 | 26 | fn sample_range(lower: &Self, upper: &Self) -> Self { 27 | let mut rng = thread_rng(); 28 | rng.gen_biguint_range(lower, upper) 29 | } 30 | } 31 | 32 | impl NumberTests for BigUint { 33 | fn is_zero(me: &Self) -> bool { 34 | me.eq(&BigUint::zero()) 35 | } 36 | fn is_even(me: &Self) -> bool { 37 | (me % BigUint::from(2 as u32)).eq(&BigUint::zero()) 38 | } 39 | fn is_negative(me: &Self) -> bool { 40 | me < &BigUint::zero() 41 | } 42 | } 43 | 44 | impl Modulo for BigUint { 45 | fn mod_pow(base: &Self, exponent: &Self, modulus: &Self) -> Self { 46 | base.modpow(&exponent, &modulus) 47 | } 48 | 49 | fn mod_mul(a: &Self, b: &Self, modulus: &Self) -> Self { 50 | (a.mod_floor(modulus) * b.mod_floor(modulus)).mod_floor(modulus) 51 | } 52 | 53 | fn mod_sub(a: &Self, b: &Self, modulus: &Self) -> Self { 54 | let a_m = a.mod_floor(modulus); 55 | let b_m = b.mod_floor(modulus); 56 | 57 | let sub_op: BigUint = (a_m + modulus) - b_m; 58 | sub_op.mod_floor(modulus) 59 | } 60 | 61 | fn mod_add(a: &Self, b: &Self, modulus: &Self) -> Self { 62 | (a.mod_floor(modulus) + b.mod_floor(modulus)).mod_floor(modulus) 63 | } 64 | 65 | fn mod_inv(a: &Self, modulus: &Self) -> Self { 66 | let x = egcd(a, modulus).1; //[d,x,y] 67 | let x_ubn = x 68 | .mod_floor(&modulus.to_bigint().unwrap()) 69 | .to_biguint() 70 | .unwrap(); 71 | x_ubn 72 | } 73 | 74 | fn mod_egcd(a: &Self, modulus: &Self) -> (Self, Self, Self) { 75 | let (gcd1, x1, y1) = egcd(a, modulus); 76 | let gcd = gcd1.to_biguint().unwrap(); 77 | let x = x1 78 | .mod_floor(&modulus.to_bigint().unwrap()) 79 | .to_biguint() 80 | .unwrap(); 81 | let y = y1 82 | .mod_floor(&modulus.to_bigint().unwrap()) 83 | .to_biguint() 84 | .unwrap(); 85 | (gcd, x, y) 86 | } 87 | } 88 | 89 | fn egcd(a: &BigUint, b: &BigUint) -> (BN, BN, BN) { 90 | let mut a = a.clone().to_bigint().unwrap(); 91 | let mut b = b.clone().to_bigint().unwrap(); 92 | 93 | let mut ua = BN::one(); 94 | let mut va = BN::zero(); 95 | 96 | let mut ub = BN::zero(); 97 | let mut vb = BN::one(); 98 | 99 | let mut q; 100 | let mut tmp; 101 | let mut r; 102 | 103 | while !b.is_zero() { 104 | q = &a / &b; 105 | 106 | r = &a % &b; 107 | 108 | a = b; 109 | b = r; 110 | 111 | tmp = ua; 112 | ua = ub.clone(); 113 | ub = tmp - &q * &ub; 114 | 115 | tmp = va; 116 | va = vb.clone(); 117 | vb = tmp - &q * &vb; 118 | } 119 | (a, ua, va) 120 | } 121 | impl ConvertFrom for usize { 122 | fn _from(x: &BigUint) -> usize { 123 | x.to_usize().unwrap() 124 | } 125 | } 126 | 127 | impl ConvertFrom for u8 { 128 | fn _from(x: &BigUint) -> u8 { 129 | x.to_u8().unwrap() 130 | } 131 | } 132 | 133 | impl ConvertFrom for u16 { 134 | fn _from(x: &BigUint) -> u16 { 135 | x.to_u16().unwrap() 136 | } 137 | } 138 | 139 | impl ConvertFrom for u32 { 140 | fn _from(x: &BigUint) -> u32 { 141 | x.to_u32().unwrap() 142 | } 143 | } 144 | 145 | impl ConvertFrom for u64 { 146 | fn _from(x: &BigUint) -> u64 { 147 | x.to_u64().unwrap() 148 | } 149 | } 150 | 151 | impl ConvertFrom for i8 { 152 | fn _from(x: &BigUint) -> i8 { 153 | x.to_i8().unwrap() 154 | } 155 | } 156 | 157 | impl ConvertFrom for i16 { 158 | fn _from(x: &BigUint) -> i16 { 159 | x.to_i16().unwrap() 160 | } 161 | } 162 | 163 | impl ConvertFrom for i32 { 164 | fn _from(x: &BigUint) -> i32 { 165 | x.to_i32().unwrap() 166 | } 167 | } 168 | 169 | impl ConvertFrom for i64 { 170 | fn _from(x: &BigUint) -> i64 { 171 | x.to_i64().unwrap() 172 | } 173 | } 174 | 175 | /* 176 | impl<'a> ConvertFrom<&'a [u8]> for BigUint { 177 | fn _from(other: &&'a [u8]) -> BigUint { 178 | BigInt::from_slice(*other as &[u32]) 179 | } 180 | } 181 | */ 182 | 183 | pub fn from(bytes: &[u8]) -> BigInt { 184 | BigInt::from_bytes_be(bytes) 185 | } 186 | 187 | impl BitManipulation for BigUint { 188 | fn set_bit(&self, bit: usize, bit_val: bool) -> BigUint { 189 | let one = BigInt::from(1 as u16); 190 | let one_shl = one.shl(bit); 191 | if bit_val == false { 192 | return self.bitand(&one_shl); 193 | } else { 194 | return self.bitor(&one_shl); 195 | } 196 | } 197 | 198 | fn test_bit(self: &Self, _bit: usize) -> bool { 199 | return true; //stub 200 | } 201 | } 202 | 203 | pub type BigInt = BigUint; 204 | 205 | /* 206 | impl Serialize for BigInt { 207 | fn serialize(&self, serializer: S) -> Result 208 | where 209 | S: Serializer, 210 | { 211 | serializer.serialize_str(&self.to_str_radix(16)) 212 | } 213 | } 214 | 215 | impl<'de> Deserialize<'de> for BigInt { 216 | fn deserialize(deserializer: D) -> Result 217 | where 218 | D: Deserializer<'de>, 219 | { 220 | deserializer.deserialize_str(BigUintVisitor) 221 | } 222 | } 223 | 224 | struct BigUintVisitor; 225 | 226 | impl<'de> Visitor<'de> for BigUintVisitor { 227 | type Value = BigUint; 228 | 229 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 230 | formatter.write_str("Secp256k1Scalar") 231 | } 232 | 233 | fn visit_str(self, s: &str) -> Result { 234 | let v = BigInt::from_str_radix(s, 16).expect("Failed in serde"); 235 | Ok(v) 236 | } 237 | } 238 | */ 239 | 240 | impl Converter for BigUint { 241 | fn to_bytes(value: &BigUint) -> Vec { 242 | let bytes: Vec = value.to_bytes_be(); 243 | bytes 244 | } 245 | 246 | fn from_bytes(bytes: &[u8]) -> Self { 247 | BigUint::from_bytes_be(bytes) 248 | } 249 | 250 | fn to_vec(value: &BigUint) -> Vec { 251 | let bytes: Vec = value.to_bytes_be(); 252 | 253 | bytes 254 | } 255 | 256 | fn to_hex(&self) -> String { 257 | self.to_str_radix(16) 258 | } 259 | 260 | fn from_hex(value: &str) -> BigUint { 261 | BigInt::from_str_radix(value, 16).expect("Error in serialization") 262 | } 263 | } 264 | 265 | /* 266 | impl BasicOps for BigInt { 267 | fn pow(&self, exponent: u32) -> Self { 268 | self.num.pow(exponent).wrap() 269 | } 270 | 271 | fn mul(&self, other: &Self) -> Self { 272 | self * other 273 | } 274 | 275 | fn sub(&self, other: &Self) -> Self { 276 | self - other 277 | } 278 | 279 | fn add(&self, other: &Self) -> Self { 280 | self + other 281 | } 282 | 283 | fn abs(&self) -> Self { 284 | self.num.abs().wrap() 285 | } 286 | } 287 | */ 288 | -------------------------------------------------------------------------------- /src/curv/arithmetic/traits.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Cryptography utilities 3 | 4 | Copyright 2018 by Kzen Networks 5 | 6 | This file is part of Cryptography utilities library 7 | (https://github.com/KZen-networks/cryptography-utils) 8 | 9 | Cryptography utilities is free software: you can redistribute 10 | it and/or modify it under the terms of the GNU General Public 11 | License as published by the Free Software Foundation, either 12 | version 3 of the License, or (at your option) any later version. 13 | 14 | @license GPL-3.0+ 15 | */ 16 | 17 | use num_bigint::BigUint; 18 | use std::marker::Sized; 19 | 20 | pub trait Converter { 21 | fn to_vec(n: &Self) -> Vec; 22 | fn to_hex(&self) -> String; 23 | fn from_hex(n: &str) -> Self; 24 | 25 | fn to_bytes(value: &BigUint) -> Vec; 26 | fn from_bytes(bytes: &[u8]) -> Self; 27 | } 28 | 29 | pub trait Modulo { 30 | fn mod_pow(base: &Self, exponent: &Self, modulus: &Self) -> Self; 31 | fn mod_mul(a: &Self, b: &Self, modulus: &Self) -> Self; 32 | fn mod_sub(a: &Self, b: &Self, modulus: &Self) -> Self; 33 | fn mod_add(a: &Self, b: &Self, modulus: &Self) -> Self; 34 | fn mod_inv(a: &Self, modulus: &Self) -> Self; 35 | fn mod_egcd(a: &Self, modulus: &Self) -> (Self, Self, Self) 36 | where 37 | Self: Sized; 38 | } 39 | 40 | pub trait Samplable { 41 | fn sample_below(upper: &Self) -> Self; 42 | fn sample_range(lower: &Self, upper: &Self) -> Self; 43 | fn sample(bitsize: usize) -> Self; 44 | } 45 | 46 | pub trait NumberTests { 47 | fn is_zero(_: &Self) -> bool; 48 | fn is_even(_: &Self) -> bool; 49 | fn is_negative(me: &Self) -> bool; 50 | } 51 | 52 | pub trait EGCD 53 | where 54 | Self: Sized, 55 | { 56 | fn egcd(a: &Self, b: &Self) -> (Self, Self, Self); 57 | } 58 | 59 | pub trait BitManipulation { 60 | fn set_bit(&self, bit: usize, bit_val: bool) -> Self; 61 | fn test_bit(self: &Self, bit: usize) -> bool; 62 | } 63 | 64 | pub trait ConvertFrom { 65 | fn _from(_: &T) -> Self; 66 | } 67 | //use std::ops::{Add, Div, Mul, Neg, Rem, Shr, Sub}; 68 | /// Provides basic arithmetic operators for BigInt 69 | /// 70 | /// Note that BigInt also implements std::ops::{Add, Mull, ...} traits, so you can 71 | /// use them instead. 72 | pub trait BasicOps { 73 | fn pow(&self, exponent: u32) -> Self; 74 | fn mul(&self, other: &Self) -> Self; 75 | fn sub(&self, other: &Self) -> Self; 76 | fn add(&self, other: &Self) -> Self; 77 | fn abs(&self) -> Self; 78 | } 79 | -------------------------------------------------------------------------------- /src/curv/cryptographic_primitives/commitments/hash_commitment.rs: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Curv library 3 | Copyright 2018 by Kzen Networks 4 | (https://github.com/KZen-networks/curv) 5 | License MIT: https://github.com/KZen-networks/curv/blob/master/LICENSE 6 | */ 7 | 8 | //TODO: (open issue) use this struct to represent the commitment HashCommitment{comm: BigInt, r: BigInt, m: BigInt} 9 | /// calculate commitment c = H(m,r) using SHA3 CRHF. 10 | /// r is 256bit blinding factor, m is the commited value 11 | pub struct HashCommitment; 12 | 13 | use crate::curv::arithmetic::num_bigint::BigInt; 14 | 15 | use super::traits::Commitment; 16 | use super::SECURITY_BITS; 17 | use crate::curv::arithmetic::num_bigint::from; 18 | use crate::curv::arithmetic::traits::Converter; 19 | use crate::curv::arithmetic::traits::Samplable; 20 | use cryptoxide::digest::Digest; 21 | use cryptoxide::sha3::Sha3; 22 | 23 | //TODO: using the function with BigInt's as input instead of string's makes it impossible to commit to empty message or use empty randomness 24 | impl Commitment for HashCommitment { 25 | fn create_commitment_with_user_defined_randomness( 26 | message: &BigInt, 27 | blinding_factor: &BigInt, 28 | ) -> BigInt { 29 | let mut digest = Sha3::sha3_256(); 30 | let bytes_message: Vec = BigInt::to_vec(&message); 31 | digest.input(&bytes_message); 32 | let bytes_blinding_factor: Vec = BigInt::to_vec(&blinding_factor); 33 | digest.input(&bytes_blinding_factor); 34 | 35 | let mut result = [0; 32]; 36 | digest.result(&mut result); 37 | from(result.as_ref()) 38 | } 39 | 40 | fn create_commitment(message: &BigInt) -> (BigInt, BigInt) { 41 | let blinding_factor = BigInt::sample(SECURITY_BITS); 42 | let com = HashCommitment::create_commitment_with_user_defined_randomness( 43 | message, 44 | &blinding_factor, 45 | ); 46 | (com, blinding_factor) 47 | } 48 | } 49 | 50 | #[cfg(test)] 51 | mod tests { 52 | use super::Commitment; 53 | use super::HashCommitment; 54 | use super::SECURITY_BITS; 55 | use crate::curv::arithmetic::num_bigint::from; 56 | use crate::curv::arithmetic::num_bigint::BigInt; 57 | use crate::curv::arithmetic::traits::Converter; 58 | use crate::curv::arithmetic::traits::Samplable; 59 | use cryptoxide::digest::Digest; 60 | use cryptoxide::sha3::Sha3; 61 | use num_traits::{One, Zero}; 62 | 63 | #[cfg(target_arch = "wasm32")] 64 | use wasm_bindgen_test::*; 65 | 66 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] 67 | #[test] 68 | fn test_bit_length_create_commitment() { 69 | let hex_len = SECURITY_BITS; 70 | let mut ctr_commit_len = 0; 71 | let mut ctr_blind_len = 0; 72 | let sample_size = 1000; 73 | for _ in 1..sample_size { 74 | let message = BigInt::sample(SECURITY_BITS); 75 | let (commitment, blind_factor) = HashCommitment::create_commitment(&message); 76 | if commitment.to_str_radix(2).len() == hex_len { 77 | ctr_commit_len = ctr_commit_len + 1; 78 | } 79 | if blind_factor.to_str_radix(2).len() == hex_len { 80 | ctr_blind_len = ctr_blind_len + 1; 81 | } 82 | } 83 | //test commitment length - works because SHA256 output length the same as sec_bits 84 | // we test that the probability distribuition is according to what is expected. ideally = 0.5 85 | let ctr_commit_len = ctr_commit_len as f32; 86 | let ctr_blind_len = ctr_blind_len as f32; 87 | let sample_size = sample_size as f32; 88 | assert!(ctr_commit_len / sample_size > 0.3); 89 | assert!(ctr_blind_len / sample_size > 0.3); 90 | } 91 | 92 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] 93 | #[test] 94 | fn test_bit_length_create_commitment_with_user_defined_randomness() { 95 | let message = BigInt::sample(SECURITY_BITS); 96 | let (_commitment, blind_factor) = HashCommitment::create_commitment(&message); 97 | let commitment2 = 98 | HashCommitment::create_commitment_with_user_defined_randomness(&message, &blind_factor); 99 | assert_eq!(commitment2.to_hex().len() / 2, SECURITY_BITS / 8); 100 | } 101 | 102 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] 103 | #[test] 104 | fn test_random_num_generation_create_commitment_with_user_defined_randomness() { 105 | let message = BigInt::sample(SECURITY_BITS); 106 | let (commitment, blind_factor) = HashCommitment::create_commitment(&message); 107 | let commitment2 = 108 | HashCommitment::create_commitment_with_user_defined_randomness(&message, &blind_factor); 109 | assert_eq!(commitment, commitment2); 110 | } 111 | 112 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] 113 | #[test] 114 | fn test_hashing_create_commitment_with_user_defined_randomness() { 115 | let mut digest = Sha3::sha3_256(); 116 | let message = BigInt::one(); 117 | let commitment = HashCommitment::create_commitment_with_user_defined_randomness( 118 | &message, 119 | &BigInt::zero(), 120 | ); 121 | let message2: Vec = BigInt::to_vec(&message); 122 | digest.input(&message2); 123 | let bytes_blinding_factor: Vec = (&BigInt::zero()).to_bytes_be(); 124 | digest.input(&bytes_blinding_factor); 125 | let mut result = [0; 32]; 126 | digest.result(&mut result); 127 | let hash_result = from(result.as_ref()); 128 | assert_eq!(&commitment, &hash_result); 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /src/curv/cryptographic_primitives/commitments/mod.rs: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Curv library 3 | Copyright 2018 by Kzen Networks 4 | (https://github.com/KZen-networks/curv) 5 | License MIT: https://github.com/KZen-networks/curv/blob/master/LICENSE 6 | */ 7 | 8 | const SECURITY_BITS: usize = 256; 9 | 10 | pub mod hash_commitment; 11 | pub mod traits; 12 | -------------------------------------------------------------------------------- /src/curv/cryptographic_primitives/commitments/traits.rs: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Curv library 3 | Copyright 2018 by Kzen Networks 4 | (https://github.com/KZen-networks/curv) 5 | License MIT: https://github.com/KZen-networks/curv/blob/master/LICENSE 6 | */ 7 | 8 | use crate::curv::arithmetic::num_bigint::BigInt; 9 | 10 | pub trait Commitment { 11 | fn create_commitment_with_user_defined_randomness( 12 | message: &BigInt, 13 | blinding_factor: &BigInt, 14 | ) -> T; 15 | 16 | fn create_commitment(message: &BigInt) -> (T, BigInt); 17 | } 18 | -------------------------------------------------------------------------------- /src/curv/cryptographic_primitives/hashing/constants.rs: -------------------------------------------------------------------------------- 1 | // Bitcoin secp256k1 bindings 2 | // Written in 2014 by 3 | // Dawid Ciężarkiewicz 4 | // Andrew Poelstra 5 | // 6 | // To the extent possible under law, the author(s) have dedicated all 7 | // copyright and related and neighboring rights to this software to 8 | // the public domain worldwide. This software is distributed without 9 | // any warranty. 10 | // 11 | // You should have received a copy of the CC0 Public Domain Dedication 12 | // along with this software. 13 | // If not, see . 14 | // 15 | 16 | //! # Constants 17 | //! Constants related to the API and the underlying curve 18 | 19 | /// The size (in bytes) of a message 20 | pub const MESSAGE_SIZE: usize = 32; 21 | 22 | /// The size (in bytes) of a secret key 23 | pub const SECRET_KEY_SIZE: usize = 32; 24 | 25 | /// The size (in bytes) of a serialized public key. 26 | pub const PUBLIC_KEY_SIZE: usize = 33; 27 | 28 | /// The size (in bytes) of an serialized uncompressed public key 29 | pub const UNCOMPRESSED_PUBLIC_KEY_SIZE: usize = 65; 30 | 31 | /// The maximum size of a signature 32 | pub const MAX_SIGNATURE_SIZE: usize = 72; 33 | 34 | /// The maximum size of a compact signature 35 | pub const COMPACT_SIGNATURE_SIZE: usize = 64; 36 | 37 | /// The order of the secp256k1 curve 38 | pub const CURVE_ORDER: [u8; 32] = [ 39 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 40 | 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41, 41 | ]; 42 | 43 | /// The X coordinate of the generator 44 | pub const GENERATOR_X: [u8; 32] = [ 45 | 0x79, 0xbe, 0x66, 0x7e, 0xf9, 0xdc, 0xbb, 0xac, 0x55, 0xa0, 0x62, 0x95, 0xce, 0x87, 0x0b, 0x07, 46 | 0x02, 0x9b, 0xfc, 0xdb, 0x2d, 0xce, 0x28, 0xd9, 0x59, 0xf2, 0x81, 0x5b, 0x16, 0xf8, 0x17, 0x98, 47 | ]; 48 | 49 | /// The Y coordinate of the generator 50 | pub const GENERATOR_Y: [u8; 32] = [ 51 | 0x48, 0x3a, 0xda, 0x77, 0x26, 0xa3, 0xc4, 0x65, 0x5d, 0xa4, 0xfb, 0xfc, 0x0e, 0x11, 0x08, 0xa8, 52 | 0xfd, 0x17, 0xb4, 0x48, 0xa6, 0x85, 0x54, 0x19, 0x9c, 0x47, 0xd0, 0x8f, 0xfb, 0x10, 0xd4, 0xb8, 53 | ]; 54 | -------------------------------------------------------------------------------- /src/curv/cryptographic_primitives/hashing/ext.rs: -------------------------------------------------------------------------------- 1 | use digest::Digest; 2 | // use hmac::crypto_mac::MacError; 3 | // use hmac::{Hmac, Mac}; 4 | // use typenum::Unsigned; 5 | 6 | use crate::curv::arithmetic::num_bigint::BigInt; 7 | // use crate::curv::arithmetic::*; 8 | use crate::curv::elliptic::curves::secp256_k1::{ 9 | Secp256k1Point as Point, Secp256k1Scalar as Scalar, 10 | }; 11 | use crate::curv::elliptic::curves::traits::{ECPoint, ECScalar}; 12 | 13 | pub trait DigestExt { 14 | fn input_bigint(&mut self, n: &BigInt); 15 | fn input_point(&mut self, point: &Point); 16 | fn input_scalar(&mut self, scalar: &Scalar); 17 | 18 | fn chain_bigint(mut self, n: &BigInt) -> Self 19 | where 20 | Self: Sized, 21 | { 22 | self.input_bigint(n); 23 | self 24 | } 25 | fn chain_point(mut self, point: &Point) -> Self 26 | where 27 | Self: Sized, 28 | { 29 | self.input_point(point); 30 | self 31 | } 32 | fn chain_points<'p>(mut self, points: impl IntoIterator) -> Self 33 | where 34 | Self: Sized, 35 | { 36 | for point in points { 37 | self.input_point(point) 38 | } 39 | self 40 | } 41 | fn chain_scalar(mut self, scalar: &Scalar) -> Self 42 | where 43 | Self: Sized, 44 | { 45 | self.input_scalar(scalar); 46 | self 47 | } 48 | fn chain_scalars<'s>(mut self, scalars: impl IntoIterator) -> Self 49 | where 50 | Self: Sized, 51 | { 52 | for scalar in scalars { 53 | self.input_scalar(scalar) 54 | } 55 | self 56 | } 57 | 58 | fn result_bigint(self) -> BigInt; 59 | //fn result_scalar(self) -> Scalar; 60 | 61 | fn digest_bigint(bytes: &[u8]) -> BigInt; 62 | } 63 | 64 | impl DigestExt for D 65 | where 66 | D: Digest + Clone, 67 | { 68 | fn input_bigint(&mut self, n: &BigInt) { 69 | self.update(&n.to_bytes_be()) 70 | } 71 | 72 | fn input_point(&mut self, point: &Point) { 73 | self.update(&point.to_bytes(false)[..]) 74 | } 75 | 76 | fn input_scalar(&mut self, scalar: &Scalar) { 77 | self.update(&scalar.to_big_int().to_bytes_be()) 78 | } 79 | 80 | fn result_bigint(self) -> BigInt { 81 | let result = self.finalize(); 82 | BigInt::from_bytes_be(&result) 83 | } 84 | 85 | /* 86 | fn result_scalar(self) -> Scalar { 87 | let scalar_len = ::ScalarLength as Unsigned>::to_usize(); 88 | assert!( 89 | Self::output_size() >= scalar_len, 90 | "Output size of the hash({}) is smaller than the scalar length({})", 91 | Self::output_size(), 92 | scalar_len 93 | ); 94 | // Try and increment. 95 | for i in 0u32.. { 96 | let starting_state = self.clone(); 97 | let hash = starting_state.chain(i.to_be_bytes()).finalize(); 98 | if let Ok(scalar) = Scalar::from_bytes(&hash[..scalar_len]) { 99 | return scalar; 100 | } 101 | } 102 | unreachable!("The probably of this reaching is extremely small ((2^n-q)/(2^n))^(2^32)") 103 | } 104 | */ 105 | 106 | fn digest_bigint(bytes: &[u8]) -> BigInt { 107 | Self::new().chain(bytes).result_bigint() 108 | } 109 | } 110 | 111 | /* 112 | /// [Hmac] extension allowing to use bigints to instantiate hmac, update, and finalize it. 113 | pub trait HmacExt: Sized { 114 | fn new_bigint(key: &BigInt) -> Self; 115 | 116 | fn input_bigint(&mut self, n: &BigInt); 117 | 118 | fn chain_bigint(mut self, n: &BigInt) -> Self 119 | where 120 | Self: Sized, 121 | { 122 | self.input_bigint(n); 123 | self 124 | } 125 | 126 | fn result_bigint(self) -> BigInt; 127 | fn verify_bigint(self, code: &BigInt) -> Result<(), MacError>; 128 | } 129 | 130 | impl HmacExt for Hmac 131 | where 132 | D: digest::Update + digest::BlockInput + digest::FixedOutput + digest::Reset + Default + Clone, 133 | { 134 | fn new_bigint(key: &BigInt) -> Self { 135 | let bytes = key.to_byte(); 136 | Self::new_from_slice(&bytes).expect("HMAC must take a key of any length") 137 | } 138 | 139 | fn input_bigint(&mut self, n: &BigInt) { 140 | self.update(&n.to_bytes()) 141 | } 142 | 143 | fn result_bigint(self) -> BigInt { 144 | BigInt::from_bytes_be(&self.finalize().into_bytes()) 145 | } 146 | 147 | fn verify_bigint(self, code: &BigInt) -> Result<(), MacError> { 148 | self.verify(&code.to_bytes()) 149 | } 150 | } 151 | 152 | #[cfg(test)] 153 | mod test { 154 | use digest::generic_array::ArrayLength; 155 | use digest::{BlockInput, FixedOutput, Reset, Update}; 156 | use hmac::Hmac; 157 | use sha2::{Sha256, Sha512}; 158 | 159 | use super::*; 160 | 161 | // Test Vectors taken from: 162 | // https://csrc.nist.gov/projects/cryptographic-algorithm-validation-program/secure-hashing#shavs 163 | #[test] 164 | fn vector_sha256_test() { 165 | // Empty Message 166 | let result: BigInt = Sha256::new().result_bigint(); 167 | assert_eq!( 168 | result.to_hex(), 169 | "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 170 | ); 171 | 172 | // 256 bit message 173 | let result: BigInt = Sha256::new() 174 | .chain_bigint( 175 | &BigInt::from_hex( 176 | "09fc1accc230a205e4a208e64a8f204291f581a12756392da4b8c0cf5ef02b95", 177 | ) 178 | .unwrap(), 179 | ) 180 | .result_bigint(); 181 | assert_eq!( 182 | result.to_hex(), 183 | "4f44c1c7fbebb6f9601829f3897bfd650c56fa07844be76489076356ac1886a4" 184 | ); 185 | 186 | // 2x128 bit messages 187 | let result: BigInt = Sha256::new() 188 | .chain_bigint(&BigInt::from_hex("09fc1accc230a205e4a208e64a8f2042").unwrap()) 189 | .chain_bigint(&BigInt::from_hex("91f581a12756392da4b8c0cf5ef02b95").unwrap()) 190 | .result_bigint(); 191 | assert_eq!( 192 | result.to_hex(), 193 | "4f44c1c7fbebb6f9601829f3897bfd650c56fa07844be76489076356ac1886a4" 194 | ); 195 | 196 | // 512 bit message 197 | let result: BigInt = Sha256::new() 198 | .chain_bigint(&BigInt::from_hex("5a86b737eaea8ee976a0a24da63e7ed7eefad18a101c1211e2b3650c5187c2a8a650547208251f6d4237e661c7bf4c77f335390394c37fa1a9f9be836ac28509").unwrap()) 199 | .result_bigint(); 200 | assert_eq!( 201 | result.to_hex(), 202 | "42e61e174fbb3897d6dd6cef3dd2802fe67b331953b06114a65c772859dfc1aa" 203 | ); 204 | } 205 | 206 | #[test] 207 | // Test Vectors taken from: 208 | // https://csrc.nist.gov/projects/cryptographic-algorithm-validation-program/secure-hashing#shavs 209 | fn vector_sha512_test() { 210 | // Empty message 211 | let result: BigInt = Sha512::new().result_bigint(); 212 | assert_eq!( 213 | result.to_hex(), 214 | "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e" 215 | ); 216 | 217 | // 2x256 bit message 218 | let result: BigInt = Sha512::new() 219 | .chain_bigint( 220 | &BigInt::from_hex( 221 | "c1ca70ae1279ba0b918157558b4920d6b7fba8a06be515170f202fafd36fb7f7", 222 | ) 223 | .unwrap(), 224 | ) 225 | .chain_bigint( 226 | &BigInt::from_hex( 227 | "9d69fad745dba6150568db1e2b728504113eeac34f527fc82f2200b462ecbf5d", 228 | ) 229 | .unwrap(), 230 | ) 231 | .result_bigint(); 232 | assert_eq!( 233 | result.to_hex(), 234 | "46e46623912b3932b8d662ab42583423843206301b58bf20ab6d76fd47f1cbbcf421df536ecd7e56db5354e7e0f98822d2129c197f6f0f222b8ec5231f3967d" 235 | ); 236 | 237 | // 512 bit message 238 | let result: BigInt = Sha512::new() 239 | .chain_bigint(&BigInt::from_hex( 240 | "c1ca70ae1279ba0b918157558b4920d6b7fba8a06be515170f202fafd36fb7f79d69fad745dba6150568db1e2b728504113eeac34f527fc82f2200b462ecbf5d").unwrap()) 241 | .result_bigint(); 242 | assert_eq!( 243 | result.to_hex(), 244 | "46e46623912b3932b8d662ab42583423843206301b58bf20ab6d76fd47f1cbbcf421df536ecd7e56db5354e7e0f98822d2129c197f6f0f222b8ec5231f3967d" 245 | ); 246 | 247 | // 1024 bit message 248 | let result: BigInt = Sha512::new() 249 | .chain_bigint(&BigInt::from_hex("fd2203e467574e834ab07c9097ae164532f24be1eb5d88f1af7748ceff0d2c67a21f4e4097f9d3bb4e9fbf97186e0db6db0100230a52b453d421f8ab9c9a6043aa3295ea20d2f06a2f37470d8a99075f1b8a8336f6228cf08b5942fc1fb4299c7d2480e8e82bce175540bdfad7752bc95b577f229515394f3ae5cec870a4b2f8").unwrap()) 250 | .result_bigint(); 251 | assert_eq!( 252 | result.to_hex(), 253 | "a21b1077d52b27ac545af63b32746c6e3c51cb0cb9f281eb9f3580a6d4996d5c9917d2a6e484627a9d5a06fa1b25327a9d710e027387fc3e07d7c4d14c6086cc" 254 | ); 255 | } 256 | 257 | crate::test_for_all_curves_and_hashes!(create_hash_from_ge_test); 258 | fn create_hash_from_ge_test() { 259 | let generator = Point::::generator(); 260 | let base_point2 = Point::::base_point2(); 261 | let result1 = H::new() 262 | .chain_point(&generator) 263 | .chain_point(base_point2) 264 | .result_scalar::(); 265 | assert!(result1.to_bigint().bit_length() > 240); 266 | let result2 = H::new() 267 | .chain_point(base_point2) 268 | .chain_point(&generator) 269 | .result_scalar::(); 270 | assert_ne!(result1, result2); 271 | let result3 = H::new() 272 | .chain_point(base_point2) 273 | .chain_point(&generator) 274 | .result_scalar::(); 275 | assert_eq!(result2, result3); 276 | } 277 | 278 | crate::test_for_all_hashes!(create_hmac_test); 279 | fn create_hmac_test() 280 | where 281 | H: Update + BlockInput + FixedOutput + Reset + Default + Clone, 282 | H::BlockSize: ArrayLength, 283 | H::OutputSize: ArrayLength, 284 | { 285 | let key = BigInt::sample(512); 286 | let result1 = Hmac::::new_bigint(&key) 287 | .chain_bigint(&BigInt::from(10)) 288 | .result_bigint(); 289 | assert!(Hmac::::new_bigint(&key) 290 | .chain_bigint(&BigInt::from(10)) 291 | .verify_bigint(&result1) 292 | .is_ok()); 293 | 294 | let key2 = BigInt::sample(512); 295 | // same data , different key 296 | let result2 = Hmac::::new_bigint(&key2) 297 | .chain_bigint(&BigInt::from(10)) 298 | .result_bigint(); 299 | assert_ne!(result1, result2); 300 | // same key , different data 301 | let result3 = Hmac::::new_bigint(&key) 302 | .chain_bigint(&BigInt::from(10)) 303 | .chain_bigint(&BigInt::from(11)) 304 | .result_bigint(); 305 | assert_ne!(result1, result3); 306 | // same key, same data 307 | let result4 = Hmac::::new_bigint(&key) 308 | .chain_bigint(&BigInt::from(10)) 309 | .result_bigint(); 310 | assert_eq!(result1, result4) 311 | } 312 | } 313 | */ 314 | -------------------------------------------------------------------------------- /src/curv/cryptographic_primitives/hashing/hash_sha256.rs: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Curv library 3 | Copyright 2018 by Kzen Networks 4 | (https://github.com/KZen-networks/curv) 5 | License MIT: https://github.com/KZen-networks/curv/blob/master/LICENSE 6 | */ 7 | 8 | use super::traits::Hash; 9 | use crate::curv::arithmetic::num_bigint::{from, BigInt}; 10 | use crate::curv::elliptic::curves::secp256_k1::{FE, GE}; 11 | use crate::curv::elliptic::curves::traits::{ECPoint, ECScalar}; 12 | use cryptoxide::digest::Digest; 13 | use cryptoxide::sha2::Sha256; 14 | 15 | pub struct HSha256; 16 | 17 | impl Hash for HSha256 { 18 | fn create_hash(big_ints: &[&BigInt]) -> BigInt { 19 | let mut hasher = Sha256::new(); 20 | 21 | for value in big_ints { 22 | let bytes: Vec = value.to_bytes_be(); 23 | hasher.input(&bytes); 24 | } 25 | 26 | let mut result = [0; 32]; 27 | hasher.result(&mut result); 28 | from(result.as_ref()) 29 | } 30 | 31 | fn create_hash_from_ge(ge_vec: &[&GE]) -> FE { 32 | let mut hasher = Sha256::new(); 33 | 34 | for value in ge_vec { 35 | let bytes = value.pk_to_key_slice(); 36 | hasher.input(&bytes); 37 | } 38 | let mut result = [0; 32]; 39 | hasher.result(&mut result); 40 | let result = from(result.as_ref()); 41 | ECScalar::from(&result) 42 | } 43 | } 44 | 45 | #[cfg(test)] 46 | mod tests { 47 | use super::HSha256; 48 | use super::Hash; 49 | use crate::curv::arithmetic::num_bigint::BigInt; 50 | use crate::curv::elliptic::curves::secp256_k1::GE; 51 | use crate::curv::elliptic::curves::traits::ECPoint; 52 | use crate::curv::elliptic::curves::traits::ECScalar; 53 | use num_traits::{One, Zero}; 54 | 55 | #[cfg(target_arch = "wasm32")] 56 | use wasm_bindgen_test::*; 57 | 58 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] 59 | #[test] 60 | // Very basic test here, TODO: suggest better testing 61 | fn create_hash_test() { 62 | HSha256::create_hash(&vec![]); 63 | 64 | let result = HSha256::create_hash(&vec![&BigInt::one(), &BigInt::zero()]); 65 | assert!(result > BigInt::zero()); 66 | } 67 | 68 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] 69 | #[test] 70 | fn create_hash_from_ge_test() { 71 | let point = GE::base_point2(); 72 | let result1 = HSha256::create_hash_from_ge(&vec![&point, &GE::generator()]); 73 | assert!(result1.to_big_int().to_str_radix(2).len() > 240); 74 | let result2 = HSha256::create_hash_from_ge(&vec![&GE::generator(), &point]); 75 | assert_ne!(result1, result2); 76 | let result3 = HSha256::create_hash_from_ge(&vec![&GE::generator(), &point]); 77 | assert_eq!(result2, result3); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/curv/cryptographic_primitives/hashing/mod.rs: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Curv library 3 | Copyright 2018 by Kzen Networks 4 | (https://github.com/KZen-networks/curv) 5 | License MIT: https://github.com/KZen-networks/curv/blob/master/LICENSE 6 | */ 7 | 8 | pub mod constants; 9 | pub mod ext; 10 | pub mod hash_sha256; 11 | pub mod traits; 12 | -------------------------------------------------------------------------------- /src/curv/cryptographic_primitives/hashing/traits.rs: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Curv library 3 | Copyright 2018 by Kzen Networks 4 | (https://github.com/KZen-networks/curv) 5 | License MIT: https://github.com/KZen-networks/curv/blob/master/LICENSE 6 | */ 7 | 8 | use crate::curv::arithmetic::num_bigint::BigInt; 9 | use crate::curv::elliptic::curves::secp256_k1::{FE, GE}; 10 | 11 | pub trait Hash { 12 | fn create_hash(big_ints: &[&BigInt]) -> BigInt; 13 | fn create_hash_from_ge(ge_vec: &[&GE]) -> FE; 14 | } 15 | 16 | pub trait KeyedHash { 17 | fn create_hmac(key: &BigInt, data: &[&BigInt]) -> BigInt; 18 | } 19 | -------------------------------------------------------------------------------- /src/curv/cryptographic_primitives/mod.rs: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Curv library 3 | Copyright 2018 by Kzen Networks 4 | (https://github.com/KZen-networks/curv) 5 | License MIT: 6 | */ 7 | 8 | pub mod commitments; 9 | pub mod hashing; 10 | pub mod proofs; 11 | pub mod secret_sharing; 12 | -------------------------------------------------------------------------------- /src/curv/cryptographic_primitives/proofs/mod.rs: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Curv library 3 | Copyright 2018 by Kzen Networks 4 | (https://github.com/KZen-networks/curv) 5 | License MIT: https://github.com/KZen-networks/curv/blob/master/LICENSE 6 | */ 7 | 8 | use std::error::Error; 9 | use std::fmt; 10 | 11 | pub mod sigma_correct_homomorphic_elgamal_enc; 12 | pub mod sigma_dlog; 13 | 14 | pub const PROOF_ERROR_DESCRIPTION: &str = "Error while verifying"; 15 | 16 | #[derive(Debug, Clone, Copy)] 17 | pub struct ProofError; 18 | 19 | impl fmt::Display for ProofError { 20 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 21 | write!(f, "ProofError") 22 | } 23 | } 24 | 25 | impl Error for ProofError { 26 | fn description(&self) -> &str { 27 | PROOF_ERROR_DESCRIPTION 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/curv/cryptographic_primitives/proofs/sigma_correct_homomorphic_elgamal_enc.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | /* 3 | This file is part of Curv library 4 | Copyright 2018 by Kzen Networks 5 | (https://github.com/KZen-networks/curv) 6 | License MIT: https://github.com/KZen-networks/curv/blob/master/LICENSE 7 | */ 8 | 9 | use super::ProofError; 10 | use crate::curv::cryptographic_primitives::hashing::hash_sha256::HSha256; 11 | use crate::curv::cryptographic_primitives::hashing::traits::Hash; 12 | use crate::curv::elliptic::curves::secp256_k1::{FE, GE}; 13 | use crate::curv::elliptic::curves::traits::*; 14 | use zeroize::Zeroize; 15 | 16 | /// This is a proof of knowledge that a pair of group elements {D, E} 17 | /// form a valid homomorphic ElGamal encryption (”in the exponent”) using public key Y . 18 | /// (HEG is defined in B. Schoenmakers and P. Tuyls. Practical Two-Party Computation Based on the Conditional Gate) 19 | /// Specifically, the witness is ω = (x, r), the statement is δ = (G, H, Y, D, E). 20 | /// The relation R outputs 1 if D = xH+rY , E = rG (for the case of G=H this is ElGamal) 21 | /// 22 | #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] 23 | pub struct HomoELGamalProof { 24 | pub T: GE, 25 | pub A3: GE, 26 | pub z1: FE, 27 | pub z2: FE, 28 | } 29 | 30 | #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] 31 | pub struct HomoElGamalWitness { 32 | pub r: FE, 33 | pub x: FE, 34 | } 35 | 36 | #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] 37 | pub struct HomoElGamalStatement { 38 | pub G: GE, 39 | pub H: GE, 40 | pub Y: GE, 41 | pub D: GE, 42 | pub E: GE, 43 | } 44 | 45 | impl HomoELGamalProof { 46 | pub fn prove(w: &HomoElGamalWitness, delta: &HomoElGamalStatement) -> HomoELGamalProof { 47 | let mut s1: FE = ECScalar::new_random(); 48 | let mut s2: FE = ECScalar::new_random(); 49 | let mut A1 = delta.H.clone() * s1.clone(); 50 | let mut A2 = delta.Y.clone() * s2.clone(); 51 | let A3 = delta.G.clone() * s2.clone(); 52 | let T = A1.clone() + A2.clone(); 53 | let e = HSha256::create_hash_from_ge(&[ 54 | &T, &A3, &delta.G, &delta.H, &delta.Y, &delta.D, &delta.E, 55 | ]); 56 | // dealing with zero field element 57 | let z1 = if w.x.clone() != FE::zero() { 58 | s1.clone() + w.x.clone() * e.clone() 59 | } else { 60 | s1.clone() 61 | }; 62 | let z2 = s2.clone() + w.r.clone() * e.clone(); 63 | s1.zeroize(); 64 | s2.zeroize(); 65 | A1.zeroize(); 66 | A2.zeroize(); 67 | HomoELGamalProof { T, A3, z1, z2 } 68 | } 69 | pub fn verify(&self, delta: &HomoElGamalStatement) -> Result<(), ProofError> { 70 | let e = HSha256::create_hash_from_ge(&[ 71 | &self.T.clone(), 72 | &self.A3.clone(), 73 | &delta.G.clone(), 74 | &delta.H.clone(), 75 | &delta.Y.clone(), 76 | &delta.D.clone(), 77 | &delta.E.clone(), 78 | ]); 79 | let z1H_plus_z2Y = delta.H.clone() * self.z1.clone() + delta.Y.clone() * self.z2.clone(); 80 | let T_plus_eD = self.T.clone() + delta.D.clone() * e.clone(); 81 | let z2G = delta.G.clone() * self.z2.clone(); 82 | let A3_plus_eE = self.A3.clone() + delta.E.clone() * e.clone(); 83 | if z1H_plus_z2Y == T_plus_eD && z2G == A3_plus_eE { 84 | Ok(()) 85 | } else { 86 | Err(ProofError) 87 | } 88 | } 89 | } 90 | 91 | #[cfg(test)] 92 | mod tests { 93 | use crate::curv::cryptographic_primitives::proofs::sigma_correct_homomorphic_elgamal_enc::*; 94 | use crate::curv::cryptographic_primitives::proofs::PROOF_ERROR_DESCRIPTION; 95 | use crate::curv::elliptic::curves::secp256_k1::{FE, GE}; 96 | use std::error::Error; 97 | 98 | #[cfg(target_arch = "wasm32")] 99 | use wasm_bindgen_test::*; 100 | 101 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] 102 | #[test] 103 | fn test_correct_general_homo_elgamal() { 104 | let witness = HomoElGamalWitness { 105 | r: ECScalar::new_random(), 106 | x: ECScalar::new_random(), 107 | }; 108 | let G: GE = ECPoint::generator(); 109 | let h: FE = ECScalar::new_random(); 110 | let H = &G * &h; 111 | let y: FE = ECScalar::new_random(); 112 | let Y = &G * &y; 113 | let D = &H * &witness.x + Y.clone() * &witness.r; 114 | let E = G.clone() * &witness.r; 115 | let delta = HomoElGamalStatement { G, H, Y, D, E }; 116 | let proof = HomoELGamalProof::prove(&witness, &delta); 117 | assert!(proof.verify(&delta).is_ok()); 118 | } 119 | 120 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] 121 | #[test] 122 | fn test_correct_homo_elgamal() { 123 | let witness = HomoElGamalWitness { 124 | r: FE::new_random(), 125 | x: FE::new_random(), 126 | }; 127 | let G: GE = GE::generator(); 128 | let y: FE = FE::new_random(); 129 | let Y = &G * &y; 130 | let D = &G * &witness.x + Y.clone() * &witness.r; 131 | let E = G.clone() * &witness.r; 132 | let delta = HomoElGamalStatement { 133 | G: G.clone(), 134 | H: G, 135 | Y, 136 | D, 137 | E, 138 | }; 139 | let proof = HomoELGamalProof::prove(&witness, &delta); 140 | assert!(proof.verify(&delta).is_ok()); 141 | } 142 | 143 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] 144 | #[test] 145 | fn test_wrong_homo_elgamal() { 146 | // test for E = (r+1)G 147 | let witness = HomoElGamalWitness { 148 | r: ECScalar::new_random(), 149 | x: ECScalar::new_random(), 150 | }; 151 | let G: GE = ECPoint::generator(); 152 | let h: FE = ECScalar::new_random(); 153 | let H = &G * &h; 154 | let y: FE = ECScalar::new_random(); 155 | let Y = &G * &y; 156 | let D = &H * &witness.x + Y.clone() * &witness.r; 157 | let E = &G * &witness.r + G.clone(); 158 | let delta = HomoElGamalStatement { G, H, Y, D, E }; 159 | let proof = HomoELGamalProof::prove(&witness, &delta); 160 | let result = proof.verify(&delta); 161 | assert_eq!(result.unwrap_err().description(), PROOF_ERROR_DESCRIPTION); 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /src/curv/cryptographic_primitives/proofs/sigma_dlog.rs: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Curv library 3 | Copyright 2018 by Kzen Networks 4 | (https://github.com/KZen-networks/curv) 5 | License MIT: https://github.com/KZen-networks/curv/blob/master/LICENSE 6 | */ 7 | 8 | use super::ProofError; 9 | use crate::curv::elliptic::curves::secp256_k1::{FE, GE}; 10 | use crate::curv::elliptic::curves::traits::*; 11 | 12 | use crate::curv::cryptographic_primitives::hashing::hash_sha256::HSha256; 13 | use crate::curv::cryptographic_primitives::hashing::traits::Hash; 14 | use zeroize::Zeroize; 15 | 16 | /// This is implementation of Schnorr's identification protocol for elliptic curve groups or a 17 | /// sigma protocol for Proof of knowledge of the discrete log of an Elliptic-curve point: 18 | /// C.P. Schnorr. Efficient Identification and Signatures for Smart Cards. In 19 | /// CRYPTO 1989, Springer (LNCS 435), pages 239–252, 1990. 20 | /// https://pdfs.semanticscholar.org/8d69/c06d48b618a090dd19185aea7a13def894a5.pdf. 21 | /// 22 | /// The protocol is using Fiat-Shamir Transform: Amos Fiat and Adi Shamir. 23 | /// How to prove yourself: Practical solutions to identification and signature problems. 24 | /// In Advances in Cryptology - CRYPTO ’86, Santa Barbara, California, USA, 1986, Proceedings, 25 | /// pages 186–194, 1986. 26 | #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] 27 | pub struct DLogProof { 28 | pub pk: GE, 29 | pub pk_t_rand_commitment: GE, 30 | pub challenge_response: FE, 31 | } 32 | 33 | pub trait ProveDLog { 34 | fn prove(sk: &FE) -> DLogProof; 35 | 36 | fn verify(proof: &DLogProof) -> Result<(), ProofError>; 37 | } 38 | 39 | impl ProveDLog for DLogProof { 40 | fn prove(sk: &FE) -> DLogProof { 41 | let base_point: GE = ECPoint::generator(); 42 | let generator_x = base_point.bytes_compressed_to_big_int(); 43 | let mut sk_t_rand_commitment: FE = ECScalar::new_random(); 44 | let pk_t_rand_commitment = base_point.scalar_mul(&sk_t_rand_commitment.get_element()); 45 | let ec_point: GE = ECPoint::generator(); 46 | let pk = ec_point.scalar_mul(&sk.get_element()); 47 | let challenge = HSha256::create_hash(&[ 48 | &pk_t_rand_commitment.bytes_compressed_to_big_int(), 49 | &generator_x, 50 | &pk.bytes_compressed_to_big_int(), 51 | ]); 52 | let challenge_fe: FE = ECScalar::from(&challenge); 53 | let challenge_mul_sk = challenge_fe.mul(&sk.get_element()); 54 | let challenge_response = sk_t_rand_commitment.sub(&challenge_mul_sk.get_element()); 55 | sk_t_rand_commitment.zeroize(); 56 | DLogProof { 57 | pk, 58 | pk_t_rand_commitment, 59 | challenge_response, 60 | } 61 | } 62 | 63 | fn verify(proof: &DLogProof) -> Result<(), ProofError> { 64 | let ec_point: GE = ECPoint::generator(); 65 | let challenge = HSha256::create_hash(&[ 66 | &proof.pk_t_rand_commitment.bytes_compressed_to_big_int(), 67 | &ec_point.bytes_compressed_to_big_int(), 68 | &proof.pk.clone().bytes_compressed_to_big_int(), 69 | ]); 70 | 71 | let sk_challenge: FE = ECScalar::from(&challenge); 72 | let pk = proof.pk.clone(); 73 | let pk_challenge = pk.scalar_mul(&sk_challenge.get_element()); 74 | 75 | let base_point: GE = ECPoint::generator(); 76 | 77 | let mut pk_verifier = base_point.scalar_mul(&proof.challenge_response.get_element()); 78 | 79 | pk_verifier = pk_verifier.add_point(&pk_challenge.get_element()); 80 | 81 | if pk_verifier == proof.pk_t_rand_commitment { 82 | Ok(()) 83 | } else { 84 | Err(ProofError) 85 | } 86 | } 87 | } 88 | 89 | #[cfg(test)] 90 | mod tests { 91 | use crate::curv::cryptographic_primitives::proofs::sigma_dlog::*; 92 | use crate::curv::elliptic::curves::secp256_k1::FE; 93 | 94 | #[cfg(target_arch = "wasm32")] 95 | use wasm_bindgen_test::*; 96 | 97 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] 98 | #[test] 99 | fn test_dlog_proof() { 100 | let witness: FE = ECScalar::new_random(); 101 | let dlog_proof = DLogProof::prove(&witness); 102 | let verified = DLogProof::verify(&dlog_proof); 103 | match verified { 104 | Ok(_t) => assert!(true), 105 | Err(_e) => assert!(false), 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/curv/cryptographic_primitives/secret_sharing/feldman_vss.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | /* 3 | This file is part of Curv library 4 | Copyright 2018 by Kzen Networks 5 | (https://github.com/KZen-networks/curv) 6 | License MIT: 7 | */ 8 | 9 | use crate::curv::arithmetic::num_bigint::BigInt; 10 | use crate::curv::elliptic::curves::secp256_k1::{FE, GE}; 11 | use crate::curv::elliptic::curves::traits::*; 12 | use crate::errors::TssError::{self, VerifyShareError}; 13 | use num_traits::One; 14 | #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] 15 | pub struct ShamirSecretSharing { 16 | pub threshold: usize, //t 17 | pub share_count: usize, //n 18 | } 19 | /// Feldman VSS, based on Paul Feldman. 1987. A practical scheme for non-interactive verifiable secret sharing. 20 | /// In Foundations of Computer Science, 1987., 28th Annual Symposium on.IEEE, 427–43 21 | /// 22 | /// implementation details: The code is using FE and GE. Each party is given an index from 1,..,n and a secret share of type FE. 23 | /// The index of the party is also the point on the polynomial where we treat this number as u32 but converting it to FE internally. 24 | #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] 25 | pub struct VerifiableSS { 26 | pub parameters: ShamirSecretSharing, 27 | pub commitments: Vec, 28 | } 29 | 30 | impl VerifiableSS { 31 | pub fn reconstruct_limit(&self) -> usize { 32 | self.parameters.threshold + 1 33 | } 34 | 35 | // generate VerifiableSS from a secret 36 | pub fn share(t: usize, n: usize, secret: &FE) -> (VerifiableSS, Vec) { 37 | assert!(t < n); 38 | let poly = VerifiableSS::sample_polynomial(t, secret); 39 | let index_vec: Vec = (1..=n).collect(); 40 | let secret_shares = VerifiableSS::evaluate_polynomial(&poly, &index_vec); 41 | 42 | let G: GE = ECPoint::generator(); 43 | let commitments = (0..poly.len()) 44 | .map(|i| G.clone() * poly[i].clone()) 45 | .collect::>(); 46 | ( 47 | VerifiableSS { 48 | parameters: ShamirSecretSharing { 49 | threshold: t, 50 | share_count: n, 51 | }, 52 | commitments, 53 | }, 54 | secret_shares, 55 | ) 56 | } 57 | 58 | // generate VerifiableSS from a secret and user defined x values (in case user wants to distribute point f(1), f(4), f(6) and not f(1),f(2),f(3)) 59 | pub fn share_at_indices( 60 | t: usize, 61 | n: usize, 62 | secret: &FE, 63 | index_vec: &[usize], 64 | ) -> (VerifiableSS, Vec) { 65 | assert_eq!(n, index_vec.len()); 66 | let poly = VerifiableSS::sample_polynomial(t, secret); 67 | let secret_shares = VerifiableSS::evaluate_polynomial(&poly, index_vec); 68 | 69 | let G: GE = ECPoint::generator(); 70 | let commitments = (0..poly.len()) 71 | .map(|i| G.clone() * &poly[i]) 72 | .collect::>(); 73 | ( 74 | VerifiableSS { 75 | parameters: ShamirSecretSharing { 76 | threshold: t, 77 | share_count: n, 78 | }, 79 | commitments, 80 | }, 81 | secret_shares, 82 | ) 83 | } 84 | 85 | // returns vector of coefficients 86 | pub fn sample_polynomial(t: usize, coef0: &FE) -> Vec { 87 | let mut coefficients = vec![coef0.clone()]; 88 | // sample the remaining coefficients randomly using secure randomness 89 | let random_coefficients: Vec = (0..t).map(|_| ECScalar::new_random()).collect(); 90 | coefficients.extend(random_coefficients); 91 | // return 92 | coefficients 93 | } 94 | 95 | pub fn evaluate_polynomial(coefficients: &[FE], index_vec: &[usize]) -> Vec { 96 | (0..index_vec.len()) 97 | .map(|point| { 98 | let point_bn = BigInt::from(index_vec[point] as u32); 99 | 100 | VerifiableSS::mod_evaluate_polynomial(coefficients, ECScalar::from(&point_bn)) 101 | }) 102 | .collect::>() 103 | } 104 | 105 | pub fn mod_evaluate_polynomial(coefficients: &[FE], point: FE) -> FE { 106 | // evaluate using Horner's rule 107 | // - to combine with fold we consider the coefficients in reverse order 108 | let mut reversed_coefficients = coefficients.iter().rev(); 109 | // manually split due to fold insisting on an initial value 110 | let head = reversed_coefficients.next().unwrap(); 111 | let tail = reversed_coefficients; 112 | tail.fold(head.clone(), |partial, coef| { 113 | let partial_times_point = partial.mul(&point.get_element()); 114 | partial_times_point.add(&coef.get_element()) 115 | }) 116 | } 117 | 118 | pub fn reconstruct(&self, indices: &[usize], shares: &[FE]) -> FE { 119 | assert_eq!(shares.len(), indices.len()); 120 | assert!(shares.len() >= self.reconstruct_limit()); 121 | // add one to indices to get points 122 | let points = indices 123 | .iter() 124 | .map(|i| { 125 | let index_bn = BigInt::from(*i as u32 + 1 as u32); 126 | ECScalar::from(&index_bn) 127 | }) 128 | .collect::>(); 129 | VerifiableSS::lagrange_interpolation_at_zero(&points, &shares) 130 | } 131 | 132 | // Performs a Lagrange interpolation in field Zp at the origin 133 | // for a polynomial defined by `points` and `values`. 134 | // `points` and `values` are expected to be two arrays of the same size, containing 135 | // respectively the evaluation points (x) and the value of the polynomial at those point (p(x)). 136 | 137 | // The result is the value of the polynomial at x=0. It is also its zero-degree coefficient. 138 | 139 | // This is obviously less general than `newton_interpolation_general` as we 140 | // only get a single value, but it is much faster. 141 | 142 | pub fn lagrange_interpolation_at_zero(points: &[FE], values: &[FE]) -> FE { 143 | let vec_len = values.len(); 144 | 145 | assert_eq!(points.len(), vec_len); 146 | // Lagrange interpolation for point 0 147 | // let mut acc = 0i64; 148 | let lag_coef = 149 | (0..vec_len) 150 | .map(|i| { 151 | let xi = &points[i]; 152 | let yi = &values[i]; 153 | let num: FE = ECScalar::from(&BigInt::one()); 154 | let denum: FE = ECScalar::from(&BigInt::one()); 155 | let num = points.iter().zip(0..vec_len).fold(num, |acc, x| { 156 | if i != x.1 { 157 | acc * x.0 158 | } else { 159 | acc 160 | } 161 | }); 162 | let denum = points.iter().zip(0..vec_len).fold(denum, |acc, x| { 163 | if i != x.1 { 164 | let xj_sub_xi = x.0.sub(&xi.get_element()); 165 | acc * xj_sub_xi 166 | } else { 167 | acc 168 | } 169 | }); 170 | let denum = denum.invert(); 171 | num * denum * yi 172 | }) 173 | .collect::>(); 174 | let mut lag_coef_iter = lag_coef.iter(); 175 | let head = lag_coef_iter.next().unwrap(); 176 | let tail = lag_coef_iter; 177 | tail.fold(head.clone(), |acc, x| acc.add(&x.get_element())) 178 | } 179 | 180 | pub fn validate_share(&self, secret_share: &FE, index: usize) -> Result<(), TssError> { 181 | let G: GE = ECPoint::generator(); 182 | let ss_point = G * secret_share; 183 | self.validate_share_public(&ss_point, index) 184 | } 185 | 186 | pub fn validate_share_public(&self, ss_point: &GE, index: usize) -> Result<(), TssError> { 187 | let comm_to_point = self.get_point_commitment(index); 188 | if *ss_point == comm_to_point { 189 | Ok(()) 190 | } else { 191 | Err(VerifyShareError) 192 | } 193 | } 194 | 195 | pub fn get_point_commitment(&self, index: usize) -> GE { 196 | let index_fe: FE = ECScalar::from(&BigInt::from(index as u32)); 197 | let mut comm_iterator = self.commitments.iter().rev(); 198 | let head = comm_iterator.next().unwrap(); 199 | let tail = comm_iterator; 200 | let comm_to_point = tail.fold(head.clone(), |acc, x: &GE| { 201 | x.clone() + acc * index_fe.clone() 202 | }); 203 | comm_to_point 204 | } 205 | 206 | //compute \lambda_{index,S}, a lagrangian coefficient that change the (t,n) scheme to (|S|,|S|) 207 | // used in http://stevengoldfeder.com/papers/GG18.pdf 208 | pub fn map_share_to_new_params(&self, index: usize, s: &[usize]) -> FE { 209 | let s_len = s.len(); 210 | // assert!(s_len > self.reconstruct_limit()); 211 | // add one to indices to get points 212 | let points: Vec = (0..self.parameters.share_count) 213 | .map(|i| { 214 | let index_bn = BigInt::from(i as u32 + 1 as u32); 215 | ECScalar::from(&index_bn) 216 | }) 217 | .collect::>(); 218 | 219 | let xi = &points[index]; 220 | let num: FE = ECScalar::from(&BigInt::one()); 221 | let denum: FE = ECScalar::from(&BigInt::one()); 222 | let num = (0..s_len).fold(num, |acc, i| { 223 | if s[i] != index { 224 | acc * points[s[i]].clone() 225 | } else { 226 | acc 227 | } 228 | }); 229 | let denum = (0..s_len).fold(denum, |acc, i| { 230 | if s[i] != index { 231 | let xj_sub_xi = points[s[i]].sub(&xi.get_element()); 232 | acc * xj_sub_xi 233 | } else { 234 | acc 235 | } 236 | }); 237 | let denum = denum.invert(); 238 | num * denum 239 | } 240 | } 241 | 242 | #[cfg(test)] 243 | mod tests { 244 | use crate::curv::cryptographic_primitives::secret_sharing::feldman_vss::*; 245 | use crate::curv::elliptic::curves::secp256_k1::{FE, GE}; 246 | 247 | #[cfg(target_arch = "wasm32")] 248 | use wasm_bindgen_test::*; 249 | 250 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] 251 | #[test] 252 | fn test_secret_sharing_3_out_of_5_at_indices() { 253 | let secret: FE = ECScalar::new_random(); 254 | let parties = [1, 2, 4, 5, 6]; 255 | let (vss_scheme, secret_shares) = VerifiableSS::share_at_indices(3, 5, &secret, &parties); 256 | 257 | let mut shares_vec = Vec::new(); 258 | shares_vec.push(secret_shares[0].clone()); 259 | shares_vec.push(secret_shares[1].clone()); 260 | shares_vec.push(secret_shares[3].clone()); 261 | shares_vec.push(secret_shares[4].clone()); 262 | //test reconstruction 263 | 264 | let secret_reconstructed = vss_scheme.reconstruct(&vec![0, 1, 4, 5], &shares_vec); 265 | assert_eq!(secret, secret_reconstructed); 266 | } 267 | 268 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] 269 | #[test] 270 | fn test_secret_sharing_3_out_of_5() { 271 | let secret: FE = ECScalar::new_random(); 272 | 273 | let (vss_scheme, secret_shares) = VerifiableSS::share(3, 5, &secret); 274 | 275 | let mut shares_vec = Vec::new(); 276 | shares_vec.push(secret_shares[0].clone()); 277 | shares_vec.push(secret_shares[1].clone()); 278 | shares_vec.push(secret_shares[2].clone()); 279 | shares_vec.push(secret_shares[4].clone()); 280 | //test reconstruction 281 | 282 | let secret_reconstructed = vss_scheme.reconstruct(&vec![0, 1, 2, 4], &shares_vec); 283 | 284 | assert_eq!(secret, secret_reconstructed); 285 | // test secret shares are verifiable 286 | let valid3 = vss_scheme.validate_share(&secret_shares[2], 3); 287 | let valid1 = vss_scheme.validate_share(&secret_shares[0], 1); 288 | assert!(valid3.is_ok()); 289 | assert!(valid1.is_ok()); 290 | 291 | let g: GE = GE::generator(); 292 | let share1_public = g * &secret_shares[0]; 293 | let valid1_public = vss_scheme.validate_share_public(&share1_public, 1); 294 | assert!(valid1_public.is_ok()); 295 | 296 | // test map (t,n) - (t',t') 297 | let s = &vec![0, 1, 2, 3, 4]; 298 | let l0 = vss_scheme.map_share_to_new_params(0, &s); 299 | let l1 = vss_scheme.map_share_to_new_params(1, &s); 300 | let l2 = vss_scheme.map_share_to_new_params(2, &s); 301 | let l3 = vss_scheme.map_share_to_new_params(3, &s); 302 | let l4 = vss_scheme.map_share_to_new_params(4, &s); 303 | let w = l0 * secret_shares[0].clone() 304 | + l1 * secret_shares[1].clone() 305 | + l2 * secret_shares[2].clone() 306 | + l3 * secret_shares[3].clone() 307 | + l4 * secret_shares[4].clone(); 308 | assert_eq!(w, secret_reconstructed); 309 | } 310 | 311 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] 312 | #[test] 313 | fn test_secret_sharing_3_out_of_7() { 314 | let secret: FE = ECScalar::new_random(); 315 | 316 | let (vss_scheme, secret_shares) = VerifiableSS::share(3, 7, &secret); 317 | 318 | let mut shares_vec = Vec::new(); 319 | shares_vec.push(secret_shares[0].clone()); 320 | shares_vec.push(secret_shares[6].clone()); 321 | shares_vec.push(secret_shares[2].clone()); 322 | shares_vec.push(secret_shares[4].clone()); 323 | 324 | //test reconstruction 325 | let secret_reconstructed = vss_scheme.reconstruct(&vec![0, 6, 2, 4], &shares_vec); 326 | assert_eq!(secret, secret_reconstructed); 327 | 328 | // test secret shares are verifiable 329 | let valid3 = vss_scheme.validate_share(&secret_shares[2], 3); 330 | let valid1 = vss_scheme.validate_share(&secret_shares[0], 1); 331 | assert!(valid3.is_ok()); 332 | assert!(valid1.is_ok()); 333 | 334 | // test map (t,n) - (t',t') 335 | let s = &vec![0, 1, 3, 4, 6]; 336 | let l0 = vss_scheme.map_share_to_new_params(0, &s); 337 | let l1 = vss_scheme.map_share_to_new_params(1, &s); 338 | let l3 = vss_scheme.map_share_to_new_params(3, &s); 339 | let l4 = vss_scheme.map_share_to_new_params(4, &s); 340 | let l6 = vss_scheme.map_share_to_new_params(6, &s); 341 | let w = l0 * secret_shares[0].clone() 342 | + l1 * secret_shares[1].clone() 343 | + l3 * secret_shares[3].clone() 344 | + l4 * secret_shares[4].clone() 345 | + l6 * secret_shares[6].clone(); 346 | assert_eq!(w, secret_reconstructed); 347 | } 348 | 349 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] 350 | #[test] 351 | fn test_secret_sharing_1_out_of_2() { 352 | let secret: FE = ECScalar::new_random(); 353 | 354 | let (vss_scheme, secret_shares) = VerifiableSS::share(1, 2, &secret); 355 | 356 | let mut shares_vec = Vec::new(); 357 | shares_vec.push(secret_shares[0].clone()); 358 | shares_vec.push(secret_shares[1].clone()); 359 | 360 | //test reconstruction 361 | let secret_reconstructed = vss_scheme.reconstruct(&vec![0, 1], &shares_vec); 362 | assert_eq!(secret, secret_reconstructed); 363 | 364 | // test secret shares are verifiable 365 | let valid2 = vss_scheme.validate_share(&secret_shares[1], 2); 366 | let valid1 = vss_scheme.validate_share(&secret_shares[0], 1); 367 | assert!(valid2.is_ok()); 368 | assert!(valid1.is_ok()); 369 | 370 | // test map (t,n) - (t',t') 371 | let s = &vec![0, 1]; 372 | let l0 = vss_scheme.map_share_to_new_params(0, &s); 373 | let l1 = vss_scheme.map_share_to_new_params(1, &s); 374 | 375 | let w = l0 * secret_shares[0].clone() + l1 * secret_shares[1].clone(); 376 | assert_eq!(w, secret_reconstructed); 377 | } 378 | 379 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] 380 | #[test] 381 | fn test_secret_sharing_1_out_of_3() { 382 | let secret: FE = ECScalar::new_random(); 383 | 384 | let (vss_scheme, secret_shares) = VerifiableSS::share(1, 3, &secret); 385 | 386 | let mut shares_vec = Vec::new(); 387 | shares_vec.push(secret_shares[0].clone()); 388 | shares_vec.push(secret_shares[1].clone()); 389 | 390 | // test commitment to point and sum of commitments 391 | let (vss_scheme2, secret_shares2) = VerifiableSS::share(1, 3, &secret); 392 | let sum = secret_shares[0].clone() + secret_shares2[0].clone(); 393 | let point_comm1 = vss_scheme.get_point_commitment(1); 394 | let point_comm2 = vss_scheme.get_point_commitment(2); 395 | let g: GE = GE::generator(); 396 | let g_sum = g.clone() * ∑ 397 | assert_eq!(g.clone() * secret_shares[0].clone(), point_comm1.clone()); 398 | assert_eq!(g.clone() * secret_shares[1].clone(), point_comm2.clone()); 399 | let point1_sum_com = 400 | vss_scheme.get_point_commitment(1) + vss_scheme2.get_point_commitment(1); 401 | assert_eq!(point1_sum_com, g_sum); 402 | 403 | //test reconstruction 404 | let secret_reconstructed = vss_scheme.reconstruct(&vec![0, 1], &shares_vec); 405 | assert_eq!(secret, secret_reconstructed); 406 | 407 | // test secret shares are verifiable 408 | let valid2 = vss_scheme.validate_share(&secret_shares[1], 2); 409 | let valid1 = vss_scheme.validate_share(&secret_shares[0], 1); 410 | assert!(valid2.is_ok()); 411 | assert!(valid1.is_ok()); 412 | 413 | // test map (t,n) - (t',t') 414 | let s = &vec![0, 2]; 415 | let l0 = vss_scheme.map_share_to_new_params(0, &s); 416 | let l2 = vss_scheme.map_share_to_new_params(2, &s); 417 | 418 | let w = l0 * secret_shares[0].clone() + l2 * secret_shares[2].clone(); 419 | assert_eq!(w, secret_reconstructed); 420 | } 421 | } 422 | -------------------------------------------------------------------------------- /src/curv/cryptographic_primitives/secret_sharing/mod.rs: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Curv library 3 | Copyright 2018 by Kzen Networks 4 | (https://github.com/KZen-networks/curv) 5 | License MIT: https://github.com/KZen-networks/curv/blob/master/LICENSE 6 | */ 7 | 8 | pub mod feldman_vss; 9 | -------------------------------------------------------------------------------- /src/curv/elliptic/curves/mod.rs: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Curv library 3 | Copyright 2018 by Kzen Networks 4 | (https://github.com/KZen-networks/curv) 5 | License MIT: 6 | */ 7 | 8 | extern crate rand; 9 | 10 | extern crate secp256k1; 11 | 12 | pub mod secp256_k1; 13 | 14 | pub mod traits; 15 | -------------------------------------------------------------------------------- /src/curv/elliptic/curves/traits.rs: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Curv library 3 | Copyright 2018 by Kzen Networks 4 | (https://github.com/KZen-networks/curv) 5 | License MIT: 6 | */ 7 | 8 | use crate::curv::arithmetic::num_bigint::BigInt; 9 | use crate::errors::TssError; 10 | use generic_array::ArrayLength; 11 | use typenum::Unsigned; 12 | 13 | pub trait ECScalar { 14 | type ScalarLength: ArrayLength + Unsigned; 15 | fn new_random() -> Self; 16 | fn zero() -> Self; 17 | fn get_element(&self) -> SK; 18 | fn set_element(&mut self, element: SK); 19 | fn from(n: &BigInt) -> Self; 20 | fn to_big_int(&self) -> BigInt; 21 | fn q() -> BigInt; 22 | fn add(&self, other: &SK) -> Self; 23 | fn mul(&self, other: &SK) -> Self; 24 | fn sub(&self, other: &SK) -> Self; 25 | fn invert(&self) -> Self; 26 | fn group_order() -> &'static BigInt; 27 | } 28 | 29 | // TODO: add a fn is_point 30 | pub trait ECPoint 31 | where 32 | Self: Sized, 33 | { 34 | /// The byte length of point serialized in compressed form 35 | type CompressedPointLength: ArrayLength + Unsigned; 36 | /// The byte length of point serialized in uncompressed form 37 | type UncompressedPointLength: ArrayLength + Unsigned; 38 | fn generator() -> Self; 39 | fn get_element(&self) -> PK; 40 | fn x_coor(&self) -> Option; 41 | fn y_coor(&self) -> Option; 42 | fn bytes_compressed_to_big_int(&self) -> BigInt; 43 | fn from_bytes(bytes: &[u8]) -> Result; 44 | fn pk_to_key_slice(&self) -> Vec; 45 | fn scalar_mul(&self, fe: &SK) -> Self; 46 | fn add_point(&self, other: &PK) -> Self; 47 | fn sub_point(&self, other: &PK) -> Self; 48 | fn from_coor(x: &BigInt, y: &BigInt) -> Self; 49 | fn to_bytes(&self, compressed: bool) -> Vec; 50 | } 51 | -------------------------------------------------------------------------------- /src/curv/elliptic/mod.rs: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Curv library 3 | Copyright 2018 by Kzen Networks 4 | (https://github.com/KZen-networks/curv) 5 | License MIT: 6 | */ 7 | 8 | pub mod curves; 9 | -------------------------------------------------------------------------------- /src/curv/mod.rs: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Curv library 3 | Copyright 2018 by Kzen Networks 4 | (https://github.com/KZen-networks/curv) 5 | License MIT: 6 | */ 7 | 8 | pub mod arithmetic; 9 | pub mod cryptographic_primitives; 10 | pub mod elliptic; 11 | -------------------------------------------------------------------------------- /src/errors.rs: -------------------------------------------------------------------------------- 1 | #[cfg(target_arch = "wasm32")] 2 | use wasm_bindgen::prelude::*; 3 | 4 | use thiserror::Error; 5 | 6 | pub type Result = std::result::Result; 7 | 8 | #[derive(Error, Debug)] 9 | pub enum TssError { 10 | #[error("Context create error")] 11 | ContextError, 12 | #[error("Unknown error: {msg}, {line}")] 13 | UnknownError { msg: String, line: u32 }, 14 | #[error("json serialization error")] 15 | SerdeError(#[from] serde_json::Error), 16 | #[error("reqwest builder error")] 17 | RequestError(#[from] reqwest::Error), 18 | #[error("secp256k1 error")] 19 | Secp256k1Error(#[from] secp256k1::Error), 20 | #[error("rand error")] 21 | RandError(#[from] rand::Error), 22 | 23 | #[error("ParseIntError error")] 24 | ParseError(#[from] std::num::ParseIntError), 25 | #[error("InvalidKey")] 26 | InvalidKey, 27 | #[error("InvalidSS")] 28 | InvalidSS, 29 | #[error("InvalidCom")] 30 | InvalidCom, 31 | #[error("InvalidSig")] 32 | InvalidSig, 33 | #[error("InvalidPublicKey")] 34 | InvalidPublicKey, 35 | #[error("VerifyShareError")] 36 | VerifyShareError, 37 | } 38 | 39 | #[cfg(target_arch = "wasm32")] 40 | impl Into for TssError { 41 | fn into(self) -> JsValue { 42 | JsValue::from_str(&format!("{:?}", self)) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/gg_2018/mod.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Multi-party ECDSA 3 | 4 | Copyright 2018 by Kzen Networks 5 | 6 | This file is part of Multi-party ECDSA library 7 | (https://github.com/KZen-networks/multi-party-ecdsa) 8 | 9 | Multi-party ECDSA is free software: you can redistribute 10 | it and/or modify it under the terms of the GNU General Public 11 | License as published by the Free Software Foundation, either 12 | version 3 of the License, or (at your option) any later version. 13 | 14 | @license GPL-3.0+ 15 | */ 16 | 17 | pub mod mta; 18 | pub mod party_i; 19 | pub mod range_proofs; 20 | -------------------------------------------------------------------------------- /src/gg_2018/mta.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Multi-party ECDSA 3 | 4 | Copyright 2018 by Kzen Networks 5 | 6 | This file is part of Multi-party ECDSA library 7 | (https://github.com/KZen-networks/multi-party-ecdsa) 8 | 9 | Multi-party ECDSA is free software: you can redistribute 10 | it and/or modify it under the terms of the GNU General Public 11 | License as published by the Free Software Foundation, either 12 | version 3 of the License, or (at your option) any later version. 13 | 14 | @license GPL-3.0+ 15 | */ 16 | use crate::curv::arithmetic::num_bigint::BigInt; 17 | use crate::curv::arithmetic::traits::Samplable; 18 | use crate::curv::cryptographic_primitives::proofs::sigma_dlog::{DLogProof, ProveDLog}; 19 | use crate::curv::elliptic::curves::secp256_k1::{FE, GE}; 20 | use crate::curv::elliptic::curves::traits::*; 21 | use crate::paillier::{Add, Decrypt, Mul}; 22 | use crate::paillier::{DecryptionKey, EncryptionKey, Paillier, RawCiphertext, RawPlaintext}; 23 | 24 | use crate::errors::TssError::{self, InvalidKey}; 25 | use crate::gg_2018::party_i::PartyPrivate; 26 | 27 | use crate::gg_2018::range_proofs::AliceProof; 28 | use crate::paillier::zkproofs::DLogStatement; 29 | use crate::paillier::Randomness; 30 | 31 | use crate::curv::elliptic::curves::secp256_k1::Secp256k1Scalar; 32 | use crate::paillier::traits::EncryptWithChosenRandomness; 33 | 34 | #[derive(Clone, Debug, Serialize, Deserialize)] 35 | pub struct MessageA { 36 | pub c: BigInt, // paillier encryption 37 | pub range_proofs: Vec, // proofs (using other parties' h1,h2,N_tilde) that the plaintext is small 38 | } 39 | 40 | #[derive(Clone, Debug, Serialize, Deserialize)] 41 | pub struct MessageB { 42 | pub c: BigInt, // paillier encryption 43 | pub b_proof: DLogProof, 44 | pub beta_tag_proof: DLogProof, 45 | } 46 | 47 | impl MessageA { 48 | pub fn a( 49 | a: &Secp256k1Scalar, 50 | alice_ek: &EncryptionKey, 51 | dlog_statements: &[DLogStatement], 52 | ) -> (Self, BigInt) { 53 | let randomness = BigInt::sample_below(&alice_ek.n); 54 | let m_a = MessageA::a_with_predefined_randomness(a, alice_ek, &randomness, dlog_statements); 55 | (m_a, randomness) 56 | } 57 | 58 | pub fn a_with_predefined_randomness( 59 | a: &Secp256k1Scalar, 60 | alice_ek: &EncryptionKey, 61 | randomness: &BigInt, 62 | dlog_statements: &[DLogStatement], 63 | ) -> Self { 64 | let c_a = Paillier::encrypt_with_chosen_randomness( 65 | alice_ek, 66 | RawPlaintext::from(a.to_big_int()), 67 | &Randomness::from(randomness.clone()), 68 | ) 69 | .0 70 | .clone() 71 | .into_owned(); 72 | let alice_range_proofs = dlog_statements 73 | .iter() 74 | .map(|dlog_statement| { 75 | AliceProof::generate(&a.to_big_int(), &c_a, alice_ek, dlog_statement, randomness) 76 | }) 77 | .collect::>(); 78 | 79 | Self { 80 | c: c_a, 81 | range_proofs: alice_range_proofs, 82 | } 83 | } 84 | } 85 | 86 | impl MessageB { 87 | pub fn b( 88 | b: &Secp256k1Scalar, 89 | alice_ek: &EncryptionKey, 90 | m_a: MessageA, 91 | dlog_statements: &[DLogStatement], 92 | ) -> Result<(Self, Secp256k1Scalar, BigInt, BigInt), TssError> { 93 | let beta_tag = BigInt::sample_below(&alice_ek.n); 94 | let randomness = BigInt::sample_below(&alice_ek.n); 95 | let (m_b, beta) = MessageB::b_with_predefined_randomness( 96 | b, 97 | alice_ek, 98 | m_a, 99 | &randomness, 100 | &beta_tag, 101 | dlog_statements, 102 | )?; 103 | 104 | Ok((m_b, beta, randomness, beta_tag)) 105 | } 106 | 107 | pub fn b_with_predefined_randomness( 108 | b: &Secp256k1Scalar, 109 | alice_ek: &EncryptionKey, 110 | m_a: MessageA, 111 | randomness: &BigInt, 112 | beta_tag: &BigInt, 113 | dlog_statements: &[DLogStatement], 114 | ) -> Result<(Self, Secp256k1Scalar), TssError> { 115 | if m_a.range_proofs.len() != dlog_statements.len() { 116 | return Err(InvalidKey); 117 | } 118 | // verify proofs 119 | if !m_a 120 | .range_proofs 121 | .iter() 122 | .zip(dlog_statements) 123 | .map(|(proof, dlog_statement)| proof.verify(&m_a.c, alice_ek, dlog_statement)) 124 | .all(|x| x) 125 | { 126 | return Err(InvalidKey); 127 | }; 128 | let beta_tag_fe: Secp256k1Scalar = ECScalar::from(beta_tag); 129 | let c_beta_tag = Paillier::encrypt_with_chosen_randomness( 130 | alice_ek, 131 | RawPlaintext::from(beta_tag), 132 | &Randomness::from(randomness.clone()), 133 | ); 134 | 135 | let b_bn = b.to_big_int(); 136 | let b_c_a = Paillier::mul( 137 | alice_ek, 138 | RawCiphertext::from(m_a.c), 139 | RawPlaintext::from(b_bn), 140 | ); 141 | let c_b = Paillier::add(alice_ek, b_c_a, c_beta_tag); 142 | let beta = FE::zero().sub(&beta_tag_fe.get_element()); 143 | let dlog_proof_b = DLogProof::prove(b); 144 | let dlog_proof_beta_tag = DLogProof::prove(&beta_tag_fe); 145 | 146 | Ok(( 147 | Self { 148 | c: c_b.0.clone().into_owned(), 149 | b_proof: dlog_proof_b, 150 | beta_tag_proof: dlog_proof_beta_tag, 151 | }, 152 | beta, 153 | )) 154 | } 155 | 156 | pub fn verify_proofs_get_alpha( 157 | &self, 158 | dk: &DecryptionKey, 159 | a: &Secp256k1Scalar, 160 | ) -> Result<(Secp256k1Scalar, BigInt), TssError> { 161 | let alice_share = Paillier::decrypt(dk, &RawCiphertext::from(self.c.clone())); 162 | let g: GE = ECPoint::generator(); 163 | let alpha: FE = ECScalar::from(&alice_share.0); 164 | let g_alpha = g * α 165 | let ba_btag = &self.b_proof.pk * a + &self.beta_tag_proof.pk; 166 | match DLogProof::verify(&self.b_proof).is_ok() 167 | && DLogProof::verify(&self.beta_tag_proof).is_ok() 168 | && ba_btag == g_alpha 169 | { 170 | true => Ok((alpha, alice_share.0.into_owned())), 171 | false => Err(InvalidKey), 172 | } 173 | } 174 | 175 | // another version, supportion PartyPrivate therefore binding mta to gg18. 176 | // with the regular version mta can be used in general 177 | pub fn verify_proofs_get_alpha_gg18( 178 | &self, 179 | private: &PartyPrivate, 180 | a: &FE, 181 | ) -> Result { 182 | let alice_share = private.decrypt(self.c.clone()); 183 | let g: GE = ECPoint::generator(); 184 | let alpha: FE = ECScalar::from(&alice_share.0); 185 | let g_alpha = g * α 186 | let ba_btag = &self.b_proof.pk * a + &self.beta_tag_proof.pk; 187 | 188 | match DLogProof::verify(&self.b_proof).is_ok() 189 | && DLogProof::verify(&self.beta_tag_proof).is_ok() 190 | && ba_btag.get_element() == g_alpha.get_element() 191 | { 192 | true => Ok(alpha), 193 | false => Err(InvalidKey), 194 | } 195 | } 196 | 197 | pub fn verify_b_against_public(public_gb: &GE, mta_gb: &GE) -> bool { 198 | public_gb.get_element() == mta_gb.get_element() 199 | } 200 | } 201 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate serde_derive; 3 | extern crate serde; 4 | extern crate serde_json; 5 | 6 | extern crate num_bigint; 7 | extern crate num_integer; 8 | extern crate num_traits; 9 | extern crate rand; 10 | extern crate zeroize; 11 | 12 | extern crate aes_gcm; 13 | extern crate cryptoxide; 14 | extern crate reqwest; 15 | extern crate sha2; 16 | 17 | pub mod curv; 18 | 19 | pub mod gg_2018; 20 | pub mod paillier; 21 | 22 | #[macro_use] 23 | pub mod common; 24 | 25 | pub mod api; 26 | pub mod errors; 27 | 28 | #[cfg(target_arch = "wasm32")] 29 | extern crate wasm_bindgen; 30 | 31 | #[cfg(all(test, target_arch = "wasm32"))] 32 | extern crate wasm_bindgen_test; 33 | 34 | #[cfg(target_arch = "wasm32")] 35 | use wasm_bindgen::prelude::*; 36 | 37 | #[cfg(target_arch = "wasm32")] 38 | #[wasm_bindgen] 39 | extern "C" { 40 | // Use `js_namespace` here to bind `console.log(..)` instead of just 41 | // `log(..)` 42 | #[wasm_bindgen(js_namespace = console)] 43 | fn log(s: &str); 44 | 45 | // The `console.log` is quite polymorphic, so we can bind it with multiple 46 | // signatures. Note that we need to use `js_name` to ensure we always call 47 | // `log` in JS. 48 | #[wasm_bindgen(js_namespace = console, js_name = log)] 49 | fn log_u32(a: u32); 50 | 51 | // Multiple arguments too! 52 | #[wasm_bindgen(js_namespace = console, js_name = log)] 53 | fn log_many(a: &str, b: &str); 54 | } 55 | 56 | #[cfg(target_arch = "wasm32")] 57 | #[macro_export] 58 | macro_rules! console_log { 59 | // Note that this is using the `log` function imported above during 60 | // `bare_bones` 61 | ($($t:tt)*) => (log(&format_args!($($t)*).to_string())) 62 | } 63 | -------------------------------------------------------------------------------- /src/paillier/core.rs: -------------------------------------------------------------------------------- 1 | //! Core Paillier encryption scheme supporting ciphertext addition and plaintext multiplication. 2 | 3 | use std::borrow::{Borrow, Cow}; 4 | 5 | use crate::curv::arithmetic::num_bigint::BigInt; 6 | use crate::curv::arithmetic::traits::*; 7 | use crate::paillier::traits::*; 8 | use crate::paillier::{ 9 | DecryptionKey, EncryptionKey, Keypair, MinimalDecryptionKey, MinimalEncryptionKey, Paillier, 10 | RawCiphertext, RawPlaintext, 11 | }; 12 | use num_integer::Integer; 13 | use num_traits::One; 14 | use serde::*; 15 | 16 | impl Keypair { 17 | /// Generate default encryption and decryption keys. 18 | pub fn keys(&self) -> (EncryptionKey, DecryptionKey) { 19 | (EncryptionKey::from(self), DecryptionKey::from(self)) 20 | } 21 | } 22 | 23 | impl<'p, 'q> From<(&'p BigInt, &'q BigInt)> for Keypair { 24 | fn from((p, q): (&'p BigInt, &'q BigInt)) -> Keypair { 25 | Keypair { 26 | p: p.clone(), 27 | q: q.clone(), 28 | } 29 | } 30 | } 31 | 32 | impl<'kp> From<&'kp Keypair> for MinimalEncryptionKey { 33 | fn from(keypair: &'kp Keypair) -> Self { 34 | MinimalEncryptionKey { 35 | n: &keypair.p * &keypair.q, 36 | } 37 | } 38 | } 39 | 40 | impl<'e> From<&'e EncryptionKey> for MinimalEncryptionKey { 41 | fn from(ek: &'e EncryptionKey) -> Self { 42 | MinimalEncryptionKey { n: ek.n.clone() } 43 | } 44 | } 45 | 46 | impl<'e> From for EncryptionKey { 47 | fn from(ek: MinimalEncryptionKey) -> Self { 48 | let nn = &ek.n * &ek.n; 49 | let n = ek.n; 50 | EncryptionKey { n, nn } 51 | } 52 | } 53 | 54 | impl<'kp> From<&'kp Keypair> for EncryptionKey { 55 | fn from(keypair: &'kp Keypair) -> Self { 56 | let minimal = MinimalEncryptionKey::from(keypair); 57 | EncryptionKey::from(minimal) 58 | } 59 | } 60 | 61 | // TODO[Morten] where is this needed? 62 | impl<'n> From<&'n BigInt> for EncryptionKey { 63 | fn from(n: &'n BigInt) -> Self { 64 | let minimal = MinimalEncryptionKey { n: n.clone() }; 65 | EncryptionKey::from(minimal) 66 | } 67 | } 68 | 69 | impl Serialize for EncryptionKey { 70 | fn serialize(&self, serializer: S) -> Result { 71 | let minimal = MinimalEncryptionKey::from(self); 72 | minimal.serialize(serializer) 73 | } 74 | } 75 | 76 | impl<'de> Deserialize<'de> for EncryptionKey { 77 | fn deserialize>(deserializer: D) -> Result { 78 | let minimal = MinimalEncryptionKey::deserialize(deserializer)?; 79 | Ok(EncryptionKey::from(minimal)) 80 | } 81 | } 82 | 83 | impl<'kp> From<&'kp Keypair> for MinimalDecryptionKey { 84 | fn from(keypair: &'kp Keypair) -> Self { 85 | MinimalDecryptionKey { 86 | p: keypair.p.clone(), 87 | q: keypair.q.clone(), 88 | } 89 | } 90 | } 91 | 92 | impl<'e> From<&'e DecryptionKey> for MinimalDecryptionKey { 93 | fn from(dk: &'e DecryptionKey) -> Self { 94 | MinimalDecryptionKey { 95 | p: dk.p.clone(), 96 | q: dk.q.clone(), 97 | } 98 | } 99 | } 100 | 101 | impl<'e> From for DecryptionKey { 102 | fn from(dk: MinimalDecryptionKey) -> Self { 103 | let p = dk.p; 104 | let q = dk.q; 105 | 106 | DecryptionKey { p, q } 107 | } 108 | } 109 | 110 | impl<'kp> From<&'kp Keypair> for DecryptionKey { 111 | fn from(keypair: &'kp Keypair) -> DecryptionKey { 112 | let minimal = MinimalDecryptionKey::from(keypair); 113 | DecryptionKey::from(minimal) 114 | } 115 | } 116 | 117 | impl Serialize for DecryptionKey { 118 | fn serialize(&self, serializer: S) -> Result { 119 | let minimal = MinimalDecryptionKey::from(self); 120 | minimal.serialize(serializer) 121 | } 122 | } 123 | 124 | impl<'de> Deserialize<'de> for DecryptionKey { 125 | fn deserialize>(deserializer: D) -> Result { 126 | let minimal = MinimalDecryptionKey::deserialize(deserializer)?; 127 | Ok(DecryptionKey::from(minimal)) 128 | } 129 | } 130 | 131 | #[derive(Debug, PartialEq)] 132 | pub struct Randomness(pub BigInt); 133 | 134 | #[derive(Debug, PartialEq)] 135 | pub struct PrecomputedRandomness(BigInt); 136 | 137 | impl Randomness { 138 | pub fn sample(ek: &EncryptionKey) -> Randomness { 139 | Randomness(BigInt::sample_below(&ek.n)) 140 | } 141 | } 142 | 143 | impl From for Randomness { 144 | fn from(x: BigInt) -> Randomness { 145 | Randomness(x) 146 | } 147 | } 148 | 149 | impl<'b> From<&'b BigInt> for Randomness { 150 | fn from(x: &'b BigInt) -> Randomness { 151 | Randomness(x.clone()) 152 | } 153 | } 154 | 155 | impl<'b> From for RawPlaintext<'b> { 156 | fn from(x: BigInt) -> Self { 157 | RawPlaintext(Cow::Owned(x)) 158 | } 159 | } 160 | 161 | impl<'b> From<&'b BigInt> for RawPlaintext<'b> { 162 | fn from(x: &'b BigInt) -> Self { 163 | RawPlaintext(Cow::Borrowed(x)) 164 | } 165 | } 166 | 167 | impl<'b> From> for BigInt { 168 | fn from(x: RawPlaintext<'b>) -> Self { 169 | x.0.into_owned() 170 | } 171 | } 172 | 173 | impl<'b> From for RawCiphertext<'b> { 174 | fn from(x: BigInt) -> Self { 175 | RawCiphertext(Cow::Owned(x)) 176 | } 177 | } 178 | 179 | impl<'b> From<&'b BigInt> for RawCiphertext<'b> { 180 | fn from(x: &'b BigInt) -> Self { 181 | RawCiphertext(Cow::Borrowed(x)) 182 | } 183 | } 184 | 185 | impl<'b> From> for BigInt { 186 | fn from(x: RawCiphertext<'b>) -> Self { 187 | x.0.into_owned() 188 | } 189 | } 190 | 191 | impl<'m, 'd> Encrypt, RawCiphertext<'d>> for Paillier { 192 | fn encrypt(ek: &EncryptionKey, m: RawPlaintext<'m>) -> RawCiphertext<'d> { 193 | let r = Randomness::sample(&ek); 194 | let rn = BigInt::mod_pow(&r.0, &ek.n, &ek.nn); 195 | let gm: BigInt = (m.0.borrow() as &BigInt * &ek.n + BigInt::from(1 as u16)) % &ek.nn; 196 | let c = (gm * rn) % &ek.nn; 197 | RawCiphertext(Cow::Owned(c)) 198 | } 199 | } 200 | 201 | impl<'m, 'r, 'd> 202 | EncryptWithChosenRandomness, &'r Randomness, RawCiphertext<'d>> 203 | for Paillier 204 | { 205 | fn encrypt_with_chosen_randomness( 206 | ek: &EncryptionKey, 207 | m: RawPlaintext<'m>, 208 | r: &'r Randomness, 209 | ) -> RawCiphertext<'d> { 210 | let rn = BigInt::mod_pow(&r.0, &ek.n, &ek.nn); 211 | let gm: BigInt = (m.0.borrow() as &BigInt * &ek.n + BigInt::from(1 as u16)) % &ek.nn; 212 | let c = (gm * rn) % &ek.nn; 213 | RawCiphertext(Cow::Owned(c)) 214 | } 215 | } 216 | 217 | impl<'m, 'r, 'd> 218 | EncryptWithChosenRandomness< 219 | EncryptionKey, 220 | RawPlaintext<'m>, 221 | &'r PrecomputedRandomness, 222 | RawCiphertext<'d>, 223 | > for Paillier 224 | { 225 | fn encrypt_with_chosen_randomness( 226 | ek: &EncryptionKey, 227 | m: RawPlaintext<'m>, 228 | rn: &'r PrecomputedRandomness, 229 | ) -> RawCiphertext<'d> { 230 | let gm: BigInt = (m.0.borrow() as &BigInt * &ek.n + BigInt::from(1 as u16)) % &ek.nn; 231 | let c = (gm * &rn.0) % &ek.nn; 232 | RawCiphertext(Cow::Owned(c)) 233 | } 234 | } 235 | 236 | impl<'m, 'd> Encrypt, RawCiphertext<'d>> for Paillier { 237 | fn encrypt(dk: &DecryptionKey, m: RawPlaintext<'m>) -> RawCiphertext<'d> { 238 | let dk_pp = &dk.p * &dk.p; 239 | let dk_qq = &dk.q * &dk.q; 240 | let dk_n = &dk.q * &dk.p; 241 | let dk_ppinv = BigInt::mod_inv(&dk_pp, &dk_qq); 242 | let (mp, mq) = crt_decompose(m.0.borrow(), &dk_pp, &dk_qq); 243 | 244 | let rp = BigInt::sample_below(&dk.p); 245 | let rnp = BigInt::mod_pow(&rp, &dk_n, &dk_pp); 246 | let gmp = (BigInt::from(1 as u16) + mp * &dk_n) % &dk_pp; // TODO[Morten] maybe there's more to get here 247 | let cp = (gmp * rnp) % &dk_pp; 248 | 249 | let rq = BigInt::sample_below(&dk.q); 250 | let rnq = BigInt::mod_pow(&rq, &dk_n, &dk_qq); 251 | let gmq = (BigInt::from(1 as u16) + mq * &dk_n) % &dk_qq; // TODO[Morten] maybe there's more to get here 252 | let cq = (gmq * rnq) % &dk_qq; 253 | 254 | let c = crt_recombine(cp, cq, &dk_pp, &dk_qq, &dk_ppinv); 255 | RawCiphertext(Cow::Owned(c)) 256 | } 257 | } 258 | 259 | impl<'m, 'r, 'd> 260 | EncryptWithChosenRandomness, &'r Randomness, RawCiphertext<'d>> 261 | for Paillier 262 | { 263 | fn encrypt_with_chosen_randomness( 264 | dk: &DecryptionKey, 265 | m: RawPlaintext<'m>, 266 | r: &'r Randomness, 267 | ) -> RawCiphertext<'d> { 268 | let dk_pp = &dk.p * &dk.p; 269 | let dk_qq = &dk.q * &dk.q; 270 | let dk_n = &dk.q * &dk.p; 271 | let dk_ppinv = BigInt::mod_inv(&dk_pp, &dk_qq); 272 | let (mp, mq) = crt_decompose(m.0.borrow(), &dk_pp, &dk_qq); 273 | let (rp, rq) = crt_decompose(&r.0, &dk_pp, &dk_qq); 274 | 275 | let rnp = BigInt::mod_pow(&rp, &dk_n, &dk_pp); 276 | let gmp = (BigInt::from(1 as u16) + mp * &dk_n) % &dk_pp; // TODO[Morten] maybe there's more to get here 277 | let cp = (gmp * rnp) % &dk_pp; 278 | 279 | let rnq = BigInt::mod_pow(&rq, &dk_n, &dk_qq); 280 | let gmq = (BigInt::from(1 as u16) + mq * &dk_n) % &dk_qq; // TODO[Morten] maybe there's more to get here 281 | let cq = (gmq * rnq) % &dk_qq; 282 | 283 | let c = crt_recombine(cp, cq, &dk_pp, &dk_qq, &dk_ppinv); 284 | RawCiphertext(Cow::Owned(c)) 285 | } 286 | } 287 | 288 | impl<'m, 'r, 'd> 289 | EncryptWithChosenRandomness< 290 | DecryptionKey, 291 | RawPlaintext<'m>, 292 | &'r PrecomputedRandomness, 293 | RawCiphertext<'d>, 294 | > for Paillier 295 | { 296 | fn encrypt_with_chosen_randomness( 297 | dk: &DecryptionKey, 298 | m: RawPlaintext<'m>, 299 | rn: &'r PrecomputedRandomness, 300 | ) -> RawCiphertext<'d> { 301 | let dk_n = &dk.q * &dk.p; 302 | let dk_nn = &dk_n * &dk_n; 303 | let gm = (BigInt::from(1 as u16) + m.0.borrow() as &BigInt * &dk_n) % &dk_nn; 304 | let c = (gm * &rn.0) % &dk_nn; 305 | RawCiphertext(Cow::Owned(c)) 306 | } 307 | } 308 | 309 | impl<'ek, 'r> PrecomputeRandomness<&'ek EncryptionKey, &'r BigInt, PrecomputedRandomness> 310 | for Paillier 311 | { 312 | fn precompute(ek: &'ek EncryptionKey, r: &'r BigInt) -> PrecomputedRandomness { 313 | let rn = BigInt::mod_pow(r, &ek.n, &ek.nn); 314 | PrecomputedRandomness(rn) 315 | } 316 | } 317 | 318 | impl<'c, 'd> Rerandomize, RawCiphertext<'d>> for Paillier { 319 | fn rerandomize(ek: &EncryptionKey, c: RawCiphertext<'c>) -> RawCiphertext<'d> { 320 | let r = BigInt::sample_below(&ek.n); 321 | let rn = BigInt::mod_pow(&r, &ek.n, &ek.nn); 322 | let d = (c.0.borrow() as &BigInt * rn) % &ek.nn; 323 | RawCiphertext(Cow::Owned(d)) 324 | } 325 | } 326 | 327 | /// TODO 328 | /// 329 | /// Efficient decryption using CRT based on [Paillier99, section 7](http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.112.4035&rep=rep1&type=pdf) 330 | impl<'c, 'm> Decrypt, RawPlaintext<'m>> for Paillier { 331 | fn decrypt(dk: &DecryptionKey, c: RawCiphertext<'c>) -> RawPlaintext<'m> { 332 | Self::decrypt(dk, &c) 333 | } 334 | } 335 | 336 | /// TODO 337 | /// 338 | /// Efficient decryption using CRT based on [Paillier99, section 7](http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.112.4035&rep=rep1&type=pdf) 339 | impl<'c, 'm> Decrypt, RawPlaintext<'m>> for Paillier { 340 | fn decrypt(dk: &DecryptionKey, c: &'c RawCiphertext<'c>) -> RawPlaintext<'m> { 341 | let dk_qq = &dk.q * &dk.q; 342 | let dk_pp = &dk.p * &dk.p; 343 | let dk_n = &dk.p * &dk.q; 344 | let dk_pinv = BigInt::mod_inv(&dk.p, &dk.q); 345 | let dk_qminusone = &dk.q - BigInt::one(); 346 | let dk_pminusone = &dk.p - BigInt::one(); 347 | let dk_hp = h(&dk.p, &dk_pp, &dk_n); 348 | let dk_hq = h(&dk.q, &dk_qq, &dk_n); 349 | let (cp, cq) = crt_decompose(c.0.borrow(), &dk_pp, &dk_qq); 350 | // decrypt in parallel with respectively p and q 351 | 352 | // process using p 353 | let dp = BigInt::mod_pow(&cp, &dk_pminusone, &dk_pp); 354 | let lp = l(&dp, &dk.p); 355 | let mp = (&lp * &dk_hp) % &dk.p; 356 | 357 | // process using q 358 | let dq = BigInt::mod_pow(&cq, &dk_qminusone, &dk_qq); 359 | let lq = l(&dq, &dk.q); 360 | let mq = (&lq * &dk_hq) % &dk.q; 361 | 362 | // perform CRT 363 | let m = crt_recombine(mp, mq, &dk.p, &dk.q, &dk_pinv); 364 | RawPlaintext(Cow::Owned(m)) 365 | } 366 | } 367 | 368 | impl<'c, 'm> Open, RawPlaintext<'m>, Randomness> for Paillier { 369 | fn open(dk: &DecryptionKey, c: RawCiphertext<'c>) -> (RawPlaintext<'m>, Randomness) { 370 | Self::open(dk, &c) 371 | } 372 | } 373 | 374 | impl<'c, 'm> Open, RawPlaintext<'m>, Randomness> for Paillier { 375 | fn open(dk: &DecryptionKey, c: &'c RawCiphertext<'c>) -> (RawPlaintext<'m>, Randomness) { 376 | let dk_n = &dk.p * &dk.q; 377 | let dk_nn = &dk_n * &dk_n; 378 | 379 | let m = Self::decrypt(dk, c); 380 | let gminv = (dk_nn.clone() + BigInt::one() - (m.0.borrow() as &BigInt) * &dk_n) % &dk_nn; 381 | let rn = (c.0.borrow() as &BigInt * gminv) % &dk_nn; 382 | let r = extract_nroot(dk, &rn); 383 | (m, Randomness(r)) 384 | } 385 | } 386 | 387 | impl<'c1, 'c2, 'd> Add, RawCiphertext<'c2>, RawCiphertext<'d>> 388 | for Paillier 389 | { 390 | fn add( 391 | ek: &EncryptionKey, 392 | c1: RawCiphertext<'c1>, 393 | c2: RawCiphertext<'c2>, 394 | ) -> RawCiphertext<'d> { 395 | let d = (c1.0.borrow() as &BigInt * c2.0.borrow() as &BigInt) % &ek.nn; 396 | RawCiphertext(Cow::Owned(d)) 397 | } 398 | } 399 | 400 | impl<'c, 'm, 'd> Add, RawPlaintext<'m>, RawCiphertext<'d>> 401 | for Paillier 402 | { 403 | fn add(ek: &EncryptionKey, c: RawCiphertext<'c>, m: RawPlaintext<'m>) -> RawCiphertext<'d> { 404 | let c1 = c.0.borrow() as &BigInt; 405 | let c2 = (m.0.borrow() as &BigInt * &ek.n + BigInt::from(1 as u16)) % &ek.nn; 406 | let d = (c1 * c2) % &ek.nn; 407 | RawCiphertext(Cow::Owned(d)) 408 | } 409 | } 410 | 411 | impl<'c, 'm, 'd> Add, RawCiphertext<'c>, RawCiphertext<'d>> 412 | for Paillier 413 | { 414 | fn add(ek: &EncryptionKey, m: RawPlaintext<'m>, c: RawCiphertext<'c>) -> RawCiphertext<'d> { 415 | let c1 = (m.0.borrow() as &BigInt * &ek.n + BigInt::from(1 as u16)) % &ek.nn; 416 | let c2 = c.0.borrow() as &BigInt; 417 | let d = (c1 * c2) % &ek.nn; 418 | RawCiphertext(Cow::Owned(d)) 419 | } 420 | } 421 | 422 | impl<'c, 'm, 'd> Mul, RawPlaintext<'m>, RawCiphertext<'d>> 423 | for Paillier 424 | { 425 | fn mul(ek: &EncryptionKey, c: RawCiphertext<'c>, m: RawPlaintext<'m>) -> RawCiphertext<'d> { 426 | RawCiphertext(Cow::Owned(BigInt::mod_pow( 427 | c.0.borrow(), 428 | m.0.borrow(), 429 | &ek.nn, 430 | ))) 431 | } 432 | } 433 | 434 | impl<'c, 'm, 'd> Mul, RawCiphertext<'c>, RawCiphertext<'d>> 435 | for Paillier 436 | { 437 | fn mul(ek: &EncryptionKey, m: RawPlaintext<'m>, c: RawCiphertext<'c>) -> RawCiphertext<'d> { 438 | RawCiphertext(Cow::Owned(BigInt::mod_pow( 439 | c.0.borrow(), 440 | m.0.borrow(), 441 | &ek.nn, 442 | ))) 443 | } 444 | } 445 | 446 | fn h(p: &BigInt, pp: &BigInt, n: &BigInt) -> BigInt { 447 | // here we assume: 448 | // - p \in {P, Q} 449 | // - n = P * Q 450 | // - g = 1 + n 451 | 452 | // compute g^{p-1} mod p^2 453 | let gp = (pp + BigInt::from(1 as u16) - n.mod_floor(&pp)) % pp; 454 | // compute L_p(.) 455 | let lp = l(&gp, p); 456 | // compute L_p(.)^{-1} 457 | let hp = BigInt::mod_inv(&lp, p); 458 | hp 459 | } 460 | 461 | fn l(u: &BigInt, n: &BigInt) -> BigInt { 462 | (u - BigInt::from(1 as u16)) / n 463 | } 464 | 465 | fn crt_decompose(x: X, m1: M1, m2: M2) -> (BigInt, BigInt) 466 | where 467 | X: Borrow, 468 | M1: Borrow, 469 | M2: Borrow, 470 | { 471 | (x.borrow() % m1.borrow(), x.borrow() % m2.borrow()) 472 | } 473 | 474 | fn crt_recombine(x1: X1, x2: X2, m1: M1, m2: M2, m1inv: I) -> BigInt 475 | where 476 | X1: Borrow, 477 | X2: Borrow, 478 | M1: Borrow, 479 | M2: Borrow, 480 | I: Borrow, 481 | { 482 | let diff = BigInt::mod_sub(x2.borrow(), x1.borrow(), m2.borrow()); 483 | // let mut diff = (x2.borrow() - x1.borrow()) % m2.borrow(); 484 | // if NumberTests::is_negative(&diff) { 485 | // diff += m2.borrow(); 486 | // } 487 | let u = (diff * m1inv.borrow()) % m2.borrow(); 488 | let x = x1.borrow() + (u * m1.borrow()); 489 | x 490 | } 491 | 492 | /// Extract randomness component of a zero ciphertext. 493 | pub fn extract_nroot(dk: &DecryptionKey, z: &BigInt) -> BigInt { 494 | let dk_n = &dk.p * &dk.q; 495 | 496 | let dk_pinv = BigInt::mod_inv(&dk.p, &dk.q); 497 | let dk_qminusone = &dk.q - BigInt::one(); 498 | let dk_pminusone = &dk.p - BigInt::one(); 499 | 500 | let dk_phi = &dk_pminusone * &dk_qminusone; 501 | let dk_dn = BigInt::mod_inv(&dk_n, &dk_phi); 502 | let (dk_dp, dk_dq) = crt_decompose(dk_dn, &dk_pminusone, &dk_qminusone); 503 | let (zp, zq) = crt_decompose(z, &dk.p, &dk.q); 504 | 505 | let rp = BigInt::mod_pow(&zp, &dk_dp, &dk.p); 506 | let rq = BigInt::mod_pow(&zq, &dk_dq, &dk.q); 507 | 508 | let r = crt_recombine(rp, rq, &dk.p, &dk.q, &dk_pinv); 509 | r 510 | } 511 | 512 | #[cfg(test)] 513 | mod tests { 514 | 515 | use super::*; 516 | 517 | extern crate serde_json; 518 | 519 | #[cfg(target_arch = "wasm32")] 520 | use wasm_bindgen_test::*; 521 | 522 | fn test_keypair() -> Keypair { 523 | let p = str::parse("148677972634832330983979593310074301486537017973460461278300587514468301043894574906886127642530475786889672304776052879927627556769456140664043088700743909632312483413393134504352834240399191134336344285483935856491230340093391784574980688823380828143810804684752914935441384845195613674104960646037368551517").unwrap(); 524 | let q = str::parse("158741574437007245654463598139927898730476924736461654463975966787719309357536545869203069369466212089132653564188443272208127277664424448947476335413293018778018615899291704693105620242763173357203898195318179150836424196645745308205164116144020613415407736216097185962171301808761138424668335445923774195463").unwrap(); 525 | Keypair { p, q } 526 | } 527 | 528 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] 529 | #[test] 530 | fn test_correct_encryption_decryption() { 531 | let (ek, dk) = test_keypair().keys(); 532 | 533 | let p = RawPlaintext::from(BigInt::from(10 as u16)); 534 | let c = Paillier::encrypt(&ek, p.clone()); 535 | 536 | let recovered_p = Paillier::decrypt(&dk, c); 537 | assert_eq!(recovered_p, p); 538 | } 539 | 540 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] 541 | #[test] 542 | fn test_correct_opening() { 543 | let (ek, dk) = test_keypair().keys(); 544 | 545 | let c = Paillier::encrypt(&ek, RawPlaintext::from(BigInt::from(10 as u16))); 546 | let (m, r) = Paillier::open(&dk, &c); 547 | let d = Paillier::encrypt_with_chosen_randomness(&ek, m, &r); 548 | assert_eq!(c, d); 549 | } 550 | 551 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] 552 | #[test] 553 | fn test_correct_addition() { 554 | let (ek, dk) = test_keypair().keys(); 555 | 556 | let m1 = RawPlaintext::from(BigInt::from(10 as u16)); 557 | let c1 = Paillier::encrypt(&ek, m1); 558 | let m2 = RawPlaintext::from(BigInt::from(20 as u16)); 559 | let c2 = Paillier::encrypt(&ek, m2); 560 | 561 | let c = Paillier::add(&ek, c1, c2); 562 | let m = Paillier::decrypt(&dk, c); 563 | assert_eq!(m, BigInt::from(30 as u16).into()); 564 | } 565 | 566 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] 567 | #[test] 568 | fn correct_multiplication() { 569 | let (ek, dk) = test_keypair().keys(); 570 | 571 | let m1 = RawPlaintext::from(BigInt::from(10 as u16)); 572 | let c1 = Paillier::encrypt(&ek, m1); 573 | let m2 = RawPlaintext::from(BigInt::from(20 as u16)); 574 | 575 | let c = Paillier::mul(&ek, c1, m2); 576 | let m = Paillier::decrypt(&dk, c); 577 | assert_eq!(m, BigInt::from(200 as u16).into()); 578 | } 579 | 580 | #[cfg(feature = "keygen")] 581 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] 582 | #[test] 583 | fn test_correct_keygen() { 584 | let (ek, dk): (EncryptionKey, _) = Paillier::keypair_with_modulus_size(2048).keys(); 585 | 586 | let m = RawPlaintext::from(BigInt::from(10)); 587 | let c = Paillier::encrypt(&ek, m.clone()); // TODO avoid clone 588 | 589 | let recovered_m = Paillier::decrypt(&dk, c); 590 | assert_eq!(recovered_m, m); 591 | } 592 | 593 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] 594 | #[test] 595 | fn test_key_serialization() { 596 | let (ek, dk) = test_keypair().keys(); 597 | 598 | let ek_serialized = serde_json::to_string(&ek).unwrap(); 599 | let ek_recovered: EncryptionKey = serde_json::from_str(&ek_serialized).unwrap(); 600 | assert_eq!(ek, ek_recovered); 601 | 602 | let dk_serialized = serde_json::to_string(&dk).unwrap(); 603 | let dk_recovered: DecryptionKey = serde_json::from_str(&dk_serialized).unwrap(); 604 | assert_eq!(dk, dk_recovered); 605 | } 606 | 607 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] 608 | #[test] 609 | fn test_failing_deserialize() { 610 | let illformatted = "{\"n\":\"12345abcdef\"}"; 611 | 612 | let result: Result = serde_json::from_str(&illformatted); 613 | assert!(result.is_err()) 614 | } 615 | } 616 | -------------------------------------------------------------------------------- /src/paillier/encoding/integral.rs: -------------------------------------------------------------------------------- 1 | //! Integral code supporting both scalars and vectors. 2 | 3 | use crate::paillier::traits::Add; 4 | use crate::paillier::traits::Decrypt; 5 | use crate::paillier::traits::Encrypt; 6 | use crate::paillier::traits::Mul; 7 | use crate::paillier::traits::Rerandomize; 8 | use std::borrow::Borrow; 9 | use std::marker::PhantomData; 10 | 11 | use super::{pack, unpack, EncodedCiphertext}; 12 | use crate::curv::arithmetic::num_bigint::BigInt; 13 | use crate::curv::arithmetic::traits::*; 14 | use crate::paillier::{Paillier, RawCiphertext, RawPlaintext}; 15 | 16 | impl Encrypt> for Paillier 17 | where 18 | for<'p, 'c> Self: Encrypt, RawCiphertext<'c>>, 19 | { 20 | fn encrypt(ek: &EK, m: u64) -> EncodedCiphertext { 21 | let c = Self::encrypt(ek, RawPlaintext::from(BigInt::from(m))); 22 | EncodedCiphertext { 23 | raw: c.into(), 24 | components: 1, 25 | _phantom: PhantomData, 26 | } 27 | } 28 | } 29 | 30 | impl<'m, EK> Encrypt>> for Paillier 31 | where 32 | for<'p, 'c> Self: Encrypt, RawCiphertext<'c>>, 33 | { 34 | fn encrypt(ek: &EK, m: &'m [u64]) -> EncodedCiphertext> { 35 | let m_packed = pack(m, 64); 36 | let c = Self::encrypt(ek, RawPlaintext::from(m_packed)); 37 | EncodedCiphertext { 38 | raw: c.into(), 39 | components: m.len(), 40 | _phantom: PhantomData, 41 | } 42 | } 43 | } 44 | 45 | impl Rerandomize> for Paillier 46 | where 47 | for<'c, 'd> Self: Rerandomize, RawCiphertext<'d>>, 48 | C: Borrow>, 49 | { 50 | fn rerandomize(ek: &EK, c: C) -> EncodedCiphertext { 51 | let d = Self::rerandomize(ek, RawCiphertext::from(&c.borrow().raw)); 52 | EncodedCiphertext { 53 | raw: d.into(), 54 | components: c.borrow().components, 55 | _phantom: PhantomData, 56 | } 57 | } 58 | } 59 | 60 | impl Rerandomize>> for Paillier 61 | where 62 | for<'c, 'd> Self: Rerandomize, RawCiphertext<'d>>, 63 | C: Borrow>>, 64 | { 65 | fn rerandomize(ek: &EK, c: C) -> EncodedCiphertext> { 66 | let d = Self::rerandomize(ek, RawCiphertext::from(&c.borrow().raw)); 67 | EncodedCiphertext { 68 | raw: d.into(), 69 | components: c.borrow().components, 70 | _phantom: PhantomData, 71 | } 72 | } 73 | } 74 | 75 | impl Decrypt for Paillier 76 | where 77 | for<'c, 'p> Self: Decrypt, RawPlaintext<'p>>, 78 | C: Borrow>, 79 | { 80 | fn decrypt(dk: &DK, c: C) -> u64 { 81 | let m = Self::decrypt(dk, RawCiphertext::from(&c.borrow().raw)); 82 | u64::_from(&m.into()) 83 | } 84 | } 85 | 86 | impl Decrypt> for Paillier 87 | where 88 | for<'c, 'p> Self: Decrypt, RawPlaintext<'p>>, 89 | C: Borrow>>, 90 | { 91 | fn decrypt(dk: &DK, c: C) -> Vec { 92 | let m = Self::decrypt(dk, RawCiphertext::from(&c.borrow().raw)); 93 | unpack(m.into(), 64, c.borrow().components) 94 | } 95 | } 96 | 97 | impl Add> for Paillier 98 | where 99 | for<'c1, 'c2, 'd> Self: Add, RawCiphertext<'c2>, RawCiphertext<'d>>, 100 | C1: Borrow>, 101 | C2: Borrow>, 102 | { 103 | fn add(ek: &EK, c1: C1, c2: C2) -> EncodedCiphertext { 104 | let d = Self::add( 105 | ek, 106 | RawCiphertext::from(&c1.borrow().raw), 107 | RawCiphertext::from(&c2.borrow().raw), 108 | ); 109 | EncodedCiphertext { 110 | raw: d.into(), 111 | components: 1, 112 | _phantom: PhantomData, 113 | } 114 | } 115 | } 116 | 117 | impl Add>> for Paillier 118 | where 119 | for<'c1, 'c2, 'd> Self: Add, RawCiphertext<'c2>, RawCiphertext<'d>>, 120 | C1: Borrow>>, 121 | C2: Borrow>>, 122 | { 123 | fn add(ek: &EK, c1: C1, c2: C2) -> EncodedCiphertext> { 124 | let c1 = c1.borrow(); 125 | let c2 = c2.borrow(); 126 | assert_eq!(c1.components, c2.components); // TODO[Morten] expand one if needed 127 | 128 | let d = Self::add( 129 | ek, 130 | RawCiphertext::from(&c1.raw), 131 | RawCiphertext::from(&c2.raw), 132 | ); 133 | EncodedCiphertext { 134 | raw: d.into(), 135 | components: c1.components, 136 | _phantom: PhantomData, 137 | } 138 | } 139 | } 140 | 141 | // impl<'c1, 'c2, EK> Add>, &'c2 Ciphertext, Ciphertext>> for Paillier 142 | // where Self: Add 143 | // { 144 | // fn add(ek: &EK, c1: &'c1 Ciphertext>, c2: &'c2 Ciphertext) -> Ciphertext> { 145 | // unimplemented!() 146 | // } 147 | // } 148 | 149 | // impl<'c1, 'c2, EK> Add, &'c2 Ciphertext>, Ciphertext>> for Paillier 150 | // where Self: Add 151 | // { 152 | // fn add(ek: &EK, c1: &'c1 Ciphertext, c2: &'c2 Ciphertext>) -> Ciphertext> { 153 | // unimplemented!() 154 | // } 155 | // } 156 | 157 | impl Add> for Paillier 158 | where 159 | for<'c, 'p, 'd> Self: Add, RawPlaintext<'p>, RawCiphertext<'d>>, 160 | C: Borrow>, 161 | { 162 | fn add(ek: &EK, c: C, p: u64) -> EncodedCiphertext { 163 | let d = Self::add( 164 | ek, 165 | RawCiphertext::from(&c.borrow().raw), 166 | RawPlaintext::from(BigInt::from(p)), 167 | ); 168 | EncodedCiphertext { 169 | raw: d.into(), 170 | components: 1, 171 | _phantom: PhantomData, 172 | } 173 | } 174 | } 175 | 176 | impl Add>> for Paillier 177 | where 178 | for<'c, 'p, 'd> Self: Add, RawPlaintext<'p>, RawCiphertext<'d>>, 179 | C: Borrow>>, 180 | { 181 | fn add(ek: &EK, c: C, p: u64) -> EncodedCiphertext> { 182 | let c = c.borrow(); 183 | 184 | let m2_expanded = vec![p; c.components]; 185 | let d = Self::add( 186 | ek, 187 | RawCiphertext::from(&c.raw), 188 | RawPlaintext::from(pack(&m2_expanded, 64)), 189 | ); 190 | EncodedCiphertext { 191 | raw: d.into(), 192 | components: c.components, 193 | _phantom: PhantomData, 194 | } 195 | } 196 | } 197 | 198 | // impl<'m2, EK, C1> Add>> for Paillier 199 | // where 200 | // for<'c1> Self: Add, 201 | // C1: Borrow>>, 202 | // { 203 | // fn add(ek: &EK, c1: C1, m2: &'m2 [u64]) -> Ciphertext> { 204 | // unimplemented!() 205 | // } 206 | // } 207 | 208 | impl Add> for Paillier 209 | where 210 | for<'m, 'c, 'd> Self: Add, RawCiphertext<'c>, RawCiphertext<'d>>, 211 | C2: Borrow>, 212 | { 213 | fn add(ek: &EK, m1: u64, c2: C2) -> EncodedCiphertext { 214 | let d = Self::add( 215 | ek, 216 | RawPlaintext::from(BigInt::from(m1)), 217 | RawCiphertext::from(&c2.borrow().raw), 218 | ); 219 | EncodedCiphertext { 220 | raw: d.into(), 221 | components: 1, 222 | _phantom: PhantomData, 223 | } 224 | } 225 | } 226 | 227 | // impl Add>> for Paillier 228 | // where 229 | // for<'c2> Self: Add, 230 | // C2: Borrow>>, 231 | // { 232 | // fn add(ek: &EK, m1: u64, c2: C2) -> Ciphertext> { 233 | // unimplemented!() 234 | // } 235 | // } 236 | 237 | // impl<'m1, EK, C2> Add>> for Paillier 238 | // where 239 | // for<'c2> Self: Add, 240 | // C2: Borrow>>, 241 | // { 242 | // fn add(ek: &EK, m1: &'m1 [u64], c2: C2) -> Ciphertext> { 243 | // unimplemented!() 244 | // } 245 | // } 246 | 247 | impl Mul> for Paillier 248 | where 249 | for<'c, 'm, 'd> Self: Mul, RawPlaintext<'m>, RawCiphertext<'d>>, 250 | C: Borrow>, 251 | { 252 | fn mul(ek: &EK, c: C, m: u64) -> EncodedCiphertext { 253 | let d = Self::mul( 254 | ek, 255 | RawCiphertext::from(&c.borrow().raw), 256 | RawPlaintext::from(BigInt::from(m)), 257 | ); 258 | EncodedCiphertext { 259 | raw: d.into(), 260 | components: 1, 261 | _phantom: PhantomData, 262 | } 263 | } 264 | } 265 | 266 | impl Mul>> for Paillier 267 | where 268 | for<'c, 'm, 'd> Self: Mul, RawPlaintext<'m>, RawCiphertext<'d>>, 269 | C: Borrow>>, 270 | { 271 | fn mul(ek: &EK, c: C, m: u64) -> EncodedCiphertext> { 272 | let d = Self::mul( 273 | ek, 274 | RawCiphertext::from(&c.borrow().raw), 275 | RawPlaintext::from(BigInt::from(m)), 276 | ); 277 | EncodedCiphertext { 278 | raw: d.into(), 279 | components: c.borrow().components, 280 | _phantom: PhantomData, 281 | } 282 | } 283 | } 284 | 285 | impl Mul> for Paillier 286 | where 287 | for<'m, 'c, 'd> Self: Mul, RawCiphertext<'c>, RawCiphertext<'d>>, 288 | C: Borrow>, 289 | { 290 | fn mul(ek: &EK, m: u64, c: C) -> EncodedCiphertext { 291 | let d = Self::mul( 292 | ek, 293 | RawPlaintext::from(BigInt::from(m)), 294 | RawCiphertext::from(&c.borrow().raw), 295 | ); 296 | EncodedCiphertext { 297 | raw: d.into(), 298 | components: 1, 299 | _phantom: PhantomData, 300 | } 301 | } 302 | } 303 | 304 | impl Mul>> for Paillier 305 | where 306 | for<'m, 'c, 'd> Self: Mul, RawCiphertext<'c>, RawCiphertext<'d>>, 307 | C: Borrow>>, 308 | { 309 | fn mul(ek: &EK, m: u64, c: C) -> EncodedCiphertext> { 310 | let d = Self::mul( 311 | ek, 312 | RawPlaintext::from(BigInt::from(m)), 313 | RawCiphertext::from(&c.borrow().raw), 314 | ); 315 | EncodedCiphertext { 316 | raw: d.into(), 317 | components: c.borrow().components, 318 | _phantom: PhantomData, 319 | } 320 | } 321 | } 322 | 323 | #[cfg(test)] 324 | mod tests { 325 | 326 | use super::*; 327 | use crate::paillier::Keypair; 328 | 329 | #[cfg(target_arch = "wasm32")] 330 | use wasm_bindgen_test::*; 331 | 332 | fn test_keypair() -> Keypair { 333 | let p = str::parse("148677972634832330983979593310074301486537017973460461278300587514468301043894574906886127642530475786889672304776052879927627556769456140664043088700743909632312483413393134504352834240399191134336344285483935856491230340093391784574980688823380828143810804684752914935441384845195613674104960646037368551517").unwrap(); 334 | let q = str::parse("158741574437007245654463598139927898730476924736461654463975966787719309357536545869203069369466212089132653564188443272208127277664424448947476335413293018778018615899291704693105620242763173357203898195318179150836424196645745308205164116144020613415407736216097185962171301808761138424668335445923774195463").unwrap(); 335 | Keypair { p, q } 336 | } 337 | 338 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] 339 | #[test] 340 | fn test_scalar_encrypt_decrypt() { 341 | let (ek, dk) = test_keypair().keys(); 342 | 343 | let m = 10; 344 | let c = Paillier::encrypt(&ek, m); 345 | 346 | let recovered_m = Paillier::decrypt(&dk, &c); 347 | assert_eq!(recovered_m, m); 348 | } 349 | 350 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] 351 | #[test] 352 | fn test_vector_encrypt_decrypt() { 353 | let (ek, dk) = test_keypair().keys(); 354 | 355 | let m = vec![1, 2, 3]; 356 | let c = Paillier::encrypt(&ek, &*m); 357 | let recovered_m = Paillier::decrypt(&dk, &c); 358 | 359 | assert_eq!(recovered_m, m); 360 | } 361 | 362 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] 363 | #[test] 364 | fn test_scalar_add_plaintext_scalar() { 365 | let (ek, dk) = test_keypair().keys(); 366 | 367 | let c1 = Paillier::encrypt(&ek, 10); 368 | let m2 = 20; 369 | 370 | let c = Paillier::add(&ek, &c1, m2); 371 | let m = Paillier::decrypt(&dk, &c); 372 | assert_eq!(m, 30); 373 | } 374 | 375 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] 376 | #[test] 377 | fn test_scalar_add_ciphertext_scalar() { 378 | let (ek, dk) = test_keypair().keys(); 379 | 380 | let c1 = Paillier::encrypt(&ek, 10); 381 | let c2 = Paillier::encrypt(&ek, 20); 382 | 383 | let c = Paillier::add(&ek, &c1, &c2); 384 | let m = Paillier::decrypt(&dk, &c); 385 | assert_eq!(m, 30); 386 | } 387 | 388 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] 389 | #[test] 390 | fn test_vector_add_plaintext_vector() { 391 | let (ek, dk) = test_keypair().keys(); 392 | 393 | let m1 = vec![1, 2, 3]; 394 | let c1 = Paillier::encrypt(&ek, &*m1); 395 | let m2 = vec![3, 2, 1]; 396 | let c2 = Paillier::encrypt(&ek, &*m2); 397 | 398 | let c = Paillier::add(&ek, &c1, &c2); 399 | let m: Vec<_> = Paillier::decrypt(&dk, &c); 400 | assert_eq!(m, vec![4, 4, 4]); 401 | } 402 | 403 | // #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] #[test] 404 | // fn test_add_vector_scalar() { 405 | // let (ek, dk) = test_keypair().keys(); 406 | 407 | // let m1 = vec![1, 2, 3]; 408 | // let c1 = Paillier::encrypt(&ek, &*m1); 409 | // let m2 = 3; 410 | // let c2 = Paillier::encrypt(&ek, m2); 411 | 412 | // let c = Paillier::add(&ek, &c1, &c2); 413 | // let m: Vec<_> = Paillier::decrypt(&dk, &c); 414 | // assert_eq!(m, vec![2, 4, 6]); 415 | // } 416 | 417 | // #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] #[test] 418 | // fn test_add_scalar_vector() { 419 | // let (ek, dk) = test_keypair().keys(); 420 | 421 | // let m1 = vec![1, 2, 3]; 422 | // let c1 = Paillier::encrypt(&ek, &*m1); 423 | // let m2 = 3; 424 | // let c2 = Paillier::encrypt(&ek, m2); 425 | 426 | // let c = Paillier::add(&ek, &c1, &c2); 427 | // let m: Vec<_> = Paillier::decrypt(&dk, &c); 428 | // assert_eq!(m, vec![2, 4, 6]); 429 | // } 430 | 431 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] 432 | #[test] 433 | fn test_scalar_mul_plaintext_scalar() { 434 | let (ek, dk) = test_keypair().keys(); 435 | 436 | let c = Paillier::encrypt(&ek, 10); 437 | let d = Paillier::mul(&ek, &c, 20); 438 | let m = Paillier::decrypt(&dk, &d); 439 | assert_eq!(m, 200); 440 | } 441 | 442 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] 443 | #[test] 444 | fn test_vector_mul_plaintext_scalar() { 445 | let (ek, dk) = test_keypair().keys(); 446 | 447 | let m1 = vec![1, 2, 3]; 448 | let c1 = Paillier::encrypt(&ek, &*m1); 449 | let m2 = 4; 450 | 451 | let c = Paillier::mul(&ek, &c1, m2); 452 | let m: Vec<_> = Paillier::decrypt(&dk, &c); 453 | assert_eq!(m, vec![4, 8, 12]); 454 | } 455 | } 456 | -------------------------------------------------------------------------------- /src/paillier/encoding/mod.rs: -------------------------------------------------------------------------------- 1 | //! Various coding schemes to be used in conjunction with the core Paillier encryption scheme. 2 | 3 | use std::marker::PhantomData; 4 | 5 | use crate::curv::arithmetic::num_bigint::BigInt; 6 | use crate::curv::arithmetic::traits::ConvertFrom; 7 | pub mod integral; 8 | use num_traits::One; 9 | 10 | /// Encrypted message with type information. 11 | #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] 12 | pub struct EncodedCiphertext { 13 | raw: BigInt, 14 | 15 | components: usize, 16 | 17 | _phantom: PhantomData, 18 | } 19 | 20 | fn pack(components: &[T], component_bitsize: usize) -> BigInt 21 | where 22 | BigInt: From, 23 | T: Copy, 24 | { 25 | let mut packed = BigInt::from(components[0]); 26 | for component in &components[1..] { 27 | packed = packed << component_bitsize; 28 | packed = packed + BigInt::from(*component); 29 | } 30 | packed 31 | } 32 | 33 | fn unpack( 34 | mut packed_components: BigInt, 35 | component_bitsize: usize, 36 | component_count: usize, 37 | ) -> Vec 38 | where 39 | T: ConvertFrom, 40 | { 41 | let mask = BigInt::one() << component_bitsize; 42 | let mut components: Vec = vec![]; 43 | for _ in 0..component_count { 44 | let raw_component = &packed_components % &mask; // TODO replace with bitwise AND 45 | let component = T::_from(&raw_component); 46 | components.push(component); 47 | packed_components = &packed_components >> component_bitsize; 48 | } 49 | components.reverse(); 50 | components 51 | } 52 | 53 | #[cfg(test)] 54 | #[cfg(target_arch = "wasm32")] 55 | use wasm_bindgen_test::*; 56 | 57 | #[cfg(test)] 58 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] 59 | #[test] 60 | fn test_pack() { 61 | let v: Vec = vec![1, 2, 3]; 62 | 63 | let component_bitsize = 64; 64 | 65 | let packed = pack(&*v, component_bitsize); 66 | assert_eq!( 67 | packed, 68 | BigInt::from(1 as u32) * (BigInt::from(1 as u32) << 2 * component_bitsize) 69 | + BigInt::from(2 as u32) * (BigInt::from(1 as u32) << 1 * component_bitsize) 70 | + BigInt::from(3 as u32) * (BigInt::from(1 as u32) << 0 * component_bitsize) 71 | ); 72 | 73 | let unpacked: Vec = unpack(packed, component_bitsize, 3); 74 | assert_eq!(unpacked, v); 75 | } 76 | -------------------------------------------------------------------------------- /src/paillier/keygen.rs: -------------------------------------------------------------------------------- 1 | //! Key generation following standard recommendations. 2 | 3 | use crate::curv::arithmetic::num_bigint::BigInt; 4 | use crate::curv::arithmetic::traits::*; 5 | use crate::paillier::traits::*; 6 | use crate::paillier::{Keypair, Paillier}; 7 | use num_traits::{One, Zero}; 8 | impl KeyGeneration for Paillier { 9 | fn keypair_with_modulus_size(bit_length: usize) -> Keypair { 10 | let p = BigInt::sample_prime(bit_length / 2); 11 | let q = BigInt::sample_prime(bit_length / 2); 12 | Keypair { p, q } 13 | } 14 | } 15 | 16 | pub trait PrimeSampable { 17 | fn sample_prime(bitsize: usize) -> Self; 18 | } 19 | 20 | impl PrimeSampable for BigInt { 21 | fn sample_prime(bitsize: usize) -> Self { 22 | // See Practical Considerations section inside the section 11.5 "Prime Number Generation" 23 | // Applied Cryptography, Bruce Schneier. 24 | let one = BigInt::one(); 25 | let two = &one + &one; 26 | loop { 27 | let mut candidate = Self::sample(bitsize); 28 | // We flip the LSB to make sure tue candidate is odd. 29 | // BitManipulation::set_bit(&mut candidate, 0, true); 30 | BigInt::set_bit(&mut candidate, 0, true); 31 | 32 | // To ensure the appropiate size 33 | // we set the MSB of the candidate. 34 | BigInt::set_bit(&mut candidate, bitsize - 1, true); 35 | 36 | // If no prime number is found in 500 iterations, 37 | // restart the loop (re-seed). 38 | // FIXME: Why 500? 39 | for _ in 0..500 { 40 | if is_prime(&candidate) { 41 | return candidate; 42 | } 43 | candidate = candidate + &two; 44 | } 45 | } 46 | } 47 | } 48 | 49 | // Runs the following three tests on a given `candidate` to determine 50 | // primality: 51 | // 52 | // 1. Divide the candidate by the first 999 small prime numbers. 53 | // 2. Run Fermat's Little Theorem against the candidate. 54 | // 3. Run five rounds of the Miller-Rabin test on the candidate. 55 | fn is_prime(candidate: &BigInt) -> bool { 56 | // First, simple trial divide 57 | for p in SMALL_PRIMES.iter() { 58 | let prime = BigInt::from(*p); 59 | let r = candidate % ′ 60 | if !NumberTests::is_zero(&r) { 61 | continue; 62 | } else { 63 | return false; 64 | } 65 | } 66 | // Second, do a little Fermat test on the candidate 67 | if !fermat(candidate) { 68 | return false; 69 | } 70 | 71 | // Finally, do a Miller-Rabin test 72 | // NIST recommendation is 5 rounds for 512 and 1024 bits. For 1536 bits, the recommendation is 4 rounds. 73 | if !miller_rabin(candidate, 5) { 74 | return false; 75 | } 76 | true 77 | } 78 | 79 | /// Perform test based on Fermat's little theorem 80 | /// This might be performed more than once, see Handbook of Applied Cryptography [Algorithm 4.9 p136] 81 | fn fermat(candidate: &BigInt) -> bool { 82 | let random = BigInt::sample_below(candidate); 83 | let result = BigInt::mod_pow(&random, &(candidate - &BigInt::one()), candidate); 84 | 85 | result == BigInt::one() 86 | } 87 | 88 | /// Perform Miller-Rabin primality test 89 | fn miller_rabin(candidate: &BigInt, limit: usize) -> bool { 90 | // Iterations recommended for which p < (1/2)^{80} 91 | // 500 bits => 6 iterations 92 | // 1000 bits => 3 iterations 93 | // 2000 bits => 2 iterations 94 | 95 | let (s, d) = rewrite(&(candidate - &BigInt::one())); 96 | let one = BigInt::one(); 97 | let two = &one + &one; 98 | 99 | for _ in 0..limit { 100 | let basis = BigInt::sample_range(&two, &(candidate - &two)); 101 | let mut y = BigInt::mod_pow(&basis, &d, candidate); 102 | 103 | if y == one || y == (candidate - &one) { 104 | continue; 105 | } else { 106 | let mut counter = BigInt::one(); 107 | while counter < (&s - &one) { 108 | y = BigInt::mod_pow(&y, &two, candidate); 109 | if y == one { 110 | return false; 111 | } else if y == candidate - &one { 112 | break; 113 | } 114 | counter = counter + BigInt::one(); 115 | } 116 | return false; 117 | } 118 | } 119 | true 120 | } 121 | 122 | /// Rewrite a number n = 2^s * d 123 | /// (i.e., 2^s is the largest power of 2 that divides the candidate). 124 | fn rewrite(n: &BigInt) -> (BigInt, BigInt) { 125 | let mut d = n.clone(); 126 | let mut s = BigInt::zero(); 127 | let one = BigInt::one(); 128 | 129 | while BigInt::is_even(&d) { 130 | d = d >> 1_usize; 131 | s = &s + &one; 132 | } 133 | 134 | (s, d) 135 | } 136 | 137 | // BoringSSL's table. 138 | // https://boringssl.googlesource.com/boringssl/+/master/crypto/bn/prime.c 139 | #[cfg_attr(rustfmt, rustfmt_skip)] 140 | static SMALL_PRIMES: [u32; 2048] = [ 141 | 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 142 | 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 143 | 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 144 | 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 145 | 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 146 | 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 147 | 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 148 | 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 149 | 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 150 | 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 151 | 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 152 | 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 153 | 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 154 | 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 155 | 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 156 | 983, 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, 157 | 1051, 1061, 1063, 1069, 1087, 1091, 1093, 1097, 1103, 1109, 1117, 158 | 1123, 1129, 1151, 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, 159 | 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 160 | 1291, 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, 161 | 1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, 1453, 162 | 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511, 1523, 1531, 163 | 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, 1597, 1601, 1607, 164 | 1609, 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, 1669, 1693, 165 | 1697, 1699, 1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759, 1777, 166 | 1783, 1787, 1789, 1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871, 167 | 1873, 1877, 1879, 1889, 1901, 1907, 1913, 1931, 1933, 1949, 1951, 168 | 1973, 1979, 1987, 1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, 169 | 2039, 2053, 2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111, 2113, 170 | 2129, 2131, 2137, 2141, 2143, 2153, 2161, 2179, 2203, 2207, 2213, 171 | 2221, 2237, 2239, 2243, 2251, 2267, 2269, 2273, 2281, 2287, 2293, 172 | 2297, 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357, 2371, 2377, 173 | 2381, 2383, 2389, 2393, 2399, 2411, 2417, 2423, 2437, 2441, 2447, 174 | 2459, 2467, 2473, 2477, 2503, 2521, 2531, 2539, 2543, 2549, 2551, 175 | 2557, 2579, 2591, 2593, 2609, 2617, 2621, 2633, 2647, 2657, 2659, 176 | 2663, 2671, 2677, 2683, 2687, 2689, 2693, 2699, 2707, 2711, 2713, 177 | 2719, 2729, 2731, 2741, 2749, 2753, 2767, 2777, 2789, 2791, 2797, 178 | 2801, 2803, 2819, 2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887, 179 | 2897, 2903, 2909, 2917, 2927, 2939, 2953, 2957, 2963, 2969, 2971, 180 | 2999, 3001, 3011, 3019, 3023, 3037, 3041, 3049, 3061, 3067, 3079, 181 | 3083, 3089, 3109, 3119, 3121, 3137, 3163, 3167, 3169, 3181, 3187, 182 | 3191, 3203, 3209, 3217, 3221, 3229, 3251, 3253, 3257, 3259, 3271, 183 | 3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331, 3343, 3347, 3359, 184 | 3361, 3371, 3373, 3389, 3391, 3407, 3413, 3433, 3449, 3457, 3461, 185 | 3463, 3467, 3469, 3491, 3499, 3511, 3517, 3527, 3529, 3533, 3539, 186 | 3541, 3547, 3557, 3559, 3571, 3581, 3583, 3593, 3607, 3613, 3617, 187 | 3623, 3631, 3637, 3643, 3659, 3671, 3673, 3677, 3691, 3697, 3701, 188 | 3709, 3719, 3727, 3733, 3739, 3761, 3767, 3769, 3779, 3793, 3797, 189 | 3803, 3821, 3823, 3833, 3847, 3851, 3853, 3863, 3877, 3881, 3889, 190 | 3907, 3911, 3917, 3919, 3923, 3929, 3931, 3943, 3947, 3967, 3989, 191 | 4001, 4003, 4007, 4013, 4019, 4021, 4027, 4049, 4051, 4057, 4073, 192 | 4079, 4091, 4093, 4099, 4111, 4127, 4129, 4133, 4139, 4153, 4157, 193 | 4159, 4177, 4201, 4211, 4217, 4219, 4229, 4231, 4241, 4243, 4253, 194 | 4259, 4261, 4271, 4273, 4283, 4289, 4297, 4327, 4337, 4339, 4349, 195 | 4357, 4363, 4373, 4391, 4397, 4409, 4421, 4423, 4441, 4447, 4451, 196 | 4457, 4463, 4481, 4483, 4493, 4507, 4513, 4517, 4519, 4523, 4547, 197 | 4549, 4561, 4567, 4583, 4591, 4597, 4603, 4621, 4637, 4639, 4643, 198 | 4649, 4651, 4657, 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729, 199 | 4733, 4751, 4759, 4783, 4787, 4789, 4793, 4799, 4801, 4813, 4817, 200 | 4831, 4861, 4871, 4877, 4889, 4903, 4909, 4919, 4931, 4933, 4937, 201 | 4943, 4951, 4957, 4967, 4969, 4973, 4987, 4993, 4999, 5003, 5009, 202 | 5011, 5021, 5023, 5039, 5051, 5059, 5077, 5081, 5087, 5099, 5101, 203 | 5107, 5113, 5119, 5147, 5153, 5167, 5171, 5179, 5189, 5197, 5209, 204 | 5227, 5231, 5233, 5237, 5261, 5273, 5279, 5281, 5297, 5303, 5309, 205 | 5323, 5333, 5347, 5351, 5381, 5387, 5393, 5399, 5407, 5413, 5417, 206 | 5419, 5431, 5437, 5441, 5443, 5449, 5471, 5477, 5479, 5483, 5501, 207 | 5503, 5507, 5519, 5521, 5527, 5531, 5557, 5563, 5569, 5573, 5581, 208 | 5591, 5623, 5639, 5641, 5647, 5651, 5653, 5657, 5659, 5669, 5683, 209 | 5689, 5693, 5701, 5711, 5717, 5737, 5741, 5743, 5749, 5779, 5783, 210 | 5791, 5801, 5807, 5813, 5821, 5827, 5839, 5843, 5849, 5851, 5857, 211 | 5861, 5867, 5869, 5879, 5881, 5897, 5903, 5923, 5927, 5939, 5953, 212 | 5981, 5987, 6007, 6011, 6029, 6037, 6043, 6047, 6053, 6067, 6073, 213 | 6079, 6089, 6091, 6101, 6113, 6121, 6131, 6133, 6143, 6151, 6163, 214 | 6173, 6197, 6199, 6203, 6211, 6217, 6221, 6229, 6247, 6257, 6263, 215 | 6269, 6271, 6277, 6287, 6299, 6301, 6311, 6317, 6323, 6329, 6337, 216 | 6343, 6353, 6359, 6361, 6367, 6373, 6379, 6389, 6397, 6421, 6427, 217 | 6449, 6451, 6469, 6473, 6481, 6491, 6521, 6529, 6547, 6551, 6553, 218 | 6563, 6569, 6571, 6577, 6581, 6599, 6607, 6619, 6637, 6653, 6659, 219 | 6661, 6673, 6679, 6689, 6691, 6701, 6703, 6709, 6719, 6733, 6737, 220 | 6761, 6763, 6779, 6781, 6791, 6793, 6803, 6823, 6827, 6829, 6833, 221 | 6841, 6857, 6863, 6869, 6871, 6883, 6899, 6907, 6911, 6917, 6947, 222 | 6949, 6959, 6961, 6967, 6971, 6977, 6983, 6991, 6997, 7001, 7013, 223 | 7019, 7027, 7039, 7043, 7057, 7069, 7079, 7103, 7109, 7121, 7127, 224 | 7129, 7151, 7159, 7177, 7187, 7193, 7207, 7211, 7213, 7219, 7229, 225 | 7237, 7243, 7247, 7253, 7283, 7297, 7307, 7309, 7321, 7331, 7333, 226 | 7349, 7351, 7369, 7393, 7411, 7417, 7433, 7451, 7457, 7459, 7477, 227 | 7481, 7487, 7489, 7499, 7507, 7517, 7523, 7529, 7537, 7541, 7547, 228 | 7549, 7559, 7561, 7573, 7577, 7583, 7589, 7591, 7603, 7607, 7621, 229 | 7639, 7643, 7649, 7669, 7673, 7681, 7687, 7691, 7699, 7703, 7717, 230 | 7723, 7727, 7741, 7753, 7757, 7759, 7789, 7793, 7817, 7823, 7829, 231 | 7841, 7853, 7867, 7873, 7877, 7879, 7883, 7901, 7907, 7919, 7927, 232 | 7933, 7937, 7949, 7951, 7963, 7993, 8009, 8011, 8017, 8039, 8053, 233 | 8059, 8069, 8081, 8087, 8089, 8093, 8101, 8111, 8117, 8123, 8147, 234 | 8161, 8167, 8171, 8179, 8191, 8209, 8219, 8221, 8231, 8233, 8237, 235 | 8243, 8263, 8269, 8273, 8287, 8291, 8293, 8297, 8311, 8317, 8329, 236 | 8353, 8363, 8369, 8377, 8387, 8389, 8419, 8423, 8429, 8431, 8443, 237 | 8447, 8461, 8467, 8501, 8513, 8521, 8527, 8537, 8539, 8543, 8563, 238 | 8573, 8581, 8597, 8599, 8609, 8623, 8627, 8629, 8641, 8647, 8663, 239 | 8669, 8677, 8681, 8689, 8693, 8699, 8707, 8713, 8719, 8731, 8737, 240 | 8741, 8747, 8753, 8761, 8779, 8783, 8803, 8807, 8819, 8821, 8831, 241 | 8837, 8839, 8849, 8861, 8863, 8867, 8887, 8893, 8923, 8929, 8933, 242 | 8941, 8951, 8963, 8969, 8971, 8999, 9001, 9007, 9011, 9013, 9029, 243 | 9041, 9043, 9049, 9059, 9067, 9091, 9103, 9109, 9127, 9133, 9137, 244 | 9151, 9157, 9161, 9173, 9181, 9187, 9199, 9203, 9209, 9221, 9227, 245 | 9239, 9241, 9257, 9277, 9281, 9283, 9293, 9311, 9319, 9323, 9337, 246 | 9341, 9343, 9349, 9371, 9377, 9391, 9397, 9403, 9413, 9419, 9421, 247 | 9431, 9433, 9437, 9439, 9461, 9463, 9467, 9473, 9479, 9491, 9497, 248 | 9511, 9521, 9533, 9539, 9547, 9551, 9587, 9601, 9613, 9619, 9623, 249 | 9629, 9631, 9643, 9649, 9661, 9677, 9679, 9689, 9697, 9719, 9721, 250 | 9733, 9739, 9743, 9749, 9767, 9769, 9781, 9787, 9791, 9803, 9811, 251 | 9817, 9829, 9833, 9839, 9851, 9857, 9859, 9871, 9883, 9887, 9901, 252 | 9907, 9923, 9929, 9931, 9941, 9949, 9967, 9973, 10007, 10009, 10037, 253 | 10039, 10061, 10067, 10069, 10079, 10091, 10093, 10099, 10103, 10111, 10133, 254 | 10139, 10141, 10151, 10159, 10163, 10169, 10177, 10181, 10193, 10211, 10223, 255 | 10243, 10247, 10253, 10259, 10267, 10271, 10273, 10289, 10301, 10303, 10313, 256 | 10321, 10331, 10333, 10337, 10343, 10357, 10369, 10391, 10399, 10427, 10429, 257 | 10433, 10453, 10457, 10459, 10463, 10477, 10487, 10499, 10501, 10513, 10529, 258 | 10531, 10559, 10567, 10589, 10597, 10601, 10607, 10613, 10627, 10631, 10639, 259 | 10651, 10657, 10663, 10667, 10687, 10691, 10709, 10711, 10723, 10729, 10733, 260 | 10739, 10753, 10771, 10781, 10789, 10799, 10831, 10837, 10847, 10853, 10859, 261 | 10861, 10867, 10883, 10889, 10891, 10903, 10909, 10937, 10939, 10949, 10957, 262 | 10973, 10979, 10987, 10993, 11003, 11027, 11047, 11057, 11059, 11069, 11071, 263 | 11083, 11087, 11093, 11113, 11117, 11119, 11131, 11149, 11159, 11161, 11171, 264 | 11173, 11177, 11197, 11213, 11239, 11243, 11251, 11257, 11261, 11273, 11279, 265 | 11287, 11299, 11311, 11317, 11321, 11329, 11351, 11353, 11369, 11383, 11393, 266 | 11399, 11411, 11423, 11437, 11443, 11447, 11467, 11471, 11483, 11489, 11491, 267 | 11497, 11503, 11519, 11527, 11549, 11551, 11579, 11587, 11593, 11597, 11617, 268 | 11621, 11633, 11657, 11677, 11681, 11689, 11699, 11701, 11717, 11719, 11731, 269 | 11743, 11777, 11779, 11783, 11789, 11801, 11807, 11813, 11821, 11827, 11831, 270 | 11833, 11839, 11863, 11867, 11887, 11897, 11903, 11909, 11923, 11927, 11933, 271 | 11939, 11941, 11953, 11959, 11969, 11971, 11981, 11987, 12007, 12011, 12037, 272 | 12041, 12043, 12049, 12071, 12073, 12097, 12101, 12107, 12109, 12113, 12119, 273 | 12143, 12149, 12157, 12161, 12163, 12197, 12203, 12211, 12227, 12239, 12241, 274 | 12251, 12253, 12263, 12269, 12277, 12281, 12289, 12301, 12323, 12329, 12343, 275 | 12347, 12373, 12377, 12379, 12391, 12401, 12409, 12413, 12421, 12433, 12437, 276 | 12451, 12457, 12473, 12479, 12487, 12491, 12497, 12503, 12511, 12517, 12527, 277 | 12539, 12541, 12547, 12553, 12569, 12577, 12583, 12589, 12601, 12611, 12613, 278 | 12619, 12637, 12641, 12647, 12653, 12659, 12671, 12689, 12697, 12703, 12713, 279 | 12721, 12739, 12743, 12757, 12763, 12781, 12791, 12799, 12809, 12821, 12823, 280 | 12829, 12841, 12853, 12889, 12893, 12899, 12907, 12911, 12917, 12919, 12923, 281 | 12941, 12953, 12959, 12967, 12973, 12979, 12983, 13001, 13003, 13007, 13009, 282 | 13033, 13037, 13043, 13049, 13063, 13093, 13099, 13103, 13109, 13121, 13127, 283 | 13147, 13151, 13159, 13163, 13171, 13177, 13183, 13187, 13217, 13219, 13229, 284 | 13241, 13249, 13259, 13267, 13291, 13297, 13309, 13313, 13327, 13331, 13337, 285 | 13339, 13367, 13381, 13397, 13399, 13411, 13417, 13421, 13441, 13451, 13457, 286 | 13463, 13469, 13477, 13487, 13499, 13513, 13523, 13537, 13553, 13567, 13577, 287 | 13591, 13597, 13613, 13619, 13627, 13633, 13649, 13669, 13679, 13681, 13687, 288 | 13691, 13693, 13697, 13709, 13711, 13721, 13723, 13729, 13751, 13757, 13759, 289 | 13763, 13781, 13789, 13799, 13807, 13829, 13831, 13841, 13859, 13873, 13877, 290 | 13879, 13883, 13901, 13903, 13907, 13913, 13921, 13931, 13933, 13963, 13967, 291 | 13997, 13999, 14009, 14011, 14029, 14033, 14051, 14057, 14071, 14081, 14083, 292 | 14087, 14107, 14143, 14149, 14153, 14159, 14173, 14177, 14197, 14207, 14221, 293 | 14243, 14249, 14251, 14281, 14293, 14303, 14321, 14323, 14327, 14341, 14347, 294 | 14369, 14387, 14389, 14401, 14407, 14411, 14419, 14423, 14431, 14437, 14447, 295 | 14449, 14461, 14479, 14489, 14503, 14519, 14533, 14537, 14543, 14549, 14551, 296 | 14557, 14561, 14563, 14591, 14593, 14621, 14627, 14629, 14633, 14639, 14653, 297 | 14657, 14669, 14683, 14699, 14713, 14717, 14723, 14731, 14737, 14741, 14747, 298 | 14753, 14759, 14767, 14771, 14779, 14783, 14797, 14813, 14821, 14827, 14831, 299 | 14843, 14851, 14867, 14869, 14879, 14887, 14891, 14897, 14923, 14929, 14939, 300 | 14947, 14951, 14957, 14969, 14983, 15013, 15017, 15031, 15053, 15061, 15073, 301 | 15077, 15083, 15091, 15101, 15107, 15121, 15131, 15137, 15139, 15149, 15161, 302 | 15173, 15187, 15193, 15199, 15217, 15227, 15233, 15241, 15259, 15263, 15269, 303 | 15271, 15277, 15287, 15289, 15299, 15307, 15313, 15319, 15329, 15331, 15349, 304 | 15359, 15361, 15373, 15377, 15383, 15391, 15401, 15413, 15427, 15439, 15443, 305 | 15451, 15461, 15467, 15473, 15493, 15497, 15511, 15527, 15541, 15551, 15559, 306 | 15569, 15581, 15583, 15601, 15607, 15619, 15629, 15641, 15643, 15647, 15649, 307 | 15661, 15667, 15671, 15679, 15683, 15727, 15731, 15733, 15737, 15739, 15749, 308 | 15761, 15767, 15773, 15787, 15791, 15797, 15803, 15809, 15817, 15823, 15859, 309 | 15877, 15881, 15887, 15889, 15901, 15907, 15913, 15919, 15923, 15937, 15959, 310 | 15971, 15973, 15991, 16001, 16007, 16033, 16057, 16061, 16063, 16067, 16069, 311 | 16073, 16087, 16091, 16097, 16103, 16111, 16127, 16139, 16141, 16183, 16187, 312 | 16189, 16193, 16217, 16223, 16229, 16231, 16249, 16253, 16267, 16273, 16301, 313 | 16319, 16333, 16339, 16349, 16361, 16363, 16369, 16381, 16411, 16417, 16421, 314 | 16427, 16433, 16447, 16451, 16453, 16477, 16481, 16487, 16493, 16519, 16529, 315 | 16547, 16553, 16561, 16567, 16573, 16603, 16607, 16619, 16631, 16633, 16649, 316 | 16651, 16657, 16661, 16673, 16691, 16693, 16699, 16703, 16729, 16741, 16747, 317 | 16759, 16763, 16787, 16811, 16823, 16829, 16831, 16843, 16871, 16879, 16883, 318 | 16889, 16901, 16903, 16921, 16927, 16931, 16937, 16943, 16963, 16979, 16981, 319 | 16987, 16993, 17011, 17021, 17027, 17029, 17033, 17041, 17047, 17053, 17077, 320 | 17093, 17099, 17107, 17117, 17123, 17137, 17159, 17167, 17183, 17189, 17191, 321 | 17203, 17207, 17209, 17231, 17239, 17257, 17291, 17293, 17299, 17317, 17321, 322 | 17327, 17333, 17341, 17351, 17359, 17377, 17383, 17387, 17389, 17393, 17401, 323 | 17417, 17419, 17431, 17443, 17449, 17467, 17471, 17477, 17483, 17489, 17491, 324 | 17497, 17509, 17519, 17539, 17551, 17569, 17573, 17579, 17581, 17597, 17599, 325 | 17609, 17623, 17627, 17657, 17659, 17669, 17681, 17683, 17707, 17713, 17729, 326 | 17737, 17747, 17749, 17761, 17783, 17789, 17791, 17807, 17827, 17837, 17839, 327 | 17851, 17863 ]; 328 | -------------------------------------------------------------------------------- /src/paillier/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod core; 2 | pub mod encoding; 3 | pub mod keygen; 4 | pub mod traits; 5 | pub mod zkproofs; 6 | 7 | pub use crate::paillier::core::*; 8 | pub use crate::paillier::encoding::*; 9 | pub use crate::paillier::keygen::*; 10 | pub use crate::paillier::traits::*; 11 | 12 | use std::borrow::Cow; 13 | 14 | /// Main struct onto which most operations are added. 15 | pub struct Paillier; 16 | 17 | pub use crate::curv::arithmetic::num_bigint::BigInt; 18 | /// Keypair from which encryption and decryption keys can be derived. 19 | #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] 20 | pub struct Keypair { 21 | pub p: BigInt, // TODO[Morten] okay to make non-public? 22 | 23 | pub q: BigInt, // TODO[Morten] okay to make non-public? 24 | } 25 | 26 | /// Public encryption key with no precomputed values. 27 | /// 28 | /// Used e.g. for serialization of `EncryptionKey`. 29 | #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] 30 | pub struct MinimalEncryptionKey { 31 | pub n: BigInt, 32 | } 33 | 34 | /// Private decryption key with no precomputed values. 35 | /// 36 | /// Used e.g. for serialization of `DecryptionKey`. 37 | #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] 38 | pub struct MinimalDecryptionKey { 39 | pub p: BigInt, 40 | 41 | pub q: BigInt, 42 | } 43 | 44 | /// Public encryption key. 45 | #[derive(Clone, Debug, PartialEq)] 46 | pub struct EncryptionKey { 47 | pub n: BigInt, // the modulus 48 | pub nn: BigInt, // the modulus squared 49 | } 50 | 51 | /// Private decryption key. 52 | #[derive(Clone, Debug, PartialEq)] 53 | pub struct DecryptionKey { 54 | pub p: BigInt, // first prime 55 | pub q: BigInt, // second prime 56 | } 57 | 58 | /// Unencrypted message without type information. 59 | /// 60 | /// Used mostly for internal purposes and advanced use-cases. 61 | #[derive(Clone, Debug, PartialEq)] 62 | pub struct RawPlaintext<'b>(pub Cow<'b, BigInt>); 63 | 64 | /// Encrypted message without type information. 65 | /// 66 | /// Used mostly for internal purposes and advanced use-cases. 67 | #[derive(Clone, Debug, PartialEq)] 68 | pub struct RawCiphertext<'b>(pub Cow<'b, BigInt>); 69 | -------------------------------------------------------------------------------- /src/paillier/serialize.rs: -------------------------------------------------------------------------------- 1 | pub mod bigint { 2 | 3 | use curv::arithmetic::num_bigint::BigInt; 4 | use serde::{de, ser}; 5 | use std::fmt; 6 | 7 | pub fn serialize(x: &BigInt, serializer: S) -> Result { 8 | serializer.serialize_str(&x.to_str_radix(10)) 9 | } 10 | 11 | pub fn deserialize<'de, D: de::Deserializer<'de>>(deserializer: D) -> Result { 12 | struct BigIntVisitor; 13 | 14 | impl<'de> de::Visitor<'de> for BigIntVisitor { 15 | type Value = BigInt; 16 | 17 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 18 | formatter.write_str("bigint") 19 | } 20 | 21 | fn visit_str(self, s: &str) -> Result { 22 | let v: BigInt = str::parse(s).map_err(de::Error::custom)?; 23 | Ok(v) 24 | } 25 | } 26 | 27 | deserializer.deserialize_str(BigIntVisitor) 28 | } 29 | } 30 | 31 | pub mod vecbigint { 32 | 33 | use curv::arithmetic::num_bigint::BigInt; 34 | use num_traits::Num; 35 | use serde::de::SeqAccess; 36 | use serde::ser::SerializeSeq; 37 | use serde::{de, ser}; 38 | use std::fmt; 39 | pub fn serialize( 40 | x: &Vec, 41 | serializer: S, 42 | ) -> Result { 43 | let mut seq = serializer.serialize_seq(Some(x.len()))?; 44 | for e in x { 45 | seq.serialize_element(&e.to_str_radix(10))?; 46 | } 47 | seq.end() 48 | } 49 | 50 | pub fn deserialize<'de, D: de::Deserializer<'de>>( 51 | deserializer: D, 52 | ) -> Result, D::Error> { 53 | struct VecBigIntVisitor; 54 | 55 | impl<'de> de::Visitor<'de> for VecBigIntVisitor { 56 | type Value = Vec; 57 | 58 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 59 | formatter.write_str("vector of bigint") 60 | } 61 | 62 | fn visit_seq(self, mut seq: A) -> Result, A::Error> 63 | where 64 | A: SeqAccess<'de>, 65 | { 66 | let mut values: Vec = Vec::new(); 67 | while let Some(value) = seq.next_element::()? { 68 | values.push(BigInt::from_str_radix(&value, 10).unwrap()); 69 | } 70 | 71 | Ok(values) 72 | } 73 | } 74 | 75 | deserializer.deserialize_seq(VecBigIntVisitor) 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/paillier/traits.rs: -------------------------------------------------------------------------------- 1 | //! Abstract operations exposed by the library. 2 | 3 | /// Secure generation of fresh key pairs. 4 | pub trait KeyGeneration { 5 | /// Generate fresh key pair with currently recommended security level (2048 bit modulus). 6 | fn keypair() -> KP { 7 | Self::keypair_with_modulus_size(2048) 8 | } 9 | 10 | /// Generate fresh key pair with security level specified as the `bit_length` of the modulus. 11 | /// 12 | /// Currently recommended security level is a minimum of 2048 bits. 13 | fn keypair_with_modulus_size(big_length: usize) -> KP; 14 | } 15 | 16 | pub trait PrecomputeRandomness { 17 | fn precompute(ek: EK, r: R) -> PR; 18 | } 19 | 20 | /// Encryption of plaintext. 21 | pub trait Encrypt { 22 | /// Encrypt plaintext `m` under key `ek` into a ciphertext. 23 | fn encrypt(ek: &EK, m: PT) -> CT; 24 | } 25 | 26 | pub trait EncryptWithChosenRandomness { 27 | fn encrypt_with_chosen_randomness(ek: &EK, m: PT, r: R) -> CT; 28 | } 29 | 30 | /// Decryption of ciphertext. 31 | pub trait Decrypt { 32 | /// Decrypt ciphertext `c` using key `dk` into a plaintext. 33 | fn decrypt(ek: &DK, c: CT) -> PT; 34 | } 35 | 36 | /// Opening of ciphertext. 37 | /// 38 | /// Unlike decryption this also returns the randomness used. 39 | pub trait Open { 40 | /// Open ciphertext `c` using key `dk` into a plaintext and a randomness. 41 | fn open(dk: &DK, c: CT) -> (PT, R); 42 | } 43 | 44 | /// Addition of two ciphertexts. 45 | pub trait Add { 46 | /// Homomorphically combine ciphertexts `c1` and `c2` to obtain a ciphertext containing 47 | /// the sum of the two underlying plaintexts, reduced modulus `n` from `ek`. 48 | fn add(ek: &EK, c1: CT1, c2: CT2) -> CT; 49 | } 50 | 51 | /// Multiplication of ciphertext with plaintext. 52 | pub trait Mul { 53 | /// Homomorphically combine ciphertext `c1` and plaintext `m2` to obtain a ciphertext 54 | /// containing the multiplication of the (underlying) plaintexts, reduced modulus `n` from `ek`. 55 | fn mul(ek: &EK, c1: CT1, m2: PT2) -> CT; 56 | } 57 | 58 | /// Rerandomisation of ciphertext. 59 | pub trait Rerandomize { 60 | /// Rerandomise ciphertext `c` to hide any history of which homomorphic operations were 61 | /// used to compute it, making it look exactly like a fresh encryption of the same plaintext. 62 | fn rerandomize(ek: &EK, c: CT1) -> CT; 63 | } 64 | -------------------------------------------------------------------------------- /src/paillier/zkproofs/correct_key_ni.rs: -------------------------------------------------------------------------------- 1 | /* 2 | zk-paillier 3 | 4 | Copyright 2018 by Kzen Networks 5 | 6 | This file is part of Multisig Schnorr library 7 | (https://github.com/KZen-networks/multisig-schnorr) 8 | 9 | zk-paillier is free software: you can redistribute 10 | it and/or modify it under the terms of the GNU General Public 11 | License as published by the Free Software Foundation, either 12 | version 3 of the License, or (at your option) any later version. 13 | 14 | @license GPL-3.0+ 15 | */ 16 | use std::ops::Shl; 17 | 18 | use crate::curv::arithmetic::num_bigint::{from, BigInt}; 19 | use crate::curv::arithmetic::traits::*; 20 | use crate::curv::cryptographic_primitives::hashing::hash_sha256::HSha256; 21 | use crate::curv::cryptographic_primitives::hashing::traits::Hash; 22 | use crate::paillier::{extract_nroot, DecryptionKey, EncryptionKey}; 23 | use num_integer::Integer; 24 | use num_traits::{One, Zero}; 25 | // This protocol is based on the NIZK protocol in https://eprint.iacr.org/2018/057.pdf 26 | // for parameters = e = N, m2 = 11, alpha = 6379 see https://eprint.iacr.org/2018/987.pdf 6.2.3 27 | // for full details. 28 | 29 | // product of all primes < alpha: https://www.dcode.fr/primorial 30 | const P: &str = "1824183726245393467247644231302244136093537199057104213213550575243641782740360650490963459819244001947254814805714931325851267161710067435807383848463920901137710041673887113990643820798975386714299839914137592590654009952623014982962684955535111234311335565220917383311689115138496765310625882473439402233109450021984891450304679833752756159872219991089194187575068382762952239830901394850887215392132883640669486674102277756753260855640317510235617660944873631054630816035269100510337643250389997837634640249480037184290462924540150133678312185777228630834940021427688892876384196895677819059963882587092166301131529174343474451480089653483180602591751073139733370712300241581635049350925412683097729232092096276490229965785020041921736307394438075266234968515443716828633392848203945374591926800464450599823553052462708727219173990177119684565306222502415160037753326638045687574106534702341439991863742806351468290587722561435038912863815688133288619512790095919904026573249557024839383595481704184528960978957724597263323512030743875614290609368530643094080051166226135271385866188054556684837921935888945641944961066293159525602885452222458958772845494346799890196718717317906330936509091221354615991671869862034179206244894205681566781062633415772628848878715803040358836098609654889521393046492471227546079924219055408612815173193108753184477562256266860297096223934088509777393752624380757072082427603556077039945700711226680778392737267707541904355129695919972995501581794067880959822149963798096452613619855673307435602850208850402301583025111762622381953251883429317603005626232012725708694401272295509035367654620412640848204179955980722707996291909812529974361949926881288349518750747615837667549305083291804187179123453121466640918862622766511668478452223742058912575427337018022812631386313110243745000214354806312441270889672903307645611658893986526812130032112540367173736664288995222516688120866114984318582900331631896931709005163853429427759224323636152573453333607357348169167915027700846002932742550824939007414330697249569916339964247646402851281857942965519194576006169066153524163225631476643914033601957614124583206541834352791003930506139209204661104882701842617501635864883760885236797081996679496751254260706438583316885612406386543479255566185697792942478704336254208839180970748624881039948192415929866204318800220295457932550799088592217150597176505394120909914475575501881459804699385499576326684695531034075283165800622328491384987194944504461864105986907646706095956083156240472489616473946638879726524585936511018780747174387840018674670110430528051586069422163934697899931456041802624175449157279620104126331489491525955411465073551652840009163781923401029513048693746713122813578721687858104388238796796690"; 31 | // salt as system parameter 32 | const SALT_STRING: &[u8] = &[75, 90, 101, 110]; 33 | const M2: usize = 11; 34 | const DIGEST_SIZE: usize = 256; 35 | #[derive(Debug)] 36 | pub struct CorrectKeyProofError; 37 | #[derive(Clone, Debug, Serialize, Deserialize)] 38 | pub struct NICorrectKeyProof { 39 | pub sigma_vec: Vec, 40 | } 41 | 42 | impl NICorrectKeyProof { 43 | pub fn proof(dk: &DecryptionKey) -> NICorrectKeyProof { 44 | let dk_n = &dk.q * &dk.p; 45 | let key_length = &dk_n.bits(); 46 | 47 | let salt_bn = from(SALT_STRING); 48 | 49 | // TODO: use flatten (Morten?) 50 | let rho_vec = (0..M2) 51 | .map(|i| { 52 | let seed_bn = 53 | HSha256::create_hash(&[&dk_n, &salt_bn, &BigInt::from(i.clone() as u32)]); 54 | mask_generation(&key_length, &seed_bn) % &dk_n 55 | }) 56 | .collect::>(); 57 | 58 | let sigma_vec = rho_vec 59 | .iter() 60 | .map(|i| { 61 | let sigma_i = extract_nroot(dk, i); 62 | sigma_i 63 | }) 64 | .collect::>(); 65 | NICorrectKeyProof { sigma_vec } 66 | } 67 | 68 | pub fn verify(&self, ek: &EncryptionKey) -> Result<(), CorrectKeyProofError> { 69 | let key_length = ek.n.bits() as usize; 70 | let salt_bn = from(SALT_STRING); 71 | 72 | let rho_vec = (0..M2) 73 | .map(|i| { 74 | let seed_bn = 75 | HSha256::create_hash(&[&ek.n, &salt_bn, &BigInt::from(i.clone() as u32)]); 76 | 77 | mask_generation(&key_length, &seed_bn) % &ek.n 78 | }) 79 | .collect::>(); 80 | let alpha_primorial: BigInt = str::parse(&P).unwrap(); 81 | let gcd_test = alpha_primorial.gcd(&ek.n); 82 | 83 | let derived_rho_vec = (0..M2) 84 | .map(|i| BigInt::mod_pow(&self.sigma_vec[i], &ek.n, &ek.n)) 85 | .collect::>(); 86 | 87 | if rho_vec == derived_rho_vec && gcd_test == BigInt::one() { 88 | Ok(()) 89 | } else { 90 | Err(CorrectKeyProofError) 91 | } 92 | } 93 | } 94 | 95 | // generate random element of size : 96 | // based on https://tools.ietf.org/html/rfc8017#appendix-B.2.1 97 | pub fn mask_generation(out_length: &usize, seed: &BigInt) -> BigInt { 98 | let msklen = out_length / DIGEST_SIZE + 1; // adding one sha256 is more efficient then rejection sampling (see A.4 (e) in the paper) 99 | let msklen_hash_vec = (0..msklen) 100 | .map(|j| HSha256::create_hash(&[seed, &BigInt::from(j.clone() as u32)])) 101 | .collect::>(); 102 | msklen_hash_vec 103 | .iter() 104 | .zip(0..msklen) 105 | .fold(BigInt::zero(), |acc, x| acc + x.0.shl(x.1 * DIGEST_SIZE)) 106 | } 107 | 108 | #[cfg(test)] 109 | mod tests { 110 | use super::*; 111 | use crate::paillier::KeyGeneration; 112 | use crate::paillier::Paillier; 113 | 114 | #[cfg(target_arch = "wasm32")] 115 | use wasm_bindgen_test::*; 116 | 117 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] 118 | #[test] 119 | fn test_correct_zk_proof() { 120 | let (ek, dk) = Paillier::keypair().keys(); 121 | let proof = NICorrectKeyProof::proof(&dk); 122 | assert!(proof.verify(&ek).is_ok()); 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/paillier/zkproofs/mod.rs: -------------------------------------------------------------------------------- 1 | /* 2 | zk-paillier 3 | 4 | Copyright 2018 by Kzen Networks 5 | 6 | This file is part of Multisig Schnorr library 7 | (https://github.com/KZen-networks/multisig-schnorr) 8 | 9 | zk-paillier is free software: you can redistribute 10 | it and/or modify it under the terms of the GNU General Public 11 | License as published by the Free Software Foundation, either 12 | version 3 of the License, or (at your option) any later version. 13 | 14 | @license GPL-3.0+ 15 | */ 16 | 17 | mod correct_key_ni; 18 | pub use self::correct_key_ni::CorrectKeyProofError; 19 | pub use self::correct_key_ni::NICorrectKeyProof; 20 | mod wi_dlog_proof; 21 | pub use self::wi_dlog_proof::DLogStatement; 22 | -------------------------------------------------------------------------------- /src/paillier/zkproofs/wi_dlog_proof.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | /* 3 | zk-paillier 4 | 5 | Copyright 2018 by Kzen Networks 6 | 7 | zk-paillier is free software: you can redistribute 8 | it and/or modify it under the terms of the GNU General Public 9 | License as published by the Free Software Foundation, either 10 | version 3 of the License, or (at your option) any later version. 11 | 12 | @license GPL-3.0+ 13 | */ 14 | 15 | use std::iter; 16 | 17 | use crate::curv::arithmetic::num_bigint::BigInt; 18 | use crate::curv::arithmetic::traits::*; 19 | use crate::num_integer::Integer; 20 | use serde::{Deserialize, Serialize}; 21 | 22 | use crate::num_traits::One; 23 | use crate::num_traits::Pow; 24 | use digest::Digest; 25 | use sha2::Sha256; 26 | 27 | use std::error::Error; 28 | use std::fmt; 29 | 30 | #[derive(Debug, Clone)] 31 | pub struct IncorrectProof; 32 | 33 | impl fmt::Display for IncorrectProof { 34 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 35 | write!(f, "given proof doesn't match a statement") 36 | } 37 | } 38 | 39 | impl Error for IncorrectProof {} 40 | 41 | use std::borrow::Borrow; 42 | #[allow(dead_code)] 43 | pub fn compute_digest(it: IT) -> BigInt 44 | where 45 | IT: Iterator, 46 | IT::Item: Borrow, 47 | { 48 | let mut hasher = Sha256::new(); 49 | for value in it { 50 | let bytes: Vec = value.borrow().to_bytes_be(); 51 | hasher.update(&bytes); 52 | } 53 | 54 | let result_bytes = hasher.finalize(); 55 | BigInt::from_bytes(&result_bytes[..]) 56 | } 57 | #[allow(dead_code)] 58 | const K: usize = 128; 59 | #[allow(dead_code)] 60 | const K_PRIME: usize = 128; 61 | #[allow(dead_code)] 62 | const SAMPLE_S: usize = 256; 63 | 64 | /// Witness Indistinguishable Proof of knowledge of discrete log with composite modulus. 65 | /// 66 | /// We follow the Girault’s proof from Pointcheval paper (figure1): 67 | /// https://www.di.ens.fr/david.pointcheval/Documents/Papers/2000_pkcA.pdf 68 | /// The prover wants to prove knowledge of a secret s given a public v = g^-{s} mod N for composite N 69 | #[derive(Debug, Serialize, Deserialize, Clone)] 70 | pub struct CompositeDLogProof { 71 | pub x: BigInt, 72 | pub y: BigInt, 73 | } 74 | 75 | #[derive(Debug, Serialize, Deserialize, Clone)] 76 | pub struct DLogStatement { 77 | pub N: BigInt, 78 | pub g: BigInt, 79 | pub ni: BigInt, 80 | } 81 | 82 | impl CompositeDLogProof { 83 | #[allow(dead_code)] 84 | pub fn prove(statement: &DLogStatement, secret: &BigInt) -> CompositeDLogProof { 85 | // pub fn prove(statement: &DLogStatement, secret: &BigInt, dk: &DecryptionKey) -> DLogProof{ 86 | 87 | // let one = BigInt::one(); 88 | // let phi = (&dk.p - &one) * (&dk.q - &one); 89 | // let r = BigInt::sample_below(&phi); 90 | 91 | let R = BigInt::from(2u32).pow((K + K_PRIME + SAMPLE_S) as u32); 92 | let r = BigInt::sample_below(&R); 93 | let x = BigInt::mod_pow(&statement.g, &r, &statement.N); 94 | let e = compute_digest( 95 | iter::once(&x) 96 | .chain(iter::once(&statement.g)) 97 | .chain(iter::once(&statement.N)) 98 | .chain(iter::once(&statement.ni)), 99 | ); 100 | let y = &r + &e * secret; 101 | 102 | CompositeDLogProof { x, y } 103 | } 104 | #[allow(dead_code)] 105 | pub fn verify(&self, statement: &DLogStatement) -> Result<(), IncorrectProof> { 106 | //assert N > 2^k 107 | assert!(statement.N > BigInt::from(2u32).pow(K as u32)); 108 | 109 | //test that g, ni in multiplecative group Z_N* 110 | assert_eq!(statement.g.gcd(&statement.N), BigInt::one()); 111 | assert_eq!(statement.ni.gcd(&statement.N), BigInt::one()); 112 | 113 | let e = compute_digest( 114 | iter::once(&self.x) 115 | .chain(iter::once(&statement.g)) 116 | .chain(iter::once(&statement.N)) 117 | .chain(iter::once(&statement.ni)), 118 | ); 119 | let ni_e = BigInt::mod_pow(&statement.ni, &e, &statement.N); 120 | let g_y = BigInt::mod_pow(&statement.g, &self.y, &statement.N); 121 | let g_y_ni_e = BigInt::mod_mul(&g_y, &ni_e, &statement.N); 122 | 123 | // x=? g^yv^e modN 124 | if self.x == g_y_ni_e { 125 | Ok(()) 126 | } else { 127 | Err(IncorrectProof) 128 | } 129 | } 130 | } 131 | #[allow(dead_code)] 132 | pub fn legendre_symbol(a: &BigInt, p: &BigInt) -> i32 { 133 | let p_minus_1: BigInt = p - BigInt::one(); 134 | let pow = BigInt::mod_mul(&p_minus_1, &BigInt::mod_inv(&BigInt::from(2u32), p), p); 135 | let ls = BigInt::mod_pow(a, &pow, p); 136 | if ls == BigInt::one() { 137 | 1 138 | } else { 139 | -1 140 | } 141 | } 142 | 143 | #[cfg(test)] 144 | mod tests { 145 | 146 | use super::*; 147 | use crate::paillier::KeyGeneration; 148 | use crate::paillier::Paillier; 149 | 150 | #[test] 151 | fn test_correct_dlog_proof() { 152 | // should be safe primes (not sure if there is actual attack) 153 | let (ek, dk) = Paillier::keypair().keys(); 154 | let one = BigInt::one(); 155 | let S = BigInt::from(2u32).pow(SAMPLE_S as u32); 156 | // Per definition 3 in the paper we need to make sure h1 is asymmetric basis: 157 | // Jacobi symbol should be -1. 158 | let mut h1 = BigInt::sample_range(&one, &(&ek.n - &one)); 159 | let mut jacobi_symbol = legendre_symbol(&h1, &dk.p) * legendre_symbol(&h1, &dk.q); 160 | while jacobi_symbol != -1 { 161 | h1 = BigInt::sample_range(&one, &(&ek.n - &one)); 162 | jacobi_symbol = legendre_symbol(&h1, &dk.p) * legendre_symbol(&h1, &dk.q); 163 | } 164 | let secret = BigInt::sample_below(&S); 165 | let h1_inv = BigInt::mod_inv(&h1, &ek.n); 166 | let h2 = BigInt::mod_pow(&h1_inv, &secret, &ek.n); 167 | let statement = DLogStatement { 168 | N: ek.n, 169 | g: h1, 170 | ni: h2, 171 | }; 172 | let proof = CompositeDLogProof::prove(&statement, &secret); 173 | let v = proof.verify(&statement); 174 | assert!(v.is_ok()); 175 | } 176 | 177 | #[test] 178 | #[should_panic] 179 | fn test_bad_dlog_proof() { 180 | let (ek, dk) = Paillier::keypair().keys(); 181 | let one = BigInt::one(); 182 | let S = BigInt::from(2u32).pow(SAMPLE_S as u32); 183 | // Per definition 3 in the paper we need to make sure h1 is asymmetric basis: 184 | // Jacobi symbol should be -1. 185 | let mut h1 = BigInt::sample_range(&one, &(&ek.n - &one)); 186 | let mut jacobi_symbol = legendre_symbol(&h1, &dk.p) * legendre_symbol(&h1, &dk.q); 187 | while jacobi_symbol != -1 { 188 | h1 = BigInt::sample_range(&one, &(&ek.n - &one)); 189 | jacobi_symbol = legendre_symbol(&h1, &dk.p) * legendre_symbol(&h1, &dk.q); 190 | } 191 | let secret = BigInt::sample_below(&S); 192 | // here we use "+secret", instead of "-secret". 193 | let h2 = BigInt::mod_pow(&h1, &(secret), &ek.n); 194 | let statement = DLogStatement { 195 | N: ek.n, 196 | g: h1, 197 | ni: h2, 198 | }; 199 | let proof = CompositeDLogProof::prove(&statement, &secret); 200 | let v = proof.verify(&statement); 201 | assert!(v.is_ok()); 202 | } 203 | 204 | #[test] 205 | #[should_panic] 206 | fn test_bad_dlog_proof_2() { 207 | let (ek, dk) = Paillier::keypair().keys(); 208 | let one = BigInt::one(); 209 | let S = BigInt::from(2u32).pow(SAMPLE_S as u32); 210 | // Per definition 3 in the paper we need to make sure h1 is asymmetric basis: 211 | // Jacobi symbol should be -1. 212 | let mut h1 = BigInt::sample_range(&one, &(&ek.n - &one)); 213 | let mut jacobi_symbol = legendre_symbol(&h1, &dk.p) * legendre_symbol(&h1, &dk.q); 214 | while jacobi_symbol != -1 { 215 | h1 = BigInt::sample_range(&one, &(&ek.n - &one)); 216 | jacobi_symbol = legendre_symbol(&h1, &dk.p) * legendre_symbol(&h1, &dk.q); 217 | } 218 | let secret = BigInt::sample_below(&S); 219 | // here we let h2 to be sampled in random 220 | let h2 = BigInt::sample_range(&one, &(&ek.n - &one)); 221 | 222 | let statement = DLogStatement { 223 | N: ek.n, 224 | g: h1, 225 | ni: h2, 226 | }; 227 | let proof = CompositeDLogProof::prove(&statement, &secret); 228 | let v = proof.verify(&statement); 229 | assert!(v.is_ok()); 230 | } 231 | } 232 | -------------------------------------------------------------------------------- /tests/common/mod.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | 3 | #[cfg(not(target_arch = "wasm32"))] 4 | pub const BENCH_SAMPLE_SIZE: usize = 10; 5 | 6 | /* 7 | Multi-party ECDSA 8 | 9 | Copyright 2018 by Kzen Networks 10 | 11 | This file is part of Multi-party ECDSA library 12 | (https://github.com/KZen-networks/multi-party-ecdsa) 13 | 14 | Multi-party ECDSA is free software: you can redistribute 15 | it and/or modify it under the terms of the GNU General Public 16 | License as published by the Free Software Foundation, either 17 | version 3 of the License, or (at your option) any later version. 18 | 19 | @license GPL-3.0+ 20 | */ 21 | 22 | use tss_wasm::curv::arithmetic::num_bigint::from; 23 | use tss_wasm::curv::cryptographic_primitives::hashing::hash_sha256::HSha256; 24 | use tss_wasm::curv::cryptographic_primitives::hashing::traits::Hash; 25 | use tss_wasm::curv::cryptographic_primitives::proofs::sigma_dlog::DLogProof; 26 | use tss_wasm::curv::cryptographic_primitives::secret_sharing::feldman_vss::VerifiableSS; 27 | use tss_wasm::curv::elliptic::curves::secp256_k1::{FE, GE}; 28 | use tss_wasm::curv::elliptic::curves::traits::*; 29 | 30 | use tss_wasm::gg_2018::mta::*; 31 | use tss_wasm::gg_2018::party_i::*; 32 | 33 | pub fn keygen_t_n_parties( 34 | t: usize, 35 | n: usize, 36 | ) -> (Vec, Vec, Vec, GE, VerifiableSS) { 37 | let parames = Parameters { 38 | threshold: t, 39 | share_count: n.clone(), 40 | }; 41 | let party_keys_vec = (0..n.clone()) 42 | .map(|i| Keys::create(i)) 43 | .collect::>(); 44 | 45 | let mut bc1_vec = Vec::new(); 46 | let mut decom_vec = Vec::new(); 47 | for i in 0..n.clone() { 48 | let (bc1, decom1) = party_keys_vec[i].phase1_broadcast_phase3_proof_of_correct_key(); 49 | bc1_vec.push(bc1); 50 | decom_vec.push(decom1); 51 | } 52 | 53 | let y_vec = (0..n.clone()) 54 | .map(|i| decom_vec[i].y_i.clone()) 55 | .collect::>(); 56 | let mut y_vec_iter = y_vec.iter(); 57 | let head = y_vec_iter.next().unwrap(); 58 | let tail = y_vec_iter; 59 | let y_sum = tail.fold(head.clone(), |acc, x| acc + x); 60 | let mut vss_scheme_vec = Vec::new(); 61 | let mut secret_shares_vec = Vec::new(); 62 | let mut index_vec = Vec::new(); 63 | for i in 0..n.clone() { 64 | let (vss_scheme, secret_shares, index) = party_keys_vec[i] 65 | .phase1_verify_com_phase3_verify_correct_key_phase2_distribute( 66 | ¶mes, &decom_vec, &bc1_vec, 67 | ) 68 | .expect("invalid key"); 69 | vss_scheme_vec.push(vss_scheme); 70 | secret_shares_vec.push(secret_shares); 71 | index_vec.push(index); 72 | } 73 | let vss_scheme_for_test = vss_scheme_vec.clone(); 74 | 75 | let party_shares = (0..n.clone()) 76 | .map(|i| { 77 | (0..n.clone()) 78 | .map(|j| { 79 | let vec_j = &secret_shares_vec[j]; 80 | vec_j[i].clone() 81 | }) 82 | .collect::>() 83 | }) 84 | .collect::>>(); 85 | 86 | let mut shared_keys_vec = Vec::new(); 87 | let mut dlog_proof_vec = Vec::new(); 88 | for i in 0..n.clone() { 89 | let (shared_keys, dlog_proof) = party_keys_vec[i] 90 | .phase2_verify_vss_construct_keypair_phase3_pok_dlog( 91 | ¶mes, 92 | &y_vec, 93 | &party_shares[i], 94 | &vss_scheme_vec, 95 | &(&index_vec[i] + 1), 96 | ) 97 | .expect("invalid vss"); 98 | shared_keys_vec.push(shared_keys); 99 | dlog_proof_vec.push(dlog_proof); 100 | } 101 | 102 | let pk_vec = (0..n.clone()) 103 | .map(|i| dlog_proof_vec[i].pk.clone()) 104 | .collect::>(); 105 | 106 | //both parties run: 107 | Keys::verify_dlog_proofs(¶mes, &dlog_proof_vec, &y_vec).expect("bad dlog proof"); 108 | 109 | //test 110 | let xi_vec = (0..t.clone() + 1) 111 | .map(|i| shared_keys_vec[i].x_i.clone()) 112 | .collect::>(); 113 | let x = vss_scheme_for_test[0] 114 | .clone() 115 | .reconstruct(&index_vec[0..t.clone() + 1], &xi_vec); 116 | let sum_u_i = party_keys_vec 117 | .iter() 118 | .fold(FE::zero(), |acc, x| acc + &x.u_i); 119 | assert_eq!(x, sum_u_i); 120 | 121 | ( 122 | party_keys_vec, 123 | shared_keys_vec, 124 | pk_vec, 125 | y_sum, 126 | vss_scheme_for_test[0].clone(), 127 | ) 128 | } 129 | 130 | #[allow(dead_code)] 131 | pub fn sign(t: usize, n: usize, ttag: usize, s: Vec) { 132 | // full key gen emulation 133 | let (party_keys_vec, shared_keys_vec, _pk_vec, y, vss_scheme) = 134 | keygen_t_n_parties(t.clone(), n); 135 | 136 | let private_vec = (0..shared_keys_vec.len()) 137 | .map(|i| PartyPrivate::set_private(party_keys_vec[i].clone(), shared_keys_vec[i].clone())) 138 | .collect::>(); 139 | // make sure that we have t t); 143 | assert_eq!(s.len(), ttag); 144 | 145 | // each party creates a signing key. This happens in parallel IRL. In this test we 146 | // create a vector of signing keys, one for each party. 147 | // throughout i will index parties 148 | let sign_keys_vec = (0..ttag) 149 | .map(|i| SignKeys::create(&private_vec[s[i]], &vss_scheme, s[i], &s)) 150 | .collect::>(); 151 | 152 | // each party computes [Ci,Di] = com(g^gamma_i) and broadcast the commitments 153 | let mut bc1_vec = Vec::new(); 154 | let mut decommit_vec1 = Vec::new(); 155 | for i in 0..ttag.clone() { 156 | let (com, decommit_phase_1) = sign_keys_vec[i].phase1_broadcast(); 157 | bc1_vec.push(com); 158 | decommit_vec1.push(decommit_phase_1); 159 | } 160 | 161 | // each party i sends encryption of k_i under her Paillier key 162 | // m_a_vec = [ma_0;ma_1;,...] 163 | let mut m_a_vec = Vec::new(); 164 | for i in 0..ttag.clone() { 165 | let (m_a_k, _) = MessageA::a(&sign_keys_vec[i].k_i, &party_keys_vec[s[i]].ek, &[]); 166 | 167 | m_a_vec.push(m_a_k); 168 | } 169 | 170 | // each party i sends responses to m_a_vec she received (one response with input gamma_i and one with w_i) 171 | // m_b_gamma_vec_all is a matrix where column i is a vector of message_b's that party i answers to all ma_{j!=i} using paillier key of party j to answer to ma_j 172 | 173 | // aggregation of the n messages of all parties 174 | let mut m_b_gamma_vec_all = Vec::new(); 175 | let mut beta_vec_all = Vec::new(); 176 | let mut m_b_w_vec_all = Vec::new(); 177 | let mut ni_vec_all = Vec::new(); 178 | 179 | for i in 0..ttag.clone() { 180 | let mut m_b_gamma_vec = Vec::new(); 181 | let mut beta_vec = Vec::new(); 182 | let mut m_b_w_vec = Vec::new(); 183 | let mut ni_vec = Vec::new(); 184 | 185 | for j in 0..ttag - 1 { 186 | let ind = if j < i { j } else { j + 1 }; 187 | 188 | let (m_b_gamma, beta_gamma, _, _) = MessageB::b( 189 | &sign_keys_vec[i].gamma_i, 190 | &party_keys_vec[s[ind]].ek, 191 | m_a_vec[ind].clone(), 192 | &[], 193 | ) 194 | .unwrap(); 195 | let (m_b_w, beta_wi, _, _) = MessageB::b( 196 | &sign_keys_vec[i].w_i, 197 | &party_keys_vec[s[ind]].ek, 198 | m_a_vec[ind].clone(), 199 | &[], 200 | ) 201 | .unwrap(); 202 | 203 | m_b_gamma_vec.push(m_b_gamma); 204 | beta_vec.push(beta_gamma); 205 | m_b_w_vec.push(m_b_w); 206 | ni_vec.push(beta_wi); 207 | } 208 | m_b_gamma_vec_all.push(m_b_gamma_vec.clone()); 209 | beta_vec_all.push(beta_vec.clone()); 210 | m_b_w_vec_all.push(m_b_w_vec.clone()); 211 | ni_vec_all.push(ni_vec.clone()); 212 | } 213 | 214 | // Here we complete the MwA protocols by taking the mb matrices and starting with the first column generating the appropriate message 215 | // for example for index i=0 j=0 we need party at index s[1] to answer to mb that party s[0] sent, completing a protocol between s[0] and s[1]. 216 | // for index i=1 j=0 we need party at index s[0] to answer to mb that party s[1]. etc. 217 | // IRL each party i should get only the mb messages that other parties sent in response to the party i ma's. 218 | // TODO: simulate as IRL 219 | let mut alpha_vec_all = Vec::new(); 220 | let mut miu_vec_all = Vec::new(); 221 | 222 | for i in 0..ttag.clone() { 223 | let mut alpha_vec = Vec::new(); 224 | let mut miu_vec = Vec::new(); 225 | 226 | let m_b_gamma_vec_i = &m_b_gamma_vec_all[i]; 227 | let m_b_w_vec_i = &m_b_w_vec_all[i]; 228 | 229 | for j in 0..ttag - 1 { 230 | let ind = if j < i { j } else { j + 1 }; 231 | let m_b = m_b_gamma_vec_i[j].clone(); 232 | 233 | let alpha_ij_gamma = m_b 234 | .verify_proofs_get_alpha(&party_keys_vec[s[ind]].dk, &sign_keys_vec[ind].k_i) 235 | .expect("wrong dlog or m_b"); 236 | let m_b = m_b_w_vec_i[j].clone(); 237 | let alpha_ij_wi = m_b 238 | .verify_proofs_get_alpha(&party_keys_vec[s[ind]].dk, &sign_keys_vec[ind].k_i) 239 | .expect("wrong dlog or m_b"); 240 | 241 | // since we actually run two MtAwc each party needs to make sure that the values B are the same as the public values 242 | // here for b=w_i the parties already know W_i = g^w_i for each party so this check is done here. for b = gamma_i the check will be later when g^gamma_i will become public 243 | // currently we take the W_i from the other parties signing keys 244 | // TODO: use pk_vec (first change from x_i to w_i) for this check. 245 | assert_eq!(m_b.b_proof.pk.clone(), sign_keys_vec[i].g_w_i.clone()); 246 | 247 | alpha_vec.push(alpha_ij_gamma.0); 248 | miu_vec.push(alpha_ij_wi.0); 249 | } 250 | alpha_vec_all.push(alpha_vec.clone()); 251 | miu_vec_all.push(miu_vec.clone()); 252 | } 253 | 254 | let mut delta_vec = Vec::new(); 255 | let mut sigma_vec = Vec::new(); 256 | 257 | for i in 0..ttag.clone() { 258 | let delta = sign_keys_vec[i].phase2_delta_i(&alpha_vec_all[i], &beta_vec_all[i]); 259 | let sigma = sign_keys_vec[i].phase2_sigma_i(&miu_vec_all[i], &ni_vec_all[i]); 260 | delta_vec.push(delta); 261 | sigma_vec.push(sigma); 262 | } 263 | 264 | // all parties broadcast delta_i and compute delta_i ^(-1) 265 | let delta_inv = SignKeys::phase3_reconstruct_delta(&delta_vec); 266 | 267 | // de-commit to g^gamma_i from phase1, test comm correctness, and that it is the same value used in MtA. 268 | // Return R 269 | 270 | let _g_gamma_i_vec = (0..ttag) 271 | .map(|i| sign_keys_vec[i].g_gamma_i.clone()) 272 | .collect::>(); 273 | 274 | let R_vec = (0..ttag) 275 | .map(|_| { 276 | // each party i tests all B = g^b = g ^ gamma_i she received. 277 | let b_proof_vec = (0..ttag) 278 | .map(|j| { 279 | let b_gamma_vec = &m_b_gamma_vec_all[j]; 280 | &b_gamma_vec[0].b_proof 281 | }) 282 | .collect::>(); 283 | let R = SignKeys::phase4(&delta_inv, &b_proof_vec, decommit_vec1.clone(), &bc1_vec) 284 | .expect("bad gamma_i decommit"); 285 | R 286 | }) 287 | .collect::>(); 288 | 289 | let message: [u8; 4] = [79, 77, 69, 82]; 290 | 291 | let message_bn = HSha256::create_hash(&vec![&from(&message[..])]); 292 | let mut local_sig_vec = Vec::new(); 293 | 294 | // each party computes s_i but don't send it yet. we start with phase5 295 | for i in 0..ttag.clone() { 296 | let local_sig = LocalSignature::phase5_local_sig( 297 | &sign_keys_vec[i].k_i, 298 | &message_bn, 299 | &R_vec[i], 300 | &sigma_vec[i], 301 | &y, 302 | ); 303 | local_sig_vec.push(local_sig); 304 | } 305 | 306 | let mut phase5_com_vec: Vec = Vec::new(); 307 | let mut phase_5a_decom_vec: Vec = Vec::new(); 308 | let mut helgamal_proof_vec = Vec::new(); 309 | // we notice that the proof for V= R^sg^l, B = A^l is a general form of homomorphic elgamal. 310 | let mut dlog_proof_rho_vec = Vec::new(); 311 | for i in 0..ttag.clone() { 312 | let (phase5_com, phase_5a_decom, helgamal_proof, dlog_proof_rho) = 313 | local_sig_vec[i].phase5a_broadcast_5b_zkproof(); 314 | phase5_com_vec.push(phase5_com); 315 | phase_5a_decom_vec.push(phase_5a_decom); 316 | helgamal_proof_vec.push(helgamal_proof); 317 | dlog_proof_rho_vec.push(dlog_proof_rho); 318 | } 319 | 320 | let mut phase5_com2_vec = Vec::new(); 321 | let mut phase_5d_decom2_vec = Vec::new(); 322 | for i in 0..ttag.clone() { 323 | let mut phase_5a_decom_vec_clone = phase_5a_decom_vec.clone(); 324 | let mut phase_5a_com_vec_clone = phase5_com_vec.clone(); 325 | let mut phase_5b_elgamal_vec_clone = helgamal_proof_vec.clone(); 326 | let mut phase_5a_dlog_vec_clone = dlog_proof_rho_vec.clone(); 327 | 328 | let _decom_i = phase_5a_decom_vec_clone.remove(i); 329 | let _com_i = phase_5a_com_vec_clone.remove(i); 330 | let _elgamal_i = phase_5b_elgamal_vec_clone.remove(i); 331 | let _dlog_proof_rho = phase_5a_dlog_vec_clone.remove(i); 332 | // for j in 0..s_minus_i.len() { 333 | let (phase5_com2, phase_5d_decom2) = local_sig_vec[i] 334 | .phase5c( 335 | &phase_5a_decom_vec_clone, 336 | &phase_5a_com_vec_clone, 337 | &phase_5b_elgamal_vec_clone, 338 | &phase_5a_dlog_vec_clone, 339 | &phase_5a_decom_vec[i].V_i, 340 | &R_vec[0], 341 | ) 342 | .expect("error phase5"); 343 | phase5_com2_vec.push(phase5_com2); 344 | phase_5d_decom2_vec.push(phase_5d_decom2); 345 | // } 346 | } 347 | 348 | // assuming phase5 checks passes each party sends s_i and compute sum_i{s_i} 349 | let mut s_vec: Vec = Vec::new(); 350 | for i in 0..ttag.clone() { 351 | let s_i = local_sig_vec[i] 352 | .phase5d(&phase_5d_decom2_vec, &phase5_com2_vec, &phase_5a_decom_vec) 353 | .expect("bad com 5d"); 354 | s_vec.push(s_i); 355 | } 356 | 357 | // here we compute the signature only of party i=0 to demonstrate correctness. 358 | s_vec.remove(0); 359 | let _sig = local_sig_vec[0] 360 | .output_signature(&s_vec) 361 | .expect("verification failed"); 362 | } 363 | -------------------------------------------------------------------------------- /tests/keygen.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | #[cfg(not(target_arch = "wasm32"))] 3 | extern crate criterion; 4 | 5 | #[cfg(target_arch = "wasm32")] 6 | extern crate wasm_bindgen; 7 | 8 | #[cfg(all(test, target_arch = "wasm32"))] 9 | extern crate wasm_bindgen_test; 10 | 11 | mod common; 12 | 13 | #[cfg(target_arch = "wasm32")] 14 | use wasm_bindgen_test::*; 15 | 16 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] 17 | #[test] 18 | fn test_keygen_t1_n2() { 19 | common::keygen_t_n_parties(1, 2); 20 | } 21 | 22 | /* TODO: comment to speed up CI 23 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] 24 | #[test] 25 | fn test_keygen_t2_n3() { 26 | common::keygen_t_n_parties(2, 3); 27 | } 28 | 29 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] 30 | #[test] 31 | fn test_keygen_t2_n4() { 32 | common::keygen_t_n_parties(2, 4); 33 | } 34 | */ 35 | 36 | #[cfg(not(target_arch = "wasm32"))] 37 | pub mod bench { 38 | use criterion::Criterion; 39 | 40 | pub fn bench_full_keygen_party_one_two(c: &mut Criterion) { 41 | c.bench_function("keygen t=1 n=2", move |b| { 42 | b.iter(|| { 43 | super::common::keygen_t_n_parties(1, 2); 44 | }) 45 | }); 46 | } 47 | 48 | pub fn bench_full_keygen_party_two_three(c: &mut Criterion) { 49 | c.bench_function("keygen t=2 n=3", move |b| { 50 | b.iter(|| { 51 | super::common::keygen_t_n_parties(2, 3); 52 | }) 53 | }); 54 | } 55 | 56 | criterion_group! { 57 | name = keygen; 58 | config = Criterion::default().sample_size(super::common::BENCH_SAMPLE_SIZE); 59 | targets = 60 | self::bench_full_keygen_party_one_two, 61 | self::bench_full_keygen_party_two_three 62 | } 63 | } 64 | 65 | #[cfg(not(target_arch = "wasm32"))] 66 | criterion_main!(bench::keygen); 67 | -------------------------------------------------------------------------------- /tests/mta.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | 3 | /* 4 | Multi-party ECDSA 5 | 6 | Copyright 2018 by Kzen Networks 7 | 8 | This file is part of Multi-party ECDSA library 9 | (https://github.com/KZen-networks/multi-party-ecdsa) 10 | 11 | Multi-party ECDSA is free software: you can redistribute 12 | it and/or modify it under the terms of the GNU General Public 13 | License as published by the Free Software Foundation, either 14 | version 3 of the License, or (at your option) any later version. 15 | 16 | @license GPL-3.0+ 17 | */ 18 | #[cfg(target_arch = "wasm32")] 19 | extern crate wasm_bindgen; 20 | 21 | #[cfg(all(test, target_arch = "wasm32"))] 22 | extern crate wasm_bindgen_test; 23 | 24 | use tss_wasm::curv::elliptic::curves::secp256_k1::FE; 25 | use tss_wasm::curv::elliptic::curves::traits::*; 26 | 27 | use tss_wasm::gg_2018::mta::*; 28 | use tss_wasm::paillier::*; 29 | 30 | #[cfg(target_arch = "wasm32")] 31 | use wasm_bindgen_test::*; 32 | 33 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] 34 | #[test] 35 | fn test_mta() { 36 | let alice_input: FE = ECScalar::new_random(); 37 | let keypair = Paillier::keypair(); 38 | let (ek_alice, dk_alice) = keypair.keys(); 39 | /* 40 | let p = str::parse("148677972634832330983979593310074301486537017973460461278300587514468301043894574906886127642530475786889672304776052879927627556769456140664043088700743909632312483413393134504352834240399191134336344285483935856491230340093391784574980688823380828143810804684752914935441384845195613674104960646037368551517").unwrap(); 41 | let q = str::parse("158741574437007245654463598139927898730476924736461654463975966787719309357536545869203069369466212089132653564188443272208127277664424448947476335413293018778018615899291704693105620242763173357203898195318179150836424196645745308205164116144020613415407736216097185962171301808761138424668335445923774195463").unwrap(); 42 | let keypair = Keypair { p, q }; 43 | let (ek_alice, dk_alice) = keypair.keys(); 44 | */ 45 | let bob_input: FE = ECScalar::new_random(); 46 | let (m_a, _) = MessageA::a(&alice_input, &ek_alice, &[]); 47 | let (m_b, beta, _, _) = MessageB::b(&bob_input, &ek_alice, m_a, &[]).unwrap(); 48 | let alpha = m_b 49 | .verify_proofs_get_alpha(&dk_alice, &alice_input) 50 | .expect("wrong dlog or m_b"); 51 | 52 | let left = alpha.0 + beta; 53 | let right = alice_input * bob_input; 54 | assert_eq!(left.get_element(), right.get_element()); 55 | } 56 | -------------------------------------------------------------------------------- /tests/sign.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | #[cfg(not(target_arch = "wasm32"))] 3 | extern crate criterion; 4 | 5 | #[cfg(target_arch = "wasm32")] 6 | extern crate wasm_bindgen; 7 | 8 | #[cfg(all(test, target_arch = "wasm32"))] 9 | extern crate wasm_bindgen_test; 10 | 11 | mod common; 12 | 13 | #[cfg(target_arch = "wasm32")] 14 | use wasm_bindgen_test::*; 15 | 16 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] 17 | #[test] 18 | fn test_sign_n3_t1_ttag2() { 19 | common::sign(1, 3, 2, vec![0, 2]); 20 | } 21 | 22 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] 23 | #[test] 24 | fn test_sign_n3_t2_ttag3() { 25 | common::sign(2, 3, 3, vec![0, 1, 2]); 26 | } 27 | 28 | /* TODO: comment to speed up CI 29 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] 30 | #[test] 31 | fn test_sign_n5_t2_ttag4() { 32 | common::sign(2, 5, 4, vec![0, 2, 3, 4]) 33 | } 34 | 35 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] 36 | #[test] 37 | fn test_sign_n8_t4_ttag6() { 38 | common::sign(4, 8, 6, vec![0, 1, 2, 4, 6, 7]) 39 | } 40 | */ 41 | 42 | #[cfg(not(target_arch = "wasm32"))] 43 | pub mod bench { 44 | use criterion::Criterion; 45 | 46 | pub fn bench_sign_n3_t1_ttag2(c: &mut Criterion) { 47 | c.bench_function("sign n=3 t=1 ttag=2", move |b| { 48 | b.iter(|| { 49 | super::common::sign(1, 3, 2, vec![0, 2]); 50 | }) 51 | }); 52 | } 53 | 54 | pub fn bench_sign_n3_t2_ttag3(c: &mut Criterion) { 55 | c.bench_function("sign n=3 t=2 ttag=3", move |b| { 56 | b.iter(|| { 57 | super::common::sign(2, 3, 3, vec![0, 1, 2]); 58 | }) 59 | }); 60 | } 61 | 62 | criterion_group! { 63 | name = sign; 64 | config = Criterion::default().sample_size(super::common::BENCH_SAMPLE_SIZE); 65 | targets = 66 | self::bench_sign_n3_t1_ttag2, 67 | self::bench_sign_n3_t2_ttag3 68 | } 69 | } 70 | 71 | #[cfg(not(target_arch = "wasm32"))] 72 | criterion_main!(bench::sign); 73 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 3 | const webpack = require('webpack'); 4 | const WasmPackPlugin = require("@wasm-tool/wasm-pack-plugin"); 5 | 6 | module.exports = { 7 | entry: './run_keygen_sign.js', 8 | output: { 9 | path: path.resolve(__dirname, 'dist'), 10 | filename: 'index.js', 11 | }, 12 | plugins: [ 13 | new HtmlWebpackPlugin(), 14 | new WasmPackPlugin({ 15 | crateDirectory: path.resolve(__dirname, ".") 16 | }), 17 | // Have this example work in Edge which doesn't ship `TextEncoder` or 18 | // `TextDecoder` at this time. 19 | new webpack.ProvidePlugin({ 20 | TextDecoder: ['text-encoding', 'TextDecoder'], 21 | TextEncoder: ['text-encoding', 'TextEncoder'] 22 | }) 23 | ], 24 | mode: 'development' 25 | }; 26 | --------------------------------------------------------------------------------