├── .gitignore ├── src ├── range_proof.rs ├── lib.rs ├── transcript.rs ├── range_proof │ ├── u64_proof.rs │ └── reciprocal.rs ├── util.rs ├── tests.rs ├── wnla.rs └── circuit.rs ├── .github └── workflows │ └── rust.yml ├── macbook-m3-pro-36GB-bench-result.txt ├── Cargo.toml ├── LICENSE ├── README.md ├── benches └── range_proof.rs └── Cargo.lock /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | .idea 3 | -------------------------------------------------------------------------------- /src/range_proof.rs: -------------------------------------------------------------------------------- 1 | pub mod reciprocal; 2 | pub mod u64_proof; -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/README.md"))] 2 | 3 | pub mod wnla; 4 | pub mod circuit; 5 | pub mod transcript; 6 | pub mod range_proof; 7 | 8 | mod util; 9 | #[cfg(test)] 10 | mod tests; 11 | -------------------------------------------------------------------------------- /.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@v3 19 | - name: Run tests 20 | run: cargo test --verbose 21 | -------------------------------------------------------------------------------- /src/transcript.rs: -------------------------------------------------------------------------------- 1 | use k256::{FieldBytes, ProjectivePoint, Scalar}; 2 | use k256::elliptic_curve::group::GroupEncoding; 3 | use k256::elliptic_curve::PrimeField; 4 | use merlin::Transcript; 5 | 6 | pub fn app_point(label: &'static [u8], p: &ProjectivePoint, t: &mut Transcript) { 7 | t.append_message(label, p.to_bytes().as_slice()); 8 | } 9 | 10 | pub fn get_challenge(label: &'static [u8], t: &mut Transcript) -> Scalar { 11 | let mut buf = [0u8; 32]; 12 | t.challenge_bytes(label, &mut buf); 13 | Scalar::from_repr(*FieldBytes::from_slice(&buf)).unwrap() 14 | } 15 | -------------------------------------------------------------------------------- /macbook-m3-pro-36GB-bench-result.txt: -------------------------------------------------------------------------------- 1 | 2 | running 3 tests 3 | test tests::ac_works ... ignored 4 | test tests::u64_proof_works ... ignored 5 | test tests::wnla_works ... ignored 6 | 7 | test result: ok. 0 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 0.00s 8 | 9 | prove time: [14.348 ms 14.361 ms 14.377 ms] 10 | change: [-1.2510% -0.9116% -0.6526%] (p = 0.00 < 0.05) 11 | Change within noise threshold. 12 | Found 9 outliers among 100 measurements (9.00%) 13 | 6 (6.00%) high mild 14 | 3 (3.00%) high severe 15 | 16 | verify time: [3.7921 ms 3.8080 ms 3.8237 ms] 17 | change: [+0.6999% +1.1398% +1.5543%] (p = 0.00 < 0.05) 18 | Change within noise threshold. 19 | 20 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "bp-pp" 3 | version = "0.1.1" 4 | edition = "2021" 5 | authors = ["Oleg Fomenko "] 6 | license = "MIT" 7 | description = "Rust library for Bulletproofs++ - range-proof protocol in discret loggarithm setting" 8 | repository = "https://github.com/distributed-lab/bp-pp" 9 | categories = ["cryptography"] 10 | keywords = ["crypto", "bulletproofs", "rangeproofs", "zeroknowledge", "zkp"] 11 | readme = "README.md" 12 | 13 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 14 | 15 | [dependencies] 16 | k256 = { version = "0.13.3", features = ["serde"]} 17 | merlin = "3.0.0" 18 | serde = { version = "1.0.197", features = ["derive"] } 19 | serde_json = "1.0.114" 20 | criterion = "0.5.1" 21 | 22 | [[bench]] 23 | name = "range_proof" 24 | harness = false -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Distributed Lab 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 | # Bulletproofs++ implementation on Rust 2 | 3 | [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) 4 | [![Pull Requests welcome](https://img.shields.io/badge/PRs-welcome-ff69b4.svg?style=flat-square)](https://github.com/distributed-lab/bp-pp/issues) 5 | 6 | 7 | 8 | 9 | ⚠️ __Please note - this crypto library has not been audited, so use it at your own risk.__ 10 | 11 | ## Abstract 12 | 13 | Present Rust library contains the implementation of Bulletproofs++ 14 | over [secp256k1 curve](https://docs.rs/k256/latest/k256/) that includes: weight norm linear argument protocol, 15 | arithmetic circuit protocol and reciprocal range proofs described in Distributed 16 | Lab's [Bulletproofs++ Construction and Examples](https://distributedlab.com/whitepaper/Bulletproofs-Construction-and-Examples.pdf). 17 | Also, contains the `u64` range proof protocol as a primary use-case for reciprocal range proofs. 18 | 19 | This implementation uses [Merlin transcript](https://doc.dalek.rs/merlin/index.html) for challenges generation as was 20 | recommended by Bulletproofs protocol authors. 21 | 22 | All `Proof` data models has corresponding `SerializeProof` models where [serde](https://serde.rs/) `Serialize` 23 | and `Deserialize` was implemented. 24 | 25 | ## Performance 26 | 27 | Implemented solution has 2G points advantage over existing BP and BP+ protocols on proving of one 64-bit value and this 28 | advantage will increase for more values per proof. 29 | 30 | | Protocol | G | F | 31 | |----------|----|---| 32 | | BP | 16 | 5 | 33 | | BP+ | 15 | 3 | 34 | | Our BP++ | 13 | 3 | 35 | 36 | On MacBook M3Pro 36GB MacOS 14.1 Rust 1.78.0 it [consumes](./macbook-m3-pro-36GB-bench-result.txt): 37 | 38 | - 14.361 ms average for proof generation 39 | - 3.8080 ms average for proof verification 40 | 41 | ## Example of usage 42 | 43 | Use [tests](./src/tests.rs) to run the provided example: 44 | 45 | ```rust 46 | use k256::elliptic_curve::{Group, rand_core::OsRng}; 47 | use k256::ProjectivePoint; 48 | 49 | use bp_pp::range_proof; 50 | use bp_pp::range_proof::u64_proof::G_VEC_FULL_SZ; 51 | use bp_pp::range_proof::u64_proof::H_VEC_FULL_SZ; 52 | use bp_pp::range_proof::reciprocal::{SerializableProof, self}; 53 | 54 | fn main() { 55 | let mut rand = OsRng::default(); 56 | 57 | let x = 123456u64; // private value to create proof for. 58 | let s = k256::Scalar::generate_biased(&mut rand); // blinding value 59 | 60 | // Base points 61 | let g = k256::ProjectivePoint::random(&mut rand); 62 | let g_vec = (0..G_VEC_FULL_SZ).map(|_| k256::ProjectivePoint::random(&mut rand)).collect::>(); 63 | let h_vec = (0..H_VEC_FULL_SZ).map(|_| k256::ProjectivePoint::random(&mut rand)).collect::>(); 64 | 65 | let public = range_proof::u64_proof::U64RangeProofProtocol { 66 | g, 67 | g_vec, 68 | h_vec, 69 | }; 70 | 71 | // transcript will be used for challenge generation - to move from interactive to non-interactive protocol. 72 | // transcript should be the new instance but with same label for prover and verifier. 73 | let mut pt = merlin::Transcript::new(b"u64 range proof"); 74 | let proof = public.prove(x, &s, &mut pt, &mut rand); 75 | 76 | // value commitment: `commitment = x*g + s*h_vec[0]` 77 | let commitment = public.commit_value(x, &s); 78 | 79 | println!("{}", serde_json::to_string_pretty(&reciprocal::SerializableProof::from(&proof)).unwrap()); 80 | 81 | let mut vt = merlin::Transcript::new(b"u64 range proof"); 82 | assert!(public.verify(&commitment, proof, &mut vt)); 83 | } 84 | ``` -------------------------------------------------------------------------------- /src/range_proof/u64_proof.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | //! Definition and implementation of the u64 range-proof protocol based on reciprocal protocol. 3 | 4 | use std::ops::{Add, Mul}; 5 | use k256::{ProjectivePoint, Scalar}; 6 | use k256::elliptic_curve::rand_core::{CryptoRng, RngCore}; 7 | use merlin::Transcript; 8 | use crate::range_proof::reciprocal::{Proof, ReciprocalRangeProofProtocol, Witness}; 9 | 10 | #[allow(dead_code)] 11 | const G_VEC_CIRCUIT_SZ: usize = 16; 12 | pub const G_VEC_FULL_SZ: usize = 16; 13 | pub const H_VEC_CIRCUIT_SZ: usize = 26; 14 | pub const H_VEC_FULL_SZ: usize = 32; 15 | 16 | 17 | /// Represents public information for reciprocal range proof protocol for [0..2^64) range. 18 | #[derive(Clone, Debug)] 19 | pub struct U64RangeProofProtocol { 20 | /// Will be used for the value commitment as: `commitment = x*g + s*h_vec[0]` 21 | pub g: ProjectivePoint, 22 | /// Dimension: `16` 23 | pub g_vec: Vec, 24 | 25 | /// Will be used for the value commitment as: `commitment = x*g + s*h_vec[0]` 26 | /// Dimension: `26+6=32` 27 | pub h_vec: Vec, 28 | } 29 | 30 | impl U64RangeProofProtocol { 31 | /// Count of digits of u64 in hex representation. 32 | pub const DIM_ND: usize = 16; 33 | /// Base (hex) 34 | pub const DIM_NP: usize = 16; 35 | 36 | /// Creates commitment for the private value and blinding: `commitment = x*g + s*h_vec[0]` 37 | pub fn commit_value(&self, x: u64, s: &Scalar) -> ProjectivePoint { 38 | self.g.mul(&Scalar::from(x)).add(&self.h_vec[0].mul(s)) 39 | } 40 | 41 | /// Verifies that committed value in `v` lies in range [0..2^64). 42 | pub fn verify(&self, v: &ProjectivePoint, proof: Proof, t: &mut Transcript) -> bool { 43 | let reciprocal = ReciprocalRangeProofProtocol { 44 | dim_nd: Self::DIM_ND, 45 | dim_np: Self::DIM_NP, 46 | g: self.g, 47 | g_vec: self.g_vec.clone(), 48 | h_vec: self.h_vec[..H_VEC_CIRCUIT_SZ].to_vec(), 49 | g_vec_: vec![], 50 | h_vec_: self.h_vec[H_VEC_CIRCUIT_SZ..].to_vec(), 51 | }; 52 | 53 | reciprocal.verify(v, proof, t) 54 | } 55 | 56 | /// Creates proof that values `x` with blinding `s` lies in [0..2^64). 57 | pub fn prove(&self, x: u64, s: &Scalar, t: &mut Transcript, rng: &mut R) -> Proof 58 | where 59 | R: RngCore + CryptoRng 60 | { 61 | let digits = Self::u64_to_hex(x); 62 | let poles = Self::u64_to_hex_mapped(x); 63 | 64 | let reciprocal = ReciprocalRangeProofProtocol { 65 | dim_nd: Self::DIM_ND, 66 | dim_np: Self::DIM_NP, 67 | g: self.g, 68 | g_vec: self.g_vec.clone(), 69 | h_vec: self.h_vec[..H_VEC_CIRCUIT_SZ].to_vec(), 70 | g_vec_: vec![], 71 | h_vec_: self.h_vec[H_VEC_CIRCUIT_SZ..].to_vec(), 72 | }; 73 | 74 | let witness = Witness { 75 | x: Scalar::from(x), 76 | s: *s, 77 | m: poles, 78 | digits, 79 | }; 80 | 81 | reciprocal.prove(&reciprocal.commit_value(&witness.x, &witness.s), witness, t, rng) 82 | } 83 | 84 | pub fn u64_to_hex(mut x: u64) -> Vec { 85 | (0..16).map(|_| { 86 | let val = Scalar::from(x % 16); 87 | x /= 16; 88 | val 89 | }).collect::>() 90 | } 91 | 92 | pub fn u64_to_hex_mapped(mut x: u64) -> Vec { 93 | let mut result = vec![Scalar::ZERO; 16]; 94 | 95 | (0..16).for_each(|_| { 96 | let digit = (x % 16) as usize; 97 | result[digit] = result[digit].add(Scalar::ONE); 98 | x /= 16; 99 | }); 100 | 101 | result 102 | } 103 | } -------------------------------------------------------------------------------- /benches/range_proof.rs: -------------------------------------------------------------------------------- 1 | use criterion::{black_box, criterion_group, criterion_main, BatchSize, Criterion}; 2 | 3 | use k256::elliptic_curve::Group; 4 | use k256::elliptic_curve::rand_core::OsRng; 5 | use k256::{ProjectivePoint, Scalar}; 6 | use bp_pp::{range_proof, wnla}; 7 | use bp_pp::range_proof::u64_proof::{G_VEC_FULL_SZ, H_VEC_FULL_SZ}; 8 | 9 | fn bench_range_proof(ct: &mut Criterion) { 10 | // Preparing common data 11 | let mut rand = OsRng::default(); 12 | 13 | let x = 123456u64; 14 | let s = k256::Scalar::generate_biased(&mut rand); 15 | 16 | 17 | // Preparing Base points 18 | let g = k256::ProjectivePoint::random(&mut rand); 19 | let g_vec = (0..G_VEC_FULL_SZ).map(|_| k256::ProjectivePoint::random(&mut rand)).collect::>(); 20 | let h_vec = (0..H_VEC_FULL_SZ).map(|_| k256::ProjectivePoint::random(&mut rand)).collect::>(); 21 | 22 | let public = range_proof::u64_proof::U64RangeProofProtocol { 23 | g, 24 | g_vec, 25 | h_vec, 26 | }; 27 | 28 | // Benching proofs generation 29 | ct.bench_function("prove", |b| { 30 | b.iter_batched( 31 | || { 32 | merlin::Transcript::new(b"u64 range proof") 33 | }, 34 | |mut pt| public.prove(x, &s, &mut pt, &mut rand), 35 | BatchSize::SmallInput, 36 | ) 37 | }); 38 | 39 | 40 | // Preparing proof to bench verification 41 | let proof = public.prove(x, &s, &mut merlin::Transcript::new(b"u64 range proof"), &mut rand); 42 | let commitment = public.commit_value(x, &s); 43 | 44 | ct.bench_function("verify", |b| { 45 | b.iter_batched( 46 | || { 47 | (merlin::Transcript::new(b"u64 range proof"), proof.clone()) 48 | }, 49 | |(mut vt, proof)| assert!(public.verify(&commitment, proof, &mut vt)), 50 | BatchSize::SmallInput, 51 | ) 52 | }); 53 | } 54 | 55 | fn bench_wnla(ct: &mut Criterion) { 56 | const N: i32 = 4; 57 | let mut rand = OsRng::default(); 58 | 59 | // Preparing Base points 60 | 61 | let g = k256::ProjectivePoint::random(&mut rand); 62 | let g_vec = (0..N).map(|_| k256::ProjectivePoint::random(&mut rand)).collect(); 63 | let h_vec = (0..N).map(|_| k256::ProjectivePoint::random(&mut rand)).collect(); 64 | let c = (0..N).map(|_| k256::Scalar::generate_biased(&mut rand)).collect(); 65 | let rho = k256::Scalar::generate_biased(&mut rand); 66 | 67 | let wnla = wnla::WeightNormLinearArgument { 68 | g, 69 | g_vec, 70 | h_vec, 71 | c, 72 | rho, 73 | mu: rho.mul(&rho), 74 | }; 75 | 76 | let l = vec![Scalar::from(1 as u32), Scalar::from(2 as u32), Scalar::from(3 as u32), Scalar::from(4 as u32)]; 77 | let n = vec![Scalar::from(8 as u32), Scalar::from(7 as u32), Scalar::from(6 as u32), Scalar::from(5 as u32)]; 78 | let commit = wnla.commit(&l, &n); 79 | 80 | // Benching proofs generation 81 | ct.bench_function("prove WNLA", |b| { 82 | b.iter_batched( 83 | || { 84 | (merlin::Transcript::new(b"wnla test"), commit.clone(), l.clone(), n.clone()) 85 | }, 86 | |(mut pt, commit, l, n)| wnla.prove(&commit, &mut pt, l, n), 87 | BatchSize::SmallInput, 88 | ) 89 | }); 90 | 91 | // Preparing proof to bench verification 92 | let proof = wnla.prove(&commit, &mut merlin::Transcript::new(b"wnla test"), l, n); 93 | 94 | ct.bench_function("verify WNLA", |b| { 95 | b.iter_batched( 96 | || { 97 | (merlin::Transcript::new(b"wnla test"), proof.clone()) 98 | }, 99 | |(mut vt, proof)| assert!(wnla.verify(&commit, &mut vt, proof)), 100 | BatchSize::SmallInput, 101 | ) 102 | }); 103 | } 104 | 105 | criterion_group!(benches, bench_range_proof); 106 | criterion_main!(benches); -------------------------------------------------------------------------------- /src/util.rs: -------------------------------------------------------------------------------- 1 | use std::cmp::max; 2 | use std::ops::{Add, Mul, Sub}; 3 | use k256::elliptic_curve::Field; 4 | use k256::elliptic_curve::ops::Invert; 5 | use k256::Scalar; 6 | 7 | pub fn reduce(v: &[T]) -> (Vec, Vec) where T: Copy { 8 | let res0 = v.iter(). 9 | enumerate(). 10 | filter(|(i, _)| *i as i32 % 2 == 0). 11 | map(|(_, x)| *x). 12 | collect::>(); 13 | 14 | 15 | let res1 = v.iter(). 16 | enumerate(). 17 | filter(|(i, _)| *i as i32 % 2 == 1). 18 | map(|(_, x)| *x). 19 | collect::>(); 20 | 21 | (res0, res1) 22 | } 23 | 24 | pub fn vector_extend(v: &[T], n: usize) -> Vec where T: Copy + Default { 25 | (0..n).map(|i| if i < v.len() { v[i] } else { T::default() }).collect::>() 26 | } 27 | 28 | pub fn weight_vector_mul(a: &[T], b: &[Scalar], weight: &Scalar) -> T 29 | where 30 | T: Copy + Default + Mul + Add 31 | { 32 | let mut exp = Scalar::ONE; 33 | let mut result = T::default(); 34 | 35 | let a_ext = vector_extend(a, max(a.len(), b.len())); 36 | let b_ext = &vector_extend(b, max(a.len(), b.len())); 37 | 38 | a_ext.iter().zip(b_ext).for_each(|(a_val, b_val)| { 39 | exp = exp.mul(weight); 40 | result = result.add(a_val.mul(b_val.mul(&exp))); 41 | }); 42 | 43 | result 44 | } 45 | 46 | pub fn vector_mul(a: &[T], b: &[Scalar]) -> T 47 | where 48 | T: Copy + Default + Mul + Add 49 | { 50 | let mut result = T::default(); 51 | 52 | let a_ext = &vector_extend(a, max(a.len(), b.len())); 53 | let b_ext = &vector_extend(b, max(a.len(), b.len())); 54 | 55 | a_ext.iter().zip(b_ext).for_each(|(a_val, b_val)| { 56 | result = result.add(a_val.mul(*b_val)); 57 | }); 58 | 59 | result 60 | } 61 | 62 | pub fn vector_mul_on_scalar<'a, T>(a: &[T], s: &'a Scalar) -> Vec 63 | where 64 | T: Copy + Mul<&'a Scalar, Output=T> 65 | { 66 | a.iter().map(|x| x.mul(s)).collect::>() 67 | } 68 | 69 | pub fn vector_add(a: &[T], b: &[T]) -> Vec 70 | where 71 | T: Copy + Default + Add 72 | { 73 | let a_ext = &vector_extend(a, max(a.len(), b.len())); 74 | let b_ext = &vector_extend(b, max(a.len(), b.len())); 75 | a_ext.iter().zip(b_ext).map(|(a_val, b_val)| a_val.add(*b_val)).collect::>() 76 | } 77 | 78 | pub fn vector_sub<'a, T>(a: &'a [T], b: &'a [T]) -> Vec 79 | where 80 | T: Copy + Default + Sub 81 | { 82 | let a_ext = &vector_extend(a, max(a.len(), b.len())); 83 | let b_ext = &vector_extend(b, max(a.len(), b.len())); 84 | a_ext.iter().zip(b_ext).map(|(a_val, b_val)| a_val.sub(*b_val)).collect::>() 85 | } 86 | 87 | pub fn e(v: &Scalar, n: usize) -> Vec { 88 | let mut buf = Scalar::ONE; 89 | 90 | (0..n).map(|_| { 91 | let val = buf; 92 | buf = buf.mul(v); 93 | val 94 | }).collect::>() 95 | } 96 | 97 | pub fn pow(s: &Scalar, n: usize) -> Scalar { 98 | s.pow_vartime([n as u64]) 99 | } 100 | 101 | #[allow(dead_code)] 102 | pub fn vector_hadamard_mul(a: &[T], b: &[Scalar]) -> Vec 103 | where 104 | T: Copy + Default + Mul 105 | { 106 | let a_ext = &vector_extend(a, max(a.len(), b.len())); 107 | let b_ext = &vector_extend(b, max(a.len(), b.len())); 108 | a_ext.iter().zip(b_ext).map(|(a_val, b_val)| a_val.mul(*b_val)).collect::>() 109 | } 110 | 111 | pub fn vector_tensor_mul<'a, T>(a: &'a [T], b: &'a [Scalar]) -> Vec 112 | where 113 | T: Copy + Mul<&'a Scalar, Output=T> 114 | { 115 | b.iter().map(|x| vector_mul_on_scalar(a, x)).collect::>>().concat() 116 | } 117 | 118 | pub fn diag_inv(x: &Scalar, n: usize) -> Vec> { 119 | let x_inv = x.invert_vartime().unwrap(); 120 | let mut val = Scalar::ONE; 121 | 122 | (0..n).map(|i| 123 | (0..n).map(|j| 124 | if i == j { 125 | val = val.mul(x_inv); 126 | val 127 | } else { 128 | Scalar::ZERO 129 | } 130 | ).collect::>() 131 | ).collect::>>() 132 | } 133 | 134 | pub fn vector_mul_on_matrix(a: &[T], m: &[Vec]) -> Vec 135 | where 136 | T: Copy + Default + Mul + Add 137 | { 138 | (0..m[0].len()).map(|j| { 139 | let column = m.iter().map(|row| row[j]).collect::>(); 140 | vector_mul(a, &column) 141 | }).collect::>() 142 | } 143 | 144 | #[allow(dead_code)] 145 | pub fn matrix_mul_on_vector(a: &[T], m: &[Vec]) -> Vec 146 | where 147 | T: Copy + Default + Mul + Add 148 | { 149 | m.iter().map(|v| vector_mul(a, v)).collect::>() 150 | } 151 | 152 | 153 | pub fn minus(v: &T) -> T where T: Copy + Mul { 154 | v.mul(Scalar::ZERO.sub(&Scalar::ONE)) 155 | } -------------------------------------------------------------------------------- /src/tests.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | 3 | use k256::elliptic_curve::Group; 4 | use k256::elliptic_curve::rand_core::OsRng; 5 | use k256::{ProjectivePoint, Scalar}; 6 | use crate::circuit::{ArithmeticCircuit, PartitionType, Witness}; 7 | use crate::{circuit, range_proof, wnla}; 8 | use crate::range_proof::reciprocal; 9 | use crate::range_proof::u64_proof::*; 10 | use crate::util::{minus}; 11 | 12 | #[test] 13 | fn u64_proof_works() { 14 | let mut rand = OsRng::default(); 15 | 16 | let x = 123456u64; 17 | let s = k256::Scalar::generate_biased(&mut rand); 18 | 19 | println!("Value {}, blinding: {}", x, serde_json::to_string_pretty(&s).unwrap()); 20 | 21 | // Base points 22 | let g = k256::ProjectivePoint::random(&mut rand); 23 | let g_vec = (0..G_VEC_FULL_SZ).map(|_| k256::ProjectivePoint::random(&mut rand)).collect::>(); 24 | let h_vec = (0..H_VEC_FULL_SZ).map(|_| k256::ProjectivePoint::random(&mut rand)).collect::>(); 25 | 26 | let public = range_proof::u64_proof::U64RangeProofProtocol { 27 | g, 28 | g_vec, 29 | h_vec, 30 | }; 31 | 32 | let commitment = public.commit_value(x, &s); 33 | 34 | let mut pt = merlin::Transcript::new(b"u64 range proof"); 35 | let proof = public.prove(x, &s, &mut pt, &mut rand); 36 | 37 | println!("Commitment: {}", serde_json::to_string_pretty(&commitment.to_affine()).unwrap()); 38 | println!("Proof: {}", serde_json::to_string_pretty(&reciprocal::SerializableProof::from(&proof)).unwrap()); 39 | 40 | let mut vt = merlin::Transcript::new(b"u64 range proof"); 41 | assert!(public.verify(&commitment, proof, &mut vt)); 42 | } 43 | 44 | #[test] 45 | fn ac_works() { 46 | // Test the knowledge of x, y for public z, r, such: 47 | // x + y = r 48 | // x * y = z 49 | 50 | let x = Scalar::from(3u32); 51 | let y = Scalar::from(5u32); 52 | 53 | let r = Scalar::from(8u32); 54 | let z = Scalar::from(15u32); 55 | 56 | 57 | let w_l = vec![Scalar::from(x)]; 58 | let w_r = vec![Scalar::from(y)]; 59 | let w_o = vec![Scalar::from(z), Scalar::from(r)]; 60 | 61 | let dim_nm = 1; 62 | let dim_no = 2; 63 | let dim_nv = 2; 64 | let k = 1; 65 | 66 | let dim_nl = dim_nv * k; // 2 67 | let dim_nw = dim_nm + dim_nm + dim_no; // 4 68 | 69 | 70 | let W_m = vec![vec![Scalar::ZERO, Scalar::ZERO, Scalar::ONE, Scalar::ZERO]]; // Nm*Nw 71 | let a_m = vec![Scalar::ZERO]; // Nm 72 | 73 | let W_l = vec![ 74 | vec![Scalar::ZERO, Scalar::ONE, Scalar::ZERO, Scalar::ZERO], 75 | vec![Scalar::ZERO, Scalar::ZERO.sub(&Scalar::ONE), Scalar::ONE, Scalar::ZERO], 76 | ]; // Nl*Nw 77 | 78 | let a_l = vec![minus(&r), minus(&z)]; // Nl 79 | 80 | //let w_v = vec![Scalar::from(x), Scalar::from(y)]; 81 | //let w = vec![Scalar::from(x), Scalar::from(y), Scalar::from(z), Scalar::from(r)]; // w = wl||wr||wo 82 | //println!("Circuit check: {:?} = {:?}", vector_mul(&W_m[0], &w), vector_hadamard_mul(&w_l, &w_r)); 83 | //println!("Circuit check: {:?} = 0", vector_add(&vector_add(&vec![vector_mul(&W_l[0], &w), vector_mul(&W_l[1], &w)], &w_v), &a_l)); 84 | 85 | let mut rand = OsRng::default(); 86 | 87 | let g = k256::ProjectivePoint::random(&mut rand); 88 | let g_vec = (0..1).map(|_| k256::ProjectivePoint::random(&mut rand)).collect::>(); 89 | let h_vec = (0..16).map(|_| k256::ProjectivePoint::random(&mut rand)).collect::>(); 90 | 91 | let partition = |typ: PartitionType, index: usize| -> Option{ 92 | match typ { 93 | PartitionType::LL => Some(index), 94 | _ => None 95 | } 96 | }; 97 | 98 | let circuit = ArithmeticCircuit { 99 | dim_nm, 100 | dim_no, 101 | k, 102 | dim_nl, 103 | dim_nv, 104 | dim_nw, 105 | g, 106 | g_vec: g_vec[..dim_nm].to_vec(), 107 | h_vec: h_vec[..9 + dim_nv].to_vec(), 108 | W_m, 109 | W_l, 110 | a_m, 111 | a_l, 112 | f_l: true, 113 | f_m: false, 114 | g_vec_: g_vec[dim_nm..].to_vec(), 115 | h_vec_: h_vec[9 + dim_nv..].to_vec(), 116 | partition, 117 | }; 118 | 119 | let witness = Witness { 120 | v: vec![vec![x, y]], 121 | s_v: vec![k256::Scalar::generate_biased(&mut rand)], 122 | w_l, 123 | w_r, 124 | w_o, 125 | }; 126 | 127 | let v = (0..k).map(|i| circuit.commit(&witness.v[i], &witness.s_v[i])).collect::>(); 128 | 129 | let mut pt = merlin::Transcript::new(b"circuit test"); 130 | let proof = circuit.prove::(&v, witness, &mut pt, &mut rand); 131 | 132 | println!("{}", serde_json::to_string_pretty(&circuit::SerializableProof::from(&proof)).unwrap()); 133 | 134 | let mut vt = merlin::Transcript::new(b"circuit test"); 135 | assert!(circuit.verify(&v, &mut vt, proof)); 136 | } 137 | 138 | #[test] 139 | fn wnla_works() { 140 | const N: i32 = 4; 141 | 142 | let mut rand = OsRng::default(); 143 | 144 | let g = k256::ProjectivePoint::random(&mut rand); 145 | let g_vec = (0..N).map(|_| k256::ProjectivePoint::random(&mut rand)).collect(); 146 | let h_vec = (0..N).map(|_| k256::ProjectivePoint::random(&mut rand)).collect(); 147 | let c = (0..N).map(|_| k256::Scalar::generate_biased(&mut rand)).collect(); 148 | let rho = k256::Scalar::generate_biased(&mut rand); 149 | 150 | let wnla = wnla::WeightNormLinearArgument { 151 | g, 152 | g_vec, 153 | h_vec, 154 | c, 155 | rho, 156 | mu: rho.mul(&rho), 157 | }; 158 | 159 | let l = vec![Scalar::from(1 as u32), Scalar::from(2 as u32), Scalar::from(3 as u32), Scalar::from(4 as u32)]; 160 | let n = vec![Scalar::from(8 as u32), Scalar::from(7 as u32), Scalar::from(6 as u32), Scalar::from(5 as u32)]; 161 | 162 | let commit = wnla.commit(&l, &n); 163 | let mut pt = merlin::Transcript::new(b"wnla test"); 164 | 165 | let proof = wnla.prove(&commit, &mut pt, l, n); 166 | 167 | println!("{}", serde_json::to_string_pretty(&wnla::SerializableProof::from(&proof)).unwrap()); 168 | 169 | let mut vt = merlin::Transcript::new(b"wnla test"); 170 | assert!(wnla.verify(&commit, &mut vt, proof)) 171 | } 172 | 173 | -------------------------------------------------------------------------------- /src/wnla.rs: -------------------------------------------------------------------------------- 1 | //! Definition and implementation of the Bulletproofs++ weight norm linear argument protocol. 2 | use std::ops::{Add, Mul}; 3 | use k256::{AffinePoint, ProjectivePoint, Scalar}; 4 | use k256::elliptic_curve::ops::Invert; 5 | use merlin::Transcript; 6 | use serde::{Deserialize, Serialize}; 7 | use crate::transcript; 8 | use crate::util::*; 9 | 10 | /// Represents public information to be used in weight norm linear argument protocol. 11 | #[derive(Clone, Debug)] 12 | pub struct WeightNormLinearArgument { 13 | pub g: ProjectivePoint, 14 | pub g_vec: Vec, 15 | pub h_vec: Vec, 16 | pub c: Vec, 17 | pub rho: Scalar, 18 | pub mu: Scalar, 19 | } 20 | 21 | /// Represents weight norm linear argument proof - zk-proof of knowledge of vectors `l`, `n` that 22 | /// satisfies commitment `C = v*g + + `, where `v = |n|_{mu}^2 + ` 23 | /// with respect to public `g`, `g_vec`, `h_vec`, `c` 24 | #[derive(Clone, Debug)] 25 | pub struct Proof { 26 | pub r: Vec, 27 | pub x: Vec, 28 | pub l: Vec, 29 | pub n: Vec, 30 | } 31 | 32 | /// Represent serializable version of weight norm linear argument proof (uses AffinePoint instead of ProjectivePoint). 33 | #[derive(Serialize, Deserialize, Clone, Debug)] 34 | pub struct SerializableProof { 35 | pub r: Vec, 36 | pub x: Vec, 37 | pub l: Vec, 38 | pub n: Vec, 39 | } 40 | 41 | impl From<&SerializableProof> for Proof { 42 | fn from(value: &SerializableProof) -> Self { 43 | return Proof { 44 | r: value.r.iter().map(ProjectivePoint::from).collect::>(), 45 | x: value.x.iter().map(ProjectivePoint::from).collect::>(), 46 | l: value.l.clone(), 47 | n: value.n.clone(), 48 | }; 49 | } 50 | } 51 | 52 | impl From<&Proof> for SerializableProof { 53 | fn from(value: &Proof) -> Self { 54 | return SerializableProof { 55 | r: value.r.iter().map(|r_val| r_val.to_affine()).collect::>(), 56 | x: value.x.iter().map(|x_val| x_val.to_affine()).collect::>(), 57 | l: value.l.clone(), 58 | n: value.n.clone(), 59 | }; 60 | } 61 | } 62 | 63 | impl WeightNormLinearArgument { 64 | /// Creates weight norm linear argument commitment to vectors `l`, `n`: 65 | /// `C = v*g + + `, where `v = |n|_{mu}^2 + ` 66 | pub fn commit(&self, l: &[Scalar], n: &[Scalar]) -> ProjectivePoint { 67 | let v = vector_mul(&self.c, l).add(weight_vector_mul(n, n, &self.mu)); 68 | self. 69 | g.mul(v). 70 | add(vector_mul(&self.h_vec, l)). 71 | add(vector_mul(&self.g_vec, n)) 72 | } 73 | 74 | /// Verifies weight norm linear argument proof wor the provided `commitment`. 75 | pub fn verify(&self, commitment: &ProjectivePoint, t: &mut Transcript, proof: Proof) -> bool { 76 | if proof.x.len() != proof.r.len() { 77 | return false; 78 | } 79 | 80 | if proof.x.is_empty() { 81 | return commitment.eq(&self.commit(&proof.l, &proof.n)); 82 | } 83 | 84 | let (c0, c1) = reduce(&self.c); 85 | let (g0, g1) = reduce(&self.g_vec); 86 | let (h0, h1) = reduce(&self.h_vec); 87 | 88 | transcript::app_point(b"wnla_com", commitment, t); 89 | transcript::app_point(b"wnla_x", proof.x.last().unwrap(), t); 90 | transcript::app_point(b"wnla_r", proof.r.last().unwrap(), t); 91 | t.append_u64(b"l.sz", self.h_vec.len() as u64); 92 | t.append_u64(b"n.sz", self.g_vec.len() as u64); 93 | 94 | let y = transcript::get_challenge(b"wnla_challenge", t); 95 | 96 | let h_ = vector_add(&h0, &vector_mul_on_scalar(&h1, &y)); 97 | let g_ = vector_add(&vector_mul_on_scalar(&g0, &self.rho), &vector_mul_on_scalar(&g1, &y)); 98 | let c_ = vector_add(&c0, &vector_mul_on_scalar(&c1, &y)); 99 | 100 | let com_ = commitment. 101 | add(&proof.x.last().unwrap().mul(&y)). 102 | add(&proof.r.last().unwrap().mul(&y.mul(&y).sub(&Scalar::ONE))); 103 | 104 | let wnla = WeightNormLinearArgument { 105 | g: self.g, 106 | g_vec: g_, 107 | h_vec: h_, 108 | c: c_, 109 | rho: self.mu, 110 | mu: self.mu.mul(&self.mu), 111 | }; 112 | 113 | let proof_ = Proof { 114 | r: proof.r[..proof.r.len() - 1].to_vec(), 115 | x: proof.x[..proof.x.len() - 1].to_vec(), 116 | l: proof.l, 117 | n: proof.n, 118 | }; 119 | 120 | wnla.verify(&com_, t, proof_) 121 | } 122 | 123 | /// Creates weight norm linear argument proof. `commitment` argument should be a weight norm 124 | /// linear argument with respect to `l` and `n` private vectors. 125 | pub fn prove(&self, commitment: &ProjectivePoint, t: &mut Transcript, l: Vec, n: Vec) -> Proof { 126 | if l.len() + n.len() < 6 { 127 | return Proof { 128 | r: vec![], 129 | x: vec![], 130 | l, 131 | n, 132 | }; 133 | } 134 | 135 | let rho_inv = self.rho.invert_vartime().unwrap(); 136 | 137 | let (c0, c1) = reduce(&self.c); 138 | let (l0, l1) = reduce(&l); 139 | let (n0, n1) = reduce(&n); 140 | let (g0, g1) = reduce(&self.g_vec); 141 | let (h0, h1) = reduce(&self.h_vec); 142 | 143 | let mu2 = self.mu.mul(&self.mu); 144 | 145 | let vx = weight_vector_mul(&n0, &n1, &mu2). 146 | mul(&rho_inv.mul(&Scalar::from(2u32))). 147 | add(&vector_mul(&c0, &l1)). 148 | add(&vector_mul(&c1, &l0)); 149 | 150 | let vr = weight_vector_mul(&n1, &n1, &mu2).add(&vector_mul(&c1, &l1)); 151 | 152 | let x = self.g.mul(vx). 153 | add(&vector_mul(&h0, &l1)). 154 | add(&vector_mul(&h1, &l0)). 155 | add(&vector_mul(&g0, &vector_mul_on_scalar(&n1, &self.rho))). 156 | add(&vector_mul(&g1, &vector_mul_on_scalar(&n0, &rho_inv))); 157 | 158 | let r = self.g.mul(vr). 159 | add(vector_mul(&h1, &l1)). 160 | add(vector_mul(&g1, &n1)); 161 | 162 | transcript::app_point(b"wnla_com", commitment, t); 163 | transcript::app_point(b"wnla_x", &x, t); 164 | transcript::app_point(b"wnla_r", &r, t); 165 | t.append_u64(b"l.sz", l.len() as u64); 166 | t.append_u64(b"n.sz", n.len() as u64); 167 | 168 | let y = transcript::get_challenge(b"wnla_challenge", t); 169 | 170 | let h_ = vector_add(&h0, &vector_mul_on_scalar(&h1, &y)); 171 | let g_ = vector_add(&vector_mul_on_scalar(&g0, &self.rho), &vector_mul_on_scalar(&g1, &y)); 172 | let c_ = vector_add(&c0, &vector_mul_on_scalar(&c1, &y)); 173 | 174 | let l_ = vector_add(&l0, &vector_mul_on_scalar(&l1, &y)); 175 | let n_ = vector_add(&vector_mul_on_scalar(&n0, &rho_inv), &vector_mul_on_scalar(&n1, &y)); 176 | 177 | let wnla = WeightNormLinearArgument { 178 | g: self.g, 179 | g_vec: g_, 180 | h_vec: h_, 181 | c: c_, 182 | rho: self.mu, 183 | mu: mu2, 184 | }; 185 | 186 | let mut proof = wnla.prove(&wnla.commit(&l_, &n_), t, l_, n_); 187 | proof.r.push(r); 188 | proof.x.push(x); 189 | proof 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /src/range_proof/reciprocal.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | 3 | //! Definition and implementation of the reciprocal range-proof protocol based on arithmetic circuits protocol. 4 | 5 | use std::ops::{Add, Mul}; 6 | use k256::{AffinePoint, ProjectivePoint, Scalar}; 7 | use k256::elliptic_curve::ops::Invert; 8 | use k256::elliptic_curve::rand_core::{CryptoRng, RngCore}; 9 | use merlin::Transcript; 10 | use serde::{Deserialize, Serialize}; 11 | use crate::util::*; 12 | use crate::{circuit, transcript}; 13 | use crate::circuit::{ArithmeticCircuit, PartitionType}; 14 | 15 | /// Represents reciprocal range-proof protocol witness. 16 | #[derive(Clone, Debug)] 17 | pub struct Witness { 18 | /// Private value in range [0..dim_np^dim_nd). 19 | pub x: Scalar, 20 | /// Blinding value 21 | pub s: Scalar, 22 | /// Witness vector: value multiplicities: i-th element corresponds to the 'i-digit' multiplicity 23 | pub m: Vec, 24 | /// Witness vector: value digits. 25 | pub digits: Vec, 26 | } 27 | 28 | /// Represents reciprocal range-proof: zk-proof that committed value lies in [0..dim_np^dim_nd) range. 29 | #[derive(Clone, Debug)] 30 | pub struct Proof { 31 | pub circuit_proof: circuit::Proof, 32 | pub r: ProjectivePoint, 33 | } 34 | 35 | /// Represent serializable version of reciprocal proof (uses AffinePoint instead of ProjectivePoint 36 | /// and serialized version of circuit proof). 37 | #[derive(Serialize, Deserialize, Clone, Debug)] 38 | pub struct SerializableProof { 39 | pub circuit_proof: circuit::SerializableProof, 40 | pub r: AffinePoint, 41 | } 42 | 43 | impl From<&SerializableProof> for Proof { 44 | fn from(value: &SerializableProof) -> Self { 45 | Proof { 46 | circuit_proof: circuit::Proof::from(&value.circuit_proof), 47 | r: ProjectivePoint::from(value.r), 48 | } 49 | } 50 | } 51 | 52 | impl From<&Proof> for SerializableProof { 53 | fn from(value: &Proof) -> Self { 54 | SerializableProof { 55 | circuit_proof: circuit::SerializableProof::from(&value.circuit_proof), 56 | r: value.r.to_affine(), 57 | } 58 | } 59 | } 60 | 61 | /// Represents public reciprocal range proof protocol information. Using this information and challenge 62 | /// both prover and verifier can derive the arithmetic circuit. 63 | #[derive(Clone, Debug)] 64 | pub struct ReciprocalRangeProofProtocol { 65 | /// Count of private proles (size of committed value). Equals to: `dim_nm`. Also, `dim_nv = 1 + dim_nd`. 66 | pub dim_nd: usize, 67 | /// Count of public poles (number system base). Equals to: `dim_no`. 68 | pub dim_np: usize, 69 | 70 | /// Will be used for the value commitment: `commitment = x*g + s*h_vec[0]` 71 | pub g: ProjectivePoint, 72 | 73 | /// Dimension: `dim_nm` 74 | pub g_vec: Vec, 75 | /// Will be used for the value commitment: `commitment = x*g + s*h_vec[0]` 76 | /// Dimension: `dim_nv+9` 77 | pub h_vec: Vec, 78 | 79 | /// Additional points to be used in WNLA. 80 | /// Dimension: `2^n - dim_nm` 81 | pub g_vec_: Vec, 82 | /// Dimension: `2^n - (dim_nv+9)` 83 | pub h_vec_: Vec, 84 | } 85 | 86 | impl ReciprocalRangeProofProtocol { 87 | /// Creates commitment for the private value and blinding: `commitment = x*g + s*h_vec[0]` 88 | pub fn commit_value(&self, x: &Scalar, s: &Scalar) -> ProjectivePoint { 89 | self.g.mul(x).add(&self.h_vec[0].mul(s)) 90 | } 91 | 92 | /// Creates commitment for the reciprocals and blinding: `commitment = s*h_vec[0] + ` 93 | pub fn commit_poles(&self, r: &[Scalar], s: &Scalar) -> ProjectivePoint { 94 | self.h_vec[0].mul(s).add(&vector_mul(&self.h_vec[9..], r)) 95 | } 96 | 97 | /// Verifies zk-proof that committed value lies in [0..dim_np^dim_nd) range. 98 | pub fn verify(&self, commitment: &ProjectivePoint, proof: Proof, t: &mut Transcript) -> bool { 99 | transcript::app_point(b"reciprocal_commitment", commitment, t); 100 | let e = transcript::get_challenge(b"reciprocal_challenge", t); 101 | 102 | let circuit = self.make_circuit(e); 103 | 104 | let circuit_commitment = commitment.add(&proof.r); 105 | 106 | circuit.verify(&[circuit_commitment], t, proof.circuit_proof) 107 | } 108 | 109 | /// Creates zk-proof that committed value lies in [0..dim_np^dim_nd) range. 110 | pub fn prove(&self, commitment: &ProjectivePoint, witness: Witness, t: &mut Transcript, rng: &mut R) -> Proof 111 | where 112 | R: RngCore + CryptoRng 113 | { 114 | transcript::app_point(b"reciprocal_commitment", commitment, t); 115 | let e = transcript::get_challenge(b"reciprocal_challenge", t); 116 | 117 | let r = (0..self.dim_nd).map(|i| 118 | witness.digits[i].add(&e).invert().unwrap() 119 | ).collect::>(); 120 | 121 | let r_blind = Scalar::generate_biased(rng); 122 | let r_com = self.commit_poles(&r, &r_blind); 123 | 124 | let mut v = vec![witness.x]; 125 | r.iter().for_each(|r_val| v.push(*r_val)); 126 | 127 | let w_l = witness.digits; 128 | let w_r = r; 129 | let w_o = witness.m; 130 | 131 | let circuit = self.make_circuit(e); 132 | 133 | let circuit_witness = circuit::Witness { 134 | v: vec![v], 135 | s_v: vec![witness.s.add(r_blind)], 136 | w_l, 137 | w_r, 138 | w_o, 139 | }; 140 | 141 | let circuit_commitment = circuit.commit(&circuit_witness.v[0], &circuit_witness.s_v[0]); 142 | Proof { 143 | circuit_proof: circuit.prove::(&[circuit_commitment], circuit_witness, t, rng), 144 | r: r_com, 145 | } 146 | } 147 | 148 | /// Creates circuit parameters based on provided challenge. For the same challenge will generate same parameters. 149 | #[inline(always)] 150 | pub fn make_circuit(&self, e: Scalar) -> ArithmeticCircuit Option + '_> 151 | { 152 | let dim_nm = self.dim_nd; 153 | let dim_no = self.dim_np; 154 | 155 | let dim_nv = self.dim_nd + 1; 156 | let dim_nl = dim_nv; 157 | let dim_nw = self.dim_nd * 2 + self.dim_np; 158 | 159 | let a_m = vec![Scalar::ONE; dim_nm]; 160 | 161 | let mut W_m = vec![vec![Scalar::ZERO; dim_nw]; dim_nm]; 162 | (0..dim_nm).for_each(|i| W_m[i][i + dim_nm] = minus(&e)); 163 | 164 | let a_l = vec![Scalar::ZERO; dim_nl]; 165 | let base = Scalar::from(self.dim_np as u32); 166 | 167 | let mut W_l = vec![vec![Scalar::ZERO; dim_nw]; dim_nl]; 168 | 169 | // fill for v-part in w vector 170 | (0..dim_nm).for_each(|i| W_l[0][i] = minus(&pow(&base, i))); 171 | 172 | // fill for r-part in w vector 173 | (0..dim_nm).for_each(|i| 174 | (0..dim_nm).for_each(|j| W_l[i + 1][j + dim_nm] = Scalar::ONE) 175 | ); 176 | 177 | (0..dim_nm).for_each(|i| W_l[i + 1][i + dim_nm] = Scalar::ZERO); 178 | 179 | (0..dim_nm).for_each(|i| 180 | (0..dim_no).for_each(|j| 181 | W_l[i + 1][j + 2 * dim_nm] = minus(&(e.add(Scalar::from(j as u32)).invert_vartime().unwrap())) 182 | ) 183 | ); 184 | 185 | // partition function -> map all to ll 186 | let partition = |typ: PartitionType, index: usize| -> Option{ 187 | if typ == PartitionType::LL && index < self.dim_np { 188 | Some(index) 189 | } else { 190 | None 191 | } 192 | }; 193 | 194 | ArithmeticCircuit { 195 | dim_nm, 196 | dim_no, 197 | k: 1, 198 | dim_nl, 199 | dim_nv, 200 | dim_nw, 201 | g: self.g, 202 | g_vec: self.g_vec.clone(), 203 | h_vec: self.h_vec.clone(), 204 | W_m, 205 | W_l, 206 | a_m, 207 | a_l, 208 | f_l: true, 209 | f_m: false, 210 | g_vec_: self.g_vec_.clone(), 211 | h_vec_: self.h_vec_.clone(), 212 | partition, 213 | } 214 | } 215 | } 216 | 217 | 218 | -------------------------------------------------------------------------------- /src/circuit.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | //! Definition and implementation of the Bulletproofs++ arithmetic circuit protocol. 3 | 4 | use std::ops::{Add, Mul, Sub}; 5 | use k256::{AffinePoint, ProjectivePoint, Scalar}; 6 | use k256::elliptic_curve::ops::Invert; 7 | use k256::elliptic_curve::rand_core::{CryptoRng, RngCore}; 8 | use merlin::Transcript; 9 | use serde::{Deserialize, Serialize}; 10 | use crate::util::*; 11 | use crate::{transcript, wnla}; 12 | use crate::wnla::WeightNormLinearArgument; 13 | 14 | #[derive(Clone, Debug, Copy, PartialEq)] 15 | pub enum PartitionType { 16 | LO, 17 | LL, 18 | LR, 19 | NO, 20 | } 21 | 22 | /// Represents arithmetic circuit zero-knowledge proof. 23 | #[derive(Clone, Debug)] 24 | pub struct Proof { 25 | pub c_l: ProjectivePoint, 26 | pub c_r: ProjectivePoint, 27 | pub c_o: ProjectivePoint, 28 | pub c_s: ProjectivePoint, 29 | pub r: Vec, 30 | pub x: Vec, 31 | pub l: Vec, 32 | pub n: Vec, 33 | } 34 | 35 | /// Represent serializable version of arithmetic circuit proof (uses AffinePoint instead of ProjectivePoint). 36 | #[derive(Serialize, Deserialize, Clone, Debug)] 37 | pub struct SerializableProof { 38 | pub c_l: AffinePoint, 39 | pub c_r: AffinePoint, 40 | pub c_o: AffinePoint, 41 | pub c_s: AffinePoint, 42 | pub r: Vec, 43 | pub x: Vec, 44 | pub l: Vec, 45 | pub n: Vec, 46 | } 47 | 48 | impl From<&SerializableProof> for Proof { 49 | fn from(value: &SerializableProof) -> Self { 50 | return Proof { 51 | c_l: ProjectivePoint::from(&value.c_l), 52 | c_r: ProjectivePoint::from(&value.c_r), 53 | c_o: ProjectivePoint::from(&value.c_o), 54 | c_s: ProjectivePoint::from(&value.c_s), 55 | r: value.r.iter().map(ProjectivePoint::from).collect::>(), 56 | x: value.x.iter().map(ProjectivePoint::from).collect::>(), 57 | l: value.l.clone(), 58 | n: value.n.clone(), 59 | }; 60 | } 61 | } 62 | 63 | impl From<&Proof> for SerializableProof { 64 | fn from(value: &Proof) -> Self { 65 | return SerializableProof { 66 | c_l: value.c_l.to_affine(), 67 | c_r: value.c_r.to_affine(), 68 | c_o: value.c_o.to_affine(), 69 | c_s: value.c_s.to_affine(), 70 | r: value.r.iter().map(|r_val| r_val.to_affine()).collect::>(), 71 | x: value.x.iter().map(|x_val| x_val.to_affine()).collect::>(), 72 | l: value.l.clone(), 73 | n: value.n.clone(), 74 | }; 75 | } 76 | } 77 | 78 | /// Represents arithmetic circuit witness. 79 | #[derive(Clone, Debug)] 80 | pub struct Witness { 81 | /// Dimension: `k*dim_nv` 82 | pub v: Vec>, 83 | /// Dimension: `k` 84 | pub s_v: Vec, 85 | /// Dimension: `dim_nm` 86 | pub w_l: Vec, 87 | /// Dimension: `dim_nm` 88 | pub w_r: Vec, 89 | /// Dimension: `dim_no` 90 | pub w_o: Vec, 91 | } 92 | 93 | /// Represents arithmetic circuit. 94 | /// P - partition function. 95 | pub struct ArithmeticCircuit

96 | where 97 | P: Fn(PartitionType, usize) -> Option 98 | { 99 | pub dim_nm: usize, 100 | pub dim_no: usize, 101 | pub k: usize, 102 | 103 | /// Equals to: `dim_nv * k` 104 | pub dim_nl: usize, 105 | /// Count of witness vectors v. 106 | pub dim_nv: usize, 107 | /// Equals to: `dim_nm + dim_nm + n_o` 108 | pub dim_nw: usize, 109 | 110 | pub g: ProjectivePoint, 111 | 112 | /// Dimension: `dim_nm` 113 | pub g_vec: Vec, 114 | /// Dimension: `dim_nv+9` 115 | pub h_vec: Vec, 116 | 117 | /// Dimension: `dim_nm * dim_nw` 118 | pub W_m: Vec>, 119 | /// Dimension: `dim_nl * dim_nw` 120 | pub W_l: Vec>, 121 | 122 | /// Dimension: `dim_nm` 123 | pub a_m: Vec, 124 | /// Dimension: `dim_nl` 125 | pub a_l: Vec, 126 | 127 | pub f_l: bool, 128 | pub f_m: bool, 129 | 130 | /// Vector of points that will be used in WNLA protocol. 131 | /// Dimension: `2^n - dim_nm` 132 | pub g_vec_: Vec, 133 | /// Vector of points that will be used in WNLA protocol. 134 | /// Dimension: `2^n - (dim_nv+9)` 135 | pub h_vec_: Vec, 136 | 137 | /// Partition function to map `w_o` and corresponding parts of `W_m` and `W_l` 138 | pub partition: P, 139 | } 140 | 141 | impl

ArithmeticCircuit

142 | where 143 | P: Fn(PartitionType, usize) -> Option 144 | { 145 | /// Creates commitment to the arithmetic circuit witness. 146 | pub fn commit(&self, v: &[Scalar], s: &Scalar) -> ProjectivePoint { 147 | self. 148 | g.mul(&v[0]). 149 | add(&self.h_vec[0].mul(s)). 150 | add(&vector_mul(&self.h_vec[9..], &v[1..])) 151 | } 152 | 153 | /// Verifies arithmetic circuit proof with respect to the `v` commitments vector. 154 | pub fn verify(&self, v: &[ProjectivePoint], t: &mut Transcript, proof: Proof) -> bool { 155 | transcript::app_point(b"commitment_cl", &proof.c_l, t); 156 | transcript::app_point(b"commitment_cr", &proof.c_r, t); 157 | transcript::app_point(b"commitment_co", &proof.c_o, t); 158 | 159 | v.iter().for_each(|v_val| transcript::app_point(b"commitment_v", v_val, t)); 160 | 161 | let rho = transcript::get_challenge(b"circuit_rho", t); 162 | let lambda = transcript::get_challenge(b"circuit_lambda", t); 163 | let beta = transcript::get_challenge(b"circuit_beta", t); 164 | let delta = transcript::get_challenge(b"circuit_delta", t); 165 | 166 | let mu = rho.mul(rho); 167 | 168 | let lambda_vec = self.collect_lambda(&lambda, &mu); 169 | let mu_vec = vector_mul_on_scalar(&e(&mu, self.dim_nm), &mu); 170 | 171 | let ( 172 | c_nL, 173 | c_nR, 174 | c_nO, 175 | c_lL, 176 | c_lR, 177 | c_lO 178 | ) = self.collect_c(&lambda_vec, &mu_vec, &mu); 179 | 180 | let two = Scalar::from(2u32); 181 | 182 | let mut v_ = ProjectivePoint::IDENTITY; 183 | (0..self.k). 184 | for_each(|i| 185 | v_ = v_.add(v[i].mul(self.linear_comb_coef(i, &lambda, &mu))) 186 | ); 187 | v_ = v_.mul(&two); 188 | 189 | transcript::app_point(b"commitment_cs", &proof.c_s, t); 190 | 191 | let tau = transcript::get_challenge(b"circuit_tau", t); 192 | let tau_inv = tau.invert_vartime().unwrap(); 193 | let tau2 = tau.mul(&tau); 194 | let tau3 = tau2.mul(&tau); 195 | 196 | let delta_inv = delta.invert_vartime().unwrap(); 197 | 198 | let mut pn_tau = vector_mul_on_scalar(&c_nO, &tau3.mul(&delta_inv)); 199 | pn_tau = vector_sub(&pn_tau, &vector_mul_on_scalar(&c_nL, &tau2)); 200 | pn_tau = vector_add(&pn_tau, &vector_mul_on_scalar(&c_nR, &tau)); 201 | 202 | let ps_tau = weight_vector_mul(&pn_tau, &pn_tau, &mu). 203 | add(&vector_mul(&lambda_vec, &self.a_l).mul(&tau3).mul(&two)). 204 | sub(&vector_mul(&mu_vec, &self.a_m).mul(&tau3).mul(&two)); 205 | 206 | let pt = self.g.mul(ps_tau).add(vector_mul(&self.g_vec, &pn_tau)); 207 | 208 | let cr_tau = vec![ 209 | Scalar::ONE, 210 | tau_inv.mul(beta), 211 | tau.mul(beta), 212 | tau2.mul(beta), 213 | tau3.mul(beta), 214 | tau.mul(tau3).mul(beta), 215 | tau2.mul(tau3).mul(beta), 216 | tau3.mul(tau3).mul(beta), 217 | tau3.mul(tau3).mul(tau).mul(beta), 218 | ]; 219 | 220 | let c_l0 = self.collect_cl0(&lambda, &mu); 221 | 222 | let mut cl_tau = vector_mul_on_scalar(&c_lO, &tau3.mul(&delta_inv)); 223 | cl_tau = vector_sub(&cl_tau, &vector_mul_on_scalar(&c_lL, &tau2)); 224 | cl_tau = vector_add(&cl_tau, &vector_mul_on_scalar(&c_lR, &tau)); 225 | cl_tau = vector_mul_on_scalar(&cl_tau, &two); 226 | cl_tau = vector_sub(&cl_tau, &c_l0); 227 | 228 | let mut c = [&cr_tau[..], &cl_tau[..]].concat(); 229 | 230 | let commitment = pt. 231 | add(&proof.c_s.mul(&tau_inv)). 232 | sub(&proof.c_o.mul(&delta)). 233 | add(&proof.c_l.mul(&tau)). 234 | sub(&proof.c_r.mul(&tau2)). 235 | add(&v_.mul(&tau3)); 236 | 237 | while c.len() < self.h_vec.len() + self.h_vec_.len() { 238 | c.push(Scalar::ZERO); 239 | } 240 | 241 | let wnla = WeightNormLinearArgument { 242 | g: self.g, 243 | g_vec: [&self.g_vec[..], &self.g_vec_[..]].concat(), 244 | h_vec: [&self.h_vec[..], &self.h_vec_[..]].concat(), 245 | c, 246 | rho, 247 | mu, 248 | }; 249 | 250 | wnla.verify(&commitment, t, wnla::Proof { 251 | r: proof.r, 252 | x: proof.x, 253 | l: proof.l, 254 | n: proof.n, 255 | }) 256 | } 257 | 258 | /// Creates arithmetic circuit proof for the corresponding witness. Also, `v` commitments vector 259 | /// should correspond input witness in `witness` argument. 260 | pub fn prove(&self, v: &[ProjectivePoint], witness: Witness, t: &mut Transcript, rng: &mut R) -> Proof 261 | where 262 | R: RngCore + CryptoRng 263 | { 264 | let ro = vec![ 265 | Scalar::generate_biased(rng), 266 | Scalar::generate_biased(rng), 267 | Scalar::generate_biased(rng), 268 | Scalar::generate_biased(rng), 269 | Scalar::ZERO, 270 | Scalar::generate_biased(rng), 271 | Scalar::generate_biased(rng), 272 | Scalar::generate_biased(rng), 273 | Scalar::ZERO, 274 | ]; 275 | 276 | let rl = vec![ 277 | Scalar::generate_biased(rng), 278 | Scalar::generate_biased(rng), 279 | Scalar::generate_biased(rng), 280 | Scalar::ZERO, 281 | Scalar::generate_biased(rng), 282 | Scalar::generate_biased(rng), 283 | Scalar::generate_biased(rng), 284 | Scalar::ZERO, 285 | Scalar::ZERO, 286 | ]; 287 | 288 | let rr = vec![ 289 | Scalar::generate_biased(rng), 290 | Scalar::generate_biased(rng), 291 | Scalar::ZERO, 292 | Scalar::generate_biased(rng), 293 | Scalar::generate_biased(rng), 294 | Scalar::generate_biased(rng), 295 | Scalar::ZERO, 296 | Scalar::ZERO, 297 | Scalar::ZERO, 298 | ]; 299 | 300 | let nl = witness.w_l; 301 | let nr = witness.w_r; 302 | 303 | let no = (0..self.dim_nm).map(|j| 304 | if let Some(i) = (self.partition)(PartitionType::NO, j) { 305 | witness.w_o[i] 306 | } else { 307 | Scalar::ZERO 308 | } 309 | ).collect::>(); 310 | 311 | let lo = (0..self.dim_nv).map(|j| 312 | if let Some(i) = (self.partition)(PartitionType::LO, j) { 313 | witness.w_o[i] 314 | } else { 315 | Scalar::ZERO 316 | } 317 | ).collect::>(); 318 | 319 | let ll = (0..self.dim_nv).map(|j| 320 | if let Some(i) = (self.partition)(PartitionType::LL, j) { 321 | witness.w_o[i] 322 | } else { 323 | Scalar::ZERO 324 | } 325 | ).collect::>(); 326 | 327 | let lr = (0..self.dim_nv).map(|j| 328 | if let Some(i) = (self.partition)(PartitionType::LR, j) { 329 | witness.w_o[i] 330 | } else { 331 | Scalar::ZERO 332 | } 333 | ).collect::>(); 334 | 335 | let co = 336 | vector_mul(&self.h_vec, &[&ro[..], &lo[..]].concat()). 337 | add(vector_mul(&self.g_vec, &no)); 338 | 339 | let cl = 340 | vector_mul(&self.h_vec, &[&rl[..], &ll[..]].concat()). 341 | add(vector_mul(&self.g_vec, &nl)); 342 | 343 | let cr = 344 | vector_mul(&self.h_vec, &[&rr[..], &lr[..]].concat()). 345 | add(vector_mul(&self.g_vec, &nr)); 346 | 347 | transcript::app_point(b"commitment_cl", &cl, t); 348 | transcript::app_point(b"commitment_cr", &cr, t); 349 | transcript::app_point(b"commitment_co", &co, t); 350 | v.iter().for_each(|v_val| transcript::app_point(b"commitment_v", v_val, t)); 351 | 352 | let rho = transcript::get_challenge(b"circuit_rho", t); 353 | let lambda = transcript::get_challenge(b"circuit_lambda", t); 354 | let beta = transcript::get_challenge(b"circuit_beta", t); 355 | let delta = transcript::get_challenge(b"circuit_delta", t); 356 | 357 | let mu = rho.mul(rho); 358 | 359 | let lambda_vec = self.collect_lambda(&lambda, &mu); 360 | let mu_vec = vector_mul_on_scalar(&e(&mu, self.dim_nm), &mu); 361 | 362 | let ( 363 | c_nL, 364 | c_nR, 365 | c_nO, 366 | c_lL, 367 | c_lR, 368 | c_lO 369 | ) = self.collect_c(&lambda_vec, &mu_vec, &mu); 370 | 371 | let ls = (0..self.dim_nv).map(|_| Scalar::generate_biased(rng)).collect::>(); 372 | let ns = (0..self.dim_nm).map(|_| Scalar::generate_biased(rng)).collect::>(); 373 | 374 | let two = Scalar::from(2u32); 375 | 376 | let mut v_0 = Scalar::ZERO; 377 | (0..self.k). 378 | for_each(|i| 379 | v_0 = v_0.add(witness.v[i][0].mul(self.linear_comb_coef(i, &lambda, &mu))) 380 | ); 381 | v_0 = v_0.mul(&two); 382 | 383 | let mut rv = vec![Scalar::ZERO; 9]; 384 | (0..self.k). 385 | for_each(|i| 386 | rv[0] = rv[0].add(witness.s_v[i].mul(self.linear_comb_coef(i, &lambda, &mu))) 387 | ); 388 | rv[0] = rv[0].mul(&two); 389 | 390 | let mut v_1 = vec![Scalar::ZERO; self.dim_nv - 1]; 391 | (0..self.k). 392 | for_each(|i| 393 | v_1 = vector_add(&v_1, &vector_mul_on_scalar(&witness.v[i][1..], &self.linear_comb_coef(i, &lambda, &mu))) 394 | ); 395 | v_1 = vector_mul_on_scalar(&v_1, &two); 396 | 397 | let c_l0 = self.collect_cl0(&lambda, &mu); 398 | 399 | // [-2 -1 0 1 2 4 5 6] -> f(tau) coefficients vector 400 | let mut f_ = vec![Scalar::ZERO; 8]; 401 | 402 | let delta2 = delta.mul(&delta); 403 | let delta_inv = delta.invert_vartime().unwrap(); 404 | 405 | // -2 406 | f_[0] = minus(&weight_vector_mul(&ns, &ns, &mu)); 407 | 408 | // -1 409 | f_[1] = vector_mul(&c_l0, &ls). 410 | add(delta.mul(&two).mul(&weight_vector_mul(&ns, &no, &mu))); 411 | 412 | // 0 413 | f_[2] = minus(&vector_mul(&c_lR, &ls).mul(&two)). 414 | sub(&vector_mul(&c_l0, &lo).mul(&delta)). 415 | sub(&weight_vector_mul(&ns, &vector_add(&nl, &c_nR), &mu).mul(&two)). 416 | sub(&weight_vector_mul(&no, &no, &mu).mul(&delta2)); 417 | 418 | //1 419 | f_[3] = vector_mul(&c_lL, &ls).mul(&two). 420 | add(&vector_mul(&c_lR, &lo).mul(&delta).mul(&two)). 421 | add(&vector_mul(&c_l0, &ll)). 422 | add(&weight_vector_mul(&ns, &vector_add(&nr, &c_nL), &mu).mul(&two)). 423 | add(&weight_vector_mul(&no, &vector_add(&nl, &c_nR), &mu).mul(&two).mul(&delta)); 424 | 425 | // 2 426 | f_[4] = weight_vector_mul(&c_nR, &c_nR, &mu). 427 | sub(&vector_mul(&c_lO, &ls).mul(&delta_inv).mul(&two)). 428 | sub(&vector_mul(&c_lL, &lo).mul(&delta).mul(&two)). 429 | sub(&vector_mul(&c_lR, &ll).mul(&two)). 430 | sub(&vector_mul(&c_l0, &lr)). 431 | sub(&weight_vector_mul(&ns, &c_nO, &mu).mul(&delta_inv).mul(&two)). 432 | sub(&weight_vector_mul(&no, &vector_add(&nr, &c_nL), &mu).mul(&delta).mul(&two)). 433 | sub(&weight_vector_mul(&vector_add(&nl, &c_nR), &vector_add(&nl, &c_nR), &mu)); 434 | 435 | // 3 should be zero 436 | 437 | // 4 438 | f_[5] = weight_vector_mul(&c_nO, &c_nR, &mu).mul(&delta_inv).mul(&two). 439 | add(&weight_vector_mul(&c_nL, &c_nL, &mu)). 440 | sub(&vector_mul(&c_lO, &ll).mul(&delta_inv).mul(&two)). 441 | sub(&vector_mul(&c_lL, &lr).mul(&two)). 442 | sub(&vector_mul(&c_lR, &v_1).mul(&two)). 443 | sub(&weight_vector_mul(&vector_add(&nl, &c_nR), &c_nO, &mu).mul(&delta_inv).mul(&two)). 444 | sub(&weight_vector_mul(&vector_add(&nr, &c_nL), &vector_add(&nr, &c_nL), &mu)); 445 | 446 | // 5 447 | f_[6] = minus(&weight_vector_mul(&c_nO, &c_nL, &mu).mul(&delta_inv).mul(&two)). 448 | add(&vector_mul(&c_nO, &lr).mul(&delta_inv).mul(&two)). 449 | add(&vector_mul(&c_lL, &v_1).mul(&two)). 450 | add(&weight_vector_mul(&vector_add(&nr, &c_nL), &c_nO, &mu).mul(&delta_inv).mul(&two)); 451 | 452 | // 6 453 | f_[7] = minus(&vector_mul(&c_lO, &v_1).mul(&delta_inv).mul(&two)); 454 | 455 | let beta_inv = beta.invert_vartime().unwrap(); 456 | 457 | let rs = vec![ 458 | f_[1].add(ro[1].mul(&delta).mul(&beta)), 459 | f_[0].mul(&beta_inv), 460 | ro[0].mul(&delta).add(&f_[2]).mul(&beta_inv).sub(&rl[1]), 461 | f_[3].sub(&rl[0]).mul(&beta_inv).add(&ro[2].mul(&delta).add(rr[1])), 462 | f_[4].add(&rr[0]).mul(&beta_inv).add(&ro[3].mul(&delta).sub(rl[2])), 463 | minus(&rv[0].mul(&beta_inv)), 464 | f_[5].mul(&beta_inv).add(&ro[5].mul(&delta)).add(&rr[3]).sub(&rl[4]), 465 | f_[6].mul(&beta_inv).add(&rr[4]).add(&ro[6].mul(&delta)).sub(&rl[5]), 466 | f_[7].mul(&beta_inv).add(&ro[7].mul(&delta)).sub(&rl[6]).add(&rr[5]), 467 | ]; 468 | 469 | let cs = vector_mul(&self.h_vec, &[&rs[..], &ls[..]].concat()). 470 | add(vector_mul(&self.g_vec, &ns)); 471 | 472 | transcript::app_point(b"commitment_cs", &cs, t); 473 | 474 | let tau = transcript::get_challenge(b"circuit_tau", t); 475 | let tau_inv = tau.invert_vartime().unwrap(); 476 | let tau2 = tau.mul(&tau); 477 | let tau3 = tau2.mul(&tau); 478 | 479 | let mut l = vector_mul_on_scalar(&[&rs[..], &ls[..]].concat(), &tau_inv); 480 | l = vector_sub(&l, &vector_mul_on_scalar(&[&ro[..], &lo[..]].concat(), &delta)); 481 | l = vector_add(&l, &vector_mul_on_scalar(&[&rl[..], &ll[..]].concat(), &tau)); 482 | l = vector_sub(&l, &vector_mul_on_scalar(&[&rr[..], &lr[..]].concat(), &tau2)); 483 | l = vector_add(&l, &vector_mul_on_scalar(&[&rv[..], &v_1[..]].concat(), &tau3)); 484 | 485 | let mut pn_tau = vector_mul_on_scalar(&c_nO, &tau3.mul(&delta_inv)); 486 | pn_tau = vector_sub(&pn_tau, &vector_mul_on_scalar(&c_nL, &tau2)); 487 | pn_tau = vector_add(&pn_tau, &vector_mul_on_scalar(&c_nR, &tau)); 488 | 489 | let ps_tau = weight_vector_mul(&pn_tau, &pn_tau, &mu). 490 | add(&vector_mul(&lambda_vec, &self.a_l).mul(&tau3).mul(&two)). 491 | sub(&vector_mul(&mu_vec, &self.a_m).mul(&tau3).mul(&two)); 492 | 493 | let mut n_tau = vector_mul_on_scalar(&ns, &tau_inv); 494 | n_tau = vector_sub(&n_tau, &vector_mul_on_scalar(&no, &delta)); 495 | n_tau = vector_add(&n_tau, &vector_mul_on_scalar(&nl, &tau)); 496 | n_tau = vector_sub(&n_tau, &vector_mul_on_scalar(&nr, &tau2)); 497 | 498 | let mut n = vector_add(&pn_tau, &n_tau); 499 | 500 | let cr_tau = vec![ 501 | Scalar::ONE, 502 | tau_inv.mul(beta), 503 | tau.mul(beta), 504 | tau2.mul(beta), 505 | tau3.mul(beta), 506 | tau.mul(tau3).mul(beta), 507 | tau2.mul(tau3).mul(beta), 508 | tau3.mul(tau3).mul(beta), 509 | tau3.mul(tau3).mul(tau).mul(beta), 510 | ]; 511 | 512 | let mut cl_tau = vector_mul_on_scalar(&c_lO, &tau3.mul(&delta_inv)); 513 | cl_tau = vector_sub(&cl_tau, &vector_mul_on_scalar(&c_lL, &tau2)); 514 | cl_tau = vector_add(&cl_tau, &vector_mul_on_scalar(&c_lR, &tau)); 515 | cl_tau = vector_mul_on_scalar(&cl_tau, &two); 516 | cl_tau = vector_sub(&cl_tau, &c_l0); 517 | 518 | let mut c = [&cr_tau[..], &cl_tau[..]].concat(); 519 | 520 | let v = ps_tau.add(&tau3.mul(&v_0)); 521 | 522 | let commitment = self.g.mul(v). 523 | add(&vector_mul(&self.h_vec, &l)). 524 | add(&vector_mul(&self.g_vec, &n)); 525 | 526 | while l.len() < self.h_vec.len() + self.h_vec_.len() { 527 | l.push(Scalar::ZERO); 528 | c.push(Scalar::ZERO); 529 | } 530 | 531 | while n.len() < self.g_vec.len() + self.g_vec_.len() { 532 | n.push(Scalar::ZERO); 533 | } 534 | 535 | let wnla = WeightNormLinearArgument { 536 | g: self.g, 537 | g_vec: [&self.g_vec[..], &self.g_vec_[..]].concat(), 538 | h_vec: [&self.h_vec[..], &self.h_vec_[..]].concat(), 539 | c, 540 | rho, 541 | mu, 542 | }; 543 | 544 | let proof_wnla = wnla.prove(&commitment, t, l, n); 545 | 546 | Proof { 547 | c_l: cl, 548 | c_r: cr, 549 | c_o: co, 550 | c_s: cs, 551 | r: proof_wnla.r, 552 | x: proof_wnla.x, 553 | l: proof_wnla.l, 554 | n: proof_wnla.n, 555 | } 556 | } 557 | 558 | 559 | fn linear_comb_coef(&self, i: usize, lambda: &Scalar, mu: &Scalar) -> Scalar { 560 | let mut coef = Scalar::ZERO; 561 | if self.f_l { 562 | coef = coef.add(pow(lambda, self.dim_nv * i)) 563 | } 564 | 565 | if self.f_m { 566 | coef = coef.add(pow(mu, self.dim_nv * i + 1)) 567 | } 568 | 569 | coef 570 | } 571 | 572 | fn collect_cl0(&self, lambda: &Scalar, mu: &Scalar) -> Vec { 573 | let mut c_l0 = vec![Scalar::ZERO; self.dim_nv - 1]; 574 | if self.f_l { 575 | c_l0 = e(lambda, self.dim_nv)[1..].to_vec(); 576 | } 577 | if self.f_m { 578 | c_l0 = vector_sub(&c_l0, &vector_mul_on_scalar(&e(mu, self.dim_nv)[1..], mu)); 579 | } 580 | 581 | c_l0 582 | } 583 | 584 | fn collect_c(&self, lambda_vec: &[Scalar], mu_vec: &[Scalar], mu: &Scalar) -> (Vec, Vec, Vec, Vec, Vec, Vec) { 585 | let (M_lnL, M_mnL, M_lnR, M_mnR) = self.collect_m_rl(); 586 | let (M_lnO, M_mnO, M_llL, M_mlL, M_llR, M_mlR, M_llO, M_mlO) = self.collect_m_o(); 587 | 588 | let mu_diag_inv = diag_inv(mu, self.dim_nm); 589 | 590 | let c_nL = vector_mul_on_matrix(&vector_sub(&vector_mul_on_matrix(lambda_vec, &M_lnL), &vector_mul_on_matrix(mu_vec, &M_mnL)), &mu_diag_inv); 591 | let c_nR = vector_mul_on_matrix(&vector_sub(&vector_mul_on_matrix(lambda_vec, &M_lnR), &vector_mul_on_matrix(mu_vec, &M_mnR)), &mu_diag_inv); 592 | let c_nO = vector_mul_on_matrix(&vector_sub(&vector_mul_on_matrix(lambda_vec, &M_lnO), &vector_mul_on_matrix(mu_vec, &M_mnO)), &mu_diag_inv); 593 | 594 | let c_lL = vector_sub(&vector_mul_on_matrix(lambda_vec, &M_llL), &vector_mul_on_matrix(mu_vec, &M_mlL)); 595 | let c_lR = vector_sub(&vector_mul_on_matrix(lambda_vec, &M_llR), &vector_mul_on_matrix(mu_vec, &M_mlR)); 596 | let c_lO = vector_sub(&vector_mul_on_matrix(lambda_vec, &M_llO), &vector_mul_on_matrix(mu_vec, &M_mlO)); 597 | 598 | (c_nL, c_nR, c_nO, c_lL, c_lR, c_lO) 599 | } 600 | 601 | fn collect_lambda(&self, lambda: &Scalar, mu: &Scalar) -> Vec { 602 | let mut lambda_vec = e(lambda, self.dim_nl); 603 | if self.f_l && self.f_m { 604 | lambda_vec = vector_sub( 605 | &lambda_vec, 606 | &vector_add( 607 | &vector_tensor_mul(&vector_mul_on_scalar(&e(lambda, self.dim_nv), mu), &e(&pow(mu, self.dim_nv), self.k)), 608 | &vector_tensor_mul(&e(mu, self.dim_nv), &e(&pow(lambda, self.dim_nv), self.k)), 609 | ), 610 | ); 611 | } 612 | 613 | lambda_vec 614 | } 615 | 616 | fn collect_m_rl(&self) -> (Vec>, Vec>, Vec>, Vec>) { 617 | let M_lnL = (0..self.dim_nl).map(|i| Vec::from(&self.W_l[i][..self.dim_nm])).collect::>>(); 618 | let M_mnL = (0..self.dim_nm).map(|i| Vec::from(&self.W_m[i][..self.dim_nm])).collect::>>(); 619 | let M_lnR = (0..self.dim_nl).map(|i| Vec::from(&self.W_l[i][self.dim_nm..self.dim_nm * 2])).collect::>>(); 620 | let M_mnR = (0..self.dim_nm).map(|i| Vec::from(&self.W_m[i][self.dim_nm..self.dim_nm * 2])).collect::>>(); 621 | (M_lnL, M_mnL, M_lnR, M_mnR) 622 | } 623 | 624 | fn collect_m_o(&self) -> (Vec>, Vec>, Vec>, Vec>, Vec>, Vec>, Vec>, Vec>) { 625 | let W_lO = (0..self.dim_nl).map(|i| Vec::from(&self.W_l[i][self.dim_nm * 2..])).collect::>>(); 626 | let W_mO = (0..self.dim_nm).map(|i| Vec::from(&self.W_m[i][self.dim_nm * 2..])).collect::>>(); 627 | 628 | let map_f = |isz: usize, jsz: usize, typ: PartitionType, W_x: &Vec>| -> Vec>{ 629 | (0..isz).map(|i| 630 | (0..jsz).map(|j| 631 | if let Some(j_) = (self.partition)(typ, j) { 632 | W_x[i][j_] 633 | } else { 634 | Scalar::ZERO 635 | } 636 | ).collect::>() 637 | ).collect::>>() 638 | }; 639 | 640 | let M_lnO = map_f(self.dim_nl, self.dim_nm, PartitionType::NO, &W_lO); 641 | let M_llL = map_f(self.dim_nl, self.dim_nv, PartitionType::LL, &W_lO); 642 | let M_llR = map_f(self.dim_nl, self.dim_nv, PartitionType::LR, &W_lO); 643 | let M_llO = map_f(self.dim_nl, self.dim_nv, PartitionType::LO, &W_lO); 644 | 645 | 646 | let M_mnO = map_f(self.dim_nm, self.dim_nm, PartitionType::NO, &W_mO); 647 | let M_mlL = map_f(self.dim_nm, self.dim_nv, PartitionType::LL, &W_mO); 648 | let M_mlR = map_f(self.dim_nm, self.dim_nv, PartitionType::LR, &W_mO); 649 | let M_mlO = map_f(self.dim_nm, self.dim_nv, PartitionType::LO, &W_mO); 650 | 651 | 652 | (M_lnO, M_mnO, M_llL, M_mlL, M_llR, M_mlR, M_llO, M_mlO) 653 | } 654 | } 655 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "aho-corasick" 7 | version = "1.1.3" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" 10 | dependencies = [ 11 | "memchr", 12 | ] 13 | 14 | [[package]] 15 | name = "anes" 16 | version = "0.1.6" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" 19 | 20 | [[package]] 21 | name = "anstyle" 22 | version = "1.0.7" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" 25 | 26 | [[package]] 27 | name = "autocfg" 28 | version = "1.3.0" 29 | source = "registry+https://github.com/rust-lang/crates.io-index" 30 | checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" 31 | 32 | [[package]] 33 | name = "base16ct" 34 | version = "0.2.0" 35 | source = "registry+https://github.com/rust-lang/crates.io-index" 36 | checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" 37 | 38 | [[package]] 39 | name = "base64ct" 40 | version = "1.6.0" 41 | source = "registry+https://github.com/rust-lang/crates.io-index" 42 | checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" 43 | 44 | [[package]] 45 | name = "block-buffer" 46 | version = "0.10.4" 47 | source = "registry+https://github.com/rust-lang/crates.io-index" 48 | checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" 49 | dependencies = [ 50 | "generic-array", 51 | ] 52 | 53 | [[package]] 54 | name = "bp-pp" 55 | version = "0.1.1" 56 | dependencies = [ 57 | "criterion", 58 | "k256", 59 | "merlin", 60 | "serde", 61 | "serde_json", 62 | ] 63 | 64 | [[package]] 65 | name = "bumpalo" 66 | version = "3.16.0" 67 | source = "registry+https://github.com/rust-lang/crates.io-index" 68 | checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" 69 | 70 | [[package]] 71 | name = "byteorder" 72 | version = "1.5.0" 73 | source = "registry+https://github.com/rust-lang/crates.io-index" 74 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 75 | 76 | [[package]] 77 | name = "cast" 78 | version = "0.3.0" 79 | source = "registry+https://github.com/rust-lang/crates.io-index" 80 | checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" 81 | 82 | [[package]] 83 | name = "cfg-if" 84 | version = "1.0.0" 85 | source = "registry+https://github.com/rust-lang/crates.io-index" 86 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 87 | 88 | [[package]] 89 | name = "ciborium" 90 | version = "0.2.2" 91 | source = "registry+https://github.com/rust-lang/crates.io-index" 92 | checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" 93 | dependencies = [ 94 | "ciborium-io", 95 | "ciborium-ll", 96 | "serde", 97 | ] 98 | 99 | [[package]] 100 | name = "ciborium-io" 101 | version = "0.2.2" 102 | source = "registry+https://github.com/rust-lang/crates.io-index" 103 | checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" 104 | 105 | [[package]] 106 | name = "ciborium-ll" 107 | version = "0.2.2" 108 | source = "registry+https://github.com/rust-lang/crates.io-index" 109 | checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" 110 | dependencies = [ 111 | "ciborium-io", 112 | "half", 113 | ] 114 | 115 | [[package]] 116 | name = "clap" 117 | version = "4.5.4" 118 | source = "registry+https://github.com/rust-lang/crates.io-index" 119 | checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" 120 | dependencies = [ 121 | "clap_builder", 122 | ] 123 | 124 | [[package]] 125 | name = "clap_builder" 126 | version = "4.5.2" 127 | source = "registry+https://github.com/rust-lang/crates.io-index" 128 | checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" 129 | dependencies = [ 130 | "anstyle", 131 | "clap_lex", 132 | ] 133 | 134 | [[package]] 135 | name = "clap_lex" 136 | version = "0.7.0" 137 | source = "registry+https://github.com/rust-lang/crates.io-index" 138 | checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" 139 | 140 | [[package]] 141 | name = "const-oid" 142 | version = "0.9.6" 143 | source = "registry+https://github.com/rust-lang/crates.io-index" 144 | checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" 145 | 146 | [[package]] 147 | name = "cpufeatures" 148 | version = "0.2.12" 149 | source = "registry+https://github.com/rust-lang/crates.io-index" 150 | checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" 151 | dependencies = [ 152 | "libc", 153 | ] 154 | 155 | [[package]] 156 | name = "criterion" 157 | version = "0.5.1" 158 | source = "registry+https://github.com/rust-lang/crates.io-index" 159 | checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f" 160 | dependencies = [ 161 | "anes", 162 | "cast", 163 | "ciborium", 164 | "clap", 165 | "criterion-plot", 166 | "is-terminal", 167 | "itertools", 168 | "num-traits", 169 | "once_cell", 170 | "oorandom", 171 | "plotters", 172 | "rayon", 173 | "regex", 174 | "serde", 175 | "serde_derive", 176 | "serde_json", 177 | "tinytemplate", 178 | "walkdir", 179 | ] 180 | 181 | [[package]] 182 | name = "criterion-plot" 183 | version = "0.5.0" 184 | source = "registry+https://github.com/rust-lang/crates.io-index" 185 | checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" 186 | dependencies = [ 187 | "cast", 188 | "itertools", 189 | ] 190 | 191 | [[package]] 192 | name = "crossbeam-deque" 193 | version = "0.8.5" 194 | source = "registry+https://github.com/rust-lang/crates.io-index" 195 | checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" 196 | dependencies = [ 197 | "crossbeam-epoch", 198 | "crossbeam-utils", 199 | ] 200 | 201 | [[package]] 202 | name = "crossbeam-epoch" 203 | version = "0.9.18" 204 | source = "registry+https://github.com/rust-lang/crates.io-index" 205 | checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" 206 | dependencies = [ 207 | "crossbeam-utils", 208 | ] 209 | 210 | [[package]] 211 | name = "crossbeam-utils" 212 | version = "0.8.19" 213 | source = "registry+https://github.com/rust-lang/crates.io-index" 214 | checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" 215 | 216 | [[package]] 217 | name = "crunchy" 218 | version = "0.2.2" 219 | source = "registry+https://github.com/rust-lang/crates.io-index" 220 | checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" 221 | 222 | [[package]] 223 | name = "crypto-bigint" 224 | version = "0.5.5" 225 | source = "registry+https://github.com/rust-lang/crates.io-index" 226 | checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" 227 | dependencies = [ 228 | "generic-array", 229 | "rand_core", 230 | "subtle", 231 | "zeroize", 232 | ] 233 | 234 | [[package]] 235 | name = "crypto-common" 236 | version = "0.1.6" 237 | source = "registry+https://github.com/rust-lang/crates.io-index" 238 | checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" 239 | dependencies = [ 240 | "generic-array", 241 | "typenum", 242 | ] 243 | 244 | [[package]] 245 | name = "der" 246 | version = "0.7.8" 247 | source = "registry+https://github.com/rust-lang/crates.io-index" 248 | checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" 249 | dependencies = [ 250 | "const-oid", 251 | "zeroize", 252 | ] 253 | 254 | [[package]] 255 | name = "digest" 256 | version = "0.10.7" 257 | source = "registry+https://github.com/rust-lang/crates.io-index" 258 | checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" 259 | dependencies = [ 260 | "block-buffer", 261 | "const-oid", 262 | "crypto-common", 263 | "subtle", 264 | ] 265 | 266 | [[package]] 267 | name = "ecdsa" 268 | version = "0.16.9" 269 | source = "registry+https://github.com/rust-lang/crates.io-index" 270 | checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" 271 | dependencies = [ 272 | "der", 273 | "digest", 274 | "elliptic-curve", 275 | "rfc6979", 276 | "serdect", 277 | "signature", 278 | "spki", 279 | ] 280 | 281 | [[package]] 282 | name = "either" 283 | version = "1.11.0" 284 | source = "registry+https://github.com/rust-lang/crates.io-index" 285 | checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2" 286 | 287 | [[package]] 288 | name = "elliptic-curve" 289 | version = "0.13.8" 290 | source = "registry+https://github.com/rust-lang/crates.io-index" 291 | checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" 292 | dependencies = [ 293 | "base16ct", 294 | "crypto-bigint", 295 | "digest", 296 | "ff", 297 | "generic-array", 298 | "group", 299 | "pkcs8", 300 | "rand_core", 301 | "sec1", 302 | "serdect", 303 | "subtle", 304 | "zeroize", 305 | ] 306 | 307 | [[package]] 308 | name = "ff" 309 | version = "0.13.0" 310 | source = "registry+https://github.com/rust-lang/crates.io-index" 311 | checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" 312 | dependencies = [ 313 | "rand_core", 314 | "subtle", 315 | ] 316 | 317 | [[package]] 318 | name = "generic-array" 319 | version = "0.14.7" 320 | source = "registry+https://github.com/rust-lang/crates.io-index" 321 | checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" 322 | dependencies = [ 323 | "typenum", 324 | "version_check", 325 | "zeroize", 326 | ] 327 | 328 | [[package]] 329 | name = "getrandom" 330 | version = "0.2.12" 331 | source = "registry+https://github.com/rust-lang/crates.io-index" 332 | checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" 333 | dependencies = [ 334 | "cfg-if", 335 | "libc", 336 | "wasi", 337 | ] 338 | 339 | [[package]] 340 | name = "group" 341 | version = "0.13.0" 342 | source = "registry+https://github.com/rust-lang/crates.io-index" 343 | checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" 344 | dependencies = [ 345 | "ff", 346 | "rand_core", 347 | "subtle", 348 | ] 349 | 350 | [[package]] 351 | name = "half" 352 | version = "2.4.1" 353 | source = "registry+https://github.com/rust-lang/crates.io-index" 354 | checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" 355 | dependencies = [ 356 | "cfg-if", 357 | "crunchy", 358 | ] 359 | 360 | [[package]] 361 | name = "hermit-abi" 362 | version = "0.3.9" 363 | source = "registry+https://github.com/rust-lang/crates.io-index" 364 | checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" 365 | 366 | [[package]] 367 | name = "hmac" 368 | version = "0.12.1" 369 | source = "registry+https://github.com/rust-lang/crates.io-index" 370 | checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" 371 | dependencies = [ 372 | "digest", 373 | ] 374 | 375 | [[package]] 376 | name = "is-terminal" 377 | version = "0.4.12" 378 | source = "registry+https://github.com/rust-lang/crates.io-index" 379 | checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" 380 | dependencies = [ 381 | "hermit-abi", 382 | "libc", 383 | "windows-sys", 384 | ] 385 | 386 | [[package]] 387 | name = "itertools" 388 | version = "0.10.5" 389 | source = "registry+https://github.com/rust-lang/crates.io-index" 390 | checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" 391 | dependencies = [ 392 | "either", 393 | ] 394 | 395 | [[package]] 396 | name = "itoa" 397 | version = "1.0.10" 398 | source = "registry+https://github.com/rust-lang/crates.io-index" 399 | checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" 400 | 401 | [[package]] 402 | name = "js-sys" 403 | version = "0.3.69" 404 | source = "registry+https://github.com/rust-lang/crates.io-index" 405 | checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" 406 | dependencies = [ 407 | "wasm-bindgen", 408 | ] 409 | 410 | [[package]] 411 | name = "k256" 412 | version = "0.13.3" 413 | source = "registry+https://github.com/rust-lang/crates.io-index" 414 | checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b" 415 | dependencies = [ 416 | "cfg-if", 417 | "ecdsa", 418 | "elliptic-curve", 419 | "once_cell", 420 | "serdect", 421 | "sha2", 422 | "signature", 423 | ] 424 | 425 | [[package]] 426 | name = "keccak" 427 | version = "0.1.5" 428 | source = "registry+https://github.com/rust-lang/crates.io-index" 429 | checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" 430 | dependencies = [ 431 | "cpufeatures", 432 | ] 433 | 434 | [[package]] 435 | name = "libc" 436 | version = "0.2.153" 437 | source = "registry+https://github.com/rust-lang/crates.io-index" 438 | checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" 439 | 440 | [[package]] 441 | name = "log" 442 | version = "0.4.21" 443 | source = "registry+https://github.com/rust-lang/crates.io-index" 444 | checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" 445 | 446 | [[package]] 447 | name = "memchr" 448 | version = "2.7.2" 449 | source = "registry+https://github.com/rust-lang/crates.io-index" 450 | checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" 451 | 452 | [[package]] 453 | name = "merlin" 454 | version = "3.0.0" 455 | source = "registry+https://github.com/rust-lang/crates.io-index" 456 | checksum = "58c38e2799fc0978b65dfff8023ec7843e2330bb462f19198840b34b6582397d" 457 | dependencies = [ 458 | "byteorder", 459 | "keccak", 460 | "rand_core", 461 | "zeroize", 462 | ] 463 | 464 | [[package]] 465 | name = "num-traits" 466 | version = "0.2.19" 467 | source = "registry+https://github.com/rust-lang/crates.io-index" 468 | checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" 469 | dependencies = [ 470 | "autocfg", 471 | ] 472 | 473 | [[package]] 474 | name = "once_cell" 475 | version = "1.19.0" 476 | source = "registry+https://github.com/rust-lang/crates.io-index" 477 | checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" 478 | 479 | [[package]] 480 | name = "oorandom" 481 | version = "11.1.3" 482 | source = "registry+https://github.com/rust-lang/crates.io-index" 483 | checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" 484 | 485 | [[package]] 486 | name = "pkcs8" 487 | version = "0.10.2" 488 | source = "registry+https://github.com/rust-lang/crates.io-index" 489 | checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" 490 | dependencies = [ 491 | "der", 492 | "spki", 493 | ] 494 | 495 | [[package]] 496 | name = "plotters" 497 | version = "0.3.5" 498 | source = "registry+https://github.com/rust-lang/crates.io-index" 499 | checksum = "d2c224ba00d7cadd4d5c660deaf2098e5e80e07846537c51f9cfa4be50c1fd45" 500 | dependencies = [ 501 | "num-traits", 502 | "plotters-backend", 503 | "plotters-svg", 504 | "wasm-bindgen", 505 | "web-sys", 506 | ] 507 | 508 | [[package]] 509 | name = "plotters-backend" 510 | version = "0.3.5" 511 | source = "registry+https://github.com/rust-lang/crates.io-index" 512 | checksum = "9e76628b4d3a7581389a35d5b6e2139607ad7c75b17aed325f210aa91f4a9609" 513 | 514 | [[package]] 515 | name = "plotters-svg" 516 | version = "0.3.5" 517 | source = "registry+https://github.com/rust-lang/crates.io-index" 518 | checksum = "38f6d39893cca0701371e3c27294f09797214b86f1fb951b89ade8ec04e2abab" 519 | dependencies = [ 520 | "plotters-backend", 521 | ] 522 | 523 | [[package]] 524 | name = "proc-macro2" 525 | version = "1.0.79" 526 | source = "registry+https://github.com/rust-lang/crates.io-index" 527 | checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" 528 | dependencies = [ 529 | "unicode-ident", 530 | ] 531 | 532 | [[package]] 533 | name = "quote" 534 | version = "1.0.35" 535 | source = "registry+https://github.com/rust-lang/crates.io-index" 536 | checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" 537 | dependencies = [ 538 | "proc-macro2", 539 | ] 540 | 541 | [[package]] 542 | name = "rand_core" 543 | version = "0.6.4" 544 | source = "registry+https://github.com/rust-lang/crates.io-index" 545 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 546 | dependencies = [ 547 | "getrandom", 548 | ] 549 | 550 | [[package]] 551 | name = "rayon" 552 | version = "1.10.0" 553 | source = "registry+https://github.com/rust-lang/crates.io-index" 554 | checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" 555 | dependencies = [ 556 | "either", 557 | "rayon-core", 558 | ] 559 | 560 | [[package]] 561 | name = "rayon-core" 562 | version = "1.12.1" 563 | source = "registry+https://github.com/rust-lang/crates.io-index" 564 | checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" 565 | dependencies = [ 566 | "crossbeam-deque", 567 | "crossbeam-utils", 568 | ] 569 | 570 | [[package]] 571 | name = "regex" 572 | version = "1.10.4" 573 | source = "registry+https://github.com/rust-lang/crates.io-index" 574 | checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" 575 | dependencies = [ 576 | "aho-corasick", 577 | "memchr", 578 | "regex-automata", 579 | "regex-syntax", 580 | ] 581 | 582 | [[package]] 583 | name = "regex-automata" 584 | version = "0.4.6" 585 | source = "registry+https://github.com/rust-lang/crates.io-index" 586 | checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" 587 | dependencies = [ 588 | "aho-corasick", 589 | "memchr", 590 | "regex-syntax", 591 | ] 592 | 593 | [[package]] 594 | name = "regex-syntax" 595 | version = "0.8.3" 596 | source = "registry+https://github.com/rust-lang/crates.io-index" 597 | checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" 598 | 599 | [[package]] 600 | name = "rfc6979" 601 | version = "0.4.0" 602 | source = "registry+https://github.com/rust-lang/crates.io-index" 603 | checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" 604 | dependencies = [ 605 | "hmac", 606 | "subtle", 607 | ] 608 | 609 | [[package]] 610 | name = "ryu" 611 | version = "1.0.17" 612 | source = "registry+https://github.com/rust-lang/crates.io-index" 613 | checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" 614 | 615 | [[package]] 616 | name = "same-file" 617 | version = "1.0.6" 618 | source = "registry+https://github.com/rust-lang/crates.io-index" 619 | checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" 620 | dependencies = [ 621 | "winapi-util", 622 | ] 623 | 624 | [[package]] 625 | name = "sec1" 626 | version = "0.7.3" 627 | source = "registry+https://github.com/rust-lang/crates.io-index" 628 | checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" 629 | dependencies = [ 630 | "base16ct", 631 | "der", 632 | "generic-array", 633 | "pkcs8", 634 | "serdect", 635 | "subtle", 636 | "zeroize", 637 | ] 638 | 639 | [[package]] 640 | name = "serde" 641 | version = "1.0.197" 642 | source = "registry+https://github.com/rust-lang/crates.io-index" 643 | checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" 644 | dependencies = [ 645 | "serde_derive", 646 | ] 647 | 648 | [[package]] 649 | name = "serde_derive" 650 | version = "1.0.197" 651 | source = "registry+https://github.com/rust-lang/crates.io-index" 652 | checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" 653 | dependencies = [ 654 | "proc-macro2", 655 | "quote", 656 | "syn", 657 | ] 658 | 659 | [[package]] 660 | name = "serde_json" 661 | version = "1.0.114" 662 | source = "registry+https://github.com/rust-lang/crates.io-index" 663 | checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" 664 | dependencies = [ 665 | "itoa", 666 | "ryu", 667 | "serde", 668 | ] 669 | 670 | [[package]] 671 | name = "serdect" 672 | version = "0.2.0" 673 | source = "registry+https://github.com/rust-lang/crates.io-index" 674 | checksum = "a84f14a19e9a014bb9f4512488d9829a68e04ecabffb0f9904cd1ace94598177" 675 | dependencies = [ 676 | "base16ct", 677 | "serde", 678 | ] 679 | 680 | [[package]] 681 | name = "sha2" 682 | version = "0.10.8" 683 | source = "registry+https://github.com/rust-lang/crates.io-index" 684 | checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" 685 | dependencies = [ 686 | "cfg-if", 687 | "cpufeatures", 688 | "digest", 689 | ] 690 | 691 | [[package]] 692 | name = "signature" 693 | version = "2.2.0" 694 | source = "registry+https://github.com/rust-lang/crates.io-index" 695 | checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" 696 | dependencies = [ 697 | "digest", 698 | "rand_core", 699 | ] 700 | 701 | [[package]] 702 | name = "spki" 703 | version = "0.7.3" 704 | source = "registry+https://github.com/rust-lang/crates.io-index" 705 | checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" 706 | dependencies = [ 707 | "base64ct", 708 | "der", 709 | ] 710 | 711 | [[package]] 712 | name = "subtle" 713 | version = "2.5.0" 714 | source = "registry+https://github.com/rust-lang/crates.io-index" 715 | checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" 716 | 717 | [[package]] 718 | name = "syn" 719 | version = "2.0.53" 720 | source = "registry+https://github.com/rust-lang/crates.io-index" 721 | checksum = "7383cd0e49fff4b6b90ca5670bfd3e9d6a733b3f90c686605aa7eec8c4996032" 722 | dependencies = [ 723 | "proc-macro2", 724 | "quote", 725 | "unicode-ident", 726 | ] 727 | 728 | [[package]] 729 | name = "tinytemplate" 730 | version = "1.2.1" 731 | source = "registry+https://github.com/rust-lang/crates.io-index" 732 | checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" 733 | dependencies = [ 734 | "serde", 735 | "serde_json", 736 | ] 737 | 738 | [[package]] 739 | name = "typenum" 740 | version = "1.17.0" 741 | source = "registry+https://github.com/rust-lang/crates.io-index" 742 | checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" 743 | 744 | [[package]] 745 | name = "unicode-ident" 746 | version = "1.0.12" 747 | source = "registry+https://github.com/rust-lang/crates.io-index" 748 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" 749 | 750 | [[package]] 751 | name = "version_check" 752 | version = "0.9.4" 753 | source = "registry+https://github.com/rust-lang/crates.io-index" 754 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 755 | 756 | [[package]] 757 | name = "walkdir" 758 | version = "2.5.0" 759 | source = "registry+https://github.com/rust-lang/crates.io-index" 760 | checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" 761 | dependencies = [ 762 | "same-file", 763 | "winapi-util", 764 | ] 765 | 766 | [[package]] 767 | name = "wasi" 768 | version = "0.11.0+wasi-snapshot-preview1" 769 | source = "registry+https://github.com/rust-lang/crates.io-index" 770 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 771 | 772 | [[package]] 773 | name = "wasm-bindgen" 774 | version = "0.2.92" 775 | source = "registry+https://github.com/rust-lang/crates.io-index" 776 | checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" 777 | dependencies = [ 778 | "cfg-if", 779 | "wasm-bindgen-macro", 780 | ] 781 | 782 | [[package]] 783 | name = "wasm-bindgen-backend" 784 | version = "0.2.92" 785 | source = "registry+https://github.com/rust-lang/crates.io-index" 786 | checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" 787 | dependencies = [ 788 | "bumpalo", 789 | "log", 790 | "once_cell", 791 | "proc-macro2", 792 | "quote", 793 | "syn", 794 | "wasm-bindgen-shared", 795 | ] 796 | 797 | [[package]] 798 | name = "wasm-bindgen-macro" 799 | version = "0.2.92" 800 | source = "registry+https://github.com/rust-lang/crates.io-index" 801 | checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" 802 | dependencies = [ 803 | "quote", 804 | "wasm-bindgen-macro-support", 805 | ] 806 | 807 | [[package]] 808 | name = "wasm-bindgen-macro-support" 809 | version = "0.2.92" 810 | source = "registry+https://github.com/rust-lang/crates.io-index" 811 | checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" 812 | dependencies = [ 813 | "proc-macro2", 814 | "quote", 815 | "syn", 816 | "wasm-bindgen-backend", 817 | "wasm-bindgen-shared", 818 | ] 819 | 820 | [[package]] 821 | name = "wasm-bindgen-shared" 822 | version = "0.2.92" 823 | source = "registry+https://github.com/rust-lang/crates.io-index" 824 | checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" 825 | 826 | [[package]] 827 | name = "web-sys" 828 | version = "0.3.69" 829 | source = "registry+https://github.com/rust-lang/crates.io-index" 830 | checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" 831 | dependencies = [ 832 | "js-sys", 833 | "wasm-bindgen", 834 | ] 835 | 836 | [[package]] 837 | name = "winapi-util" 838 | version = "0.1.8" 839 | source = "registry+https://github.com/rust-lang/crates.io-index" 840 | checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" 841 | dependencies = [ 842 | "windows-sys", 843 | ] 844 | 845 | [[package]] 846 | name = "windows-sys" 847 | version = "0.52.0" 848 | source = "registry+https://github.com/rust-lang/crates.io-index" 849 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 850 | dependencies = [ 851 | "windows-targets", 852 | ] 853 | 854 | [[package]] 855 | name = "windows-targets" 856 | version = "0.52.5" 857 | source = "registry+https://github.com/rust-lang/crates.io-index" 858 | checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" 859 | dependencies = [ 860 | "windows_aarch64_gnullvm", 861 | "windows_aarch64_msvc", 862 | "windows_i686_gnu", 863 | "windows_i686_gnullvm", 864 | "windows_i686_msvc", 865 | "windows_x86_64_gnu", 866 | "windows_x86_64_gnullvm", 867 | "windows_x86_64_msvc", 868 | ] 869 | 870 | [[package]] 871 | name = "windows_aarch64_gnullvm" 872 | version = "0.52.5" 873 | source = "registry+https://github.com/rust-lang/crates.io-index" 874 | checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" 875 | 876 | [[package]] 877 | name = "windows_aarch64_msvc" 878 | version = "0.52.5" 879 | source = "registry+https://github.com/rust-lang/crates.io-index" 880 | checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" 881 | 882 | [[package]] 883 | name = "windows_i686_gnu" 884 | version = "0.52.5" 885 | source = "registry+https://github.com/rust-lang/crates.io-index" 886 | checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" 887 | 888 | [[package]] 889 | name = "windows_i686_gnullvm" 890 | version = "0.52.5" 891 | source = "registry+https://github.com/rust-lang/crates.io-index" 892 | checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" 893 | 894 | [[package]] 895 | name = "windows_i686_msvc" 896 | version = "0.52.5" 897 | source = "registry+https://github.com/rust-lang/crates.io-index" 898 | checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" 899 | 900 | [[package]] 901 | name = "windows_x86_64_gnu" 902 | version = "0.52.5" 903 | source = "registry+https://github.com/rust-lang/crates.io-index" 904 | checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" 905 | 906 | [[package]] 907 | name = "windows_x86_64_gnullvm" 908 | version = "0.52.5" 909 | source = "registry+https://github.com/rust-lang/crates.io-index" 910 | checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" 911 | 912 | [[package]] 913 | name = "windows_x86_64_msvc" 914 | version = "0.52.5" 915 | source = "registry+https://github.com/rust-lang/crates.io-index" 916 | checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" 917 | 918 | [[package]] 919 | name = "zeroize" 920 | version = "1.7.0" 921 | source = "registry+https://github.com/rust-lang/crates.io-index" 922 | checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" 923 | dependencies = [ 924 | "zeroize_derive", 925 | ] 926 | 927 | [[package]] 928 | name = "zeroize_derive" 929 | version = "1.4.2" 930 | source = "registry+https://github.com/rust-lang/crates.io-index" 931 | checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" 932 | dependencies = [ 933 | "proc-macro2", 934 | "quote", 935 | "syn", 936 | ] 937 | --------------------------------------------------------------------------------