├── .gitignore ├── src ├── protocol │ ├── mod.rs │ ├── eq.rs │ ├── div.rs │ ├── mul.rs │ ├── add.rs │ ├── sub.rs │ └── com.rs ├── marco.rs └── lib.rs ├── Cargo.toml ├── .github └── workflows │ └── rust.yml ├── LICENSE-MIT └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /src/protocol/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod add; 2 | pub mod com; 3 | pub mod div; 4 | pub mod eq; 5 | pub mod mul; 6 | pub mod sub; 7 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "SVMZK" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | wedpr_l_crypto_zkp_utils = "1.2.0" 10 | curve25519-dalek = "1" 11 | 12 | [dev-dependencies] 13 | rand = "0.8" 14 | -------------------------------------------------------------------------------- /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | name: Rust 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v2 19 | - name: Nightly 20 | run: rustup install nightly 21 | - name: Build 22 | run: cargo +nightly build --release --verbose 23 | - name: Run tests 24 | run: cargo +nightly test --verbose 25 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 SatoshiVM 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SVMZK 2 | 3 | We describe SVMZK – an efficient NIZK proof toolkit. Given commitments [a], [b], [c], the prover 4 | is able to convince the verifier either one of the following relations: 5 | - Addition: a + b = c; 6 | - Subtraction: a − b = c; 7 | - Multiplication: a · b = c; 8 | - Division: a/b = c; 9 | - Equality: a = b; 10 | - Comparison: a ≥ b; 11 | 12 | ## Getting Started 13 | 14 | You need to have Rust and Cargo installed on your machine. If you haven't installed Rust, you can do so by following the instructions on the [official Rust website](https://www.rust-lang.org/learn/get-started). 15 | 16 | ### Build 17 | 18 | To build the project without launching it, you can use the following Cargo command: 19 | 20 | ```shell 21 | cargo build --release 22 | ``` 23 | 24 | ### Test 25 | 26 | To run the tests, do the following: 27 | 28 | ```shell 29 | cargo test 30 | ``` 31 | 32 | ## Examples 33 | 34 | ### prove x >= 0 35 | 36 | ``` 37 | use SVMZK::{Comparison, ComparisonProofWithPublicParams}; 38 | 39 | let input = 209348i32; 40 | let comm = Comparison::commit(input); 41 | 42 | let proof = Comparison::prove(&comm); 43 | 44 | let res = Comparison::verify(ComparisonProofWithPublicParams { 45 | proof: proof, 46 | x: comm.comm.point, 47 | }); 48 | 49 | assert_eq!(res,true); 50 | ``` 51 | -------------------------------------------------------------------------------- /src/marco.rs: -------------------------------------------------------------------------------- 1 | #[macro_export] 2 | macro_rules! test_comparison { 3 | ($size:expr) => { 4 | let a = $size; 5 | let comparison = Comparison::commit(a); 6 | 7 | let proof = Comparison::prove(&comparison); 8 | 9 | let res = Comparison::verify(ComparisonProofWithPublicParams { 10 | proof: proof, 11 | x: comparison.comm.point, 12 | }); 13 | assert_eq!(res, true); 14 | }; 15 | } 16 | 17 | #[macro_export] 18 | macro_rules! test_comparison_negative { 19 | ($size:expr) => { 20 | let a = $size; 21 | let comparison = Comparison::commit(a); 22 | 23 | let proof = Comparison::prove(&comparison); 24 | 25 | let res = Comparison::verify(ComparisonProofWithPublicParams { 26 | proof: proof, 27 | x: comparison.comm.point, 28 | }); 29 | assert_eq!(res, false); 30 | }; 31 | } 32 | 33 | #[macro_export] 34 | macro_rules! test_addition { 35 | ($a:expr,$b:expr,$c:expr,$result:expr) => { 36 | let a_comm_secret = Addition::commit($a); 37 | let b_comm_secret = Addition::commit($b); 38 | let c_comm_secret = Addition::commit_c_witness( 39 | $c, 40 | a_comm_secret.secret.secret, 41 | b_comm_secret.secret.secret, 42 | ); 43 | 44 | let proof = Addition::prove(&a_comm_secret, &b_comm_secret, &c_comm_secret); 45 | 46 | let result = Addition::verify(AdditionProofWithPublicParams { 47 | proof: proof, 48 | a_point: a_comm_secret.comm.point, 49 | b_point: b_comm_secret.comm.point, 50 | c_point: c_comm_secret.comm.point, 51 | }); 52 | 53 | assert_eq!($result, result); 54 | }; 55 | } 56 | 57 | #[macro_export] 58 | macro_rules! test_substration { 59 | ($a:expr,$b:expr,$c:expr,$result:expr) => { 60 | let a_comm_secret = Substraction::commit($a); 61 | let b_comm_secret = Substraction::commit($b); 62 | let c_comm_secret = Substraction::commit_c_witness( 63 | $c, 64 | a_comm_secret.secret.secret, 65 | b_comm_secret.secret.secret, 66 | ); 67 | 68 | let proof = Substraction::prove(&a_comm_secret, &b_comm_secret, &c_comm_secret); 69 | 70 | let result = Substraction::verify(SubstractionWithPublicParams { 71 | proof: proof, 72 | a_point: a_comm_secret.comm.point, 73 | b_point: b_comm_secret.comm.point, 74 | c_point: c_comm_secret.comm.point, 75 | }); 76 | 77 | assert_eq!($result, result); 78 | }; 79 | } 80 | 81 | #[macro_export] 82 | macro_rules! test_multiplication { 83 | ($a:expr,$b:expr,$c:expr) => { 84 | let a_comm_secret = Multiplication::commit($a); 85 | let b_comm_secret = Multiplication::commit($b); 86 | let c_comm_secret = Multiplication::commit($c); 87 | 88 | let witness = 89 | Multiplication::witness(a_comm_secret.secret.secret, c_comm_secret.secret.secret, $b); 90 | 91 | let proof = Multiplication::prove(&a_comm_secret, &b_comm_secret, &c_comm_secret, &witness); 92 | 93 | let result = Multiplication::verify(MultiplicationWithPublicParams { 94 | proof: proof, 95 | a_point: a_comm_secret.comm.point, 96 | b_point: b_comm_secret.comm.point, 97 | c_point: c_comm_secret.comm.point, 98 | }); 99 | 100 | assert_eq!(true, result); 101 | }; 102 | } 103 | 104 | #[macro_export] 105 | macro_rules! test_division { 106 | ($a:expr,$b:expr,$c:expr,$result:expr) => { 107 | let a_comm_secret = Division::commit($a); 108 | let b_comm_secret = Division::commit($b); 109 | let c_comm_secret = Division::commit($c); 110 | 111 | let witness = 112 | Division::witness(a_comm_secret.secret.secret, c_comm_secret.secret.secret, $b); 113 | 114 | let proof = Division::prove(&a_comm_secret, &b_comm_secret, &c_comm_secret, &witness); 115 | 116 | let result = Division::verify(DivisionWithPublicParams { 117 | proof: proof, 118 | a_point: a_comm_secret.comm.point, 119 | b_point: b_comm_secret.comm.point, 120 | c_point: c_comm_secret.comm.point, 121 | }); 122 | 123 | assert_eq!($result, result); 124 | }; 125 | } 126 | 127 | #[macro_export] 128 | macro_rules! test_equality { 129 | ($a:expr,$b:expr,$result:expr) => { 130 | let a_comm_secret = Equality::commit($a); 131 | let b_comm_secret = Equality::commit($b); 132 | let c_comm_secret = 133 | Equality::commit_c_witness(a_comm_secret.secret.secret, b_comm_secret.secret.secret); 134 | 135 | let proof = Equality::prove(&a_comm_secret, &b_comm_secret, &c_comm_secret); 136 | 137 | let result = Equality::verify(EqualityWithPublicParams { 138 | proof: proof, 139 | a_point: a_comm_secret.comm.point, 140 | b_point: b_comm_secret.comm.point, 141 | c_point: c_comm_secret.comm.point, 142 | }); 143 | 144 | assert_eq!($result, result); 145 | }; 146 | } 147 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_assignments)] 2 | #![allow(non_snake_case)] 3 | 4 | mod protocol; 5 | 6 | pub use protocol::{ 7 | add::{Addition, AdditionProofWithPublicParams}, 8 | com::{Comparison, ComparisonProofWithPublicParams}, 9 | div::{Division, DivisionWithPublicParams}, 10 | eq::{Equality, EqualityWithPublicParams}, 11 | mul::{Multiplication, MultiplicationWithPublicParams}, 12 | sub::{Substraction, SubstractionWithPublicParams}, 13 | }; 14 | mod marco; 15 | 16 | #[cfg(test)] 17 | mod com_tests { 18 | use super::*; 19 | use rand::Rng; 20 | 21 | /// prove x >= 0 22 | #[test] 23 | fn batch_comparison_protocol_test() { 24 | for i in 2i32..10i32 { 25 | test_comparison!(i); 26 | test_comparison_negative!(-i); 27 | } 28 | 29 | for i in 100000i32..100010i32 { 30 | test_comparison!(i); 31 | test_comparison_negative!(-i); 32 | } 33 | 34 | for i in 500000000i32..500000010i32 { 35 | test_comparison!(i); 36 | test_comparison_negative!(-i); 37 | } 38 | } 39 | 40 | /// prove x >= 0 41 | #[test] 42 | fn small_number_comparison_protocol_test() { 43 | test_comparison!(1); 44 | test_comparison!(0); 45 | test_comparison_negative!(-1); 46 | } 47 | 48 | /// prove x >= 0 49 | #[test] 50 | fn comparison_protocol_test() { 51 | let a = -20933i32; 52 | let comparison = Comparison::commit(a); 53 | 54 | let proof = Comparison::prove(&comparison); 55 | 56 | let res = Comparison::verify(ComparisonProofWithPublicParams { 57 | proof: proof, 58 | x: comparison.comm.point, 59 | }); 60 | assert_eq!(res, false); 61 | } 62 | 63 | /// prove x + y 64 | #[test] 65 | fn addition_protocol_test() { 66 | let mut test_data = vec![ 67 | (10, 58), 68 | (84, 118), 69 | (998, 558), 70 | (154584, 5488), 71 | (15u64.pow(4), 36u64.pow(5)), 72 | ]; 73 | for _ in 0..50 { 74 | let random_a = rand::thread_rng().gen_range(0u64..=1000000); 75 | let random_b = rand::thread_rng().gen_range(0u64..=1000000); 76 | test_data.push((random_a, random_b)) 77 | } 78 | for (x, y) in test_data.clone() { 79 | test_addition!(x, y, x + y, true); 80 | } 81 | for (x, y) in test_data { 82 | test_addition!(x, y, 100, false); 83 | } 84 | } 85 | 86 | /// prove x - y 87 | #[test] 88 | fn substraction_protocol_test() { 89 | let mut test_data = vec![ 90 | (150, 58), 91 | (844, 118), 92 | (998, 558), 93 | (154584, 5488), 94 | (19u64.pow(9), 3u64.pow(5)), 95 | ]; 96 | for _ in 0..50 { 97 | let random_a = rand::thread_rng().gen_range(0u64..=1000000); 98 | let random_b = rand::thread_rng().gen_range(0u64..=random_a); 99 | test_data.push((random_a, random_b)) 100 | } 101 | for (x, y) in test_data.clone() { 102 | test_substration!(x, y, x - y, true); 103 | } 104 | for (x, y) in test_data.clone() { 105 | test_substration!(x, y, x + y, false); 106 | } 107 | } 108 | 109 | /// prove x * y 110 | #[test] 111 | fn multiplication_protocol_test() { 112 | let mut test_data = vec![ 113 | (150, 58), 114 | (844, 118), 115 | (998, 558), 116 | (154584, 5488), 117 | (3u64.pow(6), 14u64.pow(4)), 118 | ]; 119 | for _ in 0..50 { 120 | let random_a = rand::thread_rng().gen_range(0u64..=1000000); 121 | let random_b = rand::thread_rng().gen_range(0u64..=1000000); 122 | test_data.push((random_a, random_b)) 123 | } 124 | for (x, y) in test_data { 125 | test_multiplication!(x, y, x * y); 126 | } 127 | } 128 | 129 | /// prove x / y 130 | #[test] 131 | fn division_protocol_test() { 132 | let mut test_data = vec![ 133 | (150, 50), 134 | (800, 200), 135 | (1000, 250), 136 | (2u64.pow(15), 2u64.pow(15)), 137 | ]; 138 | for _ in 0..50 { 139 | let random_a = rand::thread_rng().gen_range(0u64..=1000000); 140 | let random_b = rand::thread_rng().gen_range(0u64..=1000); 141 | let random_c = random_a * random_b; 142 | test_data.push((random_c, random_a)) 143 | } 144 | for (x, y) in test_data { 145 | test_division!(x, y, x / y, true); 146 | } 147 | 148 | let test_data = vec![ 149 | (150, 77), 150 | (222, 200), 151 | (53353, 250), 152 | (2u64.pow(15), 9u64.pow(14)), 153 | ]; 154 | for (x, y) in test_data { 155 | test_division!(x, y, x / y, false); 156 | } 157 | } 158 | 159 | /// prove x = y 160 | #[test] 161 | fn equality_protocol_test() { 162 | let test_data = vec![ 163 | (15, 15), 164 | (88, 88), 165 | (77777, 77777), 166 | (154584, 154584), 167 | (2u64.pow(15), 2u64.pow(15)), 168 | ]; 169 | for (x, y) in test_data { 170 | test_equality!(x, y, true); 171 | } 172 | let test_data = vec![ 173 | (150, 58), 174 | (844, 118), 175 | (998, 558), 176 | (154584, 5488), 177 | (2u64.pow(15), 3u64.pow(5)), 178 | ]; 179 | for (x, y) in test_data { 180 | test_equality!(x, y, false); 181 | } 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /src/protocol/eq.rs: -------------------------------------------------------------------------------- 1 | use curve25519_dalek::{ristretto::RistrettoPoint, scalar::Scalar, traits::MultiscalarMul}; 2 | use wedpr_l_crypto_zkp_utils::{ 3 | get_random_scalar, hash_to_scalar, point_to_bytes, BASEPOINT_G1, BASEPOINT_G2, 4 | }; 5 | 6 | /// eq 7 | #[derive(Debug, Clone, PartialEq, Eq)] 8 | pub struct Equality { 9 | pub comm: EqualityCommitment, 10 | pub secret: EqualitySecret, 11 | } 12 | 13 | #[derive(Debug, Clone, PartialEq, Eq)] 14 | pub struct EqualityCommitment { 15 | pub point: RistrettoPoint, 16 | } 17 | 18 | #[derive(Debug, Clone, PartialEq, Eq)] 19 | pub struct EqualitySecret { 20 | pub value: u64, 21 | pub secret: Scalar, 22 | } 23 | 24 | #[derive(Debug, Clone, PartialEq, Eq)] 25 | pub struct EqualityProof { 26 | pub d: RistrettoPoint, 27 | pub u: Scalar, 28 | } 29 | 30 | #[derive(Debug, Clone, PartialEq, Eq)] 31 | pub struct EqualityWithPublicParams { 32 | pub proof: EqualityProof, 33 | pub a_point: RistrettoPoint, 34 | pub b_point: RistrettoPoint, 35 | pub c_point: RistrettoPoint, 36 | } 37 | 38 | impl Equality { 39 | pub fn commit(value: u64) -> Self { 40 | let secret = get_random_scalar(); 41 | let commitment_point = RistrettoPoint::multiscalar_mul( 42 | &[Scalar::from(value), secret], 43 | &[*BASEPOINT_G1, *BASEPOINT_G2], 44 | ); 45 | 46 | Self { 47 | comm: EqualityCommitment { 48 | point: commitment_point, 49 | }, 50 | secret: EqualitySecret { 51 | value, 52 | secret, 53 | }, 54 | } 55 | } 56 | 57 | pub fn commit_c_witness(a_sec: Scalar, b_sec: Scalar) -> Self { 58 | let t = a_sec - b_sec; 59 | let commitment_point = t * *BASEPOINT_G2; 60 | 61 | Self { 62 | comm: EqualityCommitment { 63 | point: commitment_point, 64 | }, 65 | secret: EqualitySecret { 66 | value: 0, 67 | secret: t, 68 | }, 69 | } 70 | } 71 | 72 | pub fn prove(a: &Equality, b: &Equality, c: &Equality) -> EqualityProof { 73 | let Equality { 74 | comm: EqualityCommitment { point: a_point }, 75 | secret: 76 | EqualitySecret { 77 | value: _a_value, 78 | secret: _a_secret, 79 | }, 80 | } = a; 81 | let Equality { 82 | comm: EqualityCommitment { point: b_point }, 83 | secret: 84 | EqualitySecret { 85 | value: _b_value, 86 | secret: _b_secret, 87 | }, 88 | } = b; 89 | let Equality { 90 | comm: EqualityCommitment { point: _c_point }, 91 | secret: 92 | EqualitySecret { 93 | value: _c_value, 94 | secret: c_secret, 95 | }, 96 | } = c; 97 | 98 | let x = get_random_scalar(); 99 | 100 | let d = x * *BASEPOINT_G2; 101 | 102 | let mut hash_vec = Vec::new(); 103 | hash_vec.append(&mut point_to_bytes(&BASEPOINT_G1)); 104 | hash_vec.append(&mut point_to_bytes(&BASEPOINT_G2)); 105 | hash_vec.append(&mut point_to_bytes(a_point)); 106 | hash_vec.append(&mut point_to_bytes(b_point)); 107 | hash_vec.append(&mut point_to_bytes(&d)); 108 | 109 | let e = hash_to_scalar(&hash_vec); 110 | 111 | //u = x + e · t; 112 | let u = x + e * c_secret; 113 | 114 | EqualityProof { d, u } 115 | } 116 | 117 | pub fn verify(proof: EqualityWithPublicParams) -> bool { 118 | let EqualityWithPublicParams { 119 | proof: EqualityProof { d, u }, 120 | a_point, 121 | b_point, 122 | c_point: _c_point, 123 | } = proof; 124 | 125 | let mut hash_vec = Vec::new(); 126 | hash_vec.append(&mut point_to_bytes(&BASEPOINT_G1)); 127 | hash_vec.append(&mut point_to_bytes(&BASEPOINT_G2)); 128 | hash_vec.append(&mut point_to_bytes(&a_point)); 129 | hash_vec.append(&mut point_to_bytes(&b_point)); 130 | hash_vec.append(&mut point_to_bytes(&d)); 131 | 132 | let e = hash_to_scalar(&hash_vec); 133 | 134 | //d · ([a]/[b])e = hu; 135 | let left = d + (a_point - b_point) * e; 136 | let right = u * *BASEPOINT_G2; 137 | 138 | left == right 139 | } 140 | } 141 | 142 | #[cfg(test)] 143 | mod equality_tests { 144 | use super::*; 145 | use rand::Rng; 146 | use std::assert_eq; 147 | 148 | #[test] 149 | fn it_works() { 150 | let a = 30; 151 | let b = 30; 152 | 153 | let a_comm_secret = Equality::commit(a); 154 | let b_comm_secret = Equality::commit(b); 155 | let c_comm_secret = 156 | Equality::commit_c_witness(a_comm_secret.secret.secret, b_comm_secret.secret.secret); 157 | 158 | let proof = Equality::prove(&a_comm_secret, &b_comm_secret, &c_comm_secret); 159 | 160 | let result = Equality::verify(EqualityWithPublicParams { 161 | proof, 162 | a_point: a_comm_secret.comm.point, 163 | b_point: b_comm_secret.comm.point, 164 | c_point: c_comm_secret.comm.point, 165 | }); 166 | 167 | assert_eq!(true, result); 168 | } 169 | 170 | #[test] 171 | fn random_eq_protocol_test() { 172 | for _ in 0..50 { 173 | let random_a = rand::thread_rng().gen_range(0u64..=1000000); 174 | let random_b = rand::thread_rng().gen_range(0u64..=1000000); 175 | 176 | let a = random_a; 177 | let b = random_b; 178 | 179 | let a_comm_secret = Equality::commit(a); 180 | let b_comm_secret = Equality::commit(b); 181 | let c_comm_secret = Equality::commit_c_witness( 182 | a_comm_secret.secret.secret, 183 | b_comm_secret.secret.secret, 184 | ); 185 | 186 | let proof = Equality::prove(&a_comm_secret, &b_comm_secret, &c_comm_secret); 187 | 188 | let result = Equality::verify(EqualityWithPublicParams { 189 | proof, 190 | a_point: a_comm_secret.comm.point, 191 | b_point: b_comm_secret.comm.point, 192 | c_point: c_comm_secret.comm.point, 193 | }); 194 | 195 | let result_expect = if a == b { true } else { false }; 196 | 197 | assert_eq!(result, result_expect); 198 | } 199 | } 200 | } 201 | -------------------------------------------------------------------------------- /src/protocol/div.rs: -------------------------------------------------------------------------------- 1 | use curve25519_dalek::{ristretto::RistrettoPoint, scalar::Scalar, traits::MultiscalarMul}; 2 | use wedpr_l_crypto_zkp_utils::{ 3 | get_random_scalar, hash_to_scalar, point_to_bytes, BASEPOINT_G1, BASEPOINT_G2, 4 | }; 5 | 6 | /// a / b = c 7 | #[derive(Debug, Clone, PartialEq, Eq)] 8 | pub struct Division { 9 | pub comm: DivisionCommitment, 10 | pub secret: DivisionSecret, 11 | } 12 | 13 | #[derive(Debug, Clone, PartialEq, Eq)] 14 | pub struct DivisionCommitment { 15 | pub point: RistrettoPoint, 16 | } 17 | 18 | #[derive(Debug, Clone, PartialEq, Eq)] 19 | pub struct DivisionSecret { 20 | pub value: u64, 21 | pub secret: Scalar, 22 | } 23 | 24 | #[derive(Debug, Clone, PartialEq, Eq)] 25 | pub struct DivisionProof { 26 | pub d1: RistrettoPoint, 27 | pub d2: RistrettoPoint, 28 | pub b_circumflex: Scalar, 29 | pub s_circumflex: Scalar, 30 | pub beta_circumflex: Scalar, 31 | } 32 | 33 | #[derive(Debug, Clone, PartialEq, Eq)] 34 | pub struct DivisionWitness { 35 | pub s: Scalar, 36 | } 37 | 38 | #[derive(Debug, Clone, PartialEq, Eq)] 39 | pub struct DivisionWithPublicParams { 40 | pub proof: DivisionProof, 41 | pub a_point: RistrettoPoint, 42 | pub b_point: RistrettoPoint, 43 | pub c_point: RistrettoPoint, 44 | } 45 | 46 | impl Division { 47 | pub fn commit(value: u64) -> Self { 48 | let secret = get_random_scalar(); 49 | let commitment_point = RistrettoPoint::multiscalar_mul( 50 | &[Scalar::from(value), secret], 51 | &[*BASEPOINT_G1, *BASEPOINT_G2], 52 | ); 53 | 54 | Self { 55 | comm: DivisionCommitment { 56 | point: commitment_point, 57 | }, 58 | secret: DivisionSecret { 59 | value, 60 | secret, 61 | }, 62 | } 63 | } 64 | 65 | pub fn witness(a_secret: Scalar, c_secret: Scalar, val_b: u64) -> DivisionWitness { 66 | let s = a_secret - c_secret * Scalar::from(val_b); 67 | 68 | DivisionWitness { s } 69 | } 70 | 71 | pub fn prove( 72 | a: &Division, 73 | b: &Division, 74 | c: &Division, 75 | witness: &DivisionWitness, 76 | ) -> DivisionProof { 77 | let Division { 78 | comm: DivisionCommitment { point: a_point }, 79 | secret: 80 | DivisionSecret { 81 | value: _a_value, 82 | secret: _a_secret, 83 | }, 84 | } = a; 85 | let Division { 86 | comm: DivisionCommitment { point: b_point }, 87 | secret: 88 | DivisionSecret { 89 | value: b_value, 90 | secret: b_secret, 91 | }, 92 | } = b; 93 | let Division { 94 | comm: DivisionCommitment { point: c_point }, 95 | secret: 96 | DivisionSecret { 97 | value: _c_value, 98 | secret: _c_secret, 99 | }, 100 | } = c; 101 | 102 | let DivisionWitness { s } = witness; 103 | 104 | let b_2 = get_random_scalar(); 105 | let s_2 = get_random_scalar(); 106 | let beta_2 = get_random_scalar(); 107 | 108 | let d1 = RistrettoPoint::multiscalar_mul(&[b_2, s_2], &[*c_point, *BASEPOINT_G2]); 109 | let d2 = RistrettoPoint::multiscalar_mul(&[b_2, beta_2], &[*BASEPOINT_G1, *BASEPOINT_G2]); 110 | 111 | let mut hash_vec = Vec::new(); 112 | hash_vec.append(&mut point_to_bytes(&BASEPOINT_G1)); 113 | hash_vec.append(&mut point_to_bytes(&BASEPOINT_G2)); 114 | hash_vec.append(&mut point_to_bytes(a_point)); 115 | hash_vec.append(&mut point_to_bytes(b_point)); 116 | hash_vec.append(&mut point_to_bytes(c_point)); 117 | hash_vec.append(&mut point_to_bytes(&d1)); 118 | hash_vec.append(&mut point_to_bytes(&d2)); 119 | 120 | let e = hash_to_scalar(&hash_vec); 121 | 122 | //b^= b0 + e · b, sˆ = s0 + e · s, βˆ = β0 + e · β; 123 | let b_circumflex = b_2 + e * Scalar::from(*b_value); 124 | let s_circumflex = s_2 + e * s; 125 | let beta_circumflex = beta_2 + e * b_secret; 126 | 127 | DivisionProof { 128 | d1, 129 | d2, 130 | b_circumflex, 131 | s_circumflex, 132 | beta_circumflex, 133 | } 134 | } 135 | 136 | pub fn verify(proof: DivisionWithPublicParams) -> bool { 137 | let DivisionWithPublicParams { 138 | proof: 139 | DivisionProof { 140 | d1, 141 | d2, 142 | b_circumflex, 143 | s_circumflex, 144 | beta_circumflex, 145 | }, 146 | a_point, 147 | b_point, 148 | c_point, 149 | } = proof; 150 | 151 | let mut hash_vec = Vec::new(); 152 | hash_vec.append(&mut point_to_bytes(&BASEPOINT_G1)); 153 | hash_vec.append(&mut point_to_bytes(&BASEPOINT_G2)); 154 | hash_vec.append(&mut point_to_bytes(&a_point)); 155 | hash_vec.append(&mut point_to_bytes(&b_point)); 156 | hash_vec.append(&mut point_to_bytes(&c_point)); 157 | hash_vec.append(&mut point_to_bytes(&d1)); 158 | hash_vec.append(&mut point_to_bytes(&d2)); 159 | 160 | let e = hash_to_scalar(&hash_vec); 161 | 162 | // d1 · [a]e = [c]ˆb · hs 163 | let left = d1 + e * a_point; 164 | let right = RistrettoPoint::multiscalar_mul( 165 | &[b_circumflex, s_circumflex], 166 | &[c_point, *BASEPOINT_G2], 167 | ); 168 | // d2 · [b]e = gˆb · hβ 169 | let left2 = d2 + e * b_point; 170 | let right2 = RistrettoPoint::multiscalar_mul( 171 | &[b_circumflex, beta_circumflex], 172 | &[*BASEPOINT_G1, *BASEPOINT_G2], 173 | ); 174 | 175 | left2 == right2 && left == right 176 | } 177 | } 178 | 179 | #[cfg(test)] 180 | mod division_tests { 181 | use super::*; 182 | use std::assert_eq; 183 | 184 | #[test] 185 | fn it_works() { 186 | let a = 10; 187 | let b = 5; 188 | let c = 2; 189 | 190 | let a_comm_secret = Division::commit(a); 191 | let b_comm_secret = Division::commit(b); 192 | let c_comm_secret = Division::commit(c); 193 | 194 | let witness = 195 | Division::witness(a_comm_secret.secret.secret, c_comm_secret.secret.secret, b); 196 | 197 | let proof = Division::prove(&a_comm_secret, &b_comm_secret, &c_comm_secret, &witness); 198 | 199 | let result = Division::verify(DivisionWithPublicParams { 200 | proof, 201 | a_point: a_comm_secret.comm.point, 202 | b_point: b_comm_secret.comm.point, 203 | c_point: c_comm_secret.comm.point, 204 | }); 205 | 206 | assert_eq!(true, result); 207 | } 208 | } 209 | -------------------------------------------------------------------------------- /src/protocol/mul.rs: -------------------------------------------------------------------------------- 1 | use curve25519_dalek::{ristretto::RistrettoPoint, scalar::Scalar, traits::MultiscalarMul}; 2 | use wedpr_l_crypto_zkp_utils::{ 3 | get_random_scalar, hash_to_scalar, point_to_bytes, BASEPOINT_G1, BASEPOINT_G2, 4 | }; 5 | 6 | /// a * b = c 7 | #[derive(Debug, Clone, PartialEq, Eq)] 8 | pub struct Multiplication { 9 | pub comm: MultiplicationCommitment, 10 | pub secret: MultiplicationSecret, 11 | } 12 | 13 | #[derive(Debug, Clone, PartialEq, Eq)] 14 | pub struct MultiplicationCommitment { 15 | pub point: RistrettoPoint, 16 | } 17 | 18 | #[derive(Debug, Clone, PartialEq, Eq)] 19 | pub struct MultiplicationSecret { 20 | pub value: u64, 21 | pub secret: Scalar, 22 | } 23 | 24 | #[derive(Debug, Clone, PartialEq, Eq)] 25 | pub struct MultiplicationProof { 26 | pub d1: RistrettoPoint, 27 | pub d2: RistrettoPoint, 28 | pub b_circumflex: Scalar, 29 | pub s_circumflex: Scalar, 30 | pub beta_circumflex: Scalar, 31 | } 32 | 33 | #[derive(Debug, Clone, PartialEq, Eq)] 34 | pub struct MultiplicationWitness { 35 | pub s: Scalar, 36 | } 37 | 38 | #[derive(Debug, Clone, PartialEq, Eq)] 39 | pub struct MultiplicationWithPublicParams { 40 | pub proof: MultiplicationProof, 41 | pub a_point: RistrettoPoint, 42 | pub b_point: RistrettoPoint, 43 | pub c_point: RistrettoPoint, 44 | } 45 | 46 | impl Multiplication { 47 | pub fn commit(value: u64) -> Self { 48 | let secret = get_random_scalar(); 49 | let commitment_point = RistrettoPoint::multiscalar_mul( 50 | &[Scalar::from(value), secret], 51 | &[*BASEPOINT_G1, *BASEPOINT_G2], 52 | ); 53 | 54 | Self { 55 | comm: MultiplicationCommitment { 56 | point: commitment_point, 57 | }, 58 | secret: MultiplicationSecret { 59 | value, 60 | secret, 61 | }, 62 | } 63 | } 64 | 65 | pub fn witness(a_secret: Scalar, c_secret: Scalar, val_b: u64) -> MultiplicationWitness { 66 | let s = c_secret - a_secret * Scalar::from(val_b); 67 | 68 | MultiplicationWitness { s } 69 | } 70 | 71 | pub fn prove( 72 | a: &Multiplication, 73 | b: &Multiplication, 74 | c: &Multiplication, 75 | witness: &MultiplicationWitness, 76 | ) -> MultiplicationProof { 77 | let Multiplication { 78 | comm: MultiplicationCommitment { point: a_point }, 79 | secret: 80 | MultiplicationSecret { 81 | value: _a_value, 82 | secret: _a_secret, 83 | }, 84 | } = a; 85 | let Multiplication { 86 | comm: MultiplicationCommitment { point: b_point }, 87 | secret: 88 | MultiplicationSecret { 89 | value: b_value, 90 | secret: b_secret, 91 | }, 92 | } = b; 93 | let Multiplication { 94 | comm: MultiplicationCommitment { point: c_point }, 95 | secret: 96 | MultiplicationSecret { 97 | value: _c_value, 98 | secret: _c_secret, 99 | }, 100 | } = c; 101 | 102 | let MultiplicationWitness { s } = witness; 103 | 104 | let b_2 = get_random_scalar(); 105 | let s_2 = get_random_scalar(); 106 | let beta_2 = get_random_scalar(); 107 | 108 | let d1 = RistrettoPoint::multiscalar_mul(&[b_2, s_2], &[*a_point, *BASEPOINT_G2]); 109 | let d2 = RistrettoPoint::multiscalar_mul(&[b_2, beta_2], &[*BASEPOINT_G1, *BASEPOINT_G2]); 110 | 111 | let mut hash_vec = Vec::new(); 112 | hash_vec.append(&mut point_to_bytes(&BASEPOINT_G1)); 113 | hash_vec.append(&mut point_to_bytes(&BASEPOINT_G2)); 114 | hash_vec.append(&mut point_to_bytes(a_point)); 115 | hash_vec.append(&mut point_to_bytes(b_point)); 116 | hash_vec.append(&mut point_to_bytes(c_point)); 117 | hash_vec.append(&mut point_to_bytes(&d1)); 118 | hash_vec.append(&mut point_to_bytes(&d2)); 119 | 120 | let e = hash_to_scalar(&hash_vec); 121 | 122 | //b^= b0 + e · b, sˆ = s0 + e · s, βˆ = β0 + e · β; 123 | let b_circumflex = b_2 + e * Scalar::from(*b_value); 124 | let s_circumflex = s_2 + e * s; // c_secret = s 125 | let beta_circumflex = beta_2 + e * b_secret; 126 | 127 | MultiplicationProof { 128 | d1, 129 | d2, 130 | b_circumflex, 131 | s_circumflex, 132 | beta_circumflex, 133 | } 134 | } 135 | 136 | pub fn verify(proof: MultiplicationWithPublicParams) -> bool { 137 | let MultiplicationWithPublicParams { 138 | proof: 139 | MultiplicationProof { 140 | d1, 141 | d2, 142 | b_circumflex, 143 | s_circumflex, 144 | beta_circumflex, 145 | }, 146 | a_point, 147 | b_point, 148 | c_point, 149 | } = proof; 150 | 151 | let mut hash_vec = Vec::new(); 152 | hash_vec.append(&mut point_to_bytes(&BASEPOINT_G1)); 153 | hash_vec.append(&mut point_to_bytes(&BASEPOINT_G2)); 154 | hash_vec.append(&mut point_to_bytes(&a_point)); 155 | hash_vec.append(&mut point_to_bytes(&b_point)); 156 | hash_vec.append(&mut point_to_bytes(&c_point)); 157 | hash_vec.append(&mut point_to_bytes(&d1)); 158 | hash_vec.append(&mut point_to_bytes(&d2)); 159 | 160 | let e = hash_to_scalar(&hash_vec); 161 | 162 | // d1 · [c]e = [a]ˆb · hs 163 | let left = d1 + e * c_point; 164 | let right = RistrettoPoint::multiscalar_mul( 165 | &[b_circumflex, s_circumflex], 166 | &[a_point, *BASEPOINT_G2], 167 | ); 168 | // d2 · [b]e = gˆb · hβ 169 | let left2 = d2 + e * b_point; 170 | let right2 = RistrettoPoint::multiscalar_mul( 171 | &[b_circumflex, beta_circumflex], 172 | &[*BASEPOINT_G1, *BASEPOINT_G2], 173 | ); 174 | 175 | left2 == right2 && left == right 176 | } 177 | } 178 | 179 | #[cfg(test)] 180 | mod multiplication_tests { 181 | use super::*; 182 | use std::assert_eq; 183 | 184 | #[test] 185 | fn it_works() { 186 | let a = 30; 187 | let b = 18; 188 | let c = a * b; 189 | 190 | let a_comm_secret = Multiplication::commit(a); 191 | let b_comm_secret = Multiplication::commit(b); 192 | let c_comm_secret = Multiplication::commit(c); 193 | 194 | let witness = 195 | Multiplication::witness(a_comm_secret.secret.secret, c_comm_secret.secret.secret, b); 196 | 197 | let proof = Multiplication::prove(&a_comm_secret, &b_comm_secret, &c_comm_secret, &witness); 198 | 199 | let result = Multiplication::verify(MultiplicationWithPublicParams { 200 | proof, 201 | a_point: a_comm_secret.comm.point, 202 | b_point: b_comm_secret.comm.point, 203 | c_point: c_comm_secret.comm.point, 204 | }); 205 | 206 | assert_eq!(true, result); 207 | } 208 | } 209 | -------------------------------------------------------------------------------- /src/protocol/add.rs: -------------------------------------------------------------------------------- 1 | use curve25519_dalek::{ristretto::RistrettoPoint, scalar::Scalar, traits::MultiscalarMul}; 2 | use wedpr_l_crypto_zkp_utils::{ 3 | get_random_scalar, hash_to_scalar, point_to_bytes, BASEPOINT_G1, BASEPOINT_G2, 4 | }; 5 | 6 | /// a + b = c 7 | #[derive(Debug, Clone, PartialEq, Eq)] 8 | pub struct Addition { 9 | pub comm: AdditionCommitment, 10 | pub secret: AdditionSecret, 11 | } 12 | 13 | #[derive(Debug, Clone, PartialEq, Eq)] 14 | pub struct AdditionCommitment { 15 | pub point: RistrettoPoint, 16 | } 17 | 18 | #[derive(Debug, Clone, PartialEq, Eq)] 19 | pub struct AdditionSecret { 20 | pub value: u64, 21 | pub secret: Scalar, 22 | } 23 | 24 | #[derive(Debug, Clone, PartialEq, Eq)] 25 | pub struct AdditionProof { 26 | pub d: RistrettoPoint, 27 | pub u: Scalar, 28 | pub v: Scalar, 29 | } 30 | 31 | #[derive(Debug, Clone, PartialEq, Eq)] 32 | pub struct AdditionProofWithPublicParams { 33 | pub proof: AdditionProof, 34 | pub a_point: RistrettoPoint, 35 | pub b_point: RistrettoPoint, 36 | pub c_point: RistrettoPoint, 37 | } 38 | 39 | impl Addition { 40 | pub fn commit(value: u64) -> Self { 41 | let secret = get_random_scalar(); 42 | let commitment_point = RistrettoPoint::multiscalar_mul( 43 | &[Scalar::from(value), secret], 44 | &[*BASEPOINT_G1, *BASEPOINT_G2], 45 | ); 46 | 47 | Self { 48 | comm: AdditionCommitment { 49 | point: commitment_point, 50 | }, 51 | secret: AdditionSecret { value, secret }, 52 | } 53 | } 54 | 55 | pub fn commit_c_witness(value: u64, a_sec: Scalar, b_sec: Scalar) -> Self { 56 | let commitment_point = RistrettoPoint::multiscalar_mul( 57 | &[Scalar::from(value), a_sec + b_sec], 58 | &[*BASEPOINT_G1, *BASEPOINT_G2], 59 | ); 60 | 61 | Self { 62 | comm: AdditionCommitment { 63 | point: commitment_point, 64 | }, 65 | secret: AdditionSecret { 66 | value, 67 | secret: a_sec + b_sec, 68 | }, 69 | } 70 | } 71 | 72 | pub fn prove(a: &Addition, b: &Addition, c: &Addition) -> AdditionProof { 73 | let Addition { 74 | comm: AdditionCommitment { point: a_point }, 75 | secret: 76 | AdditionSecret { 77 | value: _a_value, 78 | secret: _a_secret, 79 | }, 80 | } = a; 81 | let Addition { 82 | comm: AdditionCommitment { point: b_point }, 83 | secret: 84 | AdditionSecret { 85 | value: _b_value, 86 | secret: _b_secret, 87 | }, 88 | } = b; 89 | let Addition { 90 | comm: AdditionCommitment { point: c_point }, 91 | secret: 92 | AdditionSecret { 93 | value: c_value, 94 | secret: c_secret, 95 | }, 96 | } = c; 97 | 98 | let x = get_random_scalar(); 99 | let y = get_random_scalar(); 100 | let d_point = RistrettoPoint::multiscalar_mul(&[x, y], &[*BASEPOINT_G1, *BASEPOINT_G2]); 101 | let mut hash_vec = Vec::new(); 102 | hash_vec.append(&mut point_to_bytes(&BASEPOINT_G1)); 103 | hash_vec.append(&mut point_to_bytes(&BASEPOINT_G2)); 104 | hash_vec.append(&mut point_to_bytes(a_point)); 105 | hash_vec.append(&mut point_to_bytes(b_point)); 106 | hash_vec.append(&mut point_to_bytes(c_point)); 107 | hash_vec.append(&mut point_to_bytes(&d_point)); 108 | 109 | let e = hash_to_scalar(&hash_vec); 110 | 111 | //let u = x + (Scalar::from(_a_value.clone()) + Scalar::from(b_value.clone())) * e; 112 | let u = x + (Scalar::from(*c_value)) * e; 113 | let v = y + (c_secret) * e; 114 | AdditionProof { d: d_point, u, v } 115 | } 116 | 117 | pub fn verify(proof: AdditionProofWithPublicParams) -> bool { 118 | let AdditionProofWithPublicParams { 119 | proof: AdditionProof { d: d_point, u, v }, 120 | a_point, 121 | b_point, 122 | c_point, 123 | } = proof; 124 | 125 | let mut hash_vec = Vec::new(); 126 | hash_vec.append(&mut point_to_bytes(&BASEPOINT_G1)); 127 | hash_vec.append(&mut point_to_bytes(&BASEPOINT_G2)); 128 | hash_vec.append(&mut point_to_bytes(&a_point)); 129 | hash_vec.append(&mut point_to_bytes(&b_point)); 130 | hash_vec.append(&mut point_to_bytes(&c_point)); 131 | hash_vec.append(&mut point_to_bytes(&d_point)); 132 | 133 | let e = hash_to_scalar(&hash_vec); 134 | 135 | let c_cal = a_point + b_point; 136 | let left = d_point + e * c_point; 137 | let right = RistrettoPoint::multiscalar_mul(&[u, v], &[*BASEPOINT_G1, *BASEPOINT_G2]); 138 | //assert_eq!(c_cal, c_point); 139 | c_cal == c_point && left == right 140 | } 141 | } 142 | 143 | #[cfg(test)] 144 | mod addition_tests { 145 | use super::*; 146 | use rand::Rng; 147 | use std::assert_eq; 148 | 149 | #[test] 150 | fn it_works() { 151 | let a = 15; 152 | let b = 18; 153 | let c = a + b; 154 | 155 | let a_comm_secret = Addition::commit(a); 156 | let b_comm_secret = Addition::commit(b); 157 | let c_comm_secret = 158 | Addition::commit_c_witness(c, a_comm_secret.secret.secret, b_comm_secret.secret.secret); 159 | 160 | let proof = Addition::prove(&a_comm_secret, &b_comm_secret, &c_comm_secret); 161 | 162 | let result = Addition::verify(AdditionProofWithPublicParams { 163 | proof, 164 | a_point: a_comm_secret.comm.point, 165 | b_point: b_comm_secret.comm.point, 166 | c_point: c_comm_secret.comm.point, 167 | }); 168 | 169 | assert_eq!( 170 | a_comm_secret.comm.point + b_comm_secret.comm.point, 171 | c_comm_secret.comm.point 172 | ); 173 | assert_eq!(true, result); 174 | } 175 | 176 | #[test] 177 | fn random_add_protocol_test() { 178 | for _ in 0..50 { 179 | let random_a = rand::thread_rng().gen_range(0u64..=1000000); 180 | let random_b = rand::thread_rng().gen_range(0u64..=1000000); 181 | 182 | let a = random_a; 183 | let b = random_b; 184 | let c = a + b; 185 | 186 | let a_comm_secret = Addition::commit(a); 187 | let b_comm_secret = Addition::commit(b); 188 | let c_comm_secret = Addition::commit_c_witness( 189 | c, 190 | a_comm_secret.secret.secret, 191 | b_comm_secret.secret.secret, 192 | ); 193 | 194 | let proof = Addition::prove(&a_comm_secret, &b_comm_secret, &c_comm_secret); 195 | 196 | let result = Addition::verify(AdditionProofWithPublicParams { 197 | proof, 198 | a_point: a_comm_secret.comm.point, 199 | b_point: b_comm_secret.comm.point, 200 | c_point: c_comm_secret.comm.point, 201 | }); 202 | 203 | assert_eq!( 204 | a_comm_secret.comm.point + b_comm_secret.comm.point, 205 | c_comm_secret.comm.point 206 | ); 207 | assert_eq!(true, result); 208 | } 209 | } 210 | 211 | #[test] 212 | fn test() { 213 | let a = 15u64; 214 | let b = 18; 215 | let c = a + b; 216 | 217 | let a_secret = get_random_scalar(); 218 | let a_comm = RistrettoPoint::multiscalar_mul( 219 | &[Scalar::from(a), a_secret], 220 | &[*BASEPOINT_G1, *BASEPOINT_G2], 221 | ); 222 | 223 | let b_secret = get_random_scalar(); 224 | let b_comm = RistrettoPoint::multiscalar_mul( 225 | &[Scalar::from(b), b_secret], 226 | &[*BASEPOINT_G1, *BASEPOINT_G2], 227 | ); 228 | 229 | let c_secret = a_secret + b_secret; 230 | let c_comm = RistrettoPoint::multiscalar_mul( 231 | &[Scalar::from(c), c_secret], 232 | &[*BASEPOINT_G1, *BASEPOINT_G2], 233 | ); 234 | 235 | assert_eq!(a_comm + b_comm, c_comm); 236 | 237 | let e = get_random_scalar(); 238 | 239 | let x = get_random_scalar(); 240 | let y = get_random_scalar(); 241 | let d_point = RistrettoPoint::multiscalar_mul(&[x, y], &[*BASEPOINT_G1, *BASEPOINT_G2]); 242 | let u = x + Scalar::from(c) * e; 243 | let v = y + c_secret * e; 244 | 245 | let left = d_point + e * c_comm; 246 | let right = RistrettoPoint::multiscalar_mul(&[u, v], &[*BASEPOINT_G1, *BASEPOINT_G2]); 247 | assert_eq!(left, right); 248 | } 249 | } 250 | -------------------------------------------------------------------------------- /src/protocol/sub.rs: -------------------------------------------------------------------------------- 1 | use curve25519_dalek::{ristretto::RistrettoPoint, scalar::Scalar, traits::MultiscalarMul}; 2 | use wedpr_l_crypto_zkp_utils::{ 3 | get_random_scalar, hash_to_scalar, point_to_bytes, BASEPOINT_G1, BASEPOINT_G2, 4 | }; 5 | 6 | /// a - b = c 7 | #[derive(Debug, Clone, PartialEq, Eq)] 8 | pub struct Substraction { 9 | pub comm: SubstractionCommitment, 10 | pub secret: SubstractionSecret, 11 | } 12 | 13 | #[derive(Debug, Clone, PartialEq, Eq)] 14 | pub struct SubstractionCommitment { 15 | pub point: RistrettoPoint, 16 | } 17 | 18 | #[derive(Debug, Clone, PartialEq, Eq)] 19 | pub struct SubstractionSecret { 20 | pub value: u64, 21 | pub secret: Scalar, 22 | } 23 | 24 | #[derive(Debug, Clone, PartialEq, Eq)] 25 | pub struct SubstractionProof { 26 | pub d: RistrettoPoint, 27 | pub u: Scalar, 28 | pub v: Scalar, 29 | } 30 | 31 | #[derive(Debug, Clone, PartialEq, Eq)] 32 | pub struct SubstractionWithPublicParams { 33 | pub proof: SubstractionProof, 34 | pub a_point: RistrettoPoint, 35 | pub b_point: RistrettoPoint, 36 | pub c_point: RistrettoPoint, 37 | } 38 | 39 | impl Substraction { 40 | pub fn commit(value: u64) -> Self { 41 | let secret = get_random_scalar(); 42 | let commitment_point = RistrettoPoint::multiscalar_mul( 43 | &[Scalar::from(value), secret], 44 | &[*BASEPOINT_G1, *BASEPOINT_G2], 45 | ); 46 | 47 | Self { 48 | comm: SubstractionCommitment { 49 | point: commitment_point, 50 | }, 51 | secret: SubstractionSecret { 52 | value, 53 | secret, 54 | }, 55 | } 56 | } 57 | 58 | pub fn commit_c_witness(value: u64, a_sec: Scalar, b_sec: Scalar) -> Self { 59 | let commitment_point = RistrettoPoint::multiscalar_mul( 60 | &[Scalar::from(value), a_sec - b_sec], 61 | &[*BASEPOINT_G1, *BASEPOINT_G2], 62 | ); 63 | 64 | Self { 65 | comm: SubstractionCommitment { 66 | point: commitment_point, 67 | }, 68 | secret: SubstractionSecret { 69 | value, 70 | secret: a_sec - b_sec, 71 | }, 72 | } 73 | } 74 | 75 | pub fn prove(a: &Substraction, b: &Substraction, c: &Substraction) -> SubstractionProof { 76 | let Substraction { 77 | comm: SubstractionCommitment { point: a_point }, 78 | secret: 79 | SubstractionSecret { 80 | value: _a_value, 81 | secret: _a_secret, 82 | }, 83 | } = a; 84 | let Substraction { 85 | comm: SubstractionCommitment { point: b_point }, 86 | secret: 87 | SubstractionSecret { 88 | value: _b_value, 89 | secret: _b_secret, 90 | }, 91 | } = b; 92 | let Substraction { 93 | comm: SubstractionCommitment { point: c_point }, 94 | secret: 95 | SubstractionSecret { 96 | value: c_value, 97 | secret: c_secret, 98 | }, 99 | } = c; 100 | 101 | let x = get_random_scalar(); 102 | let y = get_random_scalar(); 103 | let d_point = RistrettoPoint::multiscalar_mul(&[x, y], &[*BASEPOINT_G1, *BASEPOINT_G2]); 104 | let mut hash_vec = Vec::new(); 105 | hash_vec.append(&mut point_to_bytes(&BASEPOINT_G1)); 106 | hash_vec.append(&mut point_to_bytes(&BASEPOINT_G2)); 107 | hash_vec.append(&mut point_to_bytes(a_point)); 108 | hash_vec.append(&mut point_to_bytes(b_point)); 109 | hash_vec.append(&mut point_to_bytes(c_point)); 110 | hash_vec.append(&mut point_to_bytes(&d_point)); 111 | 112 | let e = hash_to_scalar(&hash_vec); 113 | 114 | //let u = x + (Scalar::from(a_value.clone()) + Scalar::from(b_value.clone())) * e; 115 | let u = x + (Scalar::from(*c_value)) * e; 116 | let v = y + (c_secret) * e; 117 | SubstractionProof { 118 | d: d_point, 119 | u, 120 | v, 121 | } 122 | } 123 | 124 | pub fn verify(proof: SubstractionWithPublicParams) -> bool { 125 | let SubstractionWithPublicParams { 126 | proof: SubstractionProof { d: d_point, u, v }, 127 | a_point, 128 | b_point, 129 | c_point, 130 | } = proof; 131 | 132 | let mut hash_vec = Vec::new(); 133 | hash_vec.append(&mut point_to_bytes(&BASEPOINT_G1)); 134 | hash_vec.append(&mut point_to_bytes(&BASEPOINT_G2)); 135 | hash_vec.append(&mut point_to_bytes(&a_point)); 136 | hash_vec.append(&mut point_to_bytes(&b_point)); 137 | hash_vec.append(&mut point_to_bytes(&c_point)); 138 | hash_vec.append(&mut point_to_bytes(&d_point)); 139 | 140 | let e = hash_to_scalar(&hash_vec); 141 | 142 | let c_cal = a_point - b_point; 143 | let left = d_point + e * c_point; 144 | let right = RistrettoPoint::multiscalar_mul(&[u, v], &[*BASEPOINT_G1, *BASEPOINT_G2]); 145 | c_cal == c_point && left == right 146 | } 147 | } 148 | 149 | #[cfg(test)] 150 | mod substraction_tests { 151 | use super::*; 152 | use rand::Rng; 153 | use std::assert_eq; 154 | 155 | #[test] 156 | fn it_works() { 157 | let a = 30; 158 | let b = 18; 159 | let c = a - b; 160 | 161 | let a_comm_secret = Substraction::commit(a); 162 | let b_comm_secret = Substraction::commit(b); 163 | let c_comm_secret = Substraction::commit_c_witness( 164 | c, 165 | a_comm_secret.secret.secret, 166 | b_comm_secret.secret.secret, 167 | ); 168 | 169 | let proof = Substraction::prove(&a_comm_secret, &b_comm_secret, &c_comm_secret); 170 | 171 | let result = Substraction::verify(SubstractionWithPublicParams { 172 | proof, 173 | a_point: a_comm_secret.comm.point, 174 | b_point: b_comm_secret.comm.point, 175 | c_point: c_comm_secret.comm.point, 176 | }); 177 | 178 | assert_eq!( 179 | a_comm_secret.comm.point - b_comm_secret.comm.point, 180 | c_comm_secret.comm.point 181 | ); 182 | assert_eq!(true, result); 183 | } 184 | 185 | #[test] 186 | fn random_eq_protocol_test() { 187 | for _ in 0..50 { 188 | let random_a = rand::thread_rng().gen_range(0u64..=1000000); 189 | let random_b = rand::thread_rng().gen_range(0u64..=random_a); 190 | 191 | let a = random_a; 192 | let b = random_b; 193 | let c = a - b; 194 | 195 | let a_comm_secret = Substraction::commit(a); 196 | let b_comm_secret = Substraction::commit(b); 197 | let c_comm_secret = Substraction::commit_c_witness( 198 | c, 199 | a_comm_secret.secret.secret, 200 | b_comm_secret.secret.secret, 201 | ); 202 | 203 | let proof = Substraction::prove(&a_comm_secret, &b_comm_secret, &c_comm_secret); 204 | 205 | let result = Substraction::verify(SubstractionWithPublicParams { 206 | proof, 207 | a_point: a_comm_secret.comm.point, 208 | b_point: b_comm_secret.comm.point, 209 | c_point: c_comm_secret.comm.point, 210 | }); 211 | 212 | assert_eq!( 213 | a_comm_secret.comm.point - b_comm_secret.comm.point, 214 | c_comm_secret.comm.point 215 | ); 216 | assert_eq!(true, result); 217 | } 218 | } 219 | 220 | #[test] 221 | fn test() { 222 | let a = 19u64; 223 | let b = 18; 224 | let c = a - b; 225 | 226 | let a_secret = get_random_scalar(); 227 | let a_comm = RistrettoPoint::multiscalar_mul( 228 | &[Scalar::from(a), a_secret], 229 | &[*BASEPOINT_G1, *BASEPOINT_G2], 230 | ); 231 | 232 | let b_secret = get_random_scalar(); 233 | let b_comm = RistrettoPoint::multiscalar_mul( 234 | &[Scalar::from(b), b_secret], 235 | &[*BASEPOINT_G1, *BASEPOINT_G2], 236 | ); 237 | 238 | let c_secret = a_secret - b_secret; 239 | let c_comm = RistrettoPoint::multiscalar_mul( 240 | &[Scalar::from(c), c_secret], 241 | &[*BASEPOINT_G1, *BASEPOINT_G2], 242 | ); 243 | 244 | assert_eq!(a_comm - b_comm, c_comm); 245 | 246 | let e = get_random_scalar(); 247 | 248 | let x = get_random_scalar(); 249 | let y = get_random_scalar(); 250 | let d_point = RistrettoPoint::multiscalar_mul(&[x, y], &[*BASEPOINT_G1, *BASEPOINT_G2]); 251 | let u = x + Scalar::from(c) * e; 252 | let v = y + c_secret * e; 253 | 254 | let left = d_point + e * c_comm; 255 | let right = RistrettoPoint::multiscalar_mul(&[u, v], &[*BASEPOINT_G1, *BASEPOINT_G2]); 256 | assert_eq!(left, right); 257 | } 258 | } 259 | -------------------------------------------------------------------------------- /src/protocol/com.rs: -------------------------------------------------------------------------------- 1 | use curve25519_dalek::{ristretto::RistrettoPoint, scalar::Scalar, traits::MultiscalarMul}; 2 | use wedpr_l_crypto_zkp_utils::{ 3 | get_random_scalar, hash_to_scalar, point_to_bytes, BASEPOINT_G1, BASEPOINT_G2, 4 | }; 5 | 6 | #[derive(Debug, Clone, PartialEq, Eq)] 7 | pub struct Comparison { 8 | pub comm: ComparisonCommitment, 9 | pub secret: ComparisonSecret, 10 | } 11 | 12 | #[derive(Debug, Clone, PartialEq, Eq)] 13 | pub struct ComparisonCommitment { 14 | pub point: RistrettoPoint, 15 | pub b0: RistrettoPoint, 16 | } 17 | 18 | #[derive(Debug, Clone, PartialEq, Eq)] 19 | pub struct ComparisonSecret { 20 | value: Vec, 21 | bi_vec: Vec, 22 | ri_vec: Vec, 23 | } 24 | 25 | #[derive(Debug, Clone, PartialEq, Eq)] 26 | pub struct ComparisonProof { 27 | bi_point_vec: Vec, 28 | d1: RistrettoPoint, 29 | d2: RistrettoPoint, 30 | u_circumflex: Scalar, 31 | b_circumflex_vec: Vec, 32 | r_circumflex: Scalar, 33 | } 34 | 35 | #[derive(Debug, Clone, PartialEq, Eq)] 36 | pub struct ComparisonProofWithPublicParams { 37 | pub proof: ComparisonProof, 38 | pub x: RistrettoPoint, 39 | } 40 | 41 | impl Comparison { 42 | pub fn commit(value: i32) -> Self { 43 | let decomposed = decompose_number(value); 44 | let len = decomposed.len(); 45 | let (mut b_vec, mut r_vec) = { 46 | let mut b_vec_tmp = Vec::new(); 47 | let mut r_vec_tmp = Vec::new(); 48 | decomposed.iter().for_each(|each_bit| { 49 | let secret = get_random_scalar(); 50 | let b_commitment_point = RistrettoPoint::multiscalar_mul( 51 | &[Scalar::from(*each_bit), secret], 52 | &[*BASEPOINT_G1, *BASEPOINT_G2], 53 | ); 54 | r_vec_tmp.push(secret); 55 | b_vec_tmp.push(b_commitment_point); 56 | }); 57 | (b_vec_tmp, r_vec_tmp) 58 | }; 59 | 60 | let x = { 61 | let mut tmp = Scalar::zero(); 62 | if value < 0 { 63 | tmp = -Scalar::from(-value as u64); 64 | } else { 65 | tmp = Scalar::from(value as u64); 66 | } 67 | tmp 68 | }; 69 | let s = get_random_scalar(); 70 | let x_commitment_point = 71 | RistrettoPoint::multiscalar_mul(&[x, s], &[*BASEPOINT_G1, *BASEPOINT_G2]); 72 | 73 | if len > 1 { 74 | let mut b_sigma = Scalar::from(2_u64) * b_vec[1]; 75 | for i in 2..=len - 1 { 76 | b_sigma += Scalar::from(2u64.pow(i as u32)) * b_vec[i]; 77 | } 78 | let b0 = x_commitment_point - b_sigma; 79 | b_vec[0] = b0; 80 | 81 | let mut r_sigma = Scalar::from(2_u64) * r_vec[1]; 82 | for i in 2..=len - 1 { 83 | r_sigma += Scalar::from(2u64.pow(i as u32)) * r_vec[i]; 84 | } 85 | let r0 = s - r_sigma; 86 | r_vec[0] = r0; 87 | } else { 88 | b_vec[0] = x_commitment_point; 89 | r_vec[0] = s; 90 | } 91 | 92 | Self { 93 | comm: ComparisonCommitment { 94 | point: x_commitment_point, 95 | b0: RistrettoPoint::default(), 96 | }, 97 | secret: ComparisonSecret { 98 | value: decomposed, 99 | bi_vec: b_vec, 100 | ri_vec: r_vec, 101 | }, 102 | } 103 | } 104 | 105 | pub fn prove(a: &Comparison) -> ComparisonProof { 106 | let Comparison { 107 | comm: 108 | ComparisonCommitment { 109 | point: x_commitment_point, 110 | b0: _b0, 111 | }, 112 | secret: 113 | ComparisonSecret { 114 | value: decomposed, 115 | bi_vec: b_vec, 116 | ri_vec: r_vec, 117 | }, 118 | } = a; 119 | 120 | let len = decomposed.len(); 121 | 122 | let b_i_prime_1 = get_random_scalar(); 123 | let mut b_i_prime_vec = Vec::new(); 124 | b_i_prime_vec.push(b_i_prime_1); 125 | let mut b_sigma_prime = b_i_prime_1; 126 | let mut bi_b_sigma_prime = b_i_prime_1 * Scalar::from(decomposed[0]); 127 | for i in 1..=len - 1 { 128 | let b_i_prime = get_random_scalar(); 129 | b_i_prime_vec.push(b_i_prime); 130 | b_sigma_prime += b_i_prime; 131 | bi_b_sigma_prime += b_i_prime * Scalar::from(decomposed[i]); 132 | } 133 | 134 | let r_prime = get_random_scalar(); 135 | let d1 = RistrettoPoint::multiscalar_mul( 136 | &[b_sigma_prime, r_prime], 137 | &[*BASEPOINT_G1, *BASEPOINT_G2], 138 | ); 139 | 140 | let u_prime = get_random_scalar(); 141 | let d2 = RistrettoPoint::multiscalar_mul( 142 | &[bi_b_sigma_prime, u_prime], 143 | &[*BASEPOINT_G1, *BASEPOINT_G2], 144 | ); 145 | 146 | let mut hash_vec = Vec::new(); 147 | hash_vec.append(&mut point_to_bytes(&BASEPOINT_G1)); 148 | hash_vec.append(&mut point_to_bytes(&BASEPOINT_G2)); 149 | hash_vec.append(&mut point_to_bytes(x_commitment_point)); 150 | for i in 0..=len - 1 { 151 | hash_vec.append(&mut point_to_bytes(&b_vec[i])); 152 | } 153 | hash_vec.append(&mut point_to_bytes(&d1)); 154 | hash_vec.append(&mut point_to_bytes(&d2)); 155 | 156 | let e = hash_to_scalar(&hash_vec); 157 | 158 | let (u_circumflex, r_circumflex, b_circumflex_vec) = { 159 | let mut u_circumflex_tmp = u_prime; 160 | let mut r_circumflex_tmp = r_prime; 161 | let mut b_circumflex_tmp = Vec::new(); 162 | for i in 0..=len - 1 { 163 | let bj_each = Scalar::from(decomposed[i]) * pow_scalar(e, i) + b_i_prime_vec[i]; 164 | b_circumflex_tmp.push(bj_each); 165 | u_circumflex_tmp += (pow_scalar(e, i) - (bj_each)) * r_vec[i]; 166 | r_circumflex_tmp += r_vec[i] * pow_scalar(e, i); 167 | } 168 | (u_circumflex_tmp, r_circumflex_tmp, b_circumflex_tmp) 169 | }; 170 | 171 | ComparisonProof { 172 | bi_point_vec: b_vec.clone(), 173 | d1, 174 | d2, 175 | u_circumflex, 176 | b_circumflex_vec, 177 | r_circumflex, 178 | } 179 | } 180 | 181 | pub fn verify(proof: ComparisonProofWithPublicParams) -> bool { 182 | let ComparisonProofWithPublicParams { 183 | proof: 184 | ComparisonProof { 185 | bi_point_vec: b_vec, 186 | d1, 187 | d2, 188 | u_circumflex, 189 | b_circumflex_vec, 190 | r_circumflex, 191 | }, 192 | x: x_commitment_point, 193 | } = proof; 194 | 195 | let len = b_vec.len(); 196 | let mut hash_vec = Vec::new(); 197 | hash_vec.append(&mut point_to_bytes(&BASEPOINT_G1)); 198 | hash_vec.append(&mut point_to_bytes(&BASEPOINT_G2)); 199 | hash_vec.append(&mut point_to_bytes(&x_commitment_point)); 200 | for i in 0..=len - 1 { 201 | hash_vec.append(&mut point_to_bytes(&b_vec[i])); 202 | } 203 | hash_vec.append(&mut point_to_bytes(&d1)); 204 | hash_vec.append(&mut point_to_bytes(&d2)); 205 | 206 | let e = hash_to_scalar(&hash_vec); 207 | 208 | /////////////verify 1///////// 209 | let left_1 = { 210 | let mut tmp = d1; 211 | for i in 0..=len - 1 { 212 | tmp += b_vec[i] * pow_scalar(e, i); 213 | } 214 | tmp 215 | }; 216 | 217 | let bj_res = { 218 | let mut tmp = Scalar::zero(); 219 | for i in 0..=len - 1 { 220 | tmp += b_circumflex_vec[i]; 221 | } 222 | tmp 223 | }; 224 | 225 | let right_1 = RistrettoPoint::multiscalar_mul( 226 | &[bj_res, r_circumflex], 227 | &[*BASEPOINT_G1, *BASEPOINT_G2], 228 | ); 229 | /////////////verify 2///////// 230 | let left_2 = { 231 | let mut tmp = d2; 232 | for i in 0..=len - 1 { 233 | tmp += b_vec[i] * (pow_scalar(e, i) - b_circumflex_vec[i]); 234 | } 235 | tmp 236 | }; 237 | 238 | let right_2 = RistrettoPoint::multiscalar_mul( 239 | &[Scalar::zero(), u_circumflex], 240 | &[*BASEPOINT_G1, *BASEPOINT_G2], 241 | ); 242 | 243 | left_1 == right_1 && left_2 == right_2 244 | } 245 | } 246 | 247 | pub fn decompose_number(mut input: i32) -> Vec { 248 | if input < 0 { 249 | input = -input; 250 | } 251 | let mut res = Vec::new(); 252 | for i in format!("{:b}", input).into_bytes() { 253 | res.push(i - 48); 254 | } 255 | res.reverse(); 256 | res 257 | } 258 | 259 | pub fn pow_scalar(a: Scalar, pow: usize) -> Scalar { 260 | 261 | { 262 | let mut scalar = Scalar::one(); 263 | for _ in 0..pow { 264 | scalar *= a; 265 | } 266 | scalar 267 | } 268 | } 269 | 270 | #[cfg(test)] 271 | mod com_tests { 272 | use super::*; 273 | use rand::Rng; 274 | use std::assert_eq; 275 | 276 | #[test] 277 | fn decompose_number_test() { 278 | let a = 209348i32; 279 | let decomposed = decompose_number(a); 280 | assert_eq!( 281 | vec![0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1], 282 | decomposed 283 | ); 284 | } 285 | 286 | /// prove x >= 0 287 | #[test] 288 | fn com_protocol_test() { 289 | let a = 209348i32; 290 | let x = Comparison::commit(a); 291 | 292 | let proof = Comparison::prove(&x); 293 | 294 | let res = Comparison::verify(ComparisonProofWithPublicParams { 295 | proof, 296 | x: x.comm.point, 297 | }); 298 | assert_eq!(res, true); 299 | } 300 | 301 | #[test] 302 | fn random_com_protocol_test() { 303 | for _ in 0..50 { 304 | let random = rand::thread_rng().gen_range(-1000000i32..=1000000); 305 | let a = random; 306 | let x = Comparison::commit(a); 307 | 308 | let proof = Comparison::prove(&x); 309 | 310 | let res = Comparison::verify(ComparisonProofWithPublicParams { 311 | proof, 312 | x: x.comm.point, 313 | }); 314 | 315 | let result_expect = if random > 0 { true } else { false }; 316 | assert_eq!(res, result_expect); 317 | } 318 | } 319 | 320 | #[test] 321 | fn simple_comparison_protocol_test() { 322 | let a = 209348i32; 323 | let decomposed = decompose_number(a); 324 | assert_eq!( 325 | vec![0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1], 326 | decomposed 327 | ); 328 | let len = decomposed.len(); 329 | 330 | /////////////prove ///////// 331 | let (mut b_vec, mut r_vec) = { 332 | let mut b_vec_tmp = Vec::new(); 333 | let mut r_vec_tmp = Vec::new(); 334 | 335 | decomposed.iter().for_each(|each_bit| { 336 | let secret = get_random_scalar(); 337 | let b_commitment_point = RistrettoPoint::multiscalar_mul( 338 | &[Scalar::from(*each_bit), secret], 339 | &[*BASEPOINT_G1, *BASEPOINT_G2], 340 | ); 341 | r_vec_tmp.push(secret); 342 | b_vec_tmp.push(b_commitment_point); 343 | }); 344 | (b_vec_tmp, r_vec_tmp) 345 | }; 346 | 347 | let x = { 348 | let mut tmp = Scalar::zero(); 349 | if a < 0 { 350 | tmp = -Scalar::from(-a as u64); 351 | } else { 352 | tmp = Scalar::from(a as u64); 353 | } 354 | tmp 355 | }; 356 | let s = get_random_scalar(); 357 | let x_commitment_point = 358 | RistrettoPoint::multiscalar_mul(&[x, s], &[*BASEPOINT_G1, *BASEPOINT_G2]); 359 | 360 | if len > 1 { 361 | let mut b_sigma = Scalar::from(2 as u64) * b_vec[1]; 362 | for i in 2..=len - 1 { 363 | b_sigma += Scalar::from(2u64.pow(i as u32) as u64) * b_vec[i]; 364 | } 365 | let b0 = x_commitment_point - b_sigma; 366 | b_vec[0] = b0; 367 | 368 | let mut r_sigma = Scalar::from(2 as u64) * r_vec[1]; 369 | for i in 2..=len - 1 { 370 | r_sigma += Scalar::from(2u64.pow(i as u32) as u64) * r_vec[i]; 371 | } 372 | let r0 = s - r_sigma; 373 | r_vec[0] = r0; 374 | } else { 375 | b_vec[0] = x_commitment_point; 376 | r_vec[0] = s; 377 | } 378 | 379 | let b_i_prime_1 = get_random_scalar(); 380 | let mut b_i_prime_vec = Vec::new(); 381 | b_i_prime_vec.push(b_i_prime_1); 382 | let mut b_sigma_prime = b_i_prime_1; 383 | let mut bi_b_sigma_prime = b_i_prime_1 * Scalar::from(decomposed[0]); 384 | for i in 1..=len - 1 { 385 | let b_i_prime_i = get_random_scalar(); 386 | b_i_prime_vec.push(b_i_prime_i); 387 | b_sigma_prime += b_i_prime_i; 388 | bi_b_sigma_prime += b_i_prime_i * Scalar::from(decomposed[i]); 389 | } 390 | 391 | let r_prime = get_random_scalar(); 392 | let d1 = RistrettoPoint::multiscalar_mul( 393 | &[b_sigma_prime, r_prime], 394 | &[*BASEPOINT_G1, *BASEPOINT_G2], 395 | ); 396 | 397 | let u_prime = get_random_scalar(); 398 | let d2 = RistrettoPoint::multiscalar_mul( 399 | &[bi_b_sigma_prime, u_prime], 400 | &[*BASEPOINT_G1, *BASEPOINT_G2], 401 | ); 402 | 403 | let e = get_random_scalar(); 404 | 405 | let (uj, rj, bj) = { 406 | let mut uj_tmp = u_prime; 407 | let mut rj_tmp = r_prime; 408 | let mut bj_tmp = Vec::new(); 409 | for i in 0..=len - 1 { 410 | let bj_i = Scalar::from(decomposed[i]) * pow_scalar(e, i) + b_i_prime_vec[i]; 411 | bj_tmp.push(bj_i); 412 | uj_tmp += (pow_scalar(e, i) - (bj_i)) * r_vec[i]; 413 | rj_tmp += r_vec[i] * pow_scalar(e, i); 414 | } 415 | (uj_tmp, rj_tmp, bj_tmp) 416 | }; 417 | 418 | /////////////verify 1///////// 419 | 420 | let left_1 = { 421 | let mut tmp = d1; 422 | for i in 0..=len - 1 { 423 | tmp += b_vec[i] * pow_scalar(e, i); 424 | } 425 | tmp 426 | }; 427 | 428 | let bj_res = { 429 | let mut tmp = Scalar::zero(); 430 | for i in 0..=len - 1 { 431 | tmp += bj[i]; 432 | } 433 | tmp 434 | }; 435 | 436 | let right_1 = 437 | RistrettoPoint::multiscalar_mul(&[bj_res, rj], &[*BASEPOINT_G1, *BASEPOINT_G2]); 438 | assert_eq!(left_1, right_1); 439 | 440 | /////////////verify 2///////// 441 | let left_2 = { 442 | let mut tmp = d2; 443 | for i in 0..=len - 1 { 444 | tmp += b_vec[i] * (pow_scalar(e, i) - bj[i]); 445 | } 446 | tmp 447 | }; 448 | 449 | let right_2 = 450 | RistrettoPoint::multiscalar_mul(&[Scalar::zero(), uj], &[*BASEPOINT_G1, *BASEPOINT_G2]); 451 | assert_eq!(left_2, right_2); 452 | } 453 | } 454 | --------------------------------------------------------------------------------