From 6041b41792890f2de4beef01fcdb365c5d526f32 Mon Sep 17 00:00:00 2001 From: lovesh Date: Sat, 21 Sep 2019 14:42:00 +0530 Subject: [PATCH] misc changes Signed-off-by: lovesh --- delg_cred_cdd/Cargo.toml | 2 +- delg_cred_cdd/README.md | 6 +-- delg_cred_cdd/src/attribute_token.rs | 63 ++++++++++++---------- delg_cred_cdd/src/issuer.rs | 71 +++++++++++++++++++++++++ ps/Cargo.toml | 9 ++-- ps/src/keys.rs | 2 + ps/src/lib.rs | 4 +- ps/src/pok_sig.rs | 45 +++++++++++----- ps/src/pok_vc.rs | 9 +++- ps/src/signature.rs | 79 ++++++++++++++++------------ ps/tests/scenario.rs | 8 +-- 11 files changed, 205 insertions(+), 93 deletions(-) diff --git a/delg_cred_cdd/Cargo.toml b/delg_cred_cdd/Cargo.toml index e435d53..80246bb 100644 --- a/delg_cred_cdd/Cargo.toml +++ b/delg_cred_cdd/Cargo.toml @@ -12,6 +12,6 @@ serde = "1.0" serde_derive = "1.0" [dependencies.amcl_wrapper] -version = "0.1.5" +version = "0.1.6" default-features = false features = ["bls381"] \ No newline at end of file diff --git a/delg_cred_cdd/README.md b/delg_cred_cdd/README.md index 7019ecf..4e170c4 100644 --- a/delg_cred_cdd/README.md +++ b/delg_cred_cdd/README.md @@ -4,7 +4,7 @@ ### Brief description of the API 1. [Groth1 and Groth2 signatures](src/groth_sig.rs). - - Parameters can be generated by calling `GrothS1::setup` or `GrothS2::setup`. `setup` takes the maximum number of attributes that need to be supported. Keep it one more than the number you want to support to accomodate the public key. + - Parameters can be generated by calling `GrothS1::setup` or `GrothS2::setup`. `setup` takes the maximum number of attributes that need to be supported. Keep it one more than the number you want to support to accommodate the public key. - Signing keys can be generated by calling `GrothS1::keygen` or `GrothS2::keygen`. Takes the corresponding setup parameters. - A new signature can be created by calling `Groth1Sig:new` or `Groth2Sig:new`. An existing signature can be randomized by calling `randomize` on the siganture. - 2 methods for signature verification, `verify` and `verify_fast`, both with the same API. `verify` computes several pairings to verify the signature whereas `verify_fast` does only 1 big multi-pairing. Applies this observation to pairings: if it needs to be cheched that a == b and c == d and e == f, then choose a random number `r` and check whether (a-b) + (c-d)*r + (e-f)*r2 == 0. Refer the docs for the method for more details @@ -12,9 +12,9 @@ - Issuers are instantiated by calling `EvenLevelIssuer::new` or `OddLevelIssuer::new` by passing their level to the `new` function. Root issuers is at level 0 so always instantiated by `EvenLevelIssuer::new(0)`. - Issuers generate their keys with `EvenLevelIssuer::keygen` or `OddLevelIssuer::keygen`. - Issuers can delegate by calling `delegate` method that takes the attributes to sign, who to delegate to etc resulting in a credential. - - A credential is a called a link and there credentials issued by `EvenLevelIssuer`s are called `CredLinkOdd` and credentials issued by `OddLevelIssuer`s are called `CredLinkEven`. + - A credential is a called a link and the credentials issued by `EvenLevelIssuer`s are called `CredLinkOdd` and credentials issued by `OddLevelIssuer`s are called `CredLinkEven`. - A link stores its associated `level`, `attributes` and `signature`. The last element of `attributes` is the verification key of the delegatee and the signature is on `attributes`. - - To verify the correctness of link, call `verify` on it with delegator public key, delegatee public key ans setup params. + - To verify the correctness of link, call `verify` on it with delegator public key, delegatee public key and setup params. - The chain of credentials is kept in `CredChain` which internally has 2 lists, 1 for odd level links and 1 for even. Even or odd level links can be added by calling `extend_with_even` or `extend_with_odd` on the chain. - To verify that all delegations are valid in the chain, call `verify_delegations` on the chain. 3. [Attribute tokens](src/attribute_token.rs) diff --git a/delg_cred_cdd/src/attribute_token.rs b/delg_cred_cdd/src/attribute_token.rs index ec41027..0926ae3 100644 --- a/delg_cred_cdd/src/attribute_token.rs +++ b/delg_cred_cdd/src/attribute_token.rs @@ -363,11 +363,15 @@ impl<'a> AttributeToken<'a> { }) } - // XXX: Add other instance data - pub fn gen_challenge(at: &AttributeTokenComm, ipk: &Groth1Verkey) -> FieldElement { + pub fn gen_challenge( + at: &AttributeTokenComm, + ipk: &Groth1Verkey, + mut extra: Vec, + ) -> FieldElement { let mut bytes = Vec::::new(); bytes.extend_from_slice(&ipk.0.to_bytes()); bytes.extend_from_slice(&at.to_bytes()); + bytes.append(&mut extra); FieldElement::from_msg_hash(&bytes) } @@ -1398,7 +1402,7 @@ mod tests { assert!(com_1.odd_level_revealed_attributes[0].is_empty()); - let c_1 = AttributeToken::gen_challenge(&com_1, &l_0_issuer_vk); + let c_1 = AttributeToken::gen_challenge(&com_1, &l_0_issuer_vk, vec![]); let start_resp = Instant::now(); let resp_1 = at_1 @@ -1421,7 +1425,7 @@ mod tests { .unwrap(); let recon_duration = start_recon.elapsed(); - let recon_c_1 = AttributeToken::gen_challenge(&recon_com_1, &l_0_issuer_vk); + let recon_c_1 = AttributeToken::gen_challenge(&recon_com_1, &l_0_issuer_vk, vec![]); assert_eq!(c_1, recon_c_1); println!("For delegation chain of length {}, commitment takes {:?}, response takes {:?}, commitment reconstitution takes {:?}. Total time taken by commitment and response is {:?}", L, com_duration, resp_duration, recon_duration, com_duration + resp_duration); @@ -1449,7 +1453,7 @@ mod tests { assert!(com_2.odd_level_revealed_attributes[0].is_empty()); assert!(com_2.even_level_revealed_attributes[0].is_empty()); - let c_2 = AttributeToken::gen_challenge(&com_2, &l_0_issuer_vk); + let c_2 = AttributeToken::gen_challenge(&com_2, &l_0_issuer_vk, vec![]); let start_resp = Instant::now(); let resp_2 = at_2 @@ -1478,7 +1482,7 @@ mod tests { .unwrap(); let recon_duration = start_recon.elapsed(); - let recon_c_2 = AttributeToken::gen_challenge(&recon_com_2, &l_0_issuer_vk); + let recon_c_2 = AttributeToken::gen_challenge(&recon_com_2, &l_0_issuer_vk, vec![]); assert_eq!(c_2, recon_c_2); println!("For delegation chain of length {}, commitment takes {:?}, response takes {:?}, commitment reconstitution takes {:?}. Total time taken by commitment and response is {:?}", L, com_duration, resp_duration, recon_duration, com_duration + resp_duration); @@ -1508,7 +1512,7 @@ mod tests { assert!(com_3.odd_level_revealed_attributes[1].is_empty()); assert!(com_3.even_level_revealed_attributes[0].is_empty()); - let c_3 = AttributeToken::gen_challenge(&com_3, &l_0_issuer_vk); + let c_3 = AttributeToken::gen_challenge(&com_3, &l_0_issuer_vk, vec![]); let start_resp = Instant::now(); let resp_3 = at_3 @@ -1536,7 +1540,7 @@ mod tests { ) .unwrap(); let recon_duration = start_recon.elapsed(); - let recon_c_3 = AttributeToken::gen_challenge(&recon_com_3, &l_0_issuer_vk); + let recon_c_3 = AttributeToken::gen_challenge(&recon_com_3, &l_0_issuer_vk, vec![]); assert_eq!(c_3, recon_c_3); println!("For delegation chain of length {}, commitment takes {:?}, response takes {:?}, commitment reconstitution takes {:?}. Total time taken by commitment and response is {:?}", L, @@ -1568,7 +1572,7 @@ mod tests { assert!(com_4.even_level_revealed_attributes[0].is_empty()); assert!(com_4.even_level_revealed_attributes[1].is_empty()); - let c_4 = AttributeToken::gen_challenge(&com_4, &l_0_issuer_vk); + let c_4 = AttributeToken::gen_challenge(&com_4, &l_0_issuer_vk, vec![]); let start_resp = Instant::now(); let resp_4 = at_4 @@ -1597,7 +1601,7 @@ mod tests { .unwrap(); let recon_duration = start_recon.elapsed(); - let recon_c_4 = AttributeToken::gen_challenge(&recon_com_4, &l_0_issuer_vk); + let recon_c_4 = AttributeToken::gen_challenge(&recon_com_4, &l_0_issuer_vk, vec![]); assert_eq!(c_4, recon_c_4); println!("For delegation chain of length {}, commitment takes {:?}, response takes {:?}, commitment reconstitution takes {:?}. Total time taken by commitment and response is {:?}", L, com_duration, resp_duration, recon_duration, com_duration + resp_duration); @@ -1629,7 +1633,7 @@ mod tests { assert!(com_5.even_level_revealed_attributes[0].is_empty()); assert!(com_5.even_level_revealed_attributes[1].is_empty()); - let c_5 = AttributeToken::gen_challenge(&com_5, &l_0_issuer_vk); + let c_5 = AttributeToken::gen_challenge(&com_5, &l_0_issuer_vk, vec![]); let start_resp = Instant::now(); let resp_5 = at_5 @@ -1658,7 +1662,7 @@ mod tests { .unwrap(); let recon_duration = start_recon.elapsed(); - let recon_c_5 = AttributeToken::gen_challenge(&recon_com_5, &l_0_issuer_vk); + let recon_c_5 = AttributeToken::gen_challenge(&recon_com_5, &l_0_issuer_vk, vec![]); assert_eq!(c_5, recon_c_5); println!("For delegation chain of length {}, commitment takes {:?}, response takes {:?}, commitment reconstitution takes {:?}. Total time taken by commitment and response is {:?}", L, com_duration, resp_duration, recon_duration, com_duration + resp_duration); @@ -1691,7 +1695,7 @@ mod tests { assert!(com_6.even_level_revealed_attributes[1].is_empty()); assert!(com_6.even_level_revealed_attributes[2].is_empty()); - let c_6 = AttributeToken::gen_challenge(&com_6, &l_0_issuer_vk); + let c_6 = AttributeToken::gen_challenge(&com_6, &l_0_issuer_vk, vec![]); let start_resp = Instant::now(); let resp_6 = at_6 @@ -1720,7 +1724,7 @@ mod tests { .unwrap(); let recon_duration = start_recon.elapsed(); - let recon_c_6 = AttributeToken::gen_challenge(&recon_com_6, &l_0_issuer_vk); + let recon_c_6 = AttributeToken::gen_challenge(&recon_com_6, &l_0_issuer_vk, vec![]); assert_eq!(c_6, recon_c_6); println!("For delegation chain of length {}, commitment takes {:?}, response takes {:?}, commitment reconstitution takes {:?}. Total time taken by commitment and response is {:?}", L, com_duration, resp_duration, recon_duration, com_duration + resp_duration); @@ -1780,7 +1784,7 @@ mod tests { assert_eq!(com_1.odd_level_revealed_attributes[0][&1], attributes_1[1]); assert_eq!(com_1.odd_level_revealed_attributes[0][&3], attributes_1[3]); - let c_1 = AttributeToken::gen_challenge(&com_1, &l_0_issuer_vk); + let c_1 = AttributeToken::gen_challenge(&com_1, &l_0_issuer_vk, vec![]); let start_resp = Instant::now(); let resp_1 = at_1 @@ -1803,7 +1807,7 @@ mod tests { .unwrap(); let recon_duration = start_recon.elapsed(); - let recon_c_1 = AttributeToken::gen_challenge(&recon_com_1, &l_0_issuer_vk); + let recon_c_1 = AttributeToken::gen_challenge(&recon_com_1, &l_0_issuer_vk, vec![]); assert_eq!(c_1, recon_c_1); println!("For delegation chain of length {}, commitment takes {:?}, response takes {:?}, commitment reconstitution takes {:?}. Total time taken by commitment and response is {:?}", L, com_duration, resp_duration, recon_duration, com_duration + resp_duration); @@ -1849,7 +1853,7 @@ mod tests { assert_eq!(com_2.even_level_revealed_attributes[0][&3], attributes_2[3]); assert_eq!(com_2.even_level_revealed_attributes[0][&4], attributes_2[4]); - let c_2 = AttributeToken::gen_challenge(&com_2, &l_0_issuer_vk); + let c_2 = AttributeToken::gen_challenge(&com_2, &l_0_issuer_vk, vec![]); let start_resp = Instant::now(); let resp_2 = at_2 @@ -1881,7 +1885,7 @@ mod tests { .unwrap(); let recon_duration = start_recon.elapsed(); - let recon_c_2 = AttributeToken::gen_challenge(&recon_com_2, &l_0_issuer_vk); + let recon_c_2 = AttributeToken::gen_challenge(&recon_com_2, &l_0_issuer_vk, vec![]); assert_eq!(c_2, recon_c_2); println!("For delegation chain of length {}, commitment takes {:?}, response takes {:?}, commitment reconstitution takes {:?}. Total time taken by commitment and response is {:?}", L, com_duration, resp_duration, recon_duration, com_duration + resp_duration); @@ -1930,7 +1934,7 @@ mod tests { assert_eq!(com_3.even_level_revealed_attributes[0][&4], attributes_2[4]); assert_eq!(com_3.odd_level_revealed_attributes[1][&1], attributes_3[1]); - let c_3 = AttributeToken::gen_challenge(&com_3, &l_0_issuer_vk); + let c_3 = AttributeToken::gen_challenge(&com_3, &l_0_issuer_vk, vec![]); let start_resp = Instant::now(); let resp_3 = at_3 @@ -1962,7 +1966,7 @@ mod tests { ) .unwrap(); let recon_duration = start_recon.elapsed(); - let recon_c_3 = AttributeToken::gen_challenge(&recon_com_3, &l_0_issuer_vk); + let recon_c_3 = AttributeToken::gen_challenge(&recon_com_3, &l_0_issuer_vk, vec![]); assert_eq!(c_3, recon_c_3); println!("For delegation chain of length {}, commitment takes {:?}, response takes {:?}, commitment reconstitution takes {:?}. Total time taken by commitment and response is {:?}", L, @@ -2019,7 +2023,7 @@ mod tests { assert_eq!(com_4.even_level_revealed_attributes[1][&1], attributes_4[1]); assert_eq!(com_4.even_level_revealed_attributes[1][&4], attributes_4[4]); - let c_4 = AttributeToken::gen_challenge(&com_4, &l_0_issuer_vk); + let c_4 = AttributeToken::gen_challenge(&com_4, &l_0_issuer_vk, vec![]); let start_resp = Instant::now(); let resp_4 = at_4 @@ -2053,7 +2057,7 @@ mod tests { .unwrap(); let recon_duration = start_recon.elapsed(); - let recon_c_4 = AttributeToken::gen_challenge(&recon_com_4, &l_0_issuer_vk); + let recon_c_4 = AttributeToken::gen_challenge(&recon_com_4, &l_0_issuer_vk, vec![]); assert_eq!(c_4, recon_c_4); println!("For delegation chain of length {}, commitment takes {:?}, response takes {:?}, commitment reconstitution takes {:?}. Total time taken by commitment and response is {:?}", L, com_duration, resp_duration, recon_duration, com_duration + resp_duration); @@ -2191,9 +2195,10 @@ mod tests { .unwrap(); let com_precomp_duration = start.elapsed(); - let c = AttributeToken::gen_challenge(&com, &l_0_issuer_vk); - let c_precomp_setup = AttributeToken::gen_challenge(&com_precomp_setup, &l_0_issuer_vk); - let c_precomp = AttributeToken::gen_challenge(&com_precomp, &l_0_issuer_vk); + let c = AttributeToken::gen_challenge(&com, &l_0_issuer_vk, vec![]); + let c_precomp_setup = + AttributeToken::gen_challenge(&com_precomp_setup, &l_0_issuer_vk, vec![]); + let c_precomp = AttributeToken::gen_challenge(&com_precomp, &l_0_issuer_vk, vec![]); let sk = if i % 2 == 1 { let sk = &odd_level_issuer_keys[i / 2].0; @@ -2243,7 +2248,7 @@ mod tests { .unwrap(); let recon_duration = start.elapsed(); - let recon_c = AttributeToken::gen_challenge(&recon_com, &l_0_issuer_vk); + let recon_c = AttributeToken::gen_challenge(&recon_com, &l_0_issuer_vk, vec![]); assert_eq!(c, recon_c); let start = Instant::now(); @@ -2263,7 +2268,7 @@ mod tests { let recon_precomp_duration = start.elapsed(); let recon_c_precomp_setup_com = - AttributeToken::gen_challenge(&recon_precomp_setup_com, &l_0_issuer_vk); + AttributeToken::gen_challenge(&recon_precomp_setup_com, &l_0_issuer_vk, vec![]); assert_eq!(c_precomp_setup, recon_c_precomp_setup_com); let recon_precomp_com = AttributeToken::reconstruct_commitment_with_precomputed_vals( @@ -2280,7 +2285,7 @@ mod tests { .unwrap(); let recon_c_precomp_com = - AttributeToken::gen_challenge(&recon_precomp_com, &l_0_issuer_vk); + AttributeToken::gen_challenge(&recon_precomp_com, &l_0_issuer_vk, vec![]); assert_eq!(c_precomp, recon_c_precomp_com); println!("For delegation chain of length {}", L); @@ -2351,7 +2356,7 @@ mod tests { // Supplying same number of collections of revealed attributes as the chain size let com_1 = at_1.commitment(vec![HashSet::::new(); 1]).unwrap(); - let c_1 = AttributeToken::gen_challenge(&com_1, &l_0_issuer_vk); + let c_1 = AttributeToken::gen_challenge(&com_1, &l_0_issuer_vk, vec![]); let mut morphed_commitment = com_1.clone(); // Adding an element of comms_s to increase its size diff --git a/delg_cred_cdd/src/issuer.rs b/delg_cred_cdd/src/issuer.rs index 6b9c75a..86e2283 100644 --- a/delg_cred_cdd/src/issuer.rs +++ b/delg_cred_cdd/src/issuer.rs @@ -42,6 +42,10 @@ pub struct OddLevelIssuer { pub level: usize, } +pub struct RootIssuer {} + +pub type RootIssuerVerkey = EvenLevelVerkey; + impl CredLinkOdd { pub fn attribute_count(&self) -> usize { self.attributes.len() @@ -375,6 +379,22 @@ impl OddLevelIssuer { } } +impl RootIssuer { + pub fn keygen(setup_params: &Groth1SetupParams) -> (Sigkey, RootIssuerVerkey) { + GrothS1::keygen(setup_params) + } + + pub fn delegate( + mut delegatee_attributes: G1Vector, + delegatee_vk: OddLevelVerkey, + sk: &Sigkey, + setup_params: &Groth1SetupParams, + ) -> DelgResult { + let issuer = EvenLevelIssuer::new(0)?; + issuer.delegate(delegatee_attributes, delegatee_vk, sk, setup_params) + } +} + #[cfg(test)] mod tests { use super::*; @@ -452,6 +472,57 @@ mod tests { .unwrap()); } + #[test] + fn test_root_issuer() { + let max_attributes = 5; + let label = "test".as_bytes(); + let params1 = GrothS1::setup(max_attributes, label); + let params2 = GrothS2::setup(max_attributes, label); + + let l_1_issuer = OddLevelIssuer::new(1).unwrap(); + let l_2_issuer = EvenLevelIssuer::new(2).unwrap(); + + let (root_issuer_sk, root_issuer_vk) = RootIssuer::keygen(¶ms1); + let (l_1_issuer_sk, l_1_issuer_vk) = OddLevelIssuer::keygen(¶ms2); + let (l_2_issuer_sk, l_2_issuer_vk) = EvenLevelIssuer::keygen(¶ms1); + + let attributes_1: G1Vector = (0..max_attributes - 1) + .map(|_| G1::random()) + .collect::>() + .into(); + let cred_link_1 = RootIssuer::delegate( + attributes_1.clone(), + l_1_issuer_vk.clone(), + &root_issuer_sk, + ¶ms1, + ) + .unwrap(); + + assert!(cred_link_1 + .verify(&l_1_issuer_vk, &root_issuer_vk, ¶ms1) + .unwrap()); + + let mut chain_1 = CredChain::new(); + chain_1.extend_with_odd(cred_link_1).unwrap(); + + let attributes_2: G2Vector = (0..max_attributes - 1) + .map(|_| G2::random()) + .collect::>() + .into(); + let cred_link_2 = l_1_issuer + .delegate( + attributes_2.clone(), + l_2_issuer_vk.clone(), + &l_1_issuer_sk, + ¶ms2, + ) + .unwrap(); + + assert!(cred_link_2 + .verify(&l_2_issuer_vk, &l_1_issuer_vk, ¶ms2) + .unwrap()); + } + #[test] fn test_delegation_chain_verification() { let max_attributes = 3; diff --git a/ps/Cargo.toml b/ps/Cargo.toml index b074aac..2cb4149 100644 --- a/ps/Cargo.toml +++ b/ps/Cargo.toml @@ -1,20 +1,19 @@ [package] -name = "ps" +name = "ps_sig" version = "0.1.0" authors = ["lovesh "] edition = "2018" +description = "Pointcheval Sanders signatures" +license = "Apache-2.0" [dependencies] rand = "0.6" -lazy_static = "1.3.0" -log = "*" -merlin = "1.2.0" failure = "0.1.5" serde = "1.0" serde_derive = "1.0" [dependencies.amcl_wrapper] -version = "0.1.1" +version = "0.1.6" default-features = false features = ["bls381"] diff --git a/ps/src/keys.rs b/ps/src/keys.rs index 908f107..168e207 100644 --- a/ps/src/keys.rs +++ b/ps/src/keys.rs @@ -40,6 +40,8 @@ pub fn keygen(count_messages: usize, label: &[u8]) -> (Sigkey, Verkey) { let X = &g * &x; let X_tilde = &g_tilde * &x; for i in 0..count_messages { + // It is mandatory that all Y and Y_tilde have same discrete log wrt. g and g_tilde respectively. + // But once Y and Y_tilde are generated, y is not needed. let y = FieldElement::random(); Y.push(&g * &y); Y_tilde.push(&g_tilde * &y); diff --git a/ps/src/lib.rs b/ps/src/lib.rs index a003802..ea01a4d 100644 --- a/ps/src/lib.rs +++ b/ps/src/lib.rs @@ -17,7 +17,7 @@ pub type OtherGroup = amcl_wrapper::group_elem_g1::G1; #[cfg(feature = "G1G2")] pub type OtherGroupVec = amcl_wrapper::group_elem_g1::G1Vector; #[cfg(feature = "G1G2")] -pub(crate) fn ate_2_pairing( +pub fn ate_2_pairing( g1: &SignatureGroup, g2: &OtherGroup, h1: &SignatureGroup, @@ -35,7 +35,7 @@ pub type OtherGroup = amcl_wrapper::group_elem_g2::G2; #[cfg(feature = "G2G1")] pub type OtherGroupVec = amcl_wrapper::group_elem_g2::G2Vector; #[cfg(feature = "G2G1")] -pub(crate) fn ate_2_pairing( +pub fn ate_2_pairing( g1: &SignatureGroup, g2: &OtherGroup, h1: &SignatureGroup, diff --git a/ps/src/pok_sig.rs b/ps/src/pok_sig.rs index c227e65..e6f3682 100644 --- a/ps/src/pok_sig.rs +++ b/ps/src/pok_sig.rs @@ -32,7 +32,9 @@ As section 6.2 describes, for proving knowledge of a signature, the signature si transformed into a sequential aggregate signature with extra message t for public key g_tilde (and secret key 1). 1. Say the signature sigma is transformed to sigma_prime = (sigma_prime_1, sigma_prime_2) like step 1 in 6.2 1. The prover then sends sigma_prime and the value J = X_tilde * Y_tilde_1^m1 * Y_tilde_2^m2 * ..... * g_tilde^t and the proof J is formed correctly. -The verifier now checks whether e(sigma_prime_1, J) == e(sigma_prime_2, g_tilde) +The verifier now checks whether e(sigma_prime_1, J) == e(sigma_prime_2, g_tilde). Since X_tilde is known, +the verifier can send following a modified value J' where J' = Y_tilde_1^m_1 * Y_tilde_2^m_2 * ..... * g_tilde^t with the proof of knowledge of elements of J'. +The verifier will then check the pairing e(sigma_prime_1, J'*X_tilde) == e(sigma_prime_2, g_tilde). To reveal some of the messages from the signature but not all, in above protocol, construct J to be of the hidden values only, the verifier will then add the revealed values (raised to the respective generators) to get a final J which will then be used in the pairing check. @@ -75,10 +77,10 @@ impl PoKOfSignature { let sigma_prime_1 = &sig.sigma_1 * &r; let sigma_prime_2 = (&sig.sigma_2 + (&sig.sigma_1 * &t)) * &r; - let mut bases = OtherGroupVec::with_capacity(vk.Y_tilde.len() + 2); - let mut exponents = FieldElementVector::with_capacity(vk.Y_tilde.len() + 2); - bases.push(vk.X_tilde.clone()); - exponents.push(FieldElement::one()); + // +1 for `t` + let hidden_msg_count = vk.Y_tilde.len() - revealed_msg_indices.len() + 1; + let mut bases = OtherGroupVec::with_capacity(hidden_msg_count); + let mut exponents = FieldElementVector::with_capacity(hidden_msg_count); bases.push(vk.g_tilde.clone()); exponents.push(t.clone()); for i in 0..vk.Y_tilde.len() { @@ -88,7 +90,7 @@ impl PoKOfSignature { bases.push(vk.Y_tilde[i].clone()); exponents.push(messages[i].clone()); } - // J = X_tilde * Y_tilde_1^m1 * Y_tilde_2^m2 * ..... * g_tilde^t + // Prove knowledge of m_1, m_2, ... for all hidden m_i and t in J = Y_tilde_1^m_1 * Y_tilde_2^m_2 * ..... * g_tilde^t let J = bases.multi_scalar_mul_const_time(&exponents).unwrap(); // For proving knowledge of messages in J. @@ -110,6 +112,15 @@ impl PoKOfSignature { }) } + /// Return byte representation of public elements so they can be used for challenge computation + pub fn to_bytes(&self) -> Vec { + let mut bytes = vec![]; + bytes.append(&mut self.sig.to_bytes()); + bytes.append(&mut self.J.to_bytes()); + bytes.append(&mut self.pok_vc.to_bytes()); + bytes + } + pub fn gen_proof(self, challenge: &FieldElement) -> Result { let proof_vc = self.pok_vc.gen_proof(challenge, self.secrets.as_slice())?; Ok(PoKOfSignatureProof { @@ -127,9 +138,14 @@ impl PoKOfSignatureProof { revealed_msgs: HashMap, challenge: &FieldElement, ) -> Result { + if self.sig.sigma_1.is_identity() || self.sig.sigma_2.is_identity() { + return Ok(false); + } + vk.validate()?; - let mut bases = OtherGroupVec::with_capacity(vk.Y_tilde.len() + 2); - bases.push(vk.X_tilde.clone()); + // +1 for `t` + let hidden_msg_count = vk.Y_tilde.len() - revealed_msgs.len() + 1; + let mut bases = OtherGroupVec::with_capacity(hidden_msg_count); bases.push(vk.g_tilde.clone()); for i in 0..vk.Y_tilde.len() { if revealed_msgs.contains_key(&i) { @@ -140,9 +156,8 @@ impl PoKOfSignatureProof { if !self.proof_vc.verify(bases.as_slice(), &self.J, challenge)? { return Ok(false); } - // e(sigma_prime_1, J) == e(sigma_prime_2, g_tilde) => e(sigma_prime_1, J) * e(sigma_prime_2, g_tilde^-1) == 1 - let neg_g_tilde = vk.g_tilde.negation(); - let mut j = OtherGroup::new(); + // e(sigma_prime_1, J*X_tilde) == e(sigma_prime_2, g_tilde) => e(sigma_prime_1, J*X_tilde) * e(sigma_prime_2^-1, g_tilde) == 1 + let mut j; let J = if revealed_msgs.is_empty() { &self.J } else { @@ -156,7 +171,13 @@ impl PoKOfSignatureProof { j += b.multi_scalar_mul_var_time(&e).unwrap(); &j }; - let res = ate_2_pairing(&self.sig.sigma_1, J, &self.sig.sigma_2, &neg_g_tilde); + // Slight optimization possible by precomputing inverse of g_tilde and storing to avoid inverse of sig.sigma_2 + let res = ate_2_pairing( + &self.sig.sigma_1, + &(J + &vk.X_tilde), + &(-&self.sig.sigma_2), + &vk.g_tilde, + ); Ok(res.is_one()) } } diff --git a/ps/src/pok_vc.rs b/ps/src/pok_vc.rs index 81dd807..27db40e 100644 --- a/ps/src/pok_vc.rs +++ b/ps/src/pok_vc.rs @@ -130,13 +130,18 @@ macro_rules! impl_PoK_VC { } impl $ProverCommitted { - /// This step will be done by the main protocol for which this PoK is a sub-protocol - pub fn gen_challenge(&self, mut extra: Vec) -> FieldElement { + pub fn to_bytes(&self) -> Vec { let mut bytes = vec![]; for b in self.gens.as_slice() { bytes.append(&mut b.to_bytes()); } bytes.append(&mut self.commitment.to_bytes()); + bytes + } + + /// This step will be done by the main protocol for which this PoK is a sub-protocol + pub fn gen_challenge(&self, mut extra: Vec) -> FieldElement { + let mut bytes = self.to_bytes(); bytes.append(&mut extra); FieldElement::from_msg_hash(&bytes) } diff --git a/ps/src/signature.rs b/ps/src/signature.rs index 194f6ba..7c361e6 100644 --- a/ps/src/signature.rs +++ b/ps/src/signature.rs @@ -21,18 +21,7 @@ impl Signature { ) -> Result { // TODO: Take PRNG as argument. This will allow deterministic signatures as well Self::check_verkey_and_messages_compat(messages, verkey)?; - let u = FieldElement::random(); - let sigma_1 = &verkey.g * &u; - let mut points = SignatureGroupVec::new(0); - let mut scalars = FieldElementVector::new(0); - points.push(sigkey.X.clone()); - scalars.push(FieldElement::one()); - for i in 0..messages.len() { - scalars.push(messages[i].clone()); - points.push(verkey.Y[i].clone()); - } - // TODO: Remove unwrap by accommodating wrapper's error in PSError - let sigma_2 = points.multi_scalar_mul_const_time(&scalars).unwrap() * &u; + let (sigma_1, sigma_2) = Self::_sign(messages, sigkey, verkey, None); Ok(Signature { sigma_1, sigma_2 }) } @@ -45,48 +34,36 @@ impl Signature { verkey: &Verkey, ) -> Result { verkey.validate()?; - // There should be commitment to atleast one message + // There should be commitment to at least one message if messages.len() >= verkey.Y.len() { - // TODO: Use a different error return Err(PSError::UnsupportedNoOfMessages { expected: messages.len(), given: verkey.Y.len(), }); } - let u = FieldElement::random(); - let sigma_1 = &verkey.g * &u; - let mut points = SignatureGroupVec::new(0); - let mut scalars = FieldElementVector::new(0); - points.push(sigkey.X.clone()); - scalars.push(FieldElement::one()); - points.push(commitment.clone()); - scalars.push(FieldElement::one()); - let diff = (verkey.Y.len() - messages.len()); - for i in 0..messages.len() { - scalars.push(messages[i].clone()); - points.push(verkey.Y[diff + i].clone()); - } - let sigma_2 = points.multi_scalar_mul_const_time(&scalars).unwrap() * &u; + let (sigma_1, sigma_2) = Self::_sign(messages, sigkey, verkey, Some(commitment)); Ok(Signature { sigma_1, sigma_2 }) } /// Verify a signature. During proof of knowledge also, this method is used after extending the verkey pub fn verify(&self, messages: &[FieldElement], verkey: &Verkey) -> Result { + if self.sigma_1.is_identity() || self.sigma_2.is_identity() { + return Ok(false); + } Self::check_verkey_and_messages_compat(messages, verkey)?; - let mut points = OtherGroupVec::new(0); - let mut scalars = FieldElementVector::new(0); - points.push(verkey.X_tilde.clone()); - scalars.push(FieldElement::one()); + let mut points = OtherGroupVec::with_capacity(messages.len()); + let mut scalars = FieldElementVector::with_capacity(messages.len()); for i in 0..messages.len() { scalars.push(messages[i].clone()); points.push(verkey.Y_tilde[i].clone()); } // pr = X_tilde * Y_tilde[0]^messages[0] * Y_tilde[1]^messages[1] * .... Y_tilde[i]^messages[i] - let pr = points.multi_scalar_mul_var_time(&scalars).unwrap(); + let pr = &verkey.X_tilde + &points.multi_scalar_mul_var_time(&scalars).unwrap(); // check e(sigma_1, pr) == e(sigma_2, g_tilde) => e(sigma_1, pr) * e(sigma_2, g_tilde)^-1 == 1 - let neg_g_tilde = verkey.g_tilde.negation(); - let res = ate_2_pairing(&self.sigma_1, &pr, &self.sigma_2, &neg_g_tilde); + // e(sigma_1, pr) * e(sigma_2, g_tilde)^-1 = e(sigma_1, pr) * e(sigma_2^-1, g_tilde), if precomputation can be used, then + // inverse in sigma_2 can be avoided since inverse of g_tilde can be precomputed + let res = ate_2_pairing(&self.sigma_1, &pr, &(-&self.sigma_2), &verkey.g_tilde); Ok(res.is_one()) } @@ -99,6 +76,13 @@ impl Signature { Self { sigma_1, sigma_2 } } + pub fn to_bytes(&self) -> Vec { + let mut bytes = vec![]; + bytes.append(&mut self.sigma_1.to_bytes()); + bytes.append(&mut self.sigma_2.to_bytes()); + bytes + } + pub fn check_verkey_and_messages_compat( messages: &[FieldElement], verkey: &Verkey, @@ -112,6 +96,31 @@ impl Signature { } Ok(()) } + + pub fn _sign( + messages: &[FieldElement], + sigkey: &Sigkey, + verkey: &Verkey, + commitment: Option<&SignatureGroup>, + ) -> (SignatureGroup, SignatureGroup) { + let u = FieldElement::random(); + // sigma_1 = g^u + let sigma_1 = &verkey.g * &u; + let mut points = SignatureGroupVec::new(0); + let mut scalars = FieldElementVector::new(0); + let offset = verkey.Y.len() - messages.len(); + for i in 0..messages.len() { + scalars.push(messages[i].clone()); + points.push(verkey.Y[offset + i].clone()); + } + // sigma_2 = {X + Y_i^{m_i} + commitment}^u + let mut sigma_2 = &sigkey.X + &points.multi_scalar_mul_const_time(&scalars).unwrap(); + if commitment.is_some() { + sigma_2 += commitment.unwrap() + } + sigma_2 = &sigma_2 * &u; + (sigma_1, sigma_2) + } } #[cfg(test)] diff --git a/ps/tests/scenario.rs b/ps/tests/scenario.rs index 85556a5..cbd7edb 100644 --- a/ps/tests/scenario.rs +++ b/ps/tests/scenario.rs @@ -1,9 +1,9 @@ use amcl_wrapper::field_elem::{FieldElement, FieldElementVector}; use amcl_wrapper::group_elem::{GroupElement, GroupElementVector}; -use ps::keys::keygen; -use ps::pok_sig::*; -use ps::signature::Signature; -use ps::{OtherGroupVec, SignatureGroup}; +use ps_sig::keys::keygen; +use ps_sig::pok_sig::*; +use ps_sig::signature::Signature; +use ps_sig::{OtherGroupVec, SignatureGroup}; use std::collections::{HashMap, HashSet}; #[test]