From 4c23fa2eb1d65998c16d1f4f3eb3ba71065d2b3c Mon Sep 17 00:00:00 2001 From: lovesh Date: Sun, 8 Dec 2024 11:55:16 +0530 Subject: [PATCH] Relax bounds on KV range proofs, simplify CLS range proof Signed-off-by: lovesh --- Cargo.toml | 1 + README.md | 3 + bbs_plus/Cargo.toml | 2 - bbs_plus/src/threshold/threshold_bbs.rs | 3 +- bbs_plus/src/threshold/threshold_bbs_plus.rs | 3 +- compressed_sigma/src/utils.rs | 5 +- kvac/src/bbs_sharp/README.md | 2 + kvac/src/bbs_sharp/mod.rs | 2 + kvac/src/lib.rs | 2 + legogroth16/Cargo.toml | 5 +- oblivious_transfer/Cargo.toml | 6 +- proof_system/Cargo.toml | 5 +- proof_system/src/proof_spec.rs | 2 +- proof_system/src/setup_params.rs | 11 +- proof_system/src/statement/bound_check_smc.rs | 2 +- .../src/statement/bound_check_smc_with_kv.rs | 97 +++--- proof_system/src/statement/mod.rs | 4 +- proof_system/src/statement_proof.rs | 29 +- .../src/sub_protocols/bound_check_smc.rs | 51 ++- .../sub_protocols/bound_check_smc_with_kv.rs | 107 +++--- proof_system/src/sub_protocols/mod.rs | 12 +- proof_system/src/verifier.rs | 4 +- proof_system/tests/accumulators.rs | 2 + proof_system/tests/bound_check_smc.rs | 55 +--- proof_system/tests/bound_check_smc_with_kv.rs | 67 +--- short_group_sig/src/bb_sig_pok.rs | 1 + short_group_sig/src/threshold_weak_bb_sig.rs | 2 + short_group_sig/src/weak_bb_sig.rs | 11 +- short_group_sig/src/weak_bb_sig_pok_kv.rs | 25 +- smc_range_proof/README.md | 2 +- .../src/ccs_range_proof/arbitrary_range.rs | 63 +++- .../ccs_range_proof/arbitrary_range_cdh.rs | 21 +- .../src/ccs_range_proof/kv_arbitrary_range.rs | 146 ++++----- .../src/ccs_range_proof/kv_perfect_range.rs | 119 ++++--- smc_range_proof/src/ccs_range_proof/mod.rs | 3 +- .../src/ccs_range_proof/perfect_range.rs | 44 ++- .../src/ccs_range_proof/perfect_range_cdh.rs | 35 +- smc_range_proof/src/ccs_range_proof/util.rs | 127 +++----- .../src/ccs_set_membership/kv_single.rs | 79 +++-- .../src/ccs_set_membership/setup.rs | 159 ++++++--- .../src/ccs_set_membership/single_member.rs | 2 +- .../src/cls_range_proof/kv_range_proof.rs | 257 ++++++--------- smc_range_proof/src/cls_range_proof/mod.rs | 3 +- .../src/cls_range_proof/range_proof.rs | 173 ++++------ .../src/cls_range_proof/range_proof_cdh.rs | 306 ++++++++++++++---- smc_range_proof/src/cls_range_proof/util.rs | 242 ++++++++------ smc_range_proof/src/common.rs | 31 +- smc_range_proof/src/error.rs | 1 + smc_range_proof/src/lib.rs | 2 +- syra/src/threshold_issuance.rs | 165 ++++++++-- vb_accumulator/src/batch_utils.rs | 28 +- .../src/kb_positive_accumulator/proofs.rs | 4 + .../src/kb_positive_accumulator/proofs_cdh.rs | 4 + .../src/proofs_keyed_verification.rs | 2 +- vb_accumulator/src/witness.rs | 2 +- verifiable_encryption/Cargo.toml | 10 +- 56 files changed, 1385 insertions(+), 1166 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 38843d7c..544d52a2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -48,6 +48,7 @@ blake2 = { version = "0.10", default-features = false } ark-bls12-381 = { version = "^0.4.0", default-features = false, features = [ "curve" ] } ark-secp256r1 = { version = "^0.4.0", default-features = false } itertools = "0.12.1" +sha3 = { version = "0.10.6", default-features = false } [profile.release] lto = true diff --git a/README.md b/README.md index f988893c..0b04b124 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,9 @@ For WASM, build as `cargo build --no-default-features --features=wasmer-js --tar The above maybe slower as it runs the tests in debug mode and some tests work on large inputs. For running tests faster, run `cargo test --release` +Some tess might cause a stack overflow error. To fix that, increase the stack size to about 8MB as + +`RUST_MIN_STACK=8388608 cargo test` or `RUST_MIN_STACK=8388608 cargo test --release` ## Benchmarking diff --git a/bbs_plus/Cargo.toml b/bbs_plus/Cargo.toml index 16bbdcbc..3be5a8a7 100644 --- a/bbs_plus/Cargo.toml +++ b/bbs_plus/Cargo.toml @@ -19,7 +19,6 @@ ark-std.workspace = true digest.workspace = true rayon = {workspace = true, optional = true} itertools.workspace = true -sha3 = { version = "0.10.6", default-features = false } serde.workspace = true serde_with.workspace = true zeroize.workspace = true @@ -33,7 +32,6 @@ blake2.workspace = true ark-bls12-381.workspace = true serde_json = "1.0" rmp-serde = "1.0" -ark-poly.workspace = true test_utils = { path = "../test_utils" } [features] diff --git a/bbs_plus/src/threshold/threshold_bbs.rs b/bbs_plus/src/threshold/threshold_bbs.rs index 6e12bb8a..6e1de4dd 100644 --- a/bbs_plus/src/threshold/threshold_bbs.rs +++ b/bbs_plus/src/threshold/threshold_bbs.rs @@ -36,7 +36,8 @@ pub struct Phase1Output { } /// A share of the BBS signature created by one signer. A client will aggregate many such shares to -/// create the final signature. +/// create the final signature. Note that this is done by the signer where it uses outputs of +/// phase 1 and 2 and these outputs should not be sent to the user. Only this share needs to be sent. #[derive(Clone, Debug, PartialEq, CanonicalSerialize, CanonicalDeserialize)] pub struct BBSSignatureShare { pub id: ParticipantId, diff --git a/bbs_plus/src/threshold/threshold_bbs_plus.rs b/bbs_plus/src/threshold/threshold_bbs_plus.rs index fbadfac8..770294ff 100644 --- a/bbs_plus/src/threshold/threshold_bbs_plus.rs +++ b/bbs_plus/src/threshold/threshold_bbs_plus.rs @@ -36,7 +36,8 @@ pub struct Phase1Output { } /// A share of the BBS+ signature created by one signer. A client will aggregate many such shares to -/// create the final signature. +/// create the final signature. Note that this is done by the signer where it uses outputs of +/// phase 1 and 2 and these outputs should not be sent to the user. Only this share needs to be sent. #[derive(Clone, Debug, PartialEq, CanonicalSerialize, CanonicalDeserialize)] pub struct BBSPlusSignatureShare { pub id: ParticipantId, diff --git a/compressed_sigma/src/utils.rs b/compressed_sigma/src/utils.rs index 51a54324..9151896d 100644 --- a/compressed_sigma/src/utils.rs +++ b/compressed_sigma/src/utils.rs @@ -1,10 +1,11 @@ +#![allow(unused)] + +use crate::transforms::{Homomorphism, LinearForm}; use ark_ec::{AffineRepr, CurveGroup}; use ark_ff::PrimeField; use ark_std::{vec, vec::Vec}; use dock_crypto_utils::msm::multiply_field_elems_with_same_group_elem; -use crate::transforms::{Homomorphism, LinearForm}; - /// Pad given homomorphisms such that all have the same size after padding pub fn pad_homomorphisms_to_have_same_size< G: AffineRepr, diff --git a/kvac/src/bbs_sharp/README.md b/kvac/src/bbs_sharp/README.md index cf744cd0..50321fca 100644 --- a/kvac/src/bbs_sharp/README.md +++ b/kvac/src/bbs_sharp/README.md @@ -1,3 +1,5 @@ +# BBS# (called BBS sharp) + BBS# as described [here](https://github.com/user-attachments/files/15905230/BBS_Sharp_Short_TR.pdf) This assumes that the messages/attributes have already been prepared before signing, i.e. attributes are hashed diff --git a/kvac/src/bbs_sharp/mod.rs b/kvac/src/bbs_sharp/mod.rs index 8a0f86e0..cb912b45 100644 --- a/kvac/src/bbs_sharp/mod.rs +++ b/kvac/src/bbs_sharp/mod.rs @@ -1,3 +1,5 @@ +//! # BBS# (called BBS sharp) +//! //! BBS# as described [here](https://github.com/user-attachments/files/15905230/BBS_Sharp_Short_TR.pdf) //! //! This assumes that the messages/attributes have already been prepared before signing, i.e. attributes are hashed diff --git a/kvac/src/lib.rs b/kvac/src/lib.rs index 02e8e62c..25b3f561 100644 --- a/kvac/src/lib.rs +++ b/kvac/src/lib.rs @@ -12,6 +12,8 @@ //! are not shared with the issuer. This lets us build for a use-case where issuer wants to allow anytime its issued credential is used //! (eg. to get paid by the verifier) while still not harming the user's privacy as it doesn't learn any revealed attributes. The first //! verifier, i.e. the issuer can also provide a proof of validity or invalidity to the second verifier. +//! +//! Implements BBS# (called BBS sharp) [here](./src/bbs_sharp) pub mod bbdt_2016; pub mod bbs_sharp; diff --git a/legogroth16/Cargo.toml b/legogroth16/Cargo.toml index 2aa854b3..34be616c 100644 --- a/legogroth16/Cargo.toml +++ b/legogroth16/Cargo.toml @@ -23,7 +23,7 @@ ark-r1cs-std = { workspace = true, optional = true } tracing = { version = "0.1", default-features = false, features = [ "attributes" ], optional = true } derivative = { version = "2.0", features = ["use_core"], optional = true } rayon = { workspace = true, optional = true } -wasmer = { version = "5.0.0", optional = true, default-features = false } +wasmer = { version = "5.0.2", optional = true, default-features = false } fnv = { version = "1.0.3", default-features = false, optional = true } num-bigint = { version = "0.4", default-features = false, optional = true } log = "0.4" @@ -32,9 +32,8 @@ ark-snark = { version = "^0.4.0", default-features = false, optional = true } dock_crypto_utils = { version = "0.20.0", default-features = false, path = "../utils" } [dev-dependencies] -csv = { version = "1" } ark-bn254 = { version = "^0.4.0", default-features = false, features = ["curve"] } -ark-bls12-381 = { version = "^0.4.0", default-features = false, features = ["curve"] } +ark-bls12-381.workspace = true ark-bls12-377 = { version = "^0.4.0", default-features = false, features = ["curve"] } ark-cp6-782 = { version = "^0.4.0", default-features = false } ark-mnt4-298 = { version = "^0.4.0", default-features = false, features = ["r1cs", "curve"] } diff --git a/oblivious_transfer/Cargo.toml b/oblivious_transfer/Cargo.toml index 6d6a2e2c..a235583e 100644 --- a/oblivious_transfer/Cargo.toml +++ b/oblivious_transfer/Cargo.toml @@ -19,7 +19,7 @@ serde_with.workspace = true zeroize.workspace = true cipher = { version = "0.4.4", default-features = false, features = ["alloc"] } rayon = {workspace = true, optional = true} -sha3 = { version = "0.10.6", default-features = false } +sha3.workspace = true aes = { version = "0.8.2", default-features = false } itertools.workspace = true byteorder = { version = "1.4", default-features = false } @@ -38,5 +38,5 @@ cc = "1.0.77" [features] default = [ "parallel"] -std = [ "ark-ff/std", "ark-ec/std", "ark-std/std", "ark-serialize/std", "serde/std"] -parallel = [ "std", "ark-ff/parallel", "ark-ec/parallel", "ark-std/parallel", "rayon"] \ No newline at end of file +std = [ "ark-ff/std", "ark-ec/std", "ark-std/std", "ark-serialize/std", "serde/std", "dock_crypto_utils/std", "schnorr_pok/std"] +parallel = [ "std", "ark-ff/parallel", "ark-ec/parallel", "ark-std/parallel", "rayon", "dock_crypto_utils/parallel", "schnorr_pok/parallel"] \ No newline at end of file diff --git a/proof_system/Cargo.toml b/proof_system/Cargo.toml index a3afc586..81453706 100644 --- a/proof_system/Cargo.toml +++ b/proof_system/Cargo.toml @@ -25,8 +25,8 @@ ark-r1cs-std.workspace = true ark-relations.workspace = true zeroize.workspace = true itertools.workspace = true -aead = {version = "0.5.2", default-features = false, features = [ "alloc" ]} chacha20poly1305 = {version = "0.10.1", default-features = false} +sha3.workspace = true bbs_plus = { version = "0.22.0", default-features = false, path = "../bbs_plus" } schnorr_pok = { version = "0.20.0", default-features = false, path = "../schnorr_pok" } vb_accumulator = { version = "0.26.0", default-features = false, path = "../vb_accumulator" } @@ -40,7 +40,6 @@ smc_range_proof = { version = "0.6.0", default-features = false, path = "../smc_ short_group_sig = { version = "0.4.0", default-features = false, path = "../short_group_sig" } kvac = { version = "0.5.0", default-features = false, path = "../kvac" } verifiable_encryption = { version = "0.1.0", default-features = false, path = "../verifiable_encryption" } -sha3 = { version = "0.10.6", default-features = false } [dev-dependencies] ark-bls12-381.workspace = true @@ -51,7 +50,7 @@ test_utils = { default-features = false, path = "../test_utils" } [features] default = ["parallel"] -std = ["ark-ff/std", "ark-ec/std", "ark-std/std", "ark-serialize/std", "schnorr_pok/std", "dock_crypto_utils/std", "serde/std", "saver/std", "ark-groth16/std", "legogroth16/std", "ark-r1cs-std/std", "ark-relations/std", "merlin/std", "coconut-crypto/std", "bulletproofs_plus_plus/std", "smc_range_proof/std", "short_group_sig/std", "kvac/std", "verifiable_encryption/std"] +std = ["ark-ff/std", "ark-ec/std", "ark-std/std", "ark-serialize/std", "schnorr_pok/std", "dock_crypto_utils/std", "serde/std", "saver/std", "ark-groth16/std", "legogroth16/std", "ark-r1cs-std/std", "ark-relations/std", "merlin/std", "bbs_plus/std", "vb_accumulator/std", "coconut-crypto/std", "bulletproofs_plus_plus/std", "smc_range_proof/std", "short_group_sig/std", "kvac/std", "verifiable_encryption/std"] print-trace = ["ark-std/print-trace", "schnorr_pok/print-trace", "bbs_plus/print-trace", "vb_accumulator/print-trace", "dock_crypto_utils/print-trace"] parallel = ["std", "ark-ff/parallel", "ark-ec/parallel", "ark-std/parallel", "rayon", "schnorr_pok/parallel", "bbs_plus/parallel", "vb_accumulator/parallel", "saver/parallel", "ark-groth16/parallel", "legogroth16/parallel", "ark-r1cs-std/parallel", "dock_crypto_utils/parallel", "coconut-crypto/parallel", "bulletproofs_plus_plus/parallel", "smc_range_proof/parallel", "short_group_sig/parallel", "kvac/parallel", "verifiable_encryption/parallel"] wasmer-js = ["legogroth16/wasmer-js"] diff --git a/proof_system/src/proof_spec.rs b/proof_system/src/proof_spec.rs index da222edb..212e438c 100644 --- a/proof_system/src/proof_spec.rs +++ b/proof_system/src/proof_spec.rs @@ -35,7 +35,7 @@ use saver::prelude::{ use serde::{Deserialize, Serialize}; use smc_range_proof::prelude::MemberCommitmentKey; -use crate::prelude::bound_check_smc::{ +use crate::statement::bound_check_smc::{ SmcParamsAndCommitmentKey, SmcParamsWithPairingAndCommitmentKey, }; use vb_accumulator::{ diff --git a/proof_system/src/setup_params.rs b/proof_system/src/setup_params.rs index 9c693d6d..f118bff8 100644 --- a/proof_system/src/setup_params.rs +++ b/proof_system/src/setup_params.rs @@ -7,7 +7,9 @@ use crate::{ prelude::bound_check_smc::SmcParamsAndCommitmentKey, - statement::bound_check_smc_with_kv::SmcParamsAndCommitmentKeyAndSecretKey, + statement::bound_check_smc_with_kv::{ + SmcParamsKVAndCommitmentKey, SmcParamsKVAndCommitmentKeyAndSecretKey, + }, }; use ark_ec::{pairing::Pairing, AffineRepr}; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; @@ -66,7 +68,7 @@ pub enum SetupParams { BppSetupParams(#[serde_as(as = "ArkObjectBytes")] BppSetupParams), SmcParamsAndCommKey(#[serde_as(as = "ArkObjectBytes")] SmcParamsAndCommitmentKey), SmcParamsAndCommKeyAndSk( - #[serde_as(as = "ArkObjectBytes")] SmcParamsAndCommitmentKeyAndSecretKey, + #[serde_as(as = "ArkObjectBytes")] SmcParamsKVAndCommitmentKeyAndSecretKey, ), CommitmentKey(#[serde_as(as = "ArkObjectBytes")] PedersenCommitmentKey), BBSigProvingKey(ProvingKey), @@ -75,6 +77,9 @@ pub enum SetupParams { BBDT16MACParams(MACParams), PedersenCommitmentKeyG2(#[serde_as(as = "Vec")] Vec), CommitmentKeyG2(#[serde_as(as = "ArkObjectBytes")] PedersenCommitmentKey), + SmcParamsKVAndCommKey( + #[serde_as(as = "ArkObjectBytes")] SmcParamsKVAndCommitmentKey, + ), ElgamalEncryption(ElgamalEncryptionParams), } @@ -112,6 +117,7 @@ macro_rules! delegate { BBDT16MACParams, PedersenCommitmentKeyG2, CommitmentKeyG2, + SmcParamsKVAndCommKey, ElgamalEncryption : $($tt)+ } @@ -152,6 +158,7 @@ macro_rules! delegate_reverse { BBDT16MACParams, PedersenCommitmentKeyG2, CommitmentKeyG2, + SmcParamsKVAndCommKey, ElgamalEncryption : $($tt)+ } diff --git a/proof_system/src/statement/bound_check_smc.rs b/proof_system/src/statement/bound_check_smc.rs index 85a7d485..16e4a5e0 100644 --- a/proof_system/src/statement/bound_check_smc.rs +++ b/proof_system/src/statement/bound_check_smc.rs @@ -12,7 +12,7 @@ use smc_range_proof::prelude::{ use crate::setup_params::SetupParams; use dock_crypto_utils::serde_utils::ArkObjectBytes; -/// For ease of use, keeping setup params together but they could be generated independently +/// For ease of use, keeping setup params together, but they could be generated independently #[serde_as] #[derive( Clone, Debug, PartialEq, CanonicalSerialize, CanonicalDeserialize, Serialize, Deserialize, diff --git a/proof_system/src/statement/bound_check_smc_with_kv.rs b/proof_system/src/statement/bound_check_smc_with_kv.rs index ea4afbf6..cfa636b7 100644 --- a/proof_system/src/statement/bound_check_smc_with_kv.rs +++ b/proof_system/src/statement/bound_check_smc_with_kv.rs @@ -1,48 +1,56 @@ use crate::{ - error::ProofSystemError, - setup_params::SetupParams, - statement::{bound_check_smc::SmcParamsAndCommitmentKey, Statement}, + error::ProofSystemError, setup_params::SetupParams, statement::Statement, sub_protocols::validate_bounds, }; -use ark_ec::pairing::Pairing; +use ark_ec::{pairing::Pairing, AffineRepr}; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use ark_std::{rand::RngCore, vec::Vec}; use digest::Digest; use dock_crypto_utils::serde_utils::ArkObjectBytes; use serde::{Deserialize, Serialize}; use serde_with::serde_as; -use smc_range_proof::prelude::{MemberCommitmentKey, SecretKey, SetMembershipCheckParams}; +use smc_range_proof::{ + ccs_set_membership::setup::SetMembershipCheckParamsKV, + prelude::{MemberCommitmentKey, SecretKey}, +}; + +/// For ease of use, keeping setup params together, but they could be generated independently +#[serde_as] +#[derive( + Clone, Debug, PartialEq, CanonicalSerialize, CanonicalDeserialize, Serialize, Deserialize, +)] +pub struct SmcParamsKVAndCommitmentKey { + #[serde_as(as = "ArkObjectBytes")] + pub params: SetMembershipCheckParamsKV, + #[serde_as(as = "ArkObjectBytes")] + pub comm_key: MemberCommitmentKey, +} /// Used by the verifier as it knows the secret key. Should not be shared with the prover #[serde_as] #[derive( Clone, Debug, PartialEq, CanonicalSerialize, CanonicalDeserialize, Serialize, Deserialize, )] -pub struct SmcParamsAndCommitmentKeyAndSecretKey { - pub params_and_comm_key: SmcParamsAndCommitmentKey, +pub struct SmcParamsKVAndCommitmentKeyAndSecretKey { + pub params_and_comm_key: SmcParamsKVAndCommitmentKey, #[serde_as(as = "ArkObjectBytes")] - pub sk: SecretKey, + pub sk: SecretKey, } -impl SmcParamsAndCommitmentKeyAndSecretKey { +impl SmcParamsKVAndCommitmentKeyAndSecretKey { pub fn new(rng: &mut R, label: &[u8], base: u16) -> Self { - let (params_and_comm_key, sk) = SmcParamsAndCommitmentKey::new::(rng, label, base); + let (params_and_comm_key, sk) = SmcParamsKVAndCommitmentKey::new::(rng, label, base); Self { params_and_comm_key, sk, } } - pub fn verify(&self) -> Result<(), ProofSystemError> { - self.params_and_comm_key.verify()?; - Ok(()) - } - - pub fn get_smc_params(&self) -> &SetMembershipCheckParams { + pub fn get_smc_params(&self) -> &SetMembershipCheckParamsKV { &self.params_and_comm_key.params } - pub fn get_comm_key(&self) -> &MemberCommitmentKey { + pub fn get_comm_key(&self) -> &MemberCommitmentKey { &self.params_and_comm_key.comm_key } } @@ -52,11 +60,11 @@ impl SmcParamsAndCommitmentKeyAndSecretKey { Clone, Debug, PartialEq, CanonicalSerialize, CanonicalDeserialize, Serialize, Deserialize, )] #[serde(bound = "")] -pub struct BoundCheckSmcWithKVProver { +pub struct BoundCheckSmcWithKVProver { pub min: u64, pub max: u64, #[serde_as(as = "Option")] - pub params: Option>, + pub params: Option>, pub params_ref: Option, } @@ -65,19 +73,19 @@ pub struct BoundCheckSmcWithKVProver { Clone, Debug, PartialEq, CanonicalSerialize, CanonicalDeserialize, Serialize, Deserialize, )] #[serde(bound = "")] -pub struct BoundCheckSmcWithKVVerifier { +pub struct BoundCheckSmcWithKVVerifier { pub min: u64, pub max: u64, #[serde_as(as = "Option")] - pub params: Option>, + pub params: Option>, pub params_ref: Option, } -impl BoundCheckSmcWithKVProver { - pub fn new_statement_from_params( +impl BoundCheckSmcWithKVProver { + pub fn new_statement_from_params>( min: u64, max: u64, - params: SmcParamsAndCommitmentKey, + params: SmcParamsKVAndCommitmentKey, ) -> Result, ProofSystemError> { validate_bounds(min, max)?; @@ -89,7 +97,7 @@ impl BoundCheckSmcWithKVProver { })) } - pub fn new_statement_from_params_ref( + pub fn new_statement_from_params_ref>( min: u64, max: u64, params_ref: usize, @@ -103,35 +111,35 @@ impl BoundCheckSmcWithKVProver { })) } - pub fn get_params_and_comm_key<'a>( + pub fn get_params_and_comm_key<'a, E: Pairing>( &'a self, setup_params: &'a [SetupParams], st_idx: usize, - ) -> Result<&'a SmcParamsAndCommitmentKey, ProofSystemError> { + ) -> Result<&'a SmcParamsKVAndCommitmentKey, ProofSystemError> { extract_param!( setup_params, &self.params, self.params_ref, - SmcParamsAndCommKey, + SmcParamsKVAndCommKey, IncompatibleBoundCheckSetupParamAtIndex, st_idx ) } - pub fn get_comm_key<'a>( + pub fn get_comm_key<'a, E: Pairing>( &'a self, setup_params: &'a [SetupParams], st_idx: usize, - ) -> Result<&'a MemberCommitmentKey, ProofSystemError> { + ) -> Result<&'a MemberCommitmentKey, ProofSystemError> { Ok(&self.get_params_and_comm_key(setup_params, st_idx)?.comm_key) } } -impl BoundCheckSmcWithKVVerifier { - pub fn new_statement_from_params( +impl BoundCheckSmcWithKVVerifier { + pub fn new_statement_from_params>( min: u64, max: u64, - params: SmcParamsAndCommitmentKeyAndSecretKey, + params: SmcParamsKVAndCommitmentKeyAndSecretKey, ) -> Result, ProofSystemError> { validate_bounds(min, max)?; @@ -143,7 +151,7 @@ impl BoundCheckSmcWithKVVerifier { })) } - pub fn new_statement_from_params_ref( + pub fn new_statement_from_params_ref>( min: u64, max: u64, params_ref: usize, @@ -157,11 +165,11 @@ impl BoundCheckSmcWithKVVerifier { })) } - pub fn get_params_and_comm_key_and_sk<'a>( + pub fn get_params_and_comm_key_and_sk<'a, E: Pairing>( &'a self, setup_params: &'a [SetupParams], st_idx: usize, - ) -> Result<&'a SmcParamsAndCommitmentKeyAndSecretKey, ProofSystemError> { + ) -> Result<&'a SmcParamsKVAndCommitmentKeyAndSecretKey, ProofSystemError> { extract_param!( setup_params, &self.params, @@ -172,13 +180,26 @@ impl BoundCheckSmcWithKVVerifier { ) } - pub fn get_comm_key<'a>( + pub fn get_comm_key<'a, E: Pairing>( &'a self, setup_params: &'a [SetupParams], st_idx: usize, - ) -> Result<&'a MemberCommitmentKey, ProofSystemError> { + ) -> Result<&'a MemberCommitmentKey, ProofSystemError> { Ok(self .get_params_and_comm_key_and_sk(setup_params, st_idx)? .get_comm_key()) } } + +impl SmcParamsKVAndCommitmentKey { + pub fn new( + rng: &mut R, + label: &[u8], + base: u16, + ) -> (Self, SecretKey) { + let (params, sk) = + SetMembershipCheckParamsKV::new_for_range_proof::(rng, label, base); + let comm_key = MemberCommitmentKey::new::(label); + (Self { params, comm_key }, sk) + } +} diff --git a/proof_system/src/statement/mod.rs b/proof_system/src/statement/mod.rs index 2b77eb24..4d654e0e 100644 --- a/proof_system/src/statement/mod.rs +++ b/proof_system/src/statement/mod.rs @@ -56,9 +56,9 @@ pub enum Statement { /// For bound check using set-membership check based protocols BoundCheckSmc(bound_check_smc::BoundCheckSmc), /// Used by the prover for bound check using set-membership check with keyed verification based protocols - BoundCheckSmcWithKVProver(bound_check_smc_with_kv::BoundCheckSmcWithKVProver), + BoundCheckSmcWithKVProver(bound_check_smc_with_kv::BoundCheckSmcWithKVProver), /// Used by the verifier for bound check using set-membership check with keyed verification based protocols - BoundCheckSmcWithKVVerifier(bound_check_smc_with_kv::BoundCheckSmcWithKVVerifier), + BoundCheckSmcWithKVVerifier(bound_check_smc_with_kv::BoundCheckSmcWithKVVerifier), /// To prove inequality of a signed message with a public value PublicInequality(inequality::PublicInequality), DetachedAccumulatorMembershipProver(accumulator::DetachedAccumulatorMembershipProver), diff --git a/proof_system/src/statement_proof.rs b/proof_system/src/statement_proof.rs index 17e34f82..bdb4ee38 100644 --- a/proof_system/src/statement_proof.rs +++ b/proof_system/src/statement_proof.rs @@ -47,7 +47,7 @@ pub enum StatementProof { PoKBBSSignature23G1(PoKOfSignature23G1Proof), BoundCheckBpp(BoundCheckBppProof), BoundCheckSmc(BoundCheckSmcProof), - BoundCheckSmcWithKV(BoundCheckSmcWithKVProof), + BoundCheckSmcWithKV(BoundCheckSmcWithKVProof), Inequality(InequalityProof), DetachedAccumulatorMembership(DetachedAccumulatorMembershipProof), DetachedAccumulatorNonMembership(DetachedAccumulatorNonMembershipProof), @@ -351,9 +351,9 @@ pub enum BoundCheckSmcInnerProof { } #[derive(Clone, Debug, PartialEq)] -pub enum BoundCheckSmcWithKVInnerProof { - CCS(smc_range_proof::prelude::CCSArbitraryRangeWithKVProof), - CLS(smc_range_proof::prelude::CLSRangeProofWithKV), +pub enum BoundCheckSmcWithKVInnerProof { + CCS(smc_range_proof::prelude::CCSArbitraryRangeWithKVProof), + CLS(smc_range_proof::prelude::CLSRangeProofWithKV), } #[serde_as] @@ -374,12 +374,12 @@ pub struct BoundCheckSmcProof { Clone, Debug, PartialEq, CanonicalSerialize, CanonicalDeserialize, Serialize, Deserialize, )] #[serde(bound = "")] -pub struct BoundCheckSmcWithKVProof { +pub struct BoundCheckSmcWithKVProof { #[serde_as(as = "ArkObjectBytes")] - pub proof: BoundCheckSmcWithKVInnerProof, + pub proof: BoundCheckSmcWithKVInnerProof, #[serde_as(as = "ArkObjectBytes")] - pub comm: E::G1Affine, - pub sp: PedersenCommitmentPartialProof, + pub comm: G, + pub sp: PedersenCommitmentPartialProof, } #[serde_as] @@ -465,6 +465,7 @@ mod serialization { StatementProof, Write, }; use crate::statement_proof::{BoundCheckSmcInnerProof, BoundCheckSmcWithKVInnerProof}; + use ark_ec::AffineRepr; use ark_serialize::{Compress, Valid, Validate}; impl Valid for StatementProof { @@ -509,8 +510,8 @@ mod serialization { } macro_rules! impl_serz_for_bound_check_inner { - ( $name:ident) => { - impl Valid for $name { + ( $name:ident, $typ: ident, $typ_name: ident) => { + impl<$typ: $typ_name> Valid for $name<$typ> { fn check(&self) -> Result<(), SerializationError> { match self { Self::CCS(c) => c.check(), @@ -519,7 +520,7 @@ mod serialization { } } - impl CanonicalSerialize for $name { + impl<$typ: $typ_name> CanonicalSerialize for $name<$typ> { fn serialize_with_mode( &self, mut writer: W, @@ -545,7 +546,7 @@ mod serialization { } } - impl CanonicalDeserialize for $name { + impl<$typ: $typ_name> CanonicalDeserialize for $name<$typ> { fn deserialize_with_mode( mut reader: R, compress: Compress, @@ -574,6 +575,6 @@ mod serialization { }; } - impl_serz_for_bound_check_inner!(BoundCheckSmcInnerProof); - impl_serz_for_bound_check_inner!(BoundCheckSmcWithKVInnerProof); + impl_serz_for_bound_check_inner!(BoundCheckSmcInnerProof, E, Pairing); + impl_serz_for_bound_check_inner!(BoundCheckSmcWithKVInnerProof, G, AffineRepr); } diff --git a/proof_system/src/sub_protocols/bound_check_smc.rs b/proof_system/src/sub_protocols/bound_check_smc.rs index fe87fc1c..bb6b56d2 100644 --- a/proof_system/src/sub_protocols/bound_check_smc.rs +++ b/proof_system/src/sub_protocols/bound_check_smc.rs @@ -1,3 +1,10 @@ +use crate::{ + error::ProofSystemError, + prelude::bound_check_smc::SmcParamsWithPairingAndCommitmentKey, + statement::bound_check_smc::SmcParamsAndCommitmentKey, + statement_proof::{BoundCheckSmcInnerProof, BoundCheckSmcProof, StatementProof}, + sub_protocols::{enforce_and_get_u64, schnorr::SchnorrProtocol}, +}; use ark_ec::pairing::Pairing; use ark_serialize::CanonicalSerialize; use ark_std::{ @@ -6,14 +13,6 @@ use ark_std::{ rand::RngCore, vec, UniformRand, }; - -use crate::{ - error::ProofSystemError, - prelude::bound_check_smc::SmcParamsWithPairingAndCommitmentKey, - statement::bound_check_smc::SmcParamsAndCommitmentKey, - statement_proof::{BoundCheckSmcInnerProof, BoundCheckSmcProof, StatementProof}, - sub_protocols::{enforce_and_get_u64, schnorr::SchnorrProtocol, should_use_cls}, -}; use dock_crypto_utils::randomized_pairing_check::RandomizedPairingChecker; use smc_range_proof::prelude::{CCSArbitraryRangeProofProtocol, CLSRangeProofProtocol}; @@ -63,30 +62,16 @@ impl<'a, E: Pairing> BoundCheckSmcProtocol<'a, E> { let randomness = E::ScalarField::rand(rng); let comm_key = &self.params_and_comm_key.comm_key; self.comm = Some(comm_key.commit(&message, &randomness)); - let smc_protocol = if should_use_cls(self.min, self.max) { - let p = CLSRangeProofProtocol::init( - rng, - msg_as_u64, - randomness.clone(), - self.min, - self.max, - comm_key, - &self.params_and_comm_key.params, - )?; - SmcProtocol::CLS(p) - } else { - let p = CCSArbitraryRangeProofProtocol::init( - rng, - msg_as_u64, - randomness.clone(), - self.min, - self.max, - comm_key, - &self.params_and_comm_key.params, - )?; - SmcProtocol::CCS(p) - }; - self.smc_protocol = Some(smc_protocol); + let p = CLSRangeProofProtocol::init( + rng, + msg_as_u64, + randomness.clone(), + self.min, + self.max, + comm_key, + &self.params_and_comm_key.params, + )?; + self.smc_protocol = Some(SmcProtocol::CLS(p)); self.init_schnorr_protocol(rng, comm_key_as_slice, message, blinding, randomness) } @@ -165,7 +150,7 @@ impl<'a, E: Pairing> BoundCheckSmcProtocol<'a, E> { BoundCheckSmcInnerProof::CLS(p) } }; - // Don't generated response for index 0 since its response will come from proofs of one of the signatures. + // Don't generate response for index 0 since its response will come from proofs of one of the signatures. let skip_for = BTreeSet::from([0]); Ok(StatementProof::BoundCheckSmc(BoundCheckSmcProof { proof, diff --git a/proof_system/src/sub_protocols/bound_check_smc_with_kv.rs b/proof_system/src/sub_protocols/bound_check_smc_with_kv.rs index 18ead54f..232917da 100644 --- a/proof_system/src/sub_protocols/bound_check_smc_with_kv.rs +++ b/proof_system/src/sub_protocols/bound_check_smc_with_kv.rs @@ -1,11 +1,11 @@ use crate::{ error::ProofSystemError, - prelude::bound_check_smc_with_kv::SmcParamsAndCommitmentKeyAndSecretKey, - statement::bound_check_smc::SmcParamsAndCommitmentKey, + prelude::bound_check_smc_with_kv::SmcParamsKVAndCommitmentKeyAndSecretKey, + statement::bound_check_smc_with_kv::SmcParamsKVAndCommitmentKey, statement_proof::{BoundCheckSmcWithKVInnerProof, BoundCheckSmcWithKVProof, StatementProof}, - sub_protocols::{enforce_and_get_u64, schnorr::SchnorrProtocol, should_use_cls}, + sub_protocols::{enforce_and_get_u64, schnorr::SchnorrProtocol}, }; -use ark_ec::pairing::Pairing; +use ark_ec::{pairing::Pairing, AffineRepr}; use ark_serialize::CanonicalSerialize; use ark_std::{ collections::{BTreeMap, BTreeSet}, @@ -19,31 +19,31 @@ use smc_range_proof::{ }; #[derive(Clone, Debug, PartialEq)] -pub enum SmcProtocolWithKV { - CCS(CCSArbitraryRangeProofWithKVProtocol), - CLS(CLSRangeProofWithKVProtocol), +pub enum SmcProtocolWithKV { + CCS(CCSArbitraryRangeProofWithKVProtocol), + CLS(CLSRangeProofWithKVProtocol), } /// Runs the set-membership check based protocol with keyed-verification for proving bounds of a witness and a Schnorr protocol for proving /// knowledge of the witness committed in the commitments accompanying the proof. #[derive(Clone, Debug, PartialEq)] -pub struct BoundCheckSmcWithKVProtocol<'a, E: Pairing> { +pub struct BoundCheckSmcWithKVProtocol<'a, G: AffineRepr> { pub id: usize, pub min: u64, pub max: u64, - pub params_and_comm_key: Option<&'a SmcParamsAndCommitmentKey>, - pub params_and_comm_key_and_sk: Option<&'a SmcParamsAndCommitmentKeyAndSecretKey>, - pub comm: Option, - pub smc_protocol: Option>, - pub sp: Option>, + pub params_and_comm_key: Option<&'a SmcParamsKVAndCommitmentKey>, + pub params_and_comm_key_and_sk: Option<&'a SmcParamsKVAndCommitmentKeyAndSecretKey>, + pub comm: Option, + pub smc_protocol: Option>, + pub sp: Option>, } -impl<'a, E: Pairing> BoundCheckSmcWithKVProtocol<'a, E> { +impl<'a, G: AffineRepr> BoundCheckSmcWithKVProtocol<'a, G> { pub fn new_for_prover( id: usize, min: u64, max: u64, - params: &'a SmcParamsAndCommitmentKey, + params: &'a SmcParamsKVAndCommitmentKey, ) -> Self { Self { id, @@ -61,7 +61,7 @@ impl<'a, E: Pairing> BoundCheckSmcWithKVProtocol<'a, E> { id: usize, min: u64, max: u64, - params: &'a SmcParamsAndCommitmentKeyAndSecretKey, + params: &'a SmcParamsKVAndCommitmentKeyAndSecretKey, ) -> Self { Self { id, @@ -78,9 +78,9 @@ impl<'a, E: Pairing> BoundCheckSmcWithKVProtocol<'a, E> { pub fn init( &mut self, rng: &mut R, - comm_key_as_slice: &'a [E::G1Affine], - message: E::ScalarField, - blinding: Option, + comm_key_as_slice: &'a [G], + message: G::ScalarField, + blinding: Option, ) -> Result<(), ProofSystemError> { if self.sp.is_some() { return Err(ProofSystemError::SubProtocolAlreadyInitialized(self.id)); @@ -88,47 +88,34 @@ impl<'a, E: Pairing> BoundCheckSmcWithKVProtocol<'a, E> { let params = self .params_and_comm_key .ok_or(ProofSystemError::SmcParamsNotProvided)?; - let msg_as_u64 = enforce_and_get_u64::(&message)?; - let randomness = E::ScalarField::rand(rng); + let msg_as_u64 = enforce_and_get_u64::(&message)?; + let randomness = G::ScalarField::rand(rng); let comm_key = ¶ms.comm_key; self.comm = Some(comm_key.commit(&message, &randomness)); - let smc_protocol = if should_use_cls(self.min, self.max) { - let p = CLSRangeProofWithKVProtocol::init( - rng, - msg_as_u64, - randomness.clone(), - self.min, - self.max, - comm_key, - ¶ms.params, - )?; - SmcProtocolWithKV::CLS(p) - } else { - let p = CCSArbitraryRangeProofWithKVProtocol::init( - rng, - msg_as_u64, - randomness.clone(), - self.min, - self.max, - comm_key, - ¶ms.params, - )?; - SmcProtocolWithKV::CCS(p) - }; - self.smc_protocol = Some(smc_protocol); + let p = CLSRangeProofWithKVProtocol::init( + rng, + msg_as_u64, + randomness.clone(), + self.min, + self.max, + comm_key, + ¶ms.params, + )?; + + self.smc_protocol = Some(SmcProtocolWithKV::CLS(p)); self.init_schnorr_protocol(rng, comm_key_as_slice, message, blinding, randomness) } fn init_schnorr_protocol( &mut self, rng: &mut R, - comm_key: &'a [E::G1Affine], - message: E::ScalarField, - blinding: Option, - blinding_for_smc: E::ScalarField, + comm_key: &'a [G], + message: G::ScalarField, + blinding: Option, + blinding_for_smc: G::ScalarField, ) -> Result<(), ProofSystemError> { let blinding = if blinding.is_none() { - E::ScalarField::rand(rng) + G::ScalarField::rand(rng) } else { blinding.unwrap() }; @@ -178,9 +165,9 @@ impl<'a, E: Pairing> BoundCheckSmcWithKVProtocol<'a, E> { Ok(()) } - pub fn gen_proof_contribution( + pub fn gen_proof_contribution>( &mut self, - challenge: &E::ScalarField, + challenge: &G::ScalarField, ) -> Result, ProofSystemError> { if self.sp.is_none() { return Err(ProofSystemError::SubProtocolNotReadyToGenerateProof( @@ -197,7 +184,7 @@ impl<'a, E: Pairing> BoundCheckSmcWithKVProtocol<'a, E> { BoundCheckSmcWithKVInnerProof::CLS(p) } }; - // Don't generated response for index 0 since its response will come from proofs of one of the signatures. + // Don't generate response for index 0 since its response will come from proofs of one of the signatures. let skip_for = BTreeSet::from([0]); Ok(StatementProof::BoundCheckSmcWithKV( BoundCheckSmcWithKVProof { @@ -214,10 +201,10 @@ impl<'a, E: Pairing> BoundCheckSmcWithKVProtocol<'a, E> { pub fn verify_proof_contribution( &self, - challenge: &E::ScalarField, - proof: &BoundCheckSmcWithKVProof, - comm_key_as_slice: &[E::G1Affine], - resp_for_message: E::ScalarField, + challenge: &G::ScalarField, + proof: &BoundCheckSmcWithKVProof, + comm_key_as_slice: &[G], + resp_for_message: G::ScalarField, ) -> Result<(), ProofSystemError> { let params = self .params_and_comm_key_and_sk @@ -258,9 +245,9 @@ impl<'a, E: Pairing> BoundCheckSmcWithKVProtocol<'a, E> { } pub fn compute_challenge_contribution( - comm_key_as_slice: &[E::G1Affine], - proof: &BoundCheckSmcWithKVProof, - params: &SmcParamsAndCommitmentKeyAndSecretKey, + comm_key_as_slice: &[G], + proof: &BoundCheckSmcWithKVProof, + params: &SmcParamsKVAndCommitmentKeyAndSecretKey, mut writer: W, ) -> Result<(), ProofSystemError> { let comm_key = params.get_comm_key(); diff --git a/proof_system/src/sub_protocols/mod.rs b/proof_system/src/sub_protocols/mod.rs index 1e5a8345..4e07b1e9 100644 --- a/proof_system/src/sub_protocols/mod.rs +++ b/proof_system/src/sub_protocols/mod.rs @@ -15,12 +15,11 @@ pub mod saver; pub mod schnorr; pub mod verifiable_encryption_tz_21; -use core::borrow::Borrow; - use crate::error::ProofSystemError; use ark_ec::pairing::Pairing; use ark_ff::PrimeField; use ark_std::{format, io::Write}; +use core::borrow::Borrow; use itertools::{EitherOrBoth, Itertools}; use crate::sub_protocols::{ @@ -77,7 +76,7 @@ pub enum SubProtocol<'a, E: Pairing> { /// For range proof using set-membership check BoundCheckSmc(BoundCheckSmcProtocol<'a, E>), /// For range proof using set-membership check with keyed verification - BoundCheckSmcWithKV(BoundCheckSmcWithKVProtocol<'a, E>), + BoundCheckSmcWithKV(BoundCheckSmcWithKVProtocol<'a, E::G1Affine>), /// To prove inequality of a signed message with a public value Inequality(InequalityProtocol<'a, E::G1Affine>), DetachedAccumulatorMembership(DetachedAccumulatorMembershipSubProtocol<'a, E>), @@ -206,10 +205,3 @@ pub fn enforce_and_get_u64(val: &F) -> Result bool { - assert!(max > min); - let diff = max - min; - let bits = diff.ilog2(); - bits < 20 -} diff --git a/proof_system/src/verifier.rs b/proof_system/src/verifier.rs index 1191158e..a76bb99d 100644 --- a/proof_system/src/verifier.rs +++ b/proof_system/src/verifier.rs @@ -1886,7 +1886,7 @@ impl Proof { } } - /// Used to check if response (from Schnorr protocol) for a witness is equal to other witnesses that + /*/// Used to check if response (from Schnorr protocol) for a witness is equal to other witnesses that /// it must be equal to. This is required when the `ProofSpec` demands certain witnesses to be equal. fn check_response_for_equality<'a>( stmt_id: usize, @@ -1902,7 +1902,7 @@ impl Proof { return Err(ProofSystemError::WitnessResponseNotEqual(stmt_id, wit_id)); } Ok(()) - } + }*/ /// Get the response for a witness from the tracked responses of witness equalities. /// Expects the response to exist else throws error. This is not to be called for signature proof protocols diff --git a/proof_system/tests/accumulators.rs b/proof_system/tests/accumulators.rs index 424692f1..b9369cec 100644 --- a/proof_system/tests/accumulators.rs +++ b/proof_system/tests/accumulators.rs @@ -1,3 +1,5 @@ +#![allow(non_snake_case)] + use ark_bls12_381::{Bls12_381, Fr, G1Affine}; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use ark_std::{ diff --git a/proof_system/tests/bound_check_smc.rs b/proof_system/tests/bound_check_smc.rs index 5186c512..63f37744 100644 --- a/proof_system/tests/bound_check_smc.rs +++ b/proof_system/tests/bound_check_smc.rs @@ -3,16 +3,11 @@ use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use ark_std::rand::{prelude::StdRng, SeedableRng}; use bbs_plus::prelude::{KeypairG2, SignatureG1, SignatureParamsG1}; use blake2::Blake2b512; -use std::collections::{BTreeMap, BTreeSet}; - -use proof_system::prelude::{ - BoundCheckSmcInnerProof, EqualWitnesses, MetaStatements, ProofSpec, StatementProof, Statements, - Witness, WitnessRef, Witnesses, -}; -use test_utils::test_serialization; - use proof_system::{ - prelude::bound_check_smc::SmcParamsAndCommitmentKey, + prelude::{ + bound_check_smc::SmcParamsAndCommitmentKey, EqualWitnesses, MetaStatements, ProofSpec, + Statements, Witness, WitnessRef, Witnesses, + }, proof::Proof, statement::{ bbs_plus::{ @@ -21,9 +16,10 @@ use proof_system::{ }, bound_check_smc::BoundCheckSmc as BoundCheckStmt, }, - sub_protocols::should_use_cls, witness::PoKBBSSignatureG1 as PoKSignatureBBSG1Wit, }; +use std::collections::{BTreeMap, BTreeSet}; +use test_utils::test_serialization; #[test] fn pok_of_bbs_plus_sig_and_bounded_message_using_set_membership_check_range_proof() { @@ -51,7 +47,6 @@ fn pok_of_bbs_plus_sig_and_bounded_message_using_set_membership_check_range_proo sig: SignatureG1, smc_setup_params: SmcParamsAndCommitmentKey, valid_proof: bool, - is_cls: bool, ) { let mut prover_statements = Statements::new(); prover_statements.add(PoKSignatureBBSG1ProverStmt::new_statement_from_params( @@ -111,34 +106,6 @@ fn pok_of_bbs_plus_sig_and_bounded_message_using_set_membership_check_range_proo test_serialization!(Proof, proof); } - if is_cls { - match &proof.statement_proofs[1] { - StatementProof::BoundCheckSmc(p) => match &p.proof { - BoundCheckSmcInnerProof::CCS(_) => { - assert!(false, "expected CLS proof but found CCS") - } - BoundCheckSmcInnerProof::CLS(_) => assert!(true), - }, - _ => assert!( - false, - "this shouldn't happen as this test is checking set membership based proof" - ), - } - } else { - match &proof.statement_proofs[1] { - StatementProof::BoundCheckSmc(p) => match &p.proof { - BoundCheckSmcInnerProof::CLS(_) => { - assert!(false, "expected CCS proof but found CLS") - } - BoundCheckSmcInnerProof::CCS(_) => assert!(true), - }, - _ => assert!( - false, - "this shouldn't happen as this test is checking set membership based proof" - ), - } - } - let mut verifier_statements = Statements::new(); verifier_statements.add(PoKSignatureBBSG1VerifierStmt::new_statement_from_params( sig_params.clone(), @@ -177,9 +144,6 @@ fn pok_of_bbs_plus_sig_and_bounded_message_using_set_membership_check_range_proo sig.verify(&msgs, sig_keypair.public_key.clone(), sig_params.clone()) .unwrap(); - let is_cls = should_use_cls(min, max); - assert!(is_cls); - // Check for message that is signed and satisfies the bounds check( &mut rng, @@ -193,7 +157,6 @@ fn pok_of_bbs_plus_sig_and_bounded_message_using_set_membership_check_range_proo sig.clone(), smc_setup_params.clone(), true, - is_cls, ); // Check for message that satisfies the bounds but is not signed @@ -209,7 +172,6 @@ fn pok_of_bbs_plus_sig_and_bounded_message_using_set_membership_check_range_proo sig, smc_setup_params.clone(), false, - is_cls, ); let min = 100; @@ -223,9 +185,6 @@ fn pok_of_bbs_plus_sig_and_bounded_message_using_set_membership_check_range_proo sig.verify(&msgs, sig_keypair.public_key.clone(), sig_params.clone()) .unwrap(); - let is_cls = should_use_cls(min, max); - assert!(!is_cls); - // Check for message that is signed and satisfies the bounds check( &mut rng, @@ -239,7 +198,6 @@ fn pok_of_bbs_plus_sig_and_bounded_message_using_set_membership_check_range_proo sig.clone(), smc_setup_params.clone(), true, - is_cls, ); // Check for message that satisfies the bounds but is not signed @@ -255,6 +213,5 @@ fn pok_of_bbs_plus_sig_and_bounded_message_using_set_membership_check_range_proo sig, smc_setup_params, false, - is_cls, ); } diff --git a/proof_system/tests/bound_check_smc_with_kv.rs b/proof_system/tests/bound_check_smc_with_kv.rs index 1cd20c6c..26d0da52 100644 --- a/proof_system/tests/bound_check_smc_with_kv.rs +++ b/proof_system/tests/bound_check_smc_with_kv.rs @@ -1,20 +1,14 @@ -use ark_bls12_381::{Bls12_381, Fr}; +use ark_bls12_381::{Bls12_381, Fr, G1Affine}; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use ark_std::rand::{prelude::StdRng, SeedableRng}; use bbs_plus::prelude::{KeypairG2, SignatureG1, SignatureParamsG1}; use blake2::Blake2b512; -use std::collections::{BTreeMap, BTreeSet}; - -use proof_system::prelude::{ - BoundCheckSmcWithKVInnerProof, EqualWitnesses, MetaStatements, ProofSpec, StatementProof, - Statements, Witness, WitnessRef, Witnesses, -}; -use test_utils::test_serialization; - use proof_system::{ prelude::{ - bound_check_smc::SmcParamsAndCommitmentKey, - bound_check_smc_with_kv::SmcParamsAndCommitmentKeyAndSecretKey, + bound_check_smc_with_kv::{ + SmcParamsKVAndCommitmentKey, SmcParamsKVAndCommitmentKeyAndSecretKey, + }, + EqualWitnesses, MetaStatements, ProofSpec, Statements, Witness, WitnessRef, Witnesses, }, proof::Proof, statement::{ @@ -27,9 +21,10 @@ use proof_system::{ BoundCheckSmcWithKVVerifier as BoundCheckVerifierStmt, }, }, - sub_protocols::should_use_cls, witness::PoKBBSSignatureG1 as PoKSignatureBBSG1Wit, }; +use std::collections::{BTreeMap, BTreeSet}; +use test_utils::test_serialization; #[test] fn pok_of_bbs_plus_sig_and_bounded_message_using_set_membership_check_range_proof_with_keyed_verification( @@ -43,9 +38,8 @@ fn pok_of_bbs_plus_sig_and_bounded_message_using_set_membership_check_range_proo let sig_keypair = KeypairG2::::generate_using_rng(&mut rng, &sig_params); let (smc_setup_params, sk) = - SmcParamsAndCommitmentKey::new::<_, Blake2b512>(&mut rng, b"test", 2); - smc_setup_params.verify().unwrap(); - let smc_setup_params_with_sk = SmcParamsAndCommitmentKeyAndSecretKey { + SmcParamsKVAndCommitmentKey::new::<_, Blake2b512>(&mut rng, b"test", 2); + let smc_setup_params_with_sk = SmcParamsKVAndCommitmentKeyAndSecretKey { params_and_comm_key: smc_setup_params.clone(), sk, }; @@ -60,10 +54,9 @@ fn pok_of_bbs_plus_sig_and_bounded_message_using_set_membership_check_range_proo sig_params: SignatureParamsG1, sig_keypair: KeypairG2, sig: SignatureG1, - smc_setup_params: SmcParamsAndCommitmentKey, - smc_setup_params_with_sk: SmcParamsAndCommitmentKeyAndSecretKey, + smc_setup_params: SmcParamsKVAndCommitmentKey, + smc_setup_params_with_sk: SmcParamsKVAndCommitmentKeyAndSecretKey, valid_proof: bool, - is_cls: bool, ) { let mut prover_statements = Statements::new(); prover_statements.add(PoKSignatureBBSG1ProverStmt::new_statement_from_params( @@ -124,34 +117,6 @@ fn pok_of_bbs_plus_sig_and_bounded_message_using_set_membership_check_range_proo test_serialization!(Proof, proof); } - if is_cls { - match &proof.statement_proofs[1] { - StatementProof::BoundCheckSmcWithKV(p) => match &p.proof { - BoundCheckSmcWithKVInnerProof::CCS(_) => { - assert!(false, "expected CLS proof but found CCS") - } - BoundCheckSmcWithKVInnerProof::CLS(_) => assert!(true), - }, - _ => assert!( - false, - "this shouldn't happen as this test is checking set membership based proof" - ), - } - } else { - match &proof.statement_proofs[1] { - StatementProof::BoundCheckSmcWithKV(p) => match &p.proof { - BoundCheckSmcWithKVInnerProof::CLS(_) => { - assert!(false, "expected CCS proof but found CLS") - } - BoundCheckSmcWithKVInnerProof::CCS(_) => assert!(true), - }, - _ => assert!( - false, - "this shouldn't happen as this test is checking set membership based proof" - ), - } - } - let mut verifier_statements = Statements::new(); verifier_statements.add(PoKSignatureBBSG1VerifierStmt::new_statement_from_params( sig_params.clone(), @@ -195,9 +160,6 @@ fn pok_of_bbs_plus_sig_and_bounded_message_using_set_membership_check_range_proo sig.verify(&msgs, sig_keypair.public_key.clone(), sig_params.clone()) .unwrap(); - let is_cls = should_use_cls(min, max); - assert!(is_cls); - // Check for message that is signed and satisfies the bounds check( &mut rng, @@ -212,7 +174,6 @@ fn pok_of_bbs_plus_sig_and_bounded_message_using_set_membership_check_range_proo smc_setup_params.clone(), smc_setup_params_with_sk.clone(), true, - is_cls, ); // Check for message that satisfies the bounds but is not signed @@ -229,7 +190,6 @@ fn pok_of_bbs_plus_sig_and_bounded_message_using_set_membership_check_range_proo smc_setup_params.clone(), smc_setup_params_with_sk.clone(), false, - is_cls, ); let min = 100; @@ -243,9 +203,6 @@ fn pok_of_bbs_plus_sig_and_bounded_message_using_set_membership_check_range_proo sig.verify(&msgs, sig_keypair.public_key.clone(), sig_params.clone()) .unwrap(); - let is_cls = should_use_cls(min, max); - assert!(!is_cls); - // Check for message that is signed and satisfies the bounds check( &mut rng, @@ -260,7 +217,6 @@ fn pok_of_bbs_plus_sig_and_bounded_message_using_set_membership_check_range_proo smc_setup_params.clone(), smc_setup_params_with_sk.clone(), true, - is_cls, ); // Check for message that satisfies the bounds but is not signed @@ -277,6 +233,5 @@ fn pok_of_bbs_plus_sig_and_bounded_message_using_set_membership_check_range_proo smc_setup_params, smc_setup_params_with_sk.clone(), false, - is_cls, ); } diff --git a/short_group_sig/src/bb_sig_pok.rs b/short_group_sig/src/bb_sig_pok.rs index 951d7f7b..22b1026d 100644 --- a/short_group_sig/src/bb_sig_pok.rs +++ b/short_group_sig/src/bb_sig_pok.rs @@ -640,6 +640,7 @@ mod tests { &mut pairing_checker, ) .unwrap(); + assert!(pairing_checker.verify()); let msg_blinding = Fr::rand(&mut rng); let rand_blinding = Fr::rand(&mut rng); diff --git a/short_group_sig/src/threshold_weak_bb_sig.rs b/short_group_sig/src/threshold_weak_bb_sig.rs index 0a973c3b..8ae6608c 100644 --- a/short_group_sig/src/threshold_weak_bb_sig.rs +++ b/short_group_sig/src/threshold_weak_bb_sig.rs @@ -437,6 +437,8 @@ pub mod tests { phase1_outputs } + /// Pass `full_message` if all signers know the full message. Pass `message_shares` if each signer knows + /// only a share of the original message. fn do_phase2( rng: &mut StdRng, threshold_signers: ParticipantId, diff --git a/short_group_sig/src/weak_bb_sig.rs b/short_group_sig/src/weak_bb_sig.rs index 316bd91e..c172ae18 100644 --- a/short_group_sig/src/weak_bb_sig.rs +++ b/short_group_sig/src/weak_bb_sig.rs @@ -119,7 +119,7 @@ impl SignatureG1 { sk: impl AsRef, gen: impl AsRef, ) -> Self { - Self((*gen.as_ref() * ((*sk.as_ref() + message).inverse().unwrap())).into()) + Self(gen_sig::(message, sk, gen.as_ref())) } pub fn verify( @@ -194,6 +194,15 @@ impl AsRef for SignatureG1 { } } +/// Generate weak-BB signature. Useful when working in a non-pairing setting +pub fn gen_sig( + message: &G::ScalarField, + sk: impl AsRef, + gen: &G, +) -> G { + (*gen * ((*sk.as_ref() + message).inverse().unwrap())).into() +} + #[cfg(test)] mod tests { use super::*; diff --git a/short_group_sig/src/weak_bb_sig_pok_kv.rs b/short_group_sig/src/weak_bb_sig_pok_kv.rs index a37cbdd5..a838ca71 100644 --- a/short_group_sig/src/weak_bb_sig_pok_kv.rs +++ b/short_group_sig/src/weak_bb_sig_pok_kv.rs @@ -54,7 +54,7 @@ pub struct PoKOfSignatureG1KV { impl PoKOfSignatureG1KVProtocol { pub fn init( rng: &mut R, - signature: impl AsRef, + signature: &G, message: G::ScalarField, blinding: Option, g1: &G, @@ -77,13 +77,13 @@ impl PoKOfSignatureG1KVProtocol { sig_randomizer: G::ScalarField, msg_blinding: G::ScalarField, sc_blinding: G::ScalarField, - signature: impl AsRef, + signature: &G, message: G::ScalarField, g1: &G, ) -> Self { let sig_r = sig_randomizer.into_bigint(); // A * r - let A_prime = signature.as_ref().mul_bigint(sig_r); + let A_prime = signature.mul_bigint(sig_r); let A_prime_neg = A_prime.neg(); // A_bar = g1 * r - A' * m let A_bar = g1.mul_bigint(sig_r) + A_prime_neg * message; @@ -244,11 +244,8 @@ impl PoKOfSignatureG1KV { #[cfg(test)] mod tests { use super::*; - use crate::{ - common::SignatureParams, - weak_bb_sig::{SecretKey, SignatureG1}, - }; - use ark_bls12_381::{Bls12_381, Fr, G1Affine}; + use crate::weak_bb_sig::{gen_sig, SecretKey}; + use ark_bls12_381::{Fr, G1Affine}; use ark_std::{ rand::{rngs::StdRng, SeedableRng}, UniformRand, @@ -259,18 +256,18 @@ mod tests { #[test] fn proof_of_knowledge_of_signature() { let mut rng = StdRng::seed_from_u64(0u64); - let params = SignatureParams::::new::(b"test-params"); + let g1 = G1Affine::rand(&mut rng); let sk = SecretKey::new(&mut rng); let message = Fr::rand(&mut rng); - let sig = SignatureG1::::new(&message, &sk, ¶ms); + let sig = gen_sig::(&message, &sk, &g1); let protocol = - PoKOfSignatureG1KVProtocol::::init(&mut rng, sig, message, None, ¶ms.g1); + PoKOfSignatureG1KVProtocol::::init(&mut rng, &sig, message, None, &g1); let mut chal_bytes_prover = vec![]; protocol - .challenge_contribution(¶ms.g1, &mut chal_bytes_prover) + .challenge_contribution(&g1, &mut chal_bytes_prover) .unwrap(); let challenge_prover = compute_random_oracle_challenge::(&chal_bytes_prover); @@ -279,11 +276,11 @@ mod tests { let mut chal_bytes_verifier = vec![]; proof - .challenge_contribution(¶ms.g1, &mut chal_bytes_verifier) + .challenge_contribution(&g1, &mut chal_bytes_verifier) .unwrap(); let challenge_verifier = compute_random_oracle_challenge::(&chal_bytes_verifier); assert_eq!(challenge_prover, challenge_verifier); - proof.verify(&challenge_verifier, &sk, ¶ms.g1).unwrap(); + proof.verify(&challenge_verifier, &sk, &g1).unwrap(); } } diff --git a/smc_range_proof/README.md b/smc_range_proof/README.md index ff058245..9514b196 100644 --- a/smc_range_proof/README.md +++ b/smc_range_proof/README.md @@ -8,7 +8,7 @@ Implements the following range proof and set-membership protocols. where `u` is the base and the upper bound is a power of the base. [Code](src/ccs_range_proof/perfect_range.rs) 3. Range proof protocol as described in section 4.4 of the paper [1]. Considers an arbitrary range `[min, max)`. Some differences with the paper, check the module for more details. [Code](src/ccs_range_proof/arbitrary_range.rs) -4. Range proof using sumsets, based on Protocol 2 from the paper [2]. [Code](src/smc_range_proof.rs) +4. Range proof using sumsets, based on Protocol 2 from the paper [2] but considers range [min, max) and not [0, max]. [Code](src/smc_range_proof.rs) 5. Implements the Keyed-Verification of the above protocols where the verifier knows the secret key of the BB sig. This makes the proof generation and verification more efficient by removing the need for pairings. This idea is taken from this PhD. thesis. diff --git a/smc_range_proof/src/ccs_range_proof/arbitrary_range.rs b/smc_range_proof/src/ccs_range_proof/arbitrary_range.rs index 07c33882..dda301af 100644 --- a/smc_range_proof/src/ccs_range_proof/arbitrary_range.rs +++ b/smc_range_proof/src/ccs_range_proof/arbitrary_range.rs @@ -1,29 +1,31 @@ //! Range proof protocol as described in section 4.4 of the paper [Efficient Protocols for Set Membership and Range Proofs](https://link.springer.com/chapter/10.1007/978-3-540-89255-7_15). //! Considers an arbitrary range `[min, max)`. This essentially executes 2 instances of the protocol for perfect range `[0, u^l)` +//! //! A difference with the paper is that a single `D` is created in the paper which can lead to the verifier learning that some digits -//! are same in values in those 2 protocols +//! are same in values in those 2 protocols. +//! +//! Secondly, less number of digits are needed as `l` is chosen such that `max - min < u^l` rather than `max < u^l`. use crate::{ - ccs_set_membership::setup::SetMembershipCheckParamsWithPairing, common::MemberCommitmentKey, + ccs_range_proof::util::{check_commitment_for_arbitrary_range, find_l_for_arbitrary_range}, + ccs_set_membership::setup::SetMembershipCheckParamsWithPairing, + common::{padded_base_n_digits_as_field_elements, MemberCommitmentKey}, error::SmcRangeProofError, }; use ark_ec::{ pairing::{Pairing, PairingOutput}, AffineRepr, CurveGroup, }; - use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use ark_std::{cfg_into_iter, format, io::Write, ops::Mul, rand::RngCore, vec::Vec, UniformRand}; -use dock_crypto_utils::{expect_equality, misc::n_rand, msm::WindowTable}; - -use crate::ccs_range_proof::util::{check_commitment_for_arbitrary_range, find_l_greater_than}; -use dock_crypto_utils::randomized_pairing_check::RandomizedPairingChecker; +use dock_crypto_utils::{ + expect_equality, misc::n_rand, msm::WindowTable, + randomized_pairing_check::RandomizedPairingChecker, +}; #[cfg(feature = "parallel")] use rayon::prelude::*; -use crate::common::padded_base_n_digits_as_field_elements; - #[derive(Clone, PartialEq, Eq, Debug)] pub struct CCSArbitraryRangeProofProtocol { pub base: u16, @@ -64,6 +66,7 @@ pub struct CCSArbitraryRangeProof { } impl CCSArbitraryRangeProofProtocol { + /// Initialize the protocol for proving `min <= value < max` pub fn init( rng: &mut R, value: u64, @@ -86,6 +89,7 @@ impl CCSArbitraryRangeProofProtocol { ) } + /// Initialize the protocol for proving `min <= value < max` pub fn init_given_base( rng: &mut R, value: u64, @@ -113,7 +117,7 @@ impl CCSArbitraryRangeProofProtocol { params.validate_base(base)?; - let l = find_l_greater_than(max, base) as usize; + let l = find_l_for_arbitrary_range(max, min, base) as usize; // Different randomizer vectors `s_min` and `s_max` are chosen to avoid leaking // the information that some digits are potentially same at the same indices, i.e @@ -207,7 +211,35 @@ impl CCSArbitraryRangeProofProtocol { } pub fn gen_proof(self, challenge: &E::ScalarField) -> CCSArbitraryRangeProof { - gen_proof_arbitrary_range!(self, challenge, CCSArbitraryRangeProof) + let z_v_min = cfg_into_iter!(0..self.V_min.len()) + .map(|i| self.t_min[i] + (self.v_min[i] * challenge)) + .collect::>(); + let z_v_max = cfg_into_iter!(0..self.V_max.len()) + .map(|i| self.t_max[i] + (self.v_max[i] * challenge)) + .collect::>(); + let z_sigma_min = cfg_into_iter!(0..self.V_min.len()) + .map(|i| self.s_min[i] + (self.digits_min[i] * challenge)) + .collect::>(); + let z_sigma_max = cfg_into_iter!(0..self.V_max.len()) + .map(|i| self.s_max[i] + (self.digits_max[i] * challenge)) + .collect::>(); + let z_r_min = self.m_min + (self.r * challenge); + let z_r_max = self.m_max + (self.r * challenge); + CCSArbitraryRangeProof { + base: self.base, + V_min: self.V_min, + V_max: self.V_max, + a_min: self.a_min, + a_max: self.a_max, + D_min: self.D_min, + D_max: self.D_max, + z_v_min, + z_v_max, + z_sigma_min, + z_sigma_max, + z_r_min, + z_r_max, + } } pub fn compute_challenge_contribution( @@ -245,6 +277,7 @@ impl CCSArbitraryRangeProofProtocol { } impl CCSArbitraryRangeProof { + /// Verify the proof for `min <= value < max` where `commitment` is a Pedersen commitment to `value` pub fn verify( &self, commitment: &E::G1Affine, @@ -286,6 +319,7 @@ impl CCSArbitraryRangeProof { Ok(()) } + /// Verify the proof for `min <= value < max` where `commitment` is a Pedersen commitment to `value` pub fn verify_given_randomized_pairing_checker( &self, commitment: &E::G1Affine, @@ -353,7 +387,7 @@ impl CCSArbitraryRangeProof { ))); } params.validate_base(self.base)?; - let l = find_l_greater_than(max, self.base) as usize; + let l = find_l_for_arbitrary_range(max, min, self.base) as usize; expect_equality!( self.V_min.len(), l, @@ -384,7 +418,7 @@ impl CCSArbitraryRangeProof { l, SmcRangeProofError::ProofShorterThanExpected ); - check_commitment_for_arbitrary_range::( + check_commitment_for_arbitrary_range::( self.base, &self.z_sigma_min, &self.z_sigma_max, @@ -456,7 +490,7 @@ mod tests { fn range_proof_for_arbitrary_range() { let mut rng = StdRng::seed_from_u64(0u64); - for base in [2, 4, 8, 16] { + for base in [2, 4, 8, 10, 13, 16] { let mut proving_time = Duration::default(); let mut verifying_time = Duration::default(); let mut verifying_with_rpc_time = Duration::default(); @@ -607,6 +641,7 @@ mod tests { &mut pairing_checker, ) .unwrap(); + assert!(pairing_checker.verify()); verifying_with_rpc_time += start.elapsed(); let mut bytes = vec![]; diff --git a/smc_range_proof/src/ccs_range_proof/arbitrary_range_cdh.rs b/smc_range_proof/src/ccs_range_proof/arbitrary_range_cdh.rs index bd1c5dc6..e563d44a 100644 --- a/smc_range_proof/src/ccs_range_proof/arbitrary_range_cdh.rs +++ b/smc_range_proof/src/ccs_range_proof/arbitrary_range_cdh.rs @@ -3,7 +3,7 @@ //! The difference with the paper is the protocol used to prove knowledge of weak-BB sig which is taken from the CDH paper. use crate::{ - ccs_range_proof::util::find_l_greater_than, + ccs_range_proof::util::{check_commitment_for_arbitrary_range, find_l_for_arbitrary_range}, ccs_set_membership::setup::{SetMembershipCheckParams, SetMembershipCheckParamsWithPairing}, common::{padded_base_n_digits_as_field_elements, MemberCommitmentKey}, error::SmcRangeProofError, @@ -11,11 +11,11 @@ use crate::{ use ark_ec::pairing::Pairing; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use ark_std::{cfg_into_iter, cfg_iter, format, io::Write, rand::RngCore, vec::Vec, UniformRand}; -use dock_crypto_utils::misc::n_rand; +use dock_crypto_utils::{ + expect_equality, misc::n_rand, randomized_pairing_check::RandomizedPairingChecker, +}; use short_group_sig::weak_bb_sig_pok_cdh::{PoKOfSignatureG1, PoKOfSignatureG1Protocol}; -use crate::ccs_range_proof::util::check_commitment_for_arbitrary_range; -use dock_crypto_utils::{expect_equality, randomized_pairing_check::RandomizedPairingChecker}; #[cfg(feature = "parallel")] use rayon::prelude::*; @@ -43,6 +43,7 @@ pub struct CCSArbitraryRangeProof { } impl CCSArbitraryRangeProofProtocol { + /// Initialize the protocol for proving `min <= value < max` pub fn init( rng: &mut R, value: u64, @@ -64,6 +65,7 @@ impl CCSArbitraryRangeProofProtocol { ) } + /// Initialize the protocol for proving `min <= value < max` pub fn init_given_base( rng: &mut R, value: u64, @@ -89,7 +91,7 @@ impl CCSArbitraryRangeProofProtocol { params.validate_base(base)?; - let l = find_l_greater_than(max, base) as usize; + let l = find_l_for_arbitrary_range(max, min, base) as usize; let m_min = E::ScalarField::rand(rng); let msg_blindings_min = n_rand(rng, l).collect::>(); @@ -204,6 +206,7 @@ impl CCSArbitraryRangeProofProtocol { } impl CCSArbitraryRangeProof { + /// Verify the proof for `min <= value < max` where `commitment` is a Pedersen commitment to `value` pub fn verify( &self, commitment: &E::G1Affine, @@ -246,6 +249,7 @@ impl CCSArbitraryRangeProof { Ok(()) } + /// Verify the proof for `min <= value < max` where `commitment` is a Pedersen commitment to `value` pub fn verify_given_randomized_pairing_checker( &self, commitment: &E::G1Affine, @@ -320,7 +324,7 @@ impl CCSArbitraryRangeProof { ))); } params.validate_base(self.base)?; - let l = find_l_greater_than(max, self.base) as usize; + let l = find_l_for_arbitrary_range(max, min, self.base) as usize; expect_equality!( self.pok_sigs_min.len(), l, @@ -338,7 +342,7 @@ impl CCSArbitraryRangeProof { let resp_d_max = cfg_iter!(self.pok_sigs_max) .map(|p| *p.get_resp_for_message().unwrap()) .collect::>(); - check_commitment_for_arbitrary_range::( + check_commitment_for_arbitrary_range::( self.base, &resp_d_min, &resp_d_max, @@ -372,7 +376,7 @@ mod tests { fn range_proof_for_arbitrary_range() { let mut rng = StdRng::seed_from_u64(0u64); - for base in [2, 4, 8, 16] { + for base in [2, 4, 8, 10, 13, 16] { let mut proving_time = Duration::default(); let mut verifying_time = Duration::default(); let mut verifying_with_rpc_time = Duration::default(); @@ -508,6 +512,7 @@ mod tests { &mut pairing_checker, ) .unwrap(); + assert!(pairing_checker.verify()); verifying_with_rpc_time += start.elapsed(); let mut bytes = vec![]; diff --git a/smc_range_proof/src/ccs_range_proof/kv_arbitrary_range.rs b/smc_range_proof/src/ccs_range_proof/kv_arbitrary_range.rs index 7eb7988f..53fb6e51 100644 --- a/smc_range_proof/src/ccs_range_proof/kv_arbitrary_range.rs +++ b/smc_range_proof/src/ccs_range_proof/kv_arbitrary_range.rs @@ -2,56 +2,56 @@ //! secret key of the BB-sig use crate::{ - ccs_set_membership::setup::SetMembershipCheckParams, common::MemberCommitmentKey, + ccs_range_proof::util::{check_commitment_for_arbitrary_range, find_l_for_arbitrary_range}, + ccs_set_membership::setup::SetMembershipCheckParamsKV, + common::{padded_base_n_digits_as_field_elements, MemberCommitmentKey}, error::SmcRangeProofError, }; -use ark_ec::pairing::Pairing; - -use crate::ccs_range_proof::util::{check_commitment_for_arbitrary_range, find_l_greater_than}; +use ark_ec::AffineRepr; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use ark_std::{cfg_into_iter, cfg_iter, format, io::Write, rand::RngCore, vec::Vec, UniformRand}; use dock_crypto_utils::{expect_equality, misc::n_rand}; -#[cfg(feature = "parallel")] -use rayon::prelude::*; use short_group_sig::{ weak_bb_sig::SecretKey, weak_bb_sig_pok_kv::{PoKOfSignatureG1KV, PoKOfSignatureG1KVProtocol}, }; -use crate::common::padded_base_n_digits_as_field_elements; +#[cfg(feature = "parallel")] +use rayon::prelude::*; #[derive(Clone, PartialEq, Eq, Debug)] -pub struct CCSArbitraryRangeProofWithKVProtocol { +pub struct CCSArbitraryRangeProofWithKVProtocol { pub base: u16, - pub r: E::ScalarField, - pub pok_sigs_min: Vec>, - pub pok_sigs_max: Vec>, - pub D_min: E::G1Affine, - pub m_min: E::ScalarField, - pub D_max: E::G1Affine, - pub m_max: E::ScalarField, + pub r: G::ScalarField, + pub pok_sigs_min: Vec>, + pub pok_sigs_max: Vec>, + pub D_min: G, + pub m_min: G::ScalarField, + pub D_max: G, + pub m_max: G::ScalarField, } #[derive(Clone, PartialEq, Eq, Debug, CanonicalSerialize, CanonicalDeserialize)] -pub struct CCSArbitraryRangeWithKVProof { +pub struct CCSArbitraryRangeWithKVProof { pub base: u16, - pub D_min: E::G1Affine, - pub D_max: E::G1Affine, - pub pok_sigs_min: Vec>, - pub pok_sigs_max: Vec>, - pub resp_r_min: E::ScalarField, - pub resp_r_max: E::ScalarField, + pub D_min: G, + pub D_max: G, + pub pok_sigs_min: Vec>, + pub pok_sigs_max: Vec>, + pub resp_r_min: G::ScalarField, + pub resp_r_max: G::ScalarField, } -impl CCSArbitraryRangeProofWithKVProtocol { +impl CCSArbitraryRangeProofWithKVProtocol { + /// Initialize the protocol for proving `min <= value < max` pub fn init( rng: &mut R, value: u64, - randomness: E::ScalarField, + randomness: G::ScalarField, min: u64, max: u64, - comm_key: &MemberCommitmentKey, - params: &SetMembershipCheckParams, + comm_key: &MemberCommitmentKey, + params: &SetMembershipCheckParamsKV, ) -> Result { Self::init_given_base( rng, @@ -65,15 +65,16 @@ impl CCSArbitraryRangeProofWithKVProtocol { ) } + /// Initialize the protocol for proving `min <= value < max` pub fn init_given_base( rng: &mut R, value: u64, - randomness: E::ScalarField, + randomness: G::ScalarField, min: u64, max: u64, base: u16, - comm_key: &MemberCommitmentKey, - params: &SetMembershipCheckParams, + comm_key: &MemberCommitmentKey, + params: &SetMembershipCheckParamsKV, ) -> Result { if min > value { return Err(SmcRangeProofError::IncorrectBounds(format!( @@ -90,13 +91,13 @@ impl CCSArbitraryRangeProofWithKVProtocol { params.validate_base(base)?; - let l = find_l_greater_than(max, base) as usize; + let l = find_l_for_arbitrary_range(max, min, base) as usize; - let m_min = E::ScalarField::rand(rng); - let msg_blindings_min = n_rand(rng, l).collect::>(); + let m_min = G::ScalarField::rand(rng); + let msg_blindings_min = n_rand(rng, l).collect::>(); let D_min = comm_key.commit_decomposed(base, &msg_blindings_min, &m_min); - let m_max = E::ScalarField::rand(rng); - let msg_blindings_max = n_rand(rng, l).collect::>(); + let m_max = G::ScalarField::rand(rng); + let msg_blindings_max = n_rand(rng, l).collect::>(); let D_max = comm_key.commit_decomposed(base, &msg_blindings_max, &m_max); let digits_min = padded_base_n_digits_as_field_elements(value - min, base, l); @@ -114,10 +115,10 @@ impl CCSArbitraryRangeProofWithKVProtocol { sigs.push(params.get_sig_for_member(d)?); } - let sig_randomizers_min = n_rand(rng, l).collect::>(); - let sig_randomizers_max = n_rand(rng, l).collect::>(); - let sc_blindings_min = n_rand(rng, l).collect::>(); - let sc_blindings_max = n_rand(rng, l).collect::>(); + let sig_randomizers_min = n_rand(rng, l).collect::>(); + let sig_randomizers_max = n_rand(rng, l).collect::>(); + let sc_blindings_min = n_rand(rng, l).collect::>(); + let sc_blindings_max = n_rand(rng, l).collect::>(); let pok_sigs_min = cfg_into_iter!(sig_randomizers_min) .zip(cfg_into_iter!(msg_blindings_min)) @@ -126,13 +127,13 @@ impl CCSArbitraryRangeProofWithKVProtocol { .zip(cfg_into_iter!(digits_min)) .map( |((((sig_randomizer_i, msg_blinding_i), sc_blinding_i), sig_i), msg_i)| { - PoKOfSignatureG1KVProtocol::init_with_given_randomness( + PoKOfSignatureG1KVProtocol::::init_with_given_randomness( sig_randomizer_i, msg_blinding_i, sc_blinding_i, sig_i, msg_i, - ¶ms.bb_sig_params.g1, + ¶ms.bb_sig_params, ) }, ) @@ -145,13 +146,13 @@ impl CCSArbitraryRangeProofWithKVProtocol { .zip(cfg_into_iter!(digits_max)) .map( |((((sig_randomizer_i, msg_blinding_i), sc_blinding_i), sig_i), msg_i)| { - PoKOfSignatureG1KVProtocol::init_with_given_randomness( + PoKOfSignatureG1KVProtocol::::init_with_given_randomness( sig_randomizer_i, msg_blinding_i, sc_blinding_i, sig_i, msg_i, - ¶ms.bb_sig_params.g1, + ¶ms.bb_sig_params, ) }, ) @@ -171,16 +172,16 @@ impl CCSArbitraryRangeProofWithKVProtocol { pub fn challenge_contribution( &self, - commitment: &E::G1Affine, - comm_key: &MemberCommitmentKey, - params: &SetMembershipCheckParams, + commitment: &G, + comm_key: &MemberCommitmentKey, + params: &SetMembershipCheckParamsKV, mut writer: W, ) -> Result<(), SmcRangeProofError> { for sig in &self.pok_sigs_min { - sig.challenge_contribution(¶ms.bb_sig_params.g1, &mut writer)?; + sig.challenge_contribution(¶ms.bb_sig_params, &mut writer)?; } for sig in &self.pok_sigs_max { - sig.challenge_contribution(¶ms.bb_sig_params.g1, &mut writer)?; + sig.challenge_contribution(¶ms.bb_sig_params, &mut writer)?; } comm_key.serialize_compressed(&mut writer)?; commitment.serialize_compressed(&mut writer)?; @@ -189,7 +190,7 @@ impl CCSArbitraryRangeProofWithKVProtocol { Ok(()) } - pub fn gen_proof(self, challenge: &E::ScalarField) -> CCSArbitraryRangeWithKVProof { + pub fn gen_proof(self, challenge: &G::ScalarField) -> CCSArbitraryRangeWithKVProof { let pok_sigs_min = cfg_into_iter!(self.pok_sigs_min) .map(|p| p.gen_proof(challenge)) .collect::>(); @@ -208,19 +209,20 @@ impl CCSArbitraryRangeProofWithKVProtocol { } } -impl CCSArbitraryRangeWithKVProof { +impl CCSArbitraryRangeWithKVProof { + /// Verify the proof for `min <= value < max` where `commitment` is a Pedersen commitment to `value` pub fn verify( &self, - commitment: &E::G1Affine, - challenge: &E::ScalarField, + commitment: &G, + challenge: &G::ScalarField, min: u64, max: u64, - comm_key: &MemberCommitmentKey, - params: &SetMembershipCheckParams, - secret_key: &SecretKey, + comm_key: &MemberCommitmentKey, + params: &SetMembershipCheckParamsKV, + secret_key: &SecretKey, ) -> Result<(), SmcRangeProofError> { params.validate_base(self.base)?; - let l = find_l_greater_than(max, self.base) as usize; + let l = find_l_for_arbitrary_range(max, min, self.base) as usize; expect_equality!( self.pok_sigs_min.len(), l, @@ -238,7 +240,7 @@ impl CCSArbitraryRangeWithKVProof { let resp_d_max = cfg_iter!(self.pok_sigs_max) .map(|p| *p.get_resp_for_message().unwrap()) .collect::>(); - check_commitment_for_arbitrary_range::( + check_commitment_for_arbitrary_range::( self.base, &resp_d_min, &resp_d_max, @@ -255,7 +257,7 @@ impl CCSArbitraryRangeWithKVProof { let results = cfg_iter!(self.pok_sigs_min) .chain(cfg_iter!(self.pok_sigs_max)) .map(|p| { - if let Err(e) = p.verify(challenge, secret_key, ¶ms.bb_sig_params.g1) { + if let Err(e) = p.verify(challenge, secret_key, ¶ms.bb_sig_params) { return Err(SmcRangeProofError::ShortGroupSig(e)); } Ok(()) @@ -269,16 +271,16 @@ impl CCSArbitraryRangeWithKVProof { pub fn challenge_contribution( &self, - commitment: &E::G1Affine, - comm_key: &MemberCommitmentKey, - params: &SetMembershipCheckParams, + commitment: &G, + comm_key: &MemberCommitmentKey, + params: &SetMembershipCheckParamsKV, mut writer: W, ) -> Result<(), SmcRangeProofError> { for sig in &self.pok_sigs_min { - sig.challenge_contribution(¶ms.bb_sig_params.g1, &mut writer)?; + sig.challenge_contribution(¶ms.bb_sig_params, &mut writer)?; } for sig in &self.pok_sigs_max { - sig.challenge_contribution(¶ms.bb_sig_params.g1, &mut writer)?; + sig.challenge_contribution(¶ms.bb_sig_params, &mut writer)?; } comm_key.serialize_compressed(&mut writer)?; commitment.serialize_compressed(&mut writer)?; @@ -291,8 +293,7 @@ impl CCSArbitraryRangeWithKVProof { #[cfg(test)] mod tests { use super::*; - use crate::ccs_set_membership::setup::SetMembershipCheckParams; - use ark_bls12_381::{Bls12_381, Fr, G1Affine}; + use ark_bls12_381::{Fr, G1Affine}; use ark_std::{ rand::{rngs::StdRng, SeedableRng}, UniformRand, @@ -309,12 +310,11 @@ mod tests { let mut verifying_time = Duration::default(); let mut num_proofs = 0; - for base in [2, 4, 8, 16] { - let (params, sk) = SetMembershipCheckParams::::new_for_range_proof::< + for base in [2, 4, 8, 10, 13, 16] { + let (params, sk) = SetMembershipCheckParamsKV::::new_for_range_proof::< _, Blake2b512, >(&mut rng, b"test", base); - params.verify().unwrap(); let comm_key = MemberCommitmentKey::::generate_using_rng(&mut rng); @@ -341,11 +341,10 @@ mod tests { // Params with incorrect base should fail let params_with_smaller_base = { - let (params, _) = SetMembershipCheckParams::::new_for_range_proof::< + let (params, _) = SetMembershipCheckParamsKV::::new_for_range_proof::< _, Blake2b512, >(&mut rng, b"test", base - 1); - params.verify().unwrap(); params }; assert!(CCSArbitraryRangeProofWithKVProtocol::init_given_base( @@ -368,11 +367,10 @@ mod tests { // Params with larger base should work let (params_with_larger_base, sk_larger) = { - let (params, sk) = SetMembershipCheckParams::::new_for_range_proof::< + let (params, sk) = SetMembershipCheckParamsKV::::new_for_range_proof::< _, Blake2b512, >(&mut rng, b"test", base + 1); - params.verify().unwrap(); (params, sk) }; @@ -414,8 +412,10 @@ mod tests { } println!( - "For {} proofs, proving_time={:?} and verifying_time={:?}", - num_proofs, proving_time, verifying_time + "For {} proofs, average proving_time={:?} and average verifying_time={:?}", + num_proofs, + proving_time / num_proofs, + verifying_time / num_proofs ); } } diff --git a/smc_range_proof/src/ccs_range_proof/kv_perfect_range.rs b/smc_range_proof/src/ccs_range_proof/kv_perfect_range.rs index 8836ee43..8867351c 100644 --- a/smc_range_proof/src/ccs_range_proof/kv_perfect_range.rs +++ b/smc_range_proof/src/ccs_range_proof/kv_perfect_range.rs @@ -2,49 +2,49 @@ //! secret key of the BB-sig use crate::{ - ccs_set_membership::setup::SetMembershipCheckParams, common::MemberCommitmentKey, + ccs_range_proof::util::{check_commitment_for_prefect_range, find_l_for_perfect_range}, + ccs_set_membership::setup::SetMembershipCheckParamsKV, + common::{padded_base_n_digits_as_field_elements, MemberCommitmentKey}, error::SmcRangeProofError, }; -use ark_ec::pairing::Pairing; - +use ark_ec::AffineRepr; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use ark_std::{cfg_into_iter, cfg_iter, io::Write, rand::RngCore, vec::Vec, UniformRand}; -use dock_crypto_utils::misc::n_rand; -use short_group_sig::weak_bb_sig::SecretKey; - -use crate::common::padded_base_n_digits_as_field_elements; +use dock_crypto_utils::{expect_equality, misc::n_rand}; +use short_group_sig::{ + weak_bb_sig::SecretKey, + weak_bb_sig_pok_kv::{PoKOfSignatureG1KV, PoKOfSignatureG1KVProtocol}, +}; -use crate::ccs_range_proof::util::check_commitment_for_prefect_range; -use dock_crypto_utils::expect_equality; #[cfg(feature = "parallel")] use rayon::prelude::*; -use short_group_sig::weak_bb_sig_pok_kv::{PoKOfSignatureG1KV, PoKOfSignatureG1KVProtocol}; #[derive(Clone, PartialEq, Eq, Debug)] -pub struct CCSPerfectRangeProofWithKVProtocol { +pub struct CCSPerfectRangeProofWithKVProtocol { pub base: u16, - pub r: E::ScalarField, - pub pok_sigs: Vec>, - pub D: E::G1Affine, - pub m: E::ScalarField, + pub r: G::ScalarField, + pub pok_sigs: Vec>, + pub D: G, + pub m: G::ScalarField, } #[derive(Clone, PartialEq, Eq, Debug, CanonicalSerialize, CanonicalDeserialize)] -pub struct CCSPerfectRangeWithKVProof { +pub struct CCSPerfectRangeWithKVProof { pub base: u16, - pub pok_sigs: Vec>, - pub D: E::G1Affine, - pub resp_r: E::ScalarField, + pub pok_sigs: Vec>, + pub D: G, + pub resp_r: G::ScalarField, } -impl CCSPerfectRangeProofWithKVProtocol { +impl CCSPerfectRangeProofWithKVProtocol { + /// Initialize the protocol for proving `0 <= value < max` pub fn init( rng: &mut R, value: u64, - randomness: E::ScalarField, + randomness: G::ScalarField, max: u64, - comm_key: &MemberCommitmentKey, - params: &SetMembershipCheckParams, + comm_key: &MemberCommitmentKey, + params: &SetMembershipCheckParamsKV, ) -> Result { Self::init_given_base( rng, @@ -57,24 +57,25 @@ impl CCSPerfectRangeProofWithKVProtocol { ) } + /// Initialize the protocol for proving `0 <= value < max` pub fn init_given_base( rng: &mut R, value: u64, - randomness: E::ScalarField, + randomness: G::ScalarField, max: u64, base: u16, - comm_key: &MemberCommitmentKey, - params: &SetMembershipCheckParams, + comm_key: &MemberCommitmentKey, + params: &SetMembershipCheckParamsKV, ) -> Result { params.validate_base(base)?; - let l = find_l(max, base) as usize; + let l = find_l_for_perfect_range(max, base)? as usize; // Note: This is different from the paper as only a single `m` needs to be created. - let m = E::ScalarField::rand(rng); - let msg_blindings = n_rand(rng, l).collect::>(); - let sc_blindings = n_rand(rng, l).collect::>(); - let sig_randomizers = n_rand(rng, l).collect::>(); + let m = G::ScalarField::rand(rng); + let msg_blindings = n_rand(rng, l).collect::>(); + let sc_blindings = n_rand(rng, l).collect::>(); + let sig_randomizers = n_rand(rng, l).collect::>(); let D = comm_key.commit_decomposed(base, &msg_blindings, &m); let digits = padded_base_n_digits_as_field_elements(value, base, l); @@ -95,7 +96,7 @@ impl CCSPerfectRangeProofWithKVProtocol { sc_blinding_i, sig_i, msg_i, - ¶ms.bb_sig_params.g1, + ¶ms.bb_sig_params, ) }, ) @@ -112,13 +113,13 @@ impl CCSPerfectRangeProofWithKVProtocol { pub fn challenge_contribution( &self, - commitment: &E::G1Affine, - comm_key: &MemberCommitmentKey, - params: &SetMembershipCheckParams, + commitment: &G, + comm_key: &MemberCommitmentKey, + params: &SetMembershipCheckParamsKV, mut writer: W, ) -> Result<(), SmcRangeProofError> { for p in &self.pok_sigs { - p.challenge_contribution(¶ms.bb_sig_params.g1, &mut writer)?; + p.challenge_contribution(¶ms.bb_sig_params, &mut writer)?; } comm_key.serialize_compressed(&mut writer)?; commitment.serialize_compressed(&mut writer)?; @@ -126,7 +127,7 @@ impl CCSPerfectRangeProofWithKVProtocol { Ok(()) } - pub fn gen_proof(self, challenge: &E::ScalarField) -> CCSPerfectRangeWithKVProof { + pub fn gen_proof(self, challenge: &G::ScalarField) -> CCSPerfectRangeWithKVProof { let pok_sigs = cfg_into_iter!(self.pok_sigs) .map(|p| p.gen_proof(challenge)) .collect::>(); @@ -140,18 +141,19 @@ impl CCSPerfectRangeProofWithKVProtocol { } } -impl CCSPerfectRangeWithKVProof { +impl CCSPerfectRangeWithKVProof { + /// Verify the proof for `0 <= value < max` where `commitment` is a Pedersen commitment to `value` pub fn verify( &self, - commitment: &E::G1Affine, - challenge: &E::ScalarField, + commitment: &G, + challenge: &G::ScalarField, max: u64, - comm_key: &MemberCommitmentKey, - params: &SetMembershipCheckParams, - secret_key: &SecretKey, + comm_key: &MemberCommitmentKey, + params: &SetMembershipCheckParamsKV, + secret_key: &SecretKey, ) -> Result<(), SmcRangeProofError> { params.validate_base(self.base)?; - let l = find_l(max, self.base) as usize; + let l = find_l_for_perfect_range(max, self.base)? as usize; expect_equality!( self.pok_sigs.len(), l, @@ -160,7 +162,7 @@ impl CCSPerfectRangeWithKVProof { let z_sigma = cfg_iter!(self.pok_sigs) .map(|p| *p.get_resp_for_message().unwrap()) .collect::>(); - check_commitment_for_prefect_range::( + check_commitment_for_prefect_range::( self.base, &z_sigma, &self.resp_r, @@ -172,7 +174,7 @@ impl CCSPerfectRangeWithKVProof { let results = cfg_iter!(self.pok_sigs) .map(|p| { - p.verify(challenge, secret_key, ¶ms.bb_sig_params.g1) + p.verify(challenge, secret_key, ¶ms.bb_sig_params) .map_err(|e| SmcRangeProofError::ShortGroupSig(e)) }) .collect::>(); @@ -185,13 +187,13 @@ impl CCSPerfectRangeWithKVProof { pub fn challenge_contribution( &self, - commitment: &E::G1Affine, - comm_key: &MemberCommitmentKey, - params: &SetMembershipCheckParams, + commitment: &G, + comm_key: &MemberCommitmentKey, + params: &SetMembershipCheckParamsKV, mut writer: W, ) -> Result<(), SmcRangeProofError> { for p in &self.pok_sigs { - p.challenge_contribution(¶ms.bb_sig_params.g1, &mut writer)?; + p.challenge_contribution(¶ms.bb_sig_params, &mut writer)?; } comm_key.serialize_compressed(&mut writer)?; commitment.serialize_compressed(&mut writer)?; @@ -200,18 +202,10 @@ impl CCSPerfectRangeWithKVProof { } } -fn find_l(max: u64, base: u16) -> u16 { - let l = max.ilog(base as u64); - let power = (base as u64).pow(l); - assert_eq!(power, max); - l as u16 -} - #[cfg(test)] mod tests { use super::*; - use crate::ccs_set_membership::setup::SetMembershipCheckParams; - use ark_bls12_381::{Bls12_381, Fr, G1Affine}; + use ark_bls12_381::{Fr, G1Affine}; use ark_std::{ rand::{rngs::StdRng, SeedableRng}, UniformRand, @@ -223,17 +217,16 @@ mod tests { fn range_proof_for_perfect_range() { let mut rng = StdRng::seed_from_u64(0u64); - for base in [2, 4, 8, 16] { - let (params, sk) = SetMembershipCheckParams::::new_for_range_proof::< + for base in [2, 3, 4, 5, 8, 10, 15, 20] { + let (params, sk) = SetMembershipCheckParamsKV::::new_for_range_proof::< _, Blake2b512, >(&mut rng, b"test", base); - params.verify().unwrap(); let comm_key = MemberCommitmentKey::::generate_using_rng(&mut rng); for _ in 0..5 { - for l in [10, 15] { + for l in [10, 12] { // TODO: Combine base and l in outer for loop let max = (base as u64).pow(l); let value = u64::rand(&mut rng) % max; diff --git a/smc_range_proof/src/ccs_range_proof/mod.rs b/smc_range_proof/src/ccs_range_proof/mod.rs index 69eb0ab0..723291a1 100644 --- a/smc_range_proof/src/ccs_range_proof/mod.rs +++ b/smc_range_proof/src/ccs_range_proof/mod.rs @@ -1,13 +1,12 @@ //! Range proof protocols as described in Fig.3 and section 4.4 of [Efficient Protocols for Set Membership and Range Proofs](https://link.springer.com/chapter/10.1007/978-3-540-89255-7_15) -#[macro_use] -pub mod util; pub mod arbitrary_range; pub mod arbitrary_range_cdh; pub mod kv_arbitrary_range; pub mod kv_perfect_range; pub mod perfect_range; pub mod perfect_range_cdh; +pub mod util; pub use arbitrary_range_cdh::{CCSArbitraryRangeProof, CCSArbitraryRangeProofProtocol}; pub use kv_arbitrary_range::{CCSArbitraryRangeProofWithKVProtocol, CCSArbitraryRangeWithKVProof}; diff --git a/smc_range_proof/src/ccs_range_proof/perfect_range.rs b/smc_range_proof/src/ccs_range_proof/perfect_range.rs index ee51f6ca..44b54123 100644 --- a/smc_range_proof/src/ccs_range_proof/perfect_range.rs +++ b/smc_range_proof/src/ccs_range_proof/perfect_range.rs @@ -3,25 +3,22 @@ //! The calculations are changed a bit to be consistent with other instances of Schnorr protocol in this project. use crate::{ - ccs_set_membership::setup::SetMembershipCheckParamsWithPairing, common::MemberCommitmentKey, + ccs_range_proof::util::{check_commitment_for_prefect_range, find_l_for_perfect_range}, + ccs_set_membership::setup::SetMembershipCheckParamsWithPairing, + common::{padded_base_n_digits_as_field_elements, MemberCommitmentKey}, error::SmcRangeProofError, }; use ark_ec::{ pairing::{Pairing, PairingOutput}, AffineRepr, CurveGroup, }; - use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use ark_std::{cfg_into_iter, io::Write, ops::Mul, rand::RngCore, vec::Vec, UniformRand}; use dock_crypto_utils::{ expect_equality, misc::n_rand, msm::multiply_field_elems_with_same_group_elem, + randomized_pairing_check::RandomizedPairingChecker, }; -use crate::common::padded_base_n_digits_as_field_elements; -use dock_crypto_utils::randomized_pairing_check::RandomizedPairingChecker; - -use crate::ccs_range_proof::util::{check_commitment_for_prefect_range, find_l}; - #[cfg(feature = "parallel")] use rayon::prelude::*; @@ -51,6 +48,7 @@ pub struct CCSPerfectRangeProof { } impl CCSPerfectRangeProofProtocol { + /// Initialize the protocol for proving `0 <= value < max` pub fn init( rng: &mut R, value: u64, @@ -71,6 +69,7 @@ impl CCSPerfectRangeProofProtocol { ) } + /// Initialize the protocol for proving `0 <= value < max` pub fn init_given_base( rng: &mut R, value: u64, @@ -84,7 +83,7 @@ impl CCSPerfectRangeProofProtocol { params.validate_base(base)?; - let l = find_l(max, base) as usize; + let l = find_l_for_perfect_range(max, base)? as usize; // Note: This is different from the paper as only a single `m` needs to be created. let m = E::ScalarField::rand(rng); @@ -131,7 +130,23 @@ impl CCSPerfectRangeProofProtocol { } pub fn gen_proof(self, challenge: &E::ScalarField) -> CCSPerfectRangeProof { - gen_proof_perfect_range!(self, challenge, CCSPerfectRangeProof) + // Following is different from the paper, the paper has `-` but here its `+` + let z_v = cfg_into_iter!(0..self.V.len()) + .map(|i| self.t[i] + (self.v[i] * challenge)) + .collect::>(); + let z_sigma = cfg_into_iter!(0..self.V.len()) + .map(|i| self.s[i] + (self.digits[i] * challenge)) + .collect::>(); + let z_r = self.m + (self.r * challenge); + CCSPerfectRangeProof { + base: self.base, + V: self.V, + a: self.a, + D: self.D, + z_v, + z_sigma, + z_r, + } } pub fn compute_challenge_contribution( @@ -159,6 +174,7 @@ impl CCSPerfectRangeProofProtocol { } impl CCSPerfectRangeProof { + /// Verify the proof for `0 <= value < max` where `commitment` is a Pedersen commitment to `value` pub fn verify( &self, commitment: &E::G1Affine, @@ -186,6 +202,7 @@ impl CCSPerfectRangeProof { Ok(()) } + /// Verify the proof for `0 <= value < max` where `commitment` is a Pedersen commitment to `value` pub fn verify_given_randomized_pairing_checker( &self, commitment: &E::G1Affine, @@ -215,7 +232,8 @@ impl CCSPerfectRangeProof { params: &SetMembershipCheckParamsWithPairing, ) -> Result<(), SmcRangeProofError> { params.validate_base(self.base)?; - let l = find_l(max, self.base) as usize; + let l = find_l_for_perfect_range(max, self.base)? as usize; + expect_equality!( self.V.len(), l, @@ -236,7 +254,7 @@ impl CCSPerfectRangeProof { l, SmcRangeProofError::ProofShorterThanExpected ); - check_commitment_for_prefect_range::( + check_commitment_for_prefect_range::( self.base, &self.z_sigma, &self.z_r, @@ -300,7 +318,7 @@ mod tests { fn range_proof_for_perfect_range() { let mut rng = StdRng::seed_from_u64(0u64); - for base in [2, 4, 8, 16] { + for base in [2, 3, 4, 5, 8, 10, 15, 20] { let (params, _) = SetMembershipCheckParams::::new_for_range_proof::< _, Blake2b512, @@ -312,7 +330,7 @@ mod tests { let comm_key = MemberCommitmentKey::::generate_using_rng(&mut rng); - for l in [10, 15] { + for l in [10, 12] { let mut proving_time = Duration::default(); let mut verifying_time = Duration::default(); let mut verifying_with_rpc_time = Duration::default(); diff --git a/smc_range_proof/src/ccs_range_proof/perfect_range_cdh.rs b/smc_range_proof/src/ccs_range_proof/perfect_range_cdh.rs index 8031c8b8..f455016c 100644 --- a/smc_range_proof/src/ccs_range_proof/perfect_range_cdh.rs +++ b/smc_range_proof/src/ccs_range_proof/perfect_range_cdh.rs @@ -3,24 +3,19 @@ //! The difference with the paper is the protocol used to prove knowledge of weak-BB sig which is taken from the CDH paper. use crate::{ - ccs_set_membership::setup::SetMembershipCheckParamsWithPairing, common::MemberCommitmentKey, + ccs_range_proof::util::{check_commitment_for_prefect_range, find_l_for_perfect_range}, + ccs_set_membership::setup::{SetMembershipCheckParams, SetMembershipCheckParamsWithPairing}, + common::{padded_base_n_digits_as_field_elements, MemberCommitmentKey}, error::SmcRangeProofError, }; use ark_ec::pairing::Pairing; -use ark_std::io::Write; - -use crate::{ - ccs_range_proof::util::find_l, ccs_set_membership::setup::SetMembershipCheckParams, - common::padded_base_n_digits_as_field_elements, -}; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; -use ark_std::{cfg_into_iter, cfg_iter, rand::RngCore, vec::Vec, UniformRand}; -use dock_crypto_utils::misc::n_rand; +use ark_std::{cfg_into_iter, cfg_iter, io::Write, rand::RngCore, vec::Vec, UniformRand}; +use dock_crypto_utils::{ + expect_equality, misc::n_rand, randomized_pairing_check::RandomizedPairingChecker, +}; use short_group_sig::weak_bb_sig_pok_cdh::{PoKOfSignatureG1, PoKOfSignatureG1Protocol}; -use crate::ccs_range_proof::util::check_commitment_for_prefect_range; -use dock_crypto_utils::{expect_equality, randomized_pairing_check::RandomizedPairingChecker}; - #[cfg(feature = "parallel")] use rayon::prelude::*; @@ -45,6 +40,7 @@ pub struct CCSPerfectRangeProof { } impl CCSPerfectRangeProofProtocol { + /// Initialize the protocol for proving `0 <= value < max` pub fn init( rng: &mut R, value: u64, @@ -64,6 +60,7 @@ impl CCSPerfectRangeProofProtocol { ) } + /// Initialize the protocol for proving `0 <= value < max` pub fn init_given_base( rng: &mut R, value: u64, @@ -75,7 +72,8 @@ impl CCSPerfectRangeProofProtocol { ) -> Result { params.validate_base(base)?; - let l = find_l(max, base) as usize; + let l = find_l_for_perfect_range(max, base)? as usize; + let msg_blindings = n_rand(rng, l).collect::>(); let m = E::ScalarField::rand(rng); let digits = padded_base_n_digits_as_field_elements(value, base, l); @@ -146,6 +144,7 @@ impl CCSPerfectRangeProofProtocol { } impl CCSPerfectRangeProof { + /// Verify the proof for `0 <= value < max` where `commitment` is a Pedersen commitment to `value` pub fn verify( &self, commitment: &E::G1Affine, @@ -174,6 +173,7 @@ impl CCSPerfectRangeProof { Ok(()) } + /// Verify the proof for `0 <= value < max` where `commitment` is a Pedersen commitment to `value` pub fn verify_given_randomized_pairing_checker( &self, commitment: &E::G1Affine, @@ -219,7 +219,8 @@ impl CCSPerfectRangeProof { params: &SetMembershipCheckParamsWithPairing, ) -> Result<(), SmcRangeProofError> { params.validate_base(self.base)?; - let l = find_l(max, self.base) as usize; + let l = find_l_for_perfect_range(max, self.base)? as usize; + expect_equality!( self.pok_sigs.len(), l, @@ -229,7 +230,7 @@ impl CCSPerfectRangeProof { let resp_d = cfg_iter!(self.pok_sigs) .map(|p| *p.get_resp_for_message().unwrap()) .collect::>(); - check_commitment_for_prefect_range::( + check_commitment_for_prefect_range::( self.base, &resp_d, &self.resp_r, @@ -274,7 +275,7 @@ mod tests { fn range_proof_for_perfect_range() { let mut rng = StdRng::seed_from_u64(0u64); - for base in [2, 4, 8, 16] { + for base in [2, 3, 4, 5, 8, 10, 15, 20] { let (params, _) = SetMembershipCheckParams::::new_for_range_proof::< _, Blake2b512, @@ -286,7 +287,7 @@ mod tests { let comm_key = MemberCommitmentKey::::generate_using_rng(&mut rng); - for l in [10, 15] { + for l in [10, 12] { let mut proving_time = Duration::default(); let mut verifying_time = Duration::default(); let mut verifying_with_rpc_time = Duration::default(); diff --git a/smc_range_proof/src/ccs_range_proof/util.rs b/smc_range_proof/src/ccs_range_proof/util.rs index 910b7939..8bb0cfcf 100644 --- a/smc_range_proof/src/ccs_range_proof/util.rs +++ b/smc_range_proof/src/ccs_range_proof/util.rs @@ -1,41 +1,44 @@ use crate::{common::MemberCommitmentKey, error::SmcRangeProofError}; -use ark_ec::{pairing::Pairing, AffineRepr, CurveGroup}; +use ark_ec::{AffineRepr, CurveGroup}; use ark_std::ops::Neg; use dock_crypto_utils::ff::powers; -pub(super) fn check_commitment_for_arbitrary_range( +pub(super) fn check_commitment_for_arbitrary_range( base: u16, - z_sigma_min: &[E::ScalarField], - z_sigma_max: &[E::ScalarField], - z_r_min: &E::ScalarField, - z_r_max: &E::ScalarField, - D_min: &E::G1Affine, - D_max: &E::G1Affine, + z_sigma_min: &[G::ScalarField], + z_sigma_max: &[G::ScalarField], + z_r_min: &G::ScalarField, + z_r_max: &G::ScalarField, + D_min: &G, + D_max: &G, min: u64, max: u64, - commitment: &E::G1Affine, - challenge: &E::ScalarField, - comm_key: &MemberCommitmentKey, + commitment: &G, + challenge: &G::ScalarField, + comm_key: &MemberCommitmentKey, ) -> Result<(), SmcRangeProofError> { - let l = find_l_greater_than(max, base) as u32; + let l = find_l_for_arbitrary_range(max, min, base) as u32; let comm_c = *commitment * challenge; // Calculate powers of base once to avoid recomputing them again during commitment - let base_powers = powers(&E::ScalarField::from(base), z_sigma_min.len() as u32); + let base_powers = powers(&G::ScalarField::from(base), z_sigma_min.len() as u32); // Following 2 checks are different from the paper. The paper has typos where the exponent - // of `g` is not multiplied by the challenge. Also the paper uses only a single `D` which can leak + // of `g` is not multiplied by the challenge. Also, the paper uses only a single `D` which can leak // some information to the verifier in some cases. See the module docs for more info if (-comm_c - + comm_key.g * (E::ScalarField::from(min) * challenge) + + comm_key.g * (G::ScalarField::from(min) * challenge) + comm_key.commit_decomposed_given_base_powers(&base_powers, z_sigma_min, z_r_min)) .into_affine() != *D_min { return Err(SmcRangeProofError::InvalidRangeProof); } - if (-comm_c - comm_key.g * (E::ScalarField::from((base as u64).pow(l) - max) * challenge) + // x = base^l - max + let mut x = G::ScalarField::from((base as u64).pow(l)); + x -= G::ScalarField::from(max); + if (-comm_c - comm_key.g * (x * challenge) + comm_key.commit_decomposed_given_base_powers(&base_powers, z_sigma_max, z_r_max)) .into_affine() != *D_max @@ -45,14 +48,14 @@ pub(super) fn check_commitment_for_arbitrary_range( Ok(()) } -pub(super) fn check_commitment_for_prefect_range( +pub(super) fn check_commitment_for_prefect_range( base: u16, - z_sigma: &[E::ScalarField], - z_r: &E::ScalarField, - D: &E::G1Affine, - commitment: &E::G1Affine, - challenge: &E::ScalarField, - comm_key: &MemberCommitmentKey, + z_sigma: &[G::ScalarField], + z_r: &G::ScalarField, + D: &G, + commitment: &G, + challenge: &G::ScalarField, + comm_key: &MemberCommitmentKey, ) -> Result<(), SmcRangeProofError> { if (comm_key.commit_decomposed(base, z_sigma, z_r) + commitment.into_group().neg() * challenge) .into_affine() @@ -63,76 +66,22 @@ pub(super) fn check_commitment_for_prefect_range( Ok(()) } -pub fn find_l_greater_than(max: u64, base: u16) -> u16 { - let l = max.ilog(base as u64); - if (base as u64).pow(l) > max { +/// Returns the number of digits, `l`, needed to represent `max - min` in base `base` and satisfy `max - min < base^l` +pub fn find_l_for_arbitrary_range(max: u64, min: u64, base: u16) -> u16 { + let diff = max - min; + let l = diff.ilog(base as u64); + if (base as u64).pow(l) > diff { l as u16 } else { l as u16 + 1 } } -pub fn find_l(max: u64, base: u16) -> u16 { - let l = max.ilog(base as u64); - let power = (base as u64).pow(l); - assert_eq!(power, max); - l as u16 -} - -#[macro_export] -macro_rules! gen_proof_perfect_range { - ($self: ident, $challenge: ident, $proof: ident) => {{ - // Following is different from the paper, the paper has `-` but here its `+` - let z_v = cfg_into_iter!(0..$self.V.len()) - .map(|i| $self.t[i] + ($self.v[i] * $challenge)) - .collect::>(); - let z_sigma = cfg_into_iter!(0..$self.V.len()) - .map(|i| $self.s[i] + ($self.digits[i] * $challenge)) - .collect::>(); - let z_r = $self.m + ($self.r * $challenge); - $proof { - base: $self.base, - V: $self.V, - a: $self.a, - D: $self.D, - z_v, - z_sigma, - z_r, - } - }}; -} - -#[macro_export] -macro_rules! gen_proof_arbitrary_range { - ($self: ident, $challenge: ident, $proof: ident) => {{ - let z_v_min = cfg_into_iter!(0..$self.V_min.len()) - .map(|i| $self.t_min[i] + ($self.v_min[i] * $challenge)) - .collect::>(); - let z_v_max = cfg_into_iter!(0..$self.V_max.len()) - .map(|i| $self.t_max[i] + ($self.v_max[i] * $challenge)) - .collect::>(); - let z_sigma_min = cfg_into_iter!(0..$self.V_min.len()) - .map(|i| $self.s_min[i] + ($self.digits_min[i] * $challenge)) - .collect::>(); - let z_sigma_max = cfg_into_iter!(0..$self.V_max.len()) - .map(|i| $self.s_max[i] + ($self.digits_max[i] * $challenge)) - .collect::>(); - let z_r_min = $self.m_min + ($self.r * $challenge); - let z_r_max = $self.m_max + ($self.r * $challenge); - $proof { - base: $self.base, - V_min: $self.V_min, - V_max: $self.V_max, - a_min: $self.a_min, - a_max: $self.a_max, - D_min: $self.D_min, - D_max: $self.D_max, - z_v_min, - z_v_max, - z_sigma_min, - z_sigma_max, - z_r_min, - z_r_max, - } - }}; +/// Returns the number of digits, `l`, needed to represent `max` in base `base`, i.e. `l = log_{base} max`. `l` should satisfy `base^l = max` +pub fn find_l_for_perfect_range(max: u64, base: u16) -> Result { + let l = max.ilog(base as u64) as u16; + if (base as u64).pow(l as u32) != max { + return Err(SmcRangeProofError::NotAPerfectRange(max, base)); + } + Ok(l) } diff --git a/smc_range_proof/src/ccs_set_membership/kv_single.rs b/smc_range_proof/src/ccs_set_membership/kv_single.rs index e95c92df..b1bc22c8 100644 --- a/smc_range_proof/src/ccs_set_membership/kv_single.rs +++ b/smc_range_proof/src/ccs_set_membership/kv_single.rs @@ -2,10 +2,10 @@ //! the secret key for BB sig use crate::{ - ccs_set_membership::setup::SetMembershipCheckParams, common::MemberCommitmentKey, + ccs_set_membership::setup::SetMembershipCheckParamsKV, common::MemberCommitmentKey, error::SmcRangeProofError, }; -use ark_ec::pairing::Pairing; +use ark_ec::AffineRepr; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use ark_std::{io::Write, rand::RngCore, vec::Vec, UniformRand}; use schnorr_pok::{discrete_log::PokTwoDiscreteLogsProtocol, partial::Partial2PokTwoDiscreteLogs}; @@ -15,34 +15,34 @@ use short_group_sig::{ }; #[derive(Clone, PartialEq, Eq, Debug)] -pub struct SetMembershipCheckWithKVProtocol { - pub pok_sig: PoKOfSignatureG1KVProtocol, - pub sc: PokTwoDiscreteLogsProtocol, +pub struct SetMembershipCheckWithKVProtocol { + pub pok_sig: PoKOfSignatureG1KVProtocol, + pub sc: PokTwoDiscreteLogsProtocol, } #[derive(Clone, PartialEq, Eq, Debug, CanonicalSerialize, CanonicalDeserialize)] -pub struct SetMembershipCheckWithKVProof { - pub pok_sig: PoKOfSignatureG1KV, - pub sc: Partial2PokTwoDiscreteLogs, +pub struct SetMembershipCheckWithKVProof { + pub pok_sig: PoKOfSignatureG1KV, + pub sc: Partial2PokTwoDiscreteLogs, } -impl SetMembershipCheckWithKVProtocol { +impl SetMembershipCheckWithKVProtocol { pub fn init( rng: &mut R, - member: E::ScalarField, - r: E::ScalarField, - comm_key: &MemberCommitmentKey, - params: &SetMembershipCheckParams, + member: G::ScalarField, + r: G::ScalarField, + comm_key: &MemberCommitmentKey, + params: &SetMembershipCheckParamsKV, ) -> Result { let sig = params.get_sig_for_member(&member)?; - let blinding = E::ScalarField::rand(rng); - let m = E::ScalarField::rand(rng); + let blinding = G::ScalarField::rand(rng); + let m = G::ScalarField::rand(rng); let pok_sig = PoKOfSignatureG1KVProtocol::init( rng, sig, member, Some(blinding), - ¶ms.bb_sig_params.g1, + ¶ms.bb_sig_params, ); let sc = PokTwoDiscreteLogsProtocol::init(member, blinding, &comm_key.g, r, m, &comm_key.h); Ok(Self { pok_sig, sc }) @@ -50,19 +50,19 @@ impl SetMembershipCheckWithKVProtocol { pub fn challenge_contribution( &self, - commitment: &E::G1Affine, - comm_key: &MemberCommitmentKey, - params: &SetMembershipCheckParams, + commitment: &G, + comm_key: &MemberCommitmentKey, + params: &SetMembershipCheckParamsKV, mut writer: W, ) -> Result<(), SmcRangeProofError> { self.pok_sig - .challenge_contribution(¶ms.bb_sig_params.g1, &mut writer)?; + .challenge_contribution(¶ms.bb_sig_params, &mut writer)?; self.sc .challenge_contribution(&comm_key.g, &comm_key.h, commitment, writer)?; Ok(()) } - pub fn gen_proof(self, challenge: &E::ScalarField) -> SetMembershipCheckWithKVProof { + pub fn gen_proof(self, challenge: &G::ScalarField) -> SetMembershipCheckWithKVProof { SetMembershipCheckWithKVProof { pok_sig: self.pok_sig.gen_proof(challenge), sc: self.sc.gen_partial2_proof(challenge), @@ -70,18 +70,18 @@ impl SetMembershipCheckWithKVProtocol { } } -impl SetMembershipCheckWithKVProof { +impl SetMembershipCheckWithKVProof { pub fn verify( &self, - commitment: &E::G1Affine, - challenge: &E::ScalarField, - comm_key: &MemberCommitmentKey, - params: &SetMembershipCheckParams, - secret_key: &SecretKey, + commitment: &G, + challenge: &G::ScalarField, + comm_key: &MemberCommitmentKey, + params: &SetMembershipCheckParamsKV, + secret_key: &SecretKey, ) -> Result<(), SmcRangeProofError> { // Check commitment * challenge + g * z_sigma + h * z_r == D self.pok_sig - .verify(challenge, secret_key, ¶ms.bb_sig_params.g1)?; + .verify(challenge, secret_key, ¶ms.bb_sig_params)?; if !self.sc.verify( commitment, &comm_key.g, @@ -96,13 +96,13 @@ impl SetMembershipCheckWithKVProof { pub fn challenge_contribution( &self, - commitment: &E::G1Affine, - comm_key: &MemberCommitmentKey, - params: &SetMembershipCheckParams, + commitment: &G, + comm_key: &MemberCommitmentKey, + params: &SetMembershipCheckParamsKV, mut writer: W, ) -> Result<(), SmcRangeProofError> { self.pok_sig - .challenge_contribution(¶ms.bb_sig_params.g1, &mut writer)?; + .challenge_contribution(¶ms.bb_sig_params, &mut writer)?; self.sc .challenge_contribution(&comm_key.g, &comm_key.h, commitment, writer)?; Ok(()) @@ -112,8 +112,7 @@ impl SetMembershipCheckWithKVProof { #[cfg(test)] mod tests { use super::*; - use crate::ccs_set_membership::setup::SetMembershipCheckParams; - use ark_bls12_381::{Bls12_381, Fr}; + use ark_bls12_381::{Fr, G1Affine}; use ark_std::{ rand::{rngs::StdRng, SeedableRng}, UniformRand, @@ -121,19 +120,19 @@ mod tests { use blake2::Blake2b512; use dock_crypto_utils::misc::n_rand; use schnorr_pok::compute_random_oracle_challenge; - use short_group_sig::common::SignatureParams; #[test] fn membership_check() { let mut rng = StdRng::seed_from_u64(0u64); let set_size = 10; - let sig_params = SignatureParams::::generate_using_rng(&mut rng); - let set = n_rand(&mut rng, set_size).collect::>(); - let (params, sk) = - SetMembershipCheckParams::new_given_sig_params(&mut rng, set.clone(), sig_params); - params.verify().unwrap(); + let set = n_rand(&mut rng, set_size).collect::>(); + let (params, sk) = SetMembershipCheckParamsKV::::new::<_, Blake2b512>( + &mut rng, + b"test", + set.clone(), + ); let comm_key = MemberCommitmentKey::generate_using_rng(&mut rng); let member = set[3].clone(); diff --git a/smc_range_proof/src/ccs_set_membership/setup.rs b/smc_range_proof/src/ccs_set_membership/setup.rs index cb000b50..30dbfd5a 100644 --- a/smc_range_proof/src/ccs_set_membership/setup.rs +++ b/smc_range_proof/src/ccs_set_membership/setup.rs @@ -1,15 +1,17 @@ -use crate::error::SmcRangeProofError; +use crate::{common::generate_secret_key_for_base, error::SmcRangeProofError}; use ark_ec::{pairing::Pairing, AffineRepr}; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use ark_std::{cfg_into_iter, cfg_iter, io::Write, rand::RngCore, vec::Vec}; use digest::Digest; -use dock_crypto_utils::msm::multiply_field_elems_with_same_group_elem; +use dock_crypto_utils::{ + concat_slices, hashing_utils::affine_group_elem_from_try_and_incr, + msm::multiply_field_elems_with_same_group_elem, +}; use short_group_sig::{ common::{SignatureParams, SignatureParamsWithPairing}, - weak_bb_sig::{PublicKeyG2, SecretKey, SignatureG1}, + weak_bb_sig::{gen_sig, PublicKeyG2, SecretKey, SignatureG1}, }; -use crate::common::generate_secret_key_for_base; #[cfg(feature = "parallel")] use rayon::prelude::*; @@ -23,6 +25,13 @@ pub struct SetMembershipCheckParams { pub sigs: Vec>, } +#[derive(Clone, PartialEq, Eq, Debug, CanonicalSerialize, CanonicalDeserialize)] +pub struct SetMembershipCheckParamsKV { + pub bb_sig_params: G, + pub set: Vec, + pub sigs: Vec, +} + /// Same as `SetMembershipCheckParams` but contains the precomputed pairing for a more efficient protocol execution // Note: PartialEq cannot be implemented because of `SignatureParamsWithPairing` even when `SignatureParamsWithPairing` implements PartialEq. // This is because of G2Prepared @@ -48,9 +57,19 @@ impl From> for SetMembershipCheckParamsW } macro_rules! impl_common_functions { - ($base_function_name: ident, $get_sig_function_name: ident, $serialize_function_name: ident) => { + ($mem_type: ty, $sig_type: path) => { + /// No. of set members these params support + pub fn supported_set_size(&self) -> usize { + self.set.len() + } + + /// The base these params supported for range-proof. + pub fn get_supported_base_for_range_proof(&self) -> u16 { + self.supported_set_size() as u16 + } + /// Check if the given base can be used with these params - pub fn $base_function_name(&self, base: u16) -> Result<(), SmcRangeProofError> { + pub fn validate_base(&self, base: u16) -> Result<(), SmcRangeProofError> { // If params support a larger base, then its fine. if self.get_supported_base_for_range_proof() < base { return Err(SmcRangeProofError::UnsupportedBase( @@ -62,26 +81,16 @@ macro_rules! impl_common_functions { } /// Get signature for the given member - pub fn $get_sig_function_name( + pub fn get_sig_for_member( &self, - member: &E::ScalarField, - ) -> Result<&SignatureG1, SmcRangeProofError> { + member: &$mem_type, + ) -> Result<&$sig_type, SmcRangeProofError> { let member_idx = match self.set.iter().position(|&s| s == *member) { Some(m) => m, None => return Err(SmcRangeProofError::CannotFindElementInSet), }; Ok(&self.sigs[member_idx]) } - - pub fn $serialize_function_name( - &self, - mut writer: W, - ) -> Result<(), SmcRangeProofError> { - self.bb_sig_params.g1.serialize_compressed(&mut writer)?; - self.bb_sig_params.g2.serialize_compressed(&mut writer)?; - self.bb_pk.0.serialize_compressed(&mut writer)?; - Ok(()) - } }; } @@ -157,29 +166,17 @@ impl SetMembershipCheckParams { params.verify() } - /// No. of set members these params support - pub fn supported_set_size(&self) -> usize { - self.set.len() - } - - /// The base these params supported for range-proof. - pub fn get_supported_base_for_range_proof(&self) -> u16 { - self.supported_set_size() as u16 - } - - pub fn serialize_for_schnorr_protocol_for_kv( + pub fn serialize_for_schnorr_protocol( &self, mut writer: W, ) -> Result<(), SmcRangeProofError> { self.bb_sig_params.g1.serialize_compressed(&mut writer)?; + self.bb_sig_params.g2.serialize_compressed(&mut writer)?; + self.bb_pk.0.serialize_compressed(&mut writer)?; Ok(()) } - impl_common_functions!( - validate_base, - get_sig_for_member, - serialize_for_schnorr_protocol - ); + impl_common_functions!(E::ScalarField, SignatureG1); } impl SetMembershipCheckParamsWithPairing { @@ -200,17 +197,91 @@ impl SetMembershipCheckParamsWithPairing { Ok(()) } - pub fn supported_set_size(&self) -> usize { - self.set.len() + pub fn serialize_for_schnorr_protocol( + &self, + mut writer: W, + ) -> Result<(), SmcRangeProofError> { + self.bb_sig_params.g1.serialize_compressed(&mut writer)?; + self.bb_sig_params.g2.serialize_compressed(&mut writer)?; + self.bb_pk.0.serialize_compressed(&mut writer)?; + Ok(()) + } + + impl_common_functions!(E::ScalarField, SignatureG1); +} + +impl SetMembershipCheckParamsKV { + /// Create new params for a given set and return the BB secret key. The secret key should be discarded. `label` is to + /// generate the BB sig params + pub fn new( + rng: &mut R, + label: &[u8], + set: Vec, + ) -> (Self, SecretKey) { + let sig_params = + affine_group_elem_from_try_and_incr::(&concat_slices![label, b" : g1"]); + Self::new_given_sig_params(rng, set, sig_params) + } + + /// Create new params when the set-membership check protocol is used for a range proof. The set in + /// this case consists of elements `(0, 1, 2, 3, ..., base-1)` + pub fn new_for_range_proof( + rng: &mut R, + label: &[u8], + base: u16, + ) -> (Self, SecretKey) { + let sig_params = + affine_group_elem_from_try_and_incr::(&concat_slices![label, b" : g1"]); + Self::new_for_range_proof_given_sig_params(rng, base, sig_params) + } + + /// Same as `Self::new` except that it accepts already created BB sig params + pub fn new_given_sig_params( + rng: &mut R, + set: Vec, + sig_params: G, + ) -> (Self, SecretKey) { + let sk = SecretKey::new(rng); + Self::new_given_sig_params_and_secret_key(set, sig_params, sk) + } + + pub fn new_for_range_proof_given_sig_params( + rng: &mut R, + base: u16, + sig_params: G, + ) -> (Self, SecretKey) { + let set = cfg_into_iter!(0..base) + .map(|i| G::ScalarField::from(i)) + .collect(); + let sk = generate_secret_key_for_base::(rng, base); + Self::new_given_sig_params_and_secret_key(set, sig_params, sk) + } + + pub fn new_given_sig_params_and_secret_key( + set: Vec, + sig_params: G, + sk: SecretKey, + ) -> (Self, SecretKey) { + let sigs = cfg_iter!(set) + .map(|i| gen_sig::(i, &sk, &sig_params)) + .collect(); + ( + Self { + bb_sig_params: sig_params, + set, + sigs, + }, + sk, + ) } - pub fn get_supported_base_for_range_proof(&self) -> u16 { - self.supported_set_size() as u16 + pub fn serialize_for_schnorr_protocol( + &self, + mut writer: W, + ) -> Result<(), SmcRangeProofError> { + self.bb_sig_params.serialize_compressed(&mut writer)?; + Ok(()) } - impl_common_functions!( - validate_base, - get_sig_for_member, - serialize_for_schnorr_protocol - ); + impl_common_functions!(G::ScalarField, G); } diff --git a/smc_range_proof/src/ccs_set_membership/single_member.rs b/smc_range_proof/src/ccs_set_membership/single_member.rs index e2d3597b..625debd3 100644 --- a/smc_range_proof/src/ccs_set_membership/single_member.rs +++ b/smc_range_proof/src/ccs_set_membership/single_member.rs @@ -61,7 +61,7 @@ impl SetMembershipCheckProtocol { let s = E::ScalarField::rand(rng); let V = params.get_sig_for_member(&member)?.0 * v; let D = comm_key.commit(&s, &m); - // Following is different from the paper, the paper has `-s` and `t` but here its opposite + // Following is different from the paper, the paper has `-s` and `t` but here it's opposite // a = e(V, g2) * s + e(g1, g2) * -t = e(V * s, g2) + e(g1, g2) * -t let a = E::pairing( E::G1Prepared::from(V * s), diff --git a/smc_range_proof/src/cls_range_proof/kv_range_proof.rs b/smc_range_proof/src/cls_range_proof/kv_range_proof.rs index b06a2f72..9480855e 100644 --- a/smc_range_proof/src/cls_range_proof/kv_range_proof.rs +++ b/smc_range_proof/src/cls_range_proof/kv_range_proof.rs @@ -1,54 +1,50 @@ //! Same as CLS range range proof protocol but does Keyed-Verification, i.e the verifies knows the //! secret key of the BB-sig -use ark_ec::pairing::Pairing; -use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; -use ark_std::{cfg_into_iter, cfg_iter, format, io::Write, rand::RngCore, vec::Vec, UniformRand}; - use crate::{ - ccs_set_membership::setup::SetMembershipCheckParams, common::MemberCommitmentKey, + ccs_set_membership::setup::SetMembershipCheckParamsKV, + cls_range_proof::util::{check_commitment, get_sumset_parameters}, + common::MemberCommitmentKey, error::SmcRangeProofError, }; -use dock_crypto_utils::misc::n_rand; - -use dock_crypto_utils::ff::inner_product; -use short_group_sig::weak_bb_sig::SecretKey; +use ark_ec::AffineRepr; +use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; +use ark_std::{cfg_into_iter, cfg_iter, format, io::Write, rand::RngCore, vec::Vec, UniformRand}; +use dock_crypto_utils::{ff::inner_product, misc::n_rand}; +use short_group_sig::{ + weak_bb_sig::SecretKey, + weak_bb_sig_pok_kv::{PoKOfSignatureG1KV, PoKOfSignatureG1KVProtocol}, +}; #[cfg(feature = "parallel")] use rayon::prelude::*; -use short_group_sig::weak_bb_sig_pok_kv::{PoKOfSignatureG1KV, PoKOfSignatureG1KVProtocol}; - -use crate::cls_range_proof::util::{ - check_commitment, find_number_of_digits, find_sumset_boundaries, - get_range_and_randomness_multiple, solve_linear_equations, -}; #[derive(Clone, PartialEq, Eq, Debug)] -pub struct CLSRangeProofWithKVProtocol { +pub struct CLSRangeProofWithKVProtocol { pub base: u16, - pub pok_sigs: Vec>, - pub r: E::ScalarField, - pub D: E::G1Affine, - pub m: E::ScalarField, + pub pok_sigs: Vec>, + pub r: G::ScalarField, + pub D: G, + pub m: G::ScalarField, } #[derive(Clone, PartialEq, Eq, Debug, CanonicalSerialize, CanonicalDeserialize)] -pub struct CLSRangeProofWithKV { +pub struct CLSRangeProofWithKV { pub base: u16, - pub pok_sigs: Vec>, - pub D: E::G1Affine, - pub resp_r: E::ScalarField, + pub pok_sigs: Vec>, + pub D: G, + pub resp_r: G::ScalarField, } -impl CLSRangeProofWithKVProtocol { +impl CLSRangeProofWithKVProtocol { pub fn init( rng: &mut R, value: u64, - randomness: E::ScalarField, + randomness: G::ScalarField, min: u64, max: u64, - comm_key: &MemberCommitmentKey, - params: &SetMembershipCheckParams, + comm_key: &MemberCommitmentKey, + params: &SetMembershipCheckParamsKV, ) -> Result { Self::init_given_base( rng, @@ -64,13 +60,13 @@ impl CLSRangeProofWithKVProtocol { pub fn init_given_base( rng: &mut R, - mut value: u64, - randomness: E::ScalarField, + value: u64, + randomness: G::ScalarField, min: u64, max: u64, base: u16, - comm_key: &MemberCommitmentKey, - params: &SetMembershipCheckParams, + comm_key: &MemberCommitmentKey, + params: &SetMembershipCheckParamsKV, ) -> Result { if min > value { return Err(SmcRangeProofError::IncorrectBounds(format!( @@ -87,85 +83,66 @@ impl CLSRangeProofWithKVProtocol { params.validate_base(base)?; - let (range, randomness_multiple) = get_range_and_randomness_multiple(base, min, max); - value = value - min; - if randomness_multiple != 1 { - value = value * (base - 1) as u64; - } - - let l = find_number_of_digits(range, base); - let G = find_sumset_boundaries(range, base, l); + let (l, G, randomness_multiple, digits) = get_sumset_parameters(value, min, max, base); // Note: This is different from the paper as only a single `m` needs to be created. - let m = E::ScalarField::rand(rng); - let msg_blindings = n_rand(rng, l).collect::>(); + let m = G::ScalarField::rand(rng); + let msg_blindings = n_rand(rng, l).collect::>(); let D = comm_key.commit( &inner_product( &msg_blindings, &cfg_into_iter!(G.clone()) - .map(|G_i| E::ScalarField::from(G_i)) + .map(|G_i| G::ScalarField::from(G_i)) .collect::>(), ), - &(m * E::ScalarField::from(randomness_multiple)), + &(m * G::ScalarField::from(randomness_multiple)), ); - if let Some(digits) = solve_linear_equations(value, &G, base) { - // Following is only for debugging - // let mut expected = 0_u64; - // for j in 0..digits.len() { - // assert!(digits[j] < base); - // expected += digits[j] as u64 * G[j]; - // } - // assert_eq!(expected, value); - - let digits = cfg_into_iter!(digits) - .map(|d| E::ScalarField::from(d)) - .collect::>(); - let sc_blindings = n_rand(rng, l).collect::>(); - let sig_randomizers = n_rand(rng, l).collect::>(); - let mut sigs = Vec::with_capacity(l as usize); - for d in &digits { - sigs.push(params.get_sig_for_member(d)?); - } - let pok_sigs = cfg_into_iter!(sig_randomizers) - .zip(cfg_into_iter!(msg_blindings)) - .zip(cfg_into_iter!(sc_blindings)) - .zip(cfg_into_iter!(sigs)) - .zip(cfg_into_iter!(digits)) - .map( - |((((sig_randomizer_i, msg_blinding_i), sc_blinding_i), sig_i), msg_i)| { - PoKOfSignatureG1KVProtocol::init_with_given_randomness( - sig_randomizer_i, - msg_blinding_i, - sc_blinding_i, - sig_i, - msg_i, - ¶ms.bb_sig_params.g1, - ) - }, - ) - .collect(); - Ok(Self { - base, - pok_sigs, - r: randomness, - D, - m, - }) - } else { - Err(SmcRangeProofError::InvalidRange(range, base)) + let digits = cfg_into_iter!(digits) + .map(|d| G::ScalarField::from(d)) + .collect::>(); + let sc_blindings = n_rand(rng, l).collect::>(); + let sig_randomizers = n_rand(rng, l).collect::>(); + let mut sigs = Vec::with_capacity(l as usize); + for d in &digits { + sigs.push(params.get_sig_for_member(d)?); } + let pok_sigs = cfg_into_iter!(sig_randomizers) + .zip(cfg_into_iter!(msg_blindings)) + .zip(cfg_into_iter!(sc_blindings)) + .zip(cfg_into_iter!(sigs)) + .zip(cfg_into_iter!(digits)) + .map( + |((((sig_randomizer_i, msg_blinding_i), sc_blinding_i), sig_i), msg_i)| { + PoKOfSignatureG1KVProtocol::init_with_given_randomness( + sig_randomizer_i, + msg_blinding_i, + sc_blinding_i, + sig_i, + msg_i, + ¶ms.bb_sig_params, + ) + }, + ) + .collect(); + Ok(Self { + base, + pok_sigs, + r: randomness, + D, + m, + }) } pub fn challenge_contribution( &self, - commitment: &E::G1Affine, - comm_key: &MemberCommitmentKey, - params: &SetMembershipCheckParams, + commitment: &G, + comm_key: &MemberCommitmentKey, + params: &SetMembershipCheckParamsKV, mut writer: W, ) -> Result<(), SmcRangeProofError> { for sig in &self.pok_sigs { - sig.challenge_contribution(¶ms.bb_sig_params.g1, &mut writer)?; + sig.challenge_contribution(¶ms.bb_sig_params, &mut writer)?; } comm_key.serialize_compressed(&mut writer)?; commitment.serialize_compressed(&mut writer)?; @@ -173,7 +150,7 @@ impl CLSRangeProofWithKVProtocol { Ok(()) } - pub fn gen_proof(self, challenge: &E::ScalarField) -> CLSRangeProofWithKV { + pub fn gen_proof(self, challenge: &G::ScalarField) -> CLSRangeProofWithKV { let pok_sigs = cfg_into_iter!(self.pok_sigs) .map(|p| p.gen_proof(challenge)) .collect::>(); @@ -186,16 +163,16 @@ impl CLSRangeProofWithKVProtocol { } } -impl CLSRangeProofWithKV { +impl CLSRangeProofWithKV { pub fn verify( &self, - commitment: &E::G1Affine, - challenge: &E::ScalarField, + commitment: &G, + challenge: &G::ScalarField, min: u64, max: u64, - comm_key: &MemberCommitmentKey, - params: &SetMembershipCheckParams, - secret_key: &SecretKey, + comm_key: &MemberCommitmentKey, + params: &SetMembershipCheckParamsKV, + secret_key: &SecretKey, ) -> Result<(), SmcRangeProofError> { params.validate_base(self.base)?; if min >= max { @@ -208,7 +185,7 @@ impl CLSRangeProofWithKV { let resp_d = cfg_iter!(self.pok_sigs) .map(|p| *p.get_resp_for_message().unwrap()) .collect::>(); - check_commitment::( + check_commitment::( self.base, &resp_d, &self.resp_r, @@ -221,7 +198,7 @@ impl CLSRangeProofWithKV { )?; let results = cfg_iter!(self.pok_sigs) .map(|p| { - p.verify(challenge, secret_key, ¶ms.bb_sig_params.g1) + p.verify(challenge, secret_key, ¶ms.bb_sig_params) .map_err(|e| SmcRangeProofError::ShortGroupSig(e)) }) .collect::>(); @@ -246,13 +223,13 @@ impl CLSRangeProofWithKV { pub fn challenge_contribution( &self, - commitment: &E::G1Affine, - comm_key: &MemberCommitmentKey, - params: &SetMembershipCheckParams, + commitment: &G, + comm_key: &MemberCommitmentKey, + params: &SetMembershipCheckParamsKV, mut writer: W, ) -> Result<(), SmcRangeProofError> { for sig in &self.pok_sigs { - sig.challenge_contribution(¶ms.bb_sig_params.g1, &mut writer)?; + sig.challenge_contribution(¶ms.bb_sig_params, &mut writer)?; } comm_key.serialize_compressed(&mut writer)?; commitment.serialize_compressed(&mut writer)?; @@ -280,8 +257,7 @@ impl CLSRangeProofWithKV { #[cfg(test)] mod tests { use super::*; - use crate::ccs_set_membership::setup::SetMembershipCheckParams; - use ark_bls12_381::{Bls12_381, Fr, G1Affine}; + use ark_bls12_381::{Fr, G1Affine}; use ark_std::{ rand::{rngs::StdRng, SeedableRng}, UniformRand, @@ -290,50 +266,6 @@ mod tests { use schnorr_pok::compute_random_oracle_challenge; use std::time::{Duration, Instant}; - #[test] - fn sumsets_check() { - let mut rng = StdRng::seed_from_u64(0u64); - - fn check(max: u64, g: &[u64], base: u16) { - for i in max..=max { - let sigma = solve_linear_equations(max, g, base).unwrap(); - assert_eq!(sigma.len(), g.len()); - let mut expected = 0_u64; - for j in 0..sigma.len() { - assert!(sigma[j] < base); - expected += sigma[j] as u64 * g[j]; - } - assert_eq!(expected, i); - } - } - - let mut runs = 0; - let start = Instant::now(); - for base in [3, 4, 5, 8, 10, 11, 14, 16] { - for _ in 0..10 { - // let max = ((u16::rand(&mut rng) as u64)) * (base as u64 - 1); - // let max = ((u16::rand(&mut rng) as u64) << 4) * (base as u64 - 1); - let max = ((u16::rand(&mut rng) as u64) >> 4) * (base as u64 - 1); - // while (max % (base as u64 - 1)) != 0 { - // max = u64::rand(&mut rng); - // } - let l = find_number_of_digits(max, base); - let G = find_sumset_boundaries(max, base, l); - println!("Starting for base={} and max={}", base, max); - let start_check = Instant::now(); - check(max, &G, base); - println!( - "Check done for base={} and max={} in {:?}", - base, - max, - start_check.elapsed() - ); - runs += 1; - } - } - println!("Time for {} runs: {:?}", runs, start.elapsed()); - } - #[test] fn cls_range_proof() { let mut rng = StdRng::seed_from_u64(0u64); @@ -342,19 +274,18 @@ mod tests { let mut num_proofs = 0; for base in [2, 4, 8, 16] { - let (params, sk) = SetMembershipCheckParams::::new_for_range_proof::< + let (params, sk) = SetMembershipCheckParamsKV::::new_for_range_proof::< _, Blake2b512, >(&mut rng, b"test", base); - params.verify().unwrap(); let comm_key = MemberCommitmentKey::::generate_using_rng(&mut rng); for _ in 0..5 { let mut a = [ - u16::rand(&mut rng) as u64, - u16::rand(&mut rng) as u64, - u16::rand(&mut rng) as u64, + u64::rand(&mut rng), + u64::rand(&mut rng), + u64::rand(&mut rng), ]; a.sort(); let min = a[0]; @@ -367,11 +298,10 @@ mod tests { // Params with incorrect base should fail let params_with_smaller_base = { - let (params, _) = SetMembershipCheckParams::::new_for_range_proof::< + let (params, _) = SetMembershipCheckParamsKV::::new_for_range_proof::< _, Blake2b512, >(&mut rng, b"test", base - 1); - params.verify().unwrap(); params }; assert!(CLSRangeProofWithKVProtocol::init_given_base( @@ -394,11 +324,10 @@ mod tests { // Params with larger base should work let (params_with_larger_base, sk_larger) = { - let (params, sk) = SetMembershipCheckParams::::new_for_range_proof::< + let (params, sk) = SetMembershipCheckParamsKV::::new_for_range_proof::< _, Blake2b512, >(&mut rng, b"test", base + 1); - params.verify().unwrap(); (params, sk) }; @@ -440,8 +369,10 @@ mod tests { } println!( - "For {} proofs, proving_time={:?} and verifying_time={:?}", - num_proofs, proving_time, verifying_time + "For {} proofs, average proving_time={:?} and average verifying_time={:?}", + num_proofs, + proving_time / num_proofs, + verifying_time / num_proofs ); } } diff --git a/smc_range_proof/src/cls_range_proof/mod.rs b/smc_range_proof/src/cls_range_proof/mod.rs index e4dd3ba2..9d721dc9 100644 --- a/smc_range_proof/src/cls_range_proof/mod.rs +++ b/smc_range_proof/src/cls_range_proof/mod.rs @@ -1,4 +1,5 @@ -#[macro_use] +//! Range proof described in the paper [Additive Combinatorics and Discrete Logarithm Based Range Protocols](https://eprint.iacr.org/2009/469). + pub mod util; pub mod kv_range_proof; diff --git a/smc_range_proof/src/cls_range_proof/range_proof.rs b/smc_range_proof/src/cls_range_proof/range_proof.rs index 8879a3d7..ce1fde20 100644 --- a/smc_range_proof/src/cls_range_proof/range_proof.rs +++ b/smc_range_proof/src/cls_range_proof/range_proof.rs @@ -1,31 +1,26 @@ //! Range proof based on Protocol 2 from the paper [Additive Combinatorics and Discrete Logarithm Based Range Protocols](https://eprint.iacr.org/2009/469) +//! The protocol in the paper is for range [0, H] but the one implemented here is for range [min, max) +use crate::{ + ccs_set_membership::setup::SetMembershipCheckParamsWithPairing, + cls_range_proof::util::{check_commitment, get_sumset_parameters}, + common::MemberCommitmentKey, + error::SmcRangeProofError, +}; use ark_ec::{ pairing::{Pairing, PairingOutput}, AffineRepr, CurveGroup, }; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use ark_std::{cfg_into_iter, format, io::Write, ops::Mul, rand::RngCore, vec::Vec, UniformRand}; - -use crate::{ - ccs_set_membership::setup::SetMembershipCheckParamsWithPairing, common::MemberCommitmentKey, - error::SmcRangeProofError, -}; -use dock_crypto_utils::misc::n_rand; - use dock_crypto_utils::{ - ff::inner_product, msm::multiply_field_elems_with_same_group_elem, + ff::inner_product, misc::n_rand, msm::multiply_field_elems_with_same_group_elem, randomized_pairing_check::RandomizedPairingChecker, }; #[cfg(feature = "parallel")] use rayon::prelude::*; -use crate::cls_range_proof::{ - util, - util::{check_commitment, get_range_and_randomness_multiple}, -}; - #[derive(Clone, PartialEq, Eq, Debug)] pub struct CLSRangeProofProtocol { pub base: u16, @@ -77,7 +72,7 @@ impl CLSRangeProofProtocol { pub fn init_given_base( rng: &mut R, - mut value: u64, + value: u64, randomness: E::ScalarField, min: u64, max: u64, @@ -101,14 +96,7 @@ impl CLSRangeProofProtocol { let params = params.into(); params.validate_base(base)?; - let (range, randomness_multiple) = get_range_and_randomness_multiple(base, min, max); - value = value - min; - if randomness_multiple != 1 { - value = value * (base - 1) as u64; - } - - let l = util::find_number_of_digits(range, base); - let G = util::find_sumset_boundaries(range, base, l); + let (l, G, randomness_multiple, digits) = get_sumset_parameters(value, min, max, base); // Note: This is different from the paper as only a single `m` needs to be created. let m = E::ScalarField::rand(rng); @@ -123,45 +111,33 @@ impl CLSRangeProofProtocol { &(m * E::ScalarField::from(randomness_multiple)), ); - if let Some(digits) = util::solve_linear_equations(value, &G, base) { - // Following is only for debugging - // let mut expected = 0_u64; - // for j in 0..digits.len() { - // assert!(digits[j] < base); - // expected += digits[j] as u64 * G[j]; - // } - // assert_eq!(expected, value); - - let digits = cfg_into_iter!(digits) - .map(|d| E::ScalarField::from(d)) - .collect::>(); - let t = n_rand(rng, l).collect::>(); - let v = n_rand(rng, l).collect::>(); - let V = randomize_sigs!(&digits, &v, ¶ms); - - let a = cfg_into_iter!(0..l as usize) - .map(|i| { - E::pairing( - E::G1Prepared::from(V[i] * s[i]), - params.bb_sig_params.g2_prepared.clone(), - ) + params.bb_sig_params.g1g2.mul(-t[i]) - }) - .collect::>(); - Ok(Self { - base, - digits, - r: randomness, - v, - V: E::G1::normalize_batch(&V), - a, - D, - m, - s, - t, + let digits = cfg_into_iter!(digits) + .map(|d| E::ScalarField::from(d)) + .collect::>(); + let t = n_rand(rng, l).collect::>(); + let v = n_rand(rng, l).collect::>(); + let V = randomize_sigs!(&digits, &v, ¶ms); + + let a = cfg_into_iter!(0..l as usize) + .map(|i| { + E::pairing( + E::G1Prepared::from(V[i] * s[i]), + params.bb_sig_params.g2_prepared.clone(), + ) + params.bb_sig_params.g1g2.mul(-t[i]) }) - } else { - Err(SmcRangeProofError::InvalidRange(range, base)) - } + .collect::>(); + Ok(Self { + base, + digits, + r: randomness, + v, + V: E::G1::normalize_batch(&V), + a, + D, + m, + s, + t, + }) } pub fn challenge_contribution( @@ -177,7 +153,22 @@ impl CLSRangeProofProtocol { } pub fn gen_proof(self, challenge: &E::ScalarField) -> CLSRangeProof { - gen_proof!(self, challenge, CLSRangeProof) + let z_v = cfg_into_iter!(0..self.V.len()) + .map(|i| self.t[i] + (self.v[i] * challenge)) + .collect::>(); + let z_sigma = cfg_into_iter!(0..self.V.len()) + .map(|i| self.s[i] + (self.digits[i] * challenge)) + .collect::>(); + let z_r = self.m + (self.r * challenge); + CLSRangeProof { + base: self.base, + V: self.V, + a: self.a, + D: self.D, + z_v, + z_sigma, + z_r, + } } pub fn compute_challenge_contribution( @@ -281,7 +272,7 @@ impl CLSRangeProof { min, max ))); } - check_commitment::( + check_commitment::( self.base, &self.z_sigma, &self.z_r, @@ -319,12 +310,7 @@ impl CLSRangeProof { #[cfg(test)] mod tests { use super::*; - use crate::{ - ccs_set_membership::setup::SetMembershipCheckParams, - cls_range_proof::util::{ - find_number_of_digits, find_sumset_boundaries, solve_linear_equations, - }, - }; + use crate::ccs_set_membership::setup::SetMembershipCheckParams; use ark_bls12_381::{Bls12_381, Fr, G1Affine}; use ark_std::{ rand::{rngs::StdRng, SeedableRng}, @@ -334,50 +320,6 @@ mod tests { use schnorr_pok::compute_random_oracle_challenge; use std::time::{Duration, Instant}; - #[test] - fn sumsets_check() { - let mut rng = StdRng::seed_from_u64(0u64); - - fn check(max: u64, g: &[u64], base: u16) { - for i in max..=max { - let sigma = solve_linear_equations(max, g, base).unwrap(); - assert_eq!(sigma.len(), g.len()); - let mut expected = 0_u64; - for j in 0..sigma.len() { - assert!(sigma[j] < base); - expected += sigma[j] as u64 * g[j]; - } - assert_eq!(expected, i); - } - } - - let mut runs = 0; - let start = Instant::now(); - for base in [3, 4, 5, 8, 10, 11, 14, 16] { - for _ in 0..10 { - // let max = ((u16::rand(&mut rng) as u64)) * (base as u64 - 1); - // let max = ((u16::rand(&mut rng) as u64) << 4) * (base as u64 - 1); - let max = ((u16::rand(&mut rng) as u64) >> 4) * (base as u64 - 1); - // while (max % (base as u64 - 1)) != 0 { - // max = u64::rand(&mut rng); - // } - let l = find_number_of_digits(max, base); - let G = find_sumset_boundaries(max, base, l); - println!("Starting for base={} and max={}", base, max); - let start_check = Instant::now(); - check(max, &G, base); - println!( - "Check done for base={} and max={} in {:?}", - base, - max, - start_check.elapsed() - ); - runs += 1; - } - } - println!("Time for {} runs: {:?}", runs, start.elapsed()); - } - #[test] fn cls_range_proof() { let mut rng = StdRng::seed_from_u64(0u64); @@ -402,9 +344,9 @@ mod tests { for _ in 0..5 { let mut a = [ - u16::rand(&mut rng) as u64, - u16::rand(&mut rng) as u64, - u16::rand(&mut rng) as u64, + u64::rand(&mut rng), + u64::rand(&mut rng), + u64::rand(&mut rng), ]; a.sort(); let min = a[0]; @@ -527,6 +469,7 @@ mod tests { &mut pairing_checker, ) .unwrap(); + assert!(pairing_checker.verify()); verifying_with_rpc_time += start.elapsed(); let mut bytes = vec![]; diff --git a/smc_range_proof/src/cls_range_proof/range_proof_cdh.rs b/smc_range_proof/src/cls_range_proof/range_proof_cdh.rs index 09e703e2..a8e357db 100644 --- a/smc_range_proof/src/cls_range_proof/range_proof_cdh.rs +++ b/smc_range_proof/src/cls_range_proof/range_proof_cdh.rs @@ -1,19 +1,17 @@ use crate::{ ccs_set_membership::setup::{SetMembershipCheckParams, SetMembershipCheckParamsWithPairing}, - cls_range_proof::{util, util::get_range_and_randomness_multiple}, + cls_range_proof::util::{check_commitment, get_sumset_parameters}, common::MemberCommitmentKey, error::SmcRangeProofError, }; use ark_ec::pairing::Pairing; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use ark_std::{cfg_into_iter, cfg_iter, format, io::Write, rand::RngCore, vec::Vec, UniformRand}; -use dock_crypto_utils::{ff::inner_product, misc::n_rand}; +use dock_crypto_utils::{ + ff::inner_product, misc::n_rand, randomized_pairing_check::RandomizedPairingChecker, +}; use short_group_sig::weak_bb_sig_pok_cdh::{PoKOfSignatureG1, PoKOfSignatureG1Protocol}; -use dock_crypto_utils::randomized_pairing_check::RandomizedPairingChecker; - -use crate::cls_range_proof::util::check_commitment; - #[cfg(feature = "parallel")] use rayon::prelude::*; @@ -58,7 +56,7 @@ impl CLSRangeProofProtocol { pub fn init_given_base( rng: &mut R, - mut value: u64, + value: u64, randomness: E::ScalarField, min: u64, max: u64, @@ -81,14 +79,7 @@ impl CLSRangeProofProtocol { params.validate_base(base)?; - let (range, randomness_multiple) = get_range_and_randomness_multiple(base, min, max); - value = value - min; - if randomness_multiple != 1 { - value = value * (base - 1) as u64; - } - - let l = util::find_number_of_digits(range, base); - let G = util::find_sumset_boundaries(range, base, l); + let (l, G, randomness_multiple, digits) = get_sumset_parameters(value, min, max, base); // Note: This is different from the paper as only a single `m` needs to be created. let m = E::ScalarField::rand(rng); @@ -103,53 +94,41 @@ impl CLSRangeProofProtocol { &(m * E::ScalarField::from(randomness_multiple)), ); - if let Some(digits) = util::solve_linear_equations(value, &G, base) { - // Following is only for debugging - // let mut expected = 0_u64; - // for j in 0..digits.len() { - // assert!(digits[j] < base); - // expected += digits[j] as u64 * G[j]; - // } - // assert_eq!(expected, value); - - let digits = cfg_into_iter!(digits) - .map(|d| E::ScalarField::from(d)) - .collect::>(); - let mut sigs = Vec::with_capacity(l as usize); - for d in &digits { - sigs.push(params.get_sig_for_member(d)?); - } - let sig_randomizers = n_rand(rng, l).collect::>(); - let sc_blindings = n_rand(rng, l).collect::>(); - - let pok_sigs = cfg_into_iter!(sig_randomizers) - .zip(cfg_into_iter!(msg_blindings)) - .zip(cfg_into_iter!(sc_blindings)) - .zip(cfg_into_iter!(sigs)) - .zip(cfg_into_iter!(digits)) - .map( - |((((sig_randomizer_i, msg_blinding_i), sc_blinding_i), sig_i), msg_i)| { - PoKOfSignatureG1Protocol::init_with_given_randomness( - sig_randomizer_i, - msg_blinding_i, - sc_blinding_i, - sig_i, - msg_i, - ¶ms.bb_sig_params.g1, - ) - }, - ) - .collect::>(); - Ok(Self { - base, - r: randomness, - pok_sigs, - D, - m, - }) - } else { - Err(SmcRangeProofError::InvalidRange(range, base)) + let digits = cfg_into_iter!(digits) + .map(|d| E::ScalarField::from(d)) + .collect::>(); + let mut sigs = Vec::with_capacity(l as usize); + for d in &digits { + sigs.push(params.get_sig_for_member(d)?); } + let sig_randomizers = n_rand(rng, l).collect::>(); + let sc_blindings = n_rand(rng, l).collect::>(); + + let pok_sigs = cfg_into_iter!(sig_randomizers) + .zip(cfg_into_iter!(msg_blindings)) + .zip(cfg_into_iter!(sc_blindings)) + .zip(cfg_into_iter!(sigs)) + .zip(cfg_into_iter!(digits)) + .map( + |((((sig_randomizer_i, msg_blinding_i), sc_blinding_i), sig_i), msg_i)| { + PoKOfSignatureG1Protocol::init_with_given_randomness( + sig_randomizer_i, + msg_blinding_i, + sc_blinding_i, + sig_i, + msg_i, + ¶ms.bb_sig_params.g1, + ) + }, + ) + .collect::>(); + Ok(Self { + base, + r: randomness, + pok_sigs, + D, + m, + }) } pub fn challenge_contribution( @@ -263,7 +242,7 @@ impl CLSRangeProof { let resp_d = cfg_iter!(self.pok_sigs) .map(|p| *p.get_resp_for_message().unwrap()) .collect::>(); - check_commitment::( + check_commitment::( self.base, &resp_d, &self.resp_r, @@ -296,7 +275,10 @@ impl CLSRangeProof { #[cfg(test)] mod tests { use super::*; - use crate::ccs_set_membership::setup::SetMembershipCheckParams; + use crate::{ + ccs_range_proof::CCSArbitraryRangeProofProtocol, + ccs_set_membership::setup::SetMembershipCheckParams, common::optimal_base, + }; use ark_bls12_381::{Bls12_381, Fr, G1Affine}; use ark_std::{ rand::{rngs::StdRng, SeedableRng}, @@ -326,13 +308,14 @@ mod tests { let mut verifying_time = Duration::default(); let mut verifying_with_rpc_time = Duration::default(); let mut proof_size = 0; + let mut num_proofs = 0; for _ in 0..5 { let mut a = [ - u16::rand(&mut rng) as u64, - u16::rand(&mut rng) as u64, - u16::rand(&mut rng) as u64, + u64::rand(&mut rng), + u64::rand(&mut rng), + u64::rand(&mut rng), ]; a.sort(); let min = a[0]; @@ -422,7 +405,14 @@ mod tests { // assert_eq!(proof.V.len(), l as usize); proof - .verify(&commitment, &challenge_verifier, min, max, &comm_key, pp) + .verify( + &commitment, + &challenge_verifier, + min, + max, + &comm_key, + pp.clone(), + ) .unwrap(); verifying_time += start.elapsed(); @@ -436,10 +426,11 @@ mod tests { min, max, &comm_key, - params, + params.clone(), &mut pairing_checker, ) .unwrap(); + assert!(pairing_checker.verify()); verifying_with_rpc_time += start.elapsed(); let mut bytes = vec![]; @@ -449,7 +440,184 @@ mod tests { num_proofs += 1; } } - println!("For base={} and {} proofs, proof size = {}, average proving time={:?}, average verifying time={:?} and average verifying time using randomized pairing checker {:?}", base, num_proofs, proof_size, proving_time/num_proofs, verifying_time/num_proofs, verifying_with_rpc_time/num_proofs); + + println!("For base={} and {} proofs, proof size = {}, average proving time={:?}, average verifying time={:?} and average verifying time using randomized pairing checker={:?}", base, num_proofs, proof_size, proving_time/num_proofs, verifying_time/num_proofs, verifying_with_rpc_time/num_proofs); } } + + #[test] + fn cls_ccs_range_proof_comparison() { + let mut rng = StdRng::seed_from_u64(0u64); + + // Create params with a large enough base. The larger the base, the bigger the size of setup params. + let max_base = 100; + let (params, _) = SetMembershipCheckParams::::new_for_range_proof::<_, Blake2b512>( + &mut rng, b"test", max_base, + ); + let params_with_pairing = SetMembershipCheckParamsWithPairing::from(params.clone()); + + let comm_key = MemberCommitmentKey::::new::(b"test-key"); + + let num_tests = 100; + let num_tests_short_range = 30; + let num_tests_large_range = 30; + let mut proving_time_cls = Duration::default(); + let mut verifying_time_cls = Duration::default(); + let mut proof_size_cls = 0_u32; + + let mut proving_time_ccs = Duration::default(); + let mut verifying_time_ccs = Duration::default(); + let mut proof_size_ccs = 0_u32; + + for i in 0..num_tests { + let mut a = [0, 0, 0]; + while a[0] == a[1] || a[0] == a[2] { + if i < num_tests_short_range { + // For first num_tests_short_range iterations, choose a short range + a = [ + u16::rand(&mut rng) as u64 >> 4, + u16::rand(&mut rng) as u64 >> 4, + u16::rand(&mut rng) as u64 >> 4, + ]; + } else if i >= (num_tests - num_tests_large_range) { + // For last num_tests_large_range iterations, choose a large range + a = [ + u64::rand(&mut rng) >> 8, + u64::rand(&mut rng) >> 8, + u64::rand(&mut rng) >> 8, + ]; + } else { + // For remaining choose a medium range + a = [ + u32::rand(&mut rng) as u64, + u32::rand(&mut rng) as u64, + u32::rand(&mut rng) as u64, + ]; + } + + a.sort(); + } + let min = a[0]; + let max = a[2]; + let value = a[1]; + let randomness = Fr::rand(&mut rng); + let commitment = comm_key.commit(&Fr::from(value), &randomness); + + let mut base = optimal_base(max, min); + if base > max_base { + base = max_base; + } + + let start = Instant::now(); + let protocol = CLSRangeProofProtocol::init_given_base( + &mut rng, value, randomness, min, max, base, &comm_key, ¶ms, + ) + .unwrap(); + + let mut chal_bytes_prover = vec![]; + protocol + .challenge_contribution(&commitment, &comm_key, ¶ms, &mut chal_bytes_prover) + .unwrap(); + let challenge_prover = + compute_random_oracle_challenge::(&chal_bytes_prover); + + let proof = protocol.gen_proof(&challenge_prover); + let pt = start.elapsed(); + proving_time_cls += pt; + + let start = Instant::now(); + let mut chal_bytes_verifier = vec![]; + proof + .challenge_contribution(&commitment, &comm_key, ¶ms, &mut chal_bytes_verifier) + .unwrap(); + let challenge_verifier = + compute_random_oracle_challenge::(&chal_bytes_verifier); + assert_eq!(challenge_prover, challenge_verifier); + + proof + .verify( + &commitment, + &challenge_verifier, + min, + max, + &comm_key, + params_with_pairing.clone(), + ) + .unwrap(); + let vt = start.elapsed(); + verifying_time_cls += vt; + + let mut bytes = vec![]; + proof.serialize_compressed(&mut bytes).unwrap(); + let ps = bytes.len(); + proof_size_cls += ps as u32; + + let start = Instant::now(); + let protocol = CCSArbitraryRangeProofProtocol::init_given_base( + &mut rng, value, randomness, min, max, base, &comm_key, ¶ms, + ) + .unwrap(); + + let mut chal_bytes_prover = vec![]; + protocol + .challenge_contribution(&commitment, &comm_key, ¶ms, &mut chal_bytes_prover) + .unwrap(); + let challenge_prover = + compute_random_oracle_challenge::(&chal_bytes_prover); + + let proof = protocol.gen_proof(&challenge_prover); + let pt_ccs = start.elapsed(); + proving_time_ccs += pt_ccs; + + let start = Instant::now(); + let mut chal_bytes_verifier = vec![]; + proof + .challenge_contribution(&commitment, &comm_key, ¶ms, &mut chal_bytes_verifier) + .unwrap(); + let challenge_verifier = + compute_random_oracle_challenge::(&chal_bytes_verifier); + assert_eq!(challenge_prover, challenge_verifier); + + proof + .verify( + &commitment, + &challenge_verifier, + min, + max, + &comm_key, + params_with_pairing.clone(), + ) + .unwrap(); + let vt_ccs = start.elapsed(); + verifying_time_ccs += vt_ccs; + + let mut bytes = vec![]; + proof.serialize_compressed(&mut bytes).unwrap(); + let ps_ccs = bytes.len(); + proof_size_ccs += ps_ccs as u32; + + println!( + "For max={}, min={}, range={} and base={}:\n\ + For CLS: proof size = {}, proving time={:?}, verifying time={:?}\n\ + For CCS: proof size = {}, proving time={:?}, verifying time={:?}\n", + max, + min, + max - min, + base, + ps, + pt, + vt, + ps_ccs, + pt_ccs, + vt_ccs + ); + } + + println!("For {} proofs:\n\ + For CLS: average proof size = {}, average proving time={:?}, average verifying time={:?}\n\ + For CCS: average proof size = {}, average proving time={:?}, average verifying time={:?}\n", + num_tests, + proof_size_cls/num_tests, proving_time_cls/num_tests, verifying_time_cls/num_tests, + proof_size_ccs/num_tests, proving_time_ccs/num_tests, verifying_time_ccs/num_tests); + } } diff --git a/smc_range_proof/src/cls_range_proof/util.rs b/smc_range_proof/src/cls_range_proof/util.rs index 91082059..ec9dc6b0 100644 --- a/smc_range_proof/src/cls_range_proof/util.rs +++ b/smc_range_proof/src/cls_range_proof/util.rs @@ -1,72 +1,59 @@ -use crate::common::{base_n_digits, MemberCommitmentKey}; -use ark_ec::{pairing::Pairing, CurveGroup}; -use ark_std::{cfg_into_iter, collections::BTreeMap, vec, vec::Vec}; +use crate::{ + common::{base_n_digits_for_u128, MemberCommitmentKey}, + error::SmcRangeProofError, +}; +use ark_ec::{AffineRepr, CurveGroup}; +use ark_std::{cfg_into_iter, vec, vec::Vec}; +use dock_crypto_utils::ff::inner_product; #[cfg(feature = "parallel")] use rayon::prelude::*; -use crate::error::SmcRangeProofError; -use dock_crypto_utils::ff::inner_product; - -#[macro_export] -macro_rules! gen_proof { - ($self: ident, $challenge: ident, $proof: ident) => {{ - let z_v = cfg_into_iter!(0..$self.V.len()) - .map(|i| $self.t[i] + ($self.v[i] * $challenge)) - .collect::>(); - let z_sigma = cfg_into_iter!(0..$self.V.len()) - .map(|i| $self.s[i] + ($self.digits[i] * $challenge)) - .collect::>(); - let z_r = $self.m + ($self.r * $challenge); - $proof { - base: $self.base, - V: $self.V, - a: $self.a, - D: $self.D, - z_v, - z_sigma, - z_r, - } - }}; -} - -pub(super) fn get_range_and_randomness_multiple(base: u16, min: u64, max: u64) -> (u64, u16) { - let mut range = max - min; +/// Return range, i.e. `max - min`, such that it's a multiple of `base-1`. If `base-1` does not divide `max - min`, +/// the new range is `(max - min)*(base-1)`. This will require the randomness in the commitment to be multiplied by +/// `base-1` as well. +pub(super) fn get_range_and_randomness_multiple(base: u16, min: u64, max: u64) -> (u128, u16) { + // If the range, i.e. max - min is not a multiple of base-1, it has to be made, by multiplying it with base-1 + // which might not fit within a u64 so make it a wider type u128 + let mut range = (max - min) as u128; let mut randomness_multiple = 1; - let b_1 = (base - 1) as u64; + let b_1 = (base - 1) as u128; if range % b_1 != 0 { + // This can't fail since the original value of max-min fits in a u64 range = range * b_1; randomness_multiple = randomness_multiple * (base - 1); } (range, randomness_multiple) } -pub(super) fn check_commitment( +pub(super) fn check_commitment( base: u16, - z_sigma: &[E::ScalarField], - z_r: &E::ScalarField, - D: &E::G1Affine, + z_sigma: &[G::ScalarField], + z_r: &G::ScalarField, + D: &G, min: u64, max: u64, - commitment: &E::G1Affine, - challenge: &E::ScalarField, - comm_key: &MemberCommitmentKey, + commitment: &G, + challenge: &G::ScalarField, + comm_key: &MemberCommitmentKey, ) -> Result<(), SmcRangeProofError> { - let (range, randomness_multiple) = get_range_and_randomness_multiple(base, min, max); + // -1 because range in sumset is inclusive but in the protocol, upper bound is exclusive + let (range, randomness_multiple) = get_range_and_randomness_multiple(base, min, max - 1); let l = find_number_of_digits(range, base); let G = find_sumset_boundaries(range, base, l); - if (-(*commitment * (E::ScalarField::from(randomness_multiple) * challenge)) - + comm_key.g * (E::ScalarField::from(min * randomness_multiple as u64) * challenge) + if (-(*commitment * (G::ScalarField::from(randomness_multiple) * challenge)) + + comm_key.g + * (G::ScalarField::from(min as u128 * randomness_multiple as u128) * challenge) + comm_key.commit( &inner_product( z_sigma, &cfg_into_iter!(G) - .map(|G_i| E::ScalarField::from(G_i)) + .map(|G_i| G::ScalarField::from(G_i)) .collect::>(), ), - &(E::ScalarField::from(randomness_multiple) * z_r), + &(G::ScalarField::from(randomness_multiple) * z_r), )) .into_affine() != *D @@ -76,88 +63,135 @@ pub(super) fn check_commitment( Ok(()) } -/// Returns what the paper calls l. Here we assume that `base - 1` divides `max`. -pub fn find_number_of_digits(max: u64, base: u16) -> u16 { - // (((max + 1) as f64).log(base as f64)).ceil() as u16 - // Above can cause overflow with large u64 values as f64 can't contain the same amount of - // integers as u64 so using the below loop instead - let mut power = 1; - let mut l = 0; - while power < max { - power *= base as u64; +/// Returns what the paper calls l and calculated as `ceil(log_u(range+1))`. Here we assume that `base - 1` divides `range`. +pub fn find_number_of_digits(range: u128, base: u16) -> u32 { + let mut l = (range + 1).ilog(base as u128); + if (base as u128).pow(l) < (range + 1) { l += 1; } l } -/// Returns what the paper calls `G_i`, `max` is called `H` and `num` is called `l` in the paper -pub fn find_sumset_boundaries(max: u64, base: u16, num: u16) -> Vec { +/// Returns what the paper calls `G_i`, `range` is called `H` and `num` is called `l` in the paper. Calculates as +/// per Theorem 2 in the paper +pub fn find_sumset_boundaries(range: u128, base: u16, num: u32) -> Vec { if base == 2 { cfg_into_iter!(0..num) - .map(|i| (max + (1 << i)) >> (i + 1)) + .map(|i| (range + (1 << i)) >> (i + 1)) .collect() } else { - let h = base_n_digits(max, base); + let h = base_n_digits_for_u128(range, base); let mut g = vec![]; for i in 0..num as usize { - let h_hat = max / (base as u64).pow(i as u32 + 1); - let sum = h[..i].iter().map(|h_i| *h_i as u64).sum::() as u64; - g.push(h_hat + ((1 + h[i] as u64 + (sum % (base as u64 - 1))) / base as u64)) + // h_hat = floor(range / base^{i+1}) + let h_hat = range / (base as u128).pow(i as u32 + 1); + let sum = h[..i].iter().map(|h_i| *h_i as u128).sum::(); + g.push(h_hat + ((1 + h[i] as u128 + (sum % (base as u128 - 1))) / base as u128)) } g } } -pub fn solve_linear_equations(y: u64, coefficients: &[u64], u: u16) -> Option> { - let n = coefficients.len(); - let mut solutions = vec![0; n]; - - fn find_value_for_index( - index: usize, - remaining_y: i64, - solutions: &mut Vec, - coefficients: &[u64], - u: u16, - memo: &mut BTreeMap<(usize, i64), bool>, - ) -> bool { - if index == coefficients.len() { - if remaining_y == 0 { - return true; - } - return false; - } - - if let Some(&result) = memo.get(&(index, remaining_y)) { - return result; - } - - for x in 0..u { - solutions[index] = x; - let new_remaining_y = remaining_y - coefficients[index] as i64 * x as i64; - if new_remaining_y >= 0 - && find_value_for_index( - index + 1, - new_remaining_y, - solutions, - coefficients, - u, - memo, - ) - { - memo.insert((index, remaining_y), true); - return true; +/// Returns digits of `value` when expressed in sumset notation give sumset boundaries, i.e. `G` +pub fn decompose_for_sumset(value: u128, G: &[u128], base: u16) -> Vec { + let mut deomposition = vec![0; G.len()]; + let mut target = value; + for (i, g_i) in G.iter().enumerate() { + // For each g_i, check if target >= (base-1) * g_i. If it is then digit corresponding to g_i is (base-1) and new + // target is target - (base-1) * g_i. Else check if target >= (base-2) * g_i and so on. + for u_i in (1..base).rev() { + let g_u = *g_i * u_i as u128; + if target >= g_u { + deomposition[i] = u_i; + target -= g_u; + break; } } + } + debug_assert_eq!(target, 0); + deomposition +} - memo.insert((index, remaining_y), false); - false +/// Pre-requisites of applying sumset protocol +/// Returns number of digits, sumset boundaries (G), randomness multiple and digits of the adapted value. +pub fn get_sumset_parameters( + value: u64, + min: u64, + max: u64, + base: u16, +) -> (u32, Vec, u16, Vec) { + // The protocol works for the range [0, H], so change `value` and set range accordingly. + // New value becomes value - min + // New max becomes max-1 because the implemented protocol is asking for the proof in range [min, max) and + // sumset protocol in the paper is described for range [0, max], i.e. upper bound is inclusive in the paper, + // but it's not in the implementation + let (range, randomness_multiple) = get_range_and_randomness_multiple(base, min, max - 1); + let mut value = (value - min) as u128; + if randomness_multiple != 1 { + // range had to be artificially increased so increase the value accordingly. This won't overflow as original value is a u64 + value = value * (base - 1) as u128; } - let mut memo: BTreeMap<(usize, i64), bool> = BTreeMap::new(); + let l = find_number_of_digits(range, base); + let G = find_sumset_boundaries(range, base, l); + let digits = decompose_for_sumset(value, &G, base); + // Following is only for debugging + // let mut expected = 0_u64; + // for j in 0..digits.len() { + // assert!(digits[j] < base); + // expected += digits[j] as u64 * G[j]; + // } + // assert_eq!(expected, value); + (l, G, randomness_multiple, digits) +} - if find_value_for_index(0, y as i64, &mut solutions, coefficients, u, &mut memo) { - Some(solutions) - } else { - None +#[cfg(test)] +mod tests { + use super::*; + use ark_std::{ + rand::{prelude::StdRng, Rng, SeedableRng}, + UniformRand, + }; + use std::time::Instant; + + #[test] + fn sumsets_check() { + // Test that sumsets are correctly created and elements are correctly decomposed + let mut rng = StdRng::seed_from_u64(0u64); + + let iters_per_base = 50; + let iters_per_max = 100; + for base in [3, 4, 5, 8, 10, 11, 14, 16] { + for _ in 0..iters_per_base { + let max = u64::rand(&mut rng) as u128 * (base as u128 - 1); + let l = find_number_of_digits(max, base); + let G = find_sumset_boundaries(max, base, l); + let start = Instant::now(); + let mut test_vec = vec![0, 1, max, max - 1]; + for _ in 0..iters_per_max { + test_vec.push(rng.gen_range(2..max - 1)); + } + for i in test_vec { + let sigma = decompose_for_sumset(i, &G, base); + assert_eq!(sigma.len(), G.len()); + let mut expected = 0_u128; + for j in 0..sigma.len() { + assert!(sigma[j] < base); + expected += sigma[j] as u128 * G[j]; + } + assert_eq!( + expected, i, + "Failed for value={} with base={} and max={}. G={:?}, sigma={:?}", + i, base, max, G, sigma + ); + } + println!( + "Check for base={} and max={} finished in {:?}", + base, + max, + start.elapsed() + ); + } + } } } diff --git a/smc_range_proof/src/common.rs b/smc_range_proof/src/common.rs index af98186c..5637849f 100644 --- a/smc_range_proof/src/common.rs +++ b/smc_range_proof/src/common.rs @@ -1,5 +1,4 @@ use ark_ec::AffineRepr; - use ark_ff::PrimeField; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use ark_std::{cfg_into_iter, collections::BTreeSet, rand::RngCore, vec::Vec}; @@ -10,15 +9,14 @@ use dock_crypto_utils::{ hashing_utils::affine_group_elem_from_try_and_incr, misc::rand, }; - -#[cfg(feature = "parallel")] -use rayon::prelude::*; - pub use short_group_sig::{ common::{SignatureParams, SignatureParamsWithPairing}, weak_bb_sig::{PublicKeyG2, SecretKey, SignatureG1}, }; +#[cfg(feature = "parallel")] +use rayon::prelude::*; + /// Commitment key to commit the set member #[derive(Clone, PartialEq, Eq, Debug, CanonicalSerialize, CanonicalDeserialize)] pub struct MemberCommitmentKey { @@ -67,7 +65,7 @@ impl MemberCommitmentKey { } } -/// Representation of `value` in base `base`-representation. Returns the base `base` digits in little-endian form +/// Representation of `value` in `base`-representation. Returns the base `base` digits in little-endian form pub fn base_n_digits(mut value: u64, base: u16) -> Vec { let mut digits = Vec::::new(); while value != 0 { @@ -78,7 +76,17 @@ pub fn base_n_digits(mut value: u64, base: u16) -> Vec { digits } -/// Same as `base_n_digits` but pads representation with 0s to the until to make the output vector length as `size` +pub fn base_n_digits_for_u128(mut value: u128, base: u16) -> Vec { + let mut digits = Vec::::new(); + while value != 0 { + // Note: Can use bitwise ops if base is power of 2 + digits.push((value % base as u128) as u16); + value = value / base as u128; + } + digits +} + +/// Same as `base_n_digits` but pads representation with 0s to the end to make the output vector length as `size` pub fn padded_base_n_digits_as_field_elements( value: u64, base: u16, @@ -128,6 +136,15 @@ pub fn is_secret_key_valid_for_base(sk: &SecretKey, base: u16) position.is_none() } +/// Optimal base as suggested by the CCS and CLS paper as `log_2(range)/log_2(log_2(range))` where `range = max - min` +/// A more optimal base can be calculated using numerical methods. +pub fn optimal_base(max: u64, min: u64) -> u16 { + let range = max - min; + let lg_range = range.ilog2(); + let lg_lg_range = lg_range.ilog2(); + (lg_range / lg_lg_range) as u16 +} + #[cfg(test)] mod tests { use super::*; diff --git a/smc_range_proof/src/error.rs b/smc_range_proof/src/error.rs index ecae1730..7f62cf4a 100644 --- a/smc_range_proof/src/error.rs +++ b/smc_range_proof/src/error.rs @@ -18,6 +18,7 @@ pub enum SmcRangeProofError { ShortGroupSig(ShortGroupSigError), Schnorr(SchnorrError), ProofShorterThanExpected(usize, usize), + NotAPerfectRange(u64, u16), } impl From for SmcRangeProofError { diff --git a/smc_range_proof/src/lib.rs b/smc_range_proof/src/lib.rs index f4bdcec4..098c687f 100644 --- a/smc_range_proof/src/lib.rs +++ b/smc_range_proof/src/lib.rs @@ -7,7 +7,7 @@ //! where `u` is the base and the upper bound is a power of the base. [Code](src/ccs_range_proof/perfect_range.rs) //! 3. Range proof protocol as described in section 4.4 of the paper [1]. Considers an arbitrary range `[min, max)`. Some //! differences with the paper, check the module for more details. [Code](src/ccs_range_proof/arbitrary_range.rs) -//! 4. Range proof using sumsets, based on Protocol 2 from the paper [2]. [Code](src/smc_range_proof.rs) +//! 4. Range proof using sumsets, based on Protocol 2 from the paper [2] but considers range [min, max) and not [0, max]. [Code](src/smc_range_proof.rs) //! 5. Implements the Keyed-Verification of the above protocols where the verifier knows the secret key of the BB sig. This makes //! the proof generation and verification more efficient by removing the need for pairings. This idea is taken from this PhD. thesis. //! diff --git a/syra/src/threshold_issuance.rs b/syra/src/threshold_issuance.rs index fd08d761..b6b6ec8f 100644 --- a/syra/src/threshold_issuance.rs +++ b/syra/src/threshold_issuance.rs @@ -91,11 +91,11 @@ pub struct UserSecretKeyShare { impl Phase2 { + /// Initialize when each signer knows the complete user-id. /// This internally uses `init_for_known_message` of threshold weak-BB signature as the signers must /// know the full message which here is the user id. This is important to prevent the user from - /// getting multiple signatures over the arbitrary user ids. A way to achieve signing with user-id - /// shares could be for the user to prove that the shares belong to "certain user-id" (likely in a commitment) - pub fn init( + /// getting multiple signatures over the arbitrary user ids. + pub fn init_for_user_id( rng: &mut R, id: ParticipantId, issuer_sk: &IssuerSecretKey, @@ -124,6 +124,39 @@ impl Ok((Self(inner), m)) } + /// Initialize when each signer knows only a share of the complete user-id. This does not ensure that + /// the share is not of some bogus value. A way to achieve signing with user-id + /// shares could be for the user to prove that the shares belong to "certain user-id" (likely in a commitment) + /// before the signers call this function. + pub fn init_for_shared_user_id( + rng: &mut R, + id: ParticipantId, + issuer_sk: &IssuerSecretKey, + user_id_share: F, + phase_1_output: Phase1Output, + base_ot_output: BaseOTOutput, + ote_params: MultiplicationOTEParams, + gadget_vector: &GadgetVector, + label: &'static [u8], + ) -> Result<(Self, BTreeMap>), SyraError> { + let (inner, m) = short_group_sig::threshold_weak_bb_sig::Phase2::< + F, + KAPPA, + STATISTICAL_SECURITY_PARAMETER, + >::init_for_shared_message( + rng, + id, + issuer_sk.0, + user_id_share, + phase_1_output, + base_ot_output, + ote_params, + gadget_vector, + label, + )?; + Ok((Self(inner), m)) + } + /// Process received `Message1` from signer with id `sender_id` pub fn receive_message1( &mut self, @@ -204,7 +237,7 @@ mod tests { use ark_std::rand::{rngs::StdRng, SeedableRng}; use blake2::Blake2b512; use schnorr_pok::compute_random_oracle_challenge; - use secret_sharing_and_dkg::shamir_ss::deal_random_secret; + use secret_sharing_and_dkg::shamir_ss::{deal_random_secret, deal_secret}; use short_group_sig::threshold_weak_bb_sig::Phase1; use test_utils::ot::do_pairwise_base_ot; @@ -295,27 +328,48 @@ mod tests { phase1_outs: &[Phase1Output], expected_sk_term: Fr, secret_key_shares: &[IssuerSecretKey], - user_id: Fr, + user_id: Option, + user_id_shares: Option>, ) -> Vec> { let mut phase2s = vec![]; let mut all_msg_1s = vec![]; let label = b"test"; + + let known_id = user_id.is_some(); + let user_id = user_id.unwrap_or_default(); + let user_id_shares = user_id_shares.unwrap_or_default(); + // Signers initiate round-2 and each signer sends messages to others let start = Instant::now(); for i in 1..=threshold_signers { - let (phase, msgs) = Phase2::init( - rng, - i, - &secret_key_shares[i as usize - 1], - user_id, - phase1_outs[i as usize - 1].clone(), - base_ot_outputs[i as usize - 1].clone(), - OTE_PARAMS, - &gadget_vector, - label, - ) - .unwrap(); + let (phase, msgs) = if known_id { + Phase2::init_for_user_id( + rng, + i, + &secret_key_shares[i as usize - 1], + user_id, + phase1_outs[i as usize - 1].clone(), + base_ot_outputs[i as usize - 1].clone(), + OTE_PARAMS, + &gadget_vector, + label, + ) + .unwrap() + } else { + Phase2::init_for_shared_user_id( + rng, + i, + &secret_key_shares[i as usize - 1], + user_id_shares[i as usize - 1], + phase1_outs[i as usize - 1].clone(), + base_ot_outputs[i as usize - 1].clone(), + OTE_PARAMS, + &gadget_vector, + label, + ) + .unwrap() + }; phase2s.push(phase); all_msg_1s.push((i, msgs)); } @@ -351,7 +405,7 @@ mod tests { } #[test] - fn issue() { + fn issue_with_known_user_id() { let mut rng = StdRng::seed_from_u64(0u64); let gadget_vector = GadgetVector::::new::< @@ -399,7 +453,80 @@ mod tests { &phase1_outs, sk, &isk_shares, - user_id, + Some(user_id), + None, + ); + + let start = Instant::now(); + let usk = UserSecretKeyShare::aggregate(usk_shares); + println!( + "Aggregating {} shares took {:?}", + threshold_signers, + start.elapsed() + ); + + usk.verify(user_id, &threshold_ipk, params.clone()).unwrap(); + } + + #[test] + fn issue_with_shared_user_id() { + let mut rng = StdRng::seed_from_u64(0u64); + + let gadget_vector = GadgetVector::::new::< + Blake2b512, + >(OTE_PARAMS, b"test-gadget-vector"); + + let threshold_signers = 5; + let total_signers = 8; + let all_party_set = (1..=total_signers).into_iter().collect::>(); + + let params = SetupParams::::new::(b"test"); + + // The signers do a keygen. This is a one time setup. + let (sk, sk_shares) = + trusted_party_keygen::<_, Fr>(&mut rng, threshold_signers, total_signers); + let isk_shares = sk_shares + .into_iter() + .map(|s| IssuerSecretKey(s)) + .collect::>(); + // Public key created by the trusted party using the secret key directly. In practice, this will be a result of a DKG + let threshold_ipk = IssuerPublicKey::new(&mut rng, &IssuerSecretKey(sk), ¶ms); + + // The signers run OT protocol instances. This is also a one time setup. + let base_ot_outputs = do_pairwise_base_ot::( + &mut rng, + OTE_PARAMS.num_base_ot(), + total_signers, + all_party_set.clone(), + ); + + // Signing starts + let protocol_id = b"test".to_vec(); + + let phase1_outs = do_phase1(&mut rng, threshold_signers, protocol_id.clone()); + + // Signer creates user secret key + let user_id = compute_random_oracle_challenge::(b"low entropy user-id"); + let (user_id_shares, _) = + deal_secret::(&mut rng, user_id, threshold_signers, total_signers).unwrap(); + + let usk_shares = do_phase2( + &mut rng, + threshold_signers, + &gadget_vector, + params.clone(), + &base_ot_outputs, + &phase1_outs, + sk + user_id, + &isk_shares, + None, + Some( + user_id_shares + .0 + .into_iter() + .map(|share| share.share) + .collect(), + ), ); let start = Instant::now(); diff --git a/vb_accumulator/src/batch_utils.rs b/vb_accumulator/src/batch_utils.rs index 788550d0..33ecfa0a 100644 --- a/vb_accumulator/src/batch_utils.rs +++ b/vb_accumulator/src/batch_utils.rs @@ -30,7 +30,7 @@ use dock_crypto_utils::{ use serde::{Deserialize, Serialize}; use serde_with::serde_as; -use dock_crypto_utils::ff::{inner_product, powers}; +use dock_crypto_utils::ff::inner_product; #[cfg(feature = "parallel")] use rayon::prelude::*; @@ -477,7 +477,8 @@ where } /// Published by the accumulator manager to allow witness updates without secret info. This "represents" a polynomial which -/// will be evaluated at the element whose witness needs to be updated. Defined in section 4.1 of the paper +/// will be evaluated at the element whose witness needs to be updated. Its a binding but non-hiding commitment to the polynomial. +/// Defined in section 4.1 of the paper #[serde_as] #[derive( Clone, PartialEq, Eq, Debug, CanonicalSerialize, CanonicalDeserialize, Serialize, Deserialize, @@ -658,22 +659,15 @@ where /// Inner product of powers of `y`, i.e. the element for which witness needs to be updated and `omega`. /// Equivalent to evaluating the polynomial at `y` and multiplying the result by `scalar` /// Used by the (non)member to update its witness without the knowledge of secret key. - pub fn inner_product_with_scaled_powers_of_y( - &self, - y: &G::ScalarField, - scalar: &G::ScalarField, - ) -> G::Group { + pub fn evaluate(&self, y: &G::ScalarField, scalar: &G::ScalarField) -> G::Group { let powers_of_y = Self::scaled_powers_of_y(y, scalar, self.len()); // G::Group::msm_unchecked(&self.0, &powers_of_y) } - pub fn inner_product_with_scaled_powers_of_y_temp( - &self, - y: &G::ScalarField, - scalar: &G::ScalarField, - ) -> G::Group { - let pow = powers(y, self.len() as u32); + #[cfg(test)] + pub fn evaluate_temp(&self, y: &G::ScalarField, scalar: &G::ScalarField) -> G::Group { + let pow = dock_crypto_utils::ff::powers(y, self.len() as u32); let r = G::Group::msm_unchecked(&self.0, &pow); r * scalar } @@ -734,7 +728,7 @@ where let omega = Self::new(additions, removals, old_accumulator, sk); // * 1/d_D(x) - let y_omega_ip = omega.inner_product_with_scaled_powers_of_y(element, &d_D_inv); + let y_omega_ip = omega.evaluate(element, &d_D_inv); assert_eq!(V_prime, y_omega_ip); } @@ -763,7 +757,7 @@ where let omega = Self::new_for_kb_positive_accumulator::(removals, old_accumulator, sk); // * 1/d_D(x) - let y_omega_ip = omega.inner_product_with_scaled_powers_of_y(&member, &d_D_inv); + let y_omega_ip = omega.evaluate(&member, &d_D_inv); assert_eq!(V_prime, y_omega_ip.neg()); } @@ -972,11 +966,11 @@ mod tests { ); let start = Instant::now(); - let e1 = omega.inner_product_with_scaled_powers_of_y(&y, &scalar); + let e1 = omega.evaluate(&y, &scalar); println!("Time taken is {:?}", start.elapsed()); let start = Instant::now(); - let e2 = omega.inner_product_with_scaled_powers_of_y_temp(&y, &scalar); + let e2 = omega.evaluate_temp(&y, &scalar); println!("Time taken with temp is {:?}", start.elapsed()); assert_eq!(e1, e2); } diff --git a/vb_accumulator/src/kb_positive_accumulator/proofs.rs b/vb_accumulator/src/kb_positive_accumulator/proofs.rs index 26a461cc..c4501352 100644 --- a/vb_accumulator/src/kb_positive_accumulator/proofs.rs +++ b/vb_accumulator/src/kb_positive_accumulator/proofs.rs @@ -374,6 +374,10 @@ mod tests { proof_verif_with_rpc_duration += start.elapsed(); } + let start = Instant::now(); + assert!(pairing_checker.verify()); + proof_verif_with_rpc_duration += start.elapsed(); + println!( "Time to create {} membership proofs is {:?}", count, proof_create_duration diff --git a/vb_accumulator/src/kb_positive_accumulator/proofs_cdh.rs b/vb_accumulator/src/kb_positive_accumulator/proofs_cdh.rs index 8f914be6..32935e31 100644 --- a/vb_accumulator/src/kb_positive_accumulator/proofs_cdh.rs +++ b/vb_accumulator/src/kb_positive_accumulator/proofs_cdh.rs @@ -357,6 +357,10 @@ mod tests { proof_verif_with_rpc_duration += start.elapsed(); } + let start = Instant::now(); + assert!(pairing_checker.verify()); + proof_verif_with_rpc_duration += start.elapsed(); + println!( "Time to create {} membership proofs is {:?}", count, proof_create_duration diff --git a/vb_accumulator/src/proofs_keyed_verification.rs b/vb_accumulator/src/proofs_keyed_verification.rs index f6ec63b0..1d11d71e 100644 --- a/vb_accumulator/src/proofs_keyed_verification.rs +++ b/vb_accumulator/src/proofs_keyed_verification.rs @@ -303,7 +303,7 @@ impl MembershipProofProtocol { ) -> Self { Self(PoKOfSignatureG1KVProtocol::init( rng, - &witness, + &witness.0, element, element_blinding, accumulator, diff --git a/vb_accumulator/src/witness.rs b/vb_accumulator/src/witness.rs index 843338e9..6bee8794 100644 --- a/vb_accumulator/src/witness.rs +++ b/vb_accumulator/src/witness.rs @@ -303,7 +303,7 @@ pub trait Witness { let d_A_times_d_D_inv = d_A * d_D_inv; // * 1/d_D(x) - let y_omega_ip = omega.inner_product_with_scaled_powers_of_y(element, &d_D_inv); + let y_omega_ip = omega.evaluate(element, &d_D_inv); // d_A(x)/d_D(x) * C + 1/d_D(x) * let new_C = old_witness.mul_bigint(d_A_times_d_D_inv.into_bigint()) + y_omega_ip; diff --git a/verifiable_encryption/Cargo.toml b/verifiable_encryption/Cargo.toml index 7d26b775..775be2f7 100644 --- a/verifiable_encryption/Cargo.toml +++ b/verifiable_encryption/Cargo.toml @@ -16,18 +16,18 @@ rayon = {workspace = true, optional = true} serde.workspace = true serde_with.workspace = true zeroize.workspace = true -dock_crypto_utils = { version = "0.20.0", default-features = false, path = "../utils" } itertools.workspace = true +dock_crypto_utils = { version = "0.20.0", default-features = false, path = "../utils" } secret_sharing_and_dkg = { version = "0.13.0", default-features = false, path = "../secret_sharing_and_dkg" } [dev-dependencies] blake2.workspace = true -sha3 = { version = "0.10.6", default-features = false } +sha3.workspace = true ark-bls12-381.workspace = true -ark-secp256r1 = { version = "^0.4.0", default-features = false } +ark-secp256r1.workspace = true [features] default = [ "parallel" ] -std = [ "ark-ff/std", "ark-ec/std", "ark-std/std", "ark-serialize/std", "dock_crypto_utils/std", "serde/std"] +std = [ "ark-ff/std", "ark-ec/std", "ark-std/std", "ark-serialize/std", "dock_crypto_utils/std", "serde/std", "secret_sharing_and_dkg/std"] print-trace = [ "ark-std/print-trace", "dock_crypto_utils/print-trace" ] -parallel = [ "std", "ark-ff/parallel", "ark-ec/parallel", "ark-std/parallel", "rayon", "dock_crypto_utils/parallel" ] \ No newline at end of file +parallel = [ "std", "ark-ff/parallel", "ark-ec/parallel", "ark-std/parallel", "rayon", "dock_crypto_utils/parallel", "secret_sharing_and_dkg/parallel" ] \ No newline at end of file