├── .gitignore ├── .travis.yml ├── Cargo.toml ├── LICENCE ├── README.md ├── bls ├── Cargo.toml ├── README.md └── src │ ├── common.rs │ ├── lib.rs │ ├── multi_sig_fast.rs │ ├── multi_sig_slow.rs │ ├── simple.rs │ └── threshold_sig.rs ├── delg_cred_cdd ├── Cargo.toml ├── README.md └── src │ ├── attribute_token.rs │ ├── errors.rs │ ├── groth_sig.rs │ ├── issuer.rs │ ├── lib.rs │ └── pok_vc.rs ├── musig ├── Cargo.toml ├── README.md └── src │ ├── lib.rs │ └── musig.rs └── ps ├── Cargo.toml ├── README.md ├── src ├── errors.rs ├── keys.rs ├── lib.rs ├── pok_sig.rs ├── pok_vc.rs └── signature.rs └── tests └── scenario.rs /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | **/*.rs.bk 3 | Cargo.lock 4 | .idea/ 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | rust: 3 | - stable 4 | branches: 5 | only: 6 | - master 7 | script: 8 | - cd musig 9 | - cargo test --release 10 | - cd ../bls 11 | - cargo test --release --no-default-features --features SignatureG1 12 | - cargo test --release --no-default-features --features SignatureG2 13 | - cd ../ps 14 | - cargo test --release --no-default-features --features G2G1 15 | - cargo test --release --no-default-features --features G1G2 16 | - cd ../delg_cred_cdd 17 | - cargo test --release -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "bls", 4 | "musig", 5 | "ps", 6 | "delg_cred_cdd" 7 | ] 8 | -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | 190 | Licensed under the Apache License, Version 2.0 (the "License"); 191 | you may not use this file except in compliance with the License. 192 | You may obtain a copy of the License at 193 | 194 | http://www.apache.org/licenses/LICENSE-2.0 195 | 196 | Unless required by applicable law or agreed to in writing, software 197 | distributed under the License is distributed on an "AS IS" BASIS, 198 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 199 | See the License for the specific language governing permissions and 200 | limitations under the License. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Rust library for signatures, multi signatures, group signatures, delegatable credentials 2 | Uses the [The Apache Milagro Cryptographic Library](https://github.com/miracl/amcl) 3 | 4 | ## Supported schemes 5 | 1. BLS signatures from [Compact Multi-Signatures for Smaller Blockchains](https://eprint.iacr.org/2018/483.pdf) by Dan Boneh, Manu Drijvers and Gregory Neven. 6 | Used BLS12-381 curve from Apache Milagro. [Signing and verification API](./bls/README.md) 7 | 2. MuSig, Schnorr Multi-Signatures. [Simple Schnorr Multi-Signatures with Applications to Bitcoin](https://eprint.iacr.org/2018/068.pdf) 8 | by Gregory Maxwell and Andrew Poelstra and Yannick Seurin and Pieter Wuille. Used secp256k1 curve. [Signing and verification API](./musig/README.md) 9 | 3. [PS (Pointcheval Sanders) signatures](https://eprint.iacr.org/2015/525.pdf). 10 | 4. [Practical UC-Secure Delegatable Credentials with Attributes and Their Application to Blockchain](https://acmccs.github.io/papers/p683-camenischA.pdf) 11 | -------------------------------------------------------------------------------- /bls/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "bls_amcl" 3 | version = "0.7.0" 4 | authors = ["Lovesh Harchandani "] 5 | description = "BLS signatures. 2 variations. Multi-signature, Threshold signature, batch verification support" 6 | repository = "https://github.com/lovesh/signature-schemes/tree/master/bls" 7 | license = "Apache-2.0" 8 | 9 | [dependencies] 10 | rand = "0.7" 11 | lazy_static = "1.3.0" 12 | log = "0.4.8" 13 | serde = "1.0" 14 | serde_derive = "1.0" 15 | secret_sharing = "0.1.1" 16 | 17 | [dependencies.amcl_wrapper] 18 | version = "0.2.1" 19 | default-features = false 20 | features = ["bls381"] 21 | 22 | [features] 23 | default = ["SignatureG2"] 24 | SignatureG1 = [] # signature and message are in G1, verification key in G2 25 | SignatureG2 = [] # signature and message are in G2, verification key in G1 -------------------------------------------------------------------------------- /bls/README.md: -------------------------------------------------------------------------------- 1 | # BLS signature 2 | 3 | ## Overview 4 | The groups for verification key and message and signature are configurable by using feature flag. 5 | When using feature `SignatureG1`, signature and message are in G1, verification key in G2 which makes signing cheaper but verification expensive. 6 | When using feature `SignatureG2`, signature and message are in G2, verification key in G1 which makes signing expensive but verification cheaper. 7 | The default feature is `SignatureG2` to keep the verification fast. 8 | 2 variatons of creating multi-sigs are provided, one that requires proof of possesion to avoid rogue key attack and is fast. The other does not 9 | require proof of possesion but is slower. The former is present in `multi_sig_fast.rs` and latter in `multi_sig_slow.rs`. Both variations differ in 10 | signature and verkey aggregation only. The signing algorithms for each signer remains same. The verification algorithm remains same as well. 11 | Batch verification is supported as well. 12 | Threshold signatures can be created but the currently implemented key generation requires a trusted third party but key generation mechanisms without 13 | needing a trusted third party can be used without changing the signature aggregation or verkey aggregation mechanisms. 14 | 15 | ## API 16 | 17 | #### Generate parameters which will be used by all signers and verifiers in the system. To simulate a random oracle, a publicly known string is hashed to a generate group element 18 | ```rust 19 | let params = Params::new("some publicly known string".as_bytes()); 20 | ``` 21 | 22 | #### Generate keys 23 | ```rust 24 | let mut rng = thread_rng(); 25 | let keypair = Keypair::new(&mut rng, ¶ms); 26 | 27 | 28 | let sk = keypair.sig_key; 29 | let vk = keypair.ver_key; 30 | ``` 31 | 32 | #### Sign 33 | ```rust 34 | let msg = "Message to sign"; 35 | let b = msg.as_bytes(); 36 | let sig = Signature::new(&b, &sk); 37 | ``` 38 | 39 | #### Verify 40 | ```rust 41 | sig.verify(&b, &vk, ¶ms) 42 | ``` 43 | 44 | 45 | ### Multi-Signature and Verification (Not vulnerable to rogue public key attack but slow) 46 | #### Multi-Signature 47 | ```rust 48 | let keypair1 = Keypair::new(None); 49 | let keypair2 = Keypair::new(None); 50 | let msg = "Small msg"; 51 | let b = m.as_bytes(); 52 | let sig1 = Signature::new(&b, &keypair1.sig_key); 53 | let sig2 = Signature::new(&b, &keypair2.sig_key); 54 | let sigs_and_ver_keys: Vec<(&Signature, &VerKey)> = vec![(&sig1, &keypair1.vk), (&sig2, &keypair2.vk)] 55 | let asig = MultiSignature::from_sigs(sigs_and_ver_keys); 56 | ``` 57 | 58 | #### Multi-Signature Verification 59 | ```rust 60 | let vks = vec![&keypair1.vk, &keypair2.vk] 61 | MultiSignature::verify(&asig, &b, vks, ¶ms) 62 | OR 63 | let vks = vec![&keypair1.vk, &keypair2.vk] 64 | let avk = AggregatedVerKey::from_verkeys(vks); 65 | assert!(asig.verify(&b, &avk, ¶ms)); 66 | ``` 67 | 68 | ### Multi-Signature and Verification (vulnerable to rogue public key attack but fast) 69 | #### Proof of possession of secret key (signature over verification key) 70 | ##### Generate proof of possession of signing key 71 | ```rust 72 | let keypair = Keypair::new(None); 73 | let sk = keypair.sig_key; 74 | let vk = keypair.ver_key; 75 | 76 | let proof = ProofOfPossession::generate(&vk, &sk); 77 | ``` 78 | 79 | ##### Verify proof of possession of signing key 80 | ```rust 81 | ProofOfPossession::verify(&proof, &vk, ¶ms) 82 | ``` 83 | 84 | #### Multi-Signature 85 | ```rust 86 | let keypair1 = Keypair::new(None); 87 | let keypair2 = Keypair::new(None); 88 | let msg = "Small msg"; 89 | let b = m.as_bytes(); 90 | let sig1 = Signature::new(&b, &keypair1.sig_key); 91 | let sig2 = Signature::new(&b, &keypair2.sig_key); 92 | let sigs: Vec<&Signature> = vec![&sig1, &sig2] 93 | let asig = MultiSignatureFast::from_sigs(sigs); 94 | ``` 95 | 96 | #### Multi-Signature Verification 97 | ```rust 98 | let vks = vec![&keypair1.vk, &keypair2.vk] 99 | MultiSignatureFast::verify(&asig, &b, vks, ¶ms) 100 | OR 101 | let vks = vec![&keypair1.vk, &keypair2.vk] 102 | let avk = AggregatedVerKeyFast::from_verkeys(vks); 103 | assert!(asig.verify(&b, &avk, ¶ms)); 104 | ``` 105 | 106 | #### Batch Verification of signatures 107 | Use `Signature::batch_verify` and `Signature::batch_verify_distinct_msgs` for batch verification. The former 108 | does not assume messages are distinct but the latter does. For their speed comparison, run test `batch_verify` 109 | 110 | #### Threshold signature 111 | ```rust 112 | // To generate keys using a trusted third party 113 | let threshold = 3; 114 | let total = 5; 115 | let params = Params::new("test".as_bytes()); 116 | let (_, signers) = trusted_party_SSS_keygen(threshold, total, ¶ms); 117 | 118 | // Once threshold no of signatures are present, use ThresholdScheme::aggregate_sigs 119 | let threshold_sig = ThresholdScheme::aggregate_sigs(threshold, sigs); 120 | 121 | // Once threshold no of keys are present, use ThresholdScheme::aggregate_vk 122 | let threshold_vk = ThresholdScheme::aggregate_vk( 123 | threshold, 124 | signers 125 | .iter() 126 | .map(|s| (s.id, &s.verkey)) 127 | .collect::>(), 128 | ); 129 | 130 | // Now the threshold sig can be verified like a regular signature 131 | assert!(threshold_sig.verify(&msg, &threshold_vk, ¶ms)); 132 | ``` 133 | 134 | #### Serialization and Deserialization 135 | ```rust 136 | let bs: Vec = vec![1, 5, 190, 200, ......]; 137 | 138 | let sk = SigKey::from_bytes(&bs); 139 | let sk_bytes = sk.tobytes(); 140 | 141 | let vk = VerKey::from_bytes(&bs); 142 | let vk_bytes = vk.tobytes(); 143 | 144 | let sig = Signature::from_bytes(&bs).unwrap(); 145 | let sig_bytes = sig.tobytes(); 146 | ``` 147 | Similar for other objects like AggregatedVerKey, MultiSignature, AggregatedVerKeyFast, MultiSignatureFast 148 | -------------------------------------------------------------------------------- /bls/src/common.rs: -------------------------------------------------------------------------------- 1 | use rand::{CryptoRng, Rng}; 2 | 3 | use amcl_wrapper::errors::SerzDeserzError; 4 | use amcl_wrapper::field_elem::FieldElement; 5 | use amcl_wrapper::group_elem::GroupElement; 6 | use amcl_wrapper::group_elem_g2::G2; 7 | use VerkeyGroup; 8 | 9 | pub(crate) const MESSAGE_DOMAIN_PREFIX: [u8; 2] = [0, 0]; 10 | pub(crate) const VERKEY_DOMAIN_PREFIX: [u8; 2] = [1, 1]; 11 | 12 | pub struct Params { 13 | pub g: VerkeyGroup, 14 | } 15 | 16 | impl Params { 17 | pub fn new(label: &[u8]) -> Self { 18 | // NUMS 19 | let g = VerkeyGroup::from_msg_hash(label); 20 | Params { g } 21 | } 22 | } 23 | 24 | #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] 25 | pub struct SigKey { 26 | pub x: FieldElement, 27 | } 28 | 29 | impl SigKey { 30 | pub fn new(rng: &mut R) -> Self { 31 | Self { 32 | x: FieldElement::random_using_rng(rng), 33 | } 34 | } 35 | 36 | pub fn from_bytes(sk_bytes: &[u8]) -> Result { 37 | FieldElement::from_bytes(sk_bytes).map(|x| SigKey { x }) 38 | } 39 | 40 | pub fn to_bytes(&self) -> Vec { 41 | self.x.to_bytes() 42 | } 43 | } 44 | 45 | #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] 46 | pub struct VerKey { 47 | pub point: VerkeyGroup, 48 | } 49 | 50 | impl AsRef for VerKey { 51 | fn as_ref(&self) -> &VerKey { &self } 52 | } 53 | 54 | impl VerKey { 55 | pub fn from_sigkey(sk: &SigKey, params: &Params) -> Self { 56 | VerKey { 57 | point: ¶ms.g * &sk.x, 58 | } 59 | } 60 | 61 | pub fn from_bytes(vk_bytes: &[u8]) -> Result { 62 | VerkeyGroup::from_bytes(vk_bytes).map(|point| VerKey { point }) 63 | } 64 | 65 | pub fn to_bytes(&self) -> Vec { 66 | self.point.to_bytes() 67 | } 68 | } 69 | 70 | pub struct Keypair { 71 | pub sig_key: SigKey, 72 | pub ver_key: VerKey, 73 | } 74 | 75 | impl Keypair { 76 | pub fn new(rng: &mut R, params: &Params) -> Self { 77 | let sk = SigKey::new(rng); 78 | let vk = VerKey::from_sigkey(&sk, params); 79 | Keypair { 80 | sig_key: sk, 81 | ver_key: vk, 82 | } 83 | } 84 | } 85 | 86 | impl AsRef for Keypair { 87 | fn as_ref(&self) -> &VerKey { &self.ver_key } 88 | } 89 | 90 | #[cfg(test)] 91 | mod tests { 92 | use super::*; 93 | use rand::thread_rng; 94 | 95 | #[test] 96 | fn gen_verkey() { 97 | let mut rng = thread_rng(); 98 | let sk1 = SigKey::new(&mut rng); 99 | let sk2 = SigKey::new(&mut rng); 100 | let params = Params::new("test".as_bytes()); 101 | for mut sk in vec![sk1, sk2] { 102 | let mut vk1 = VerKey::from_sigkey(&sk, ¶ms); 103 | debug!("{}", sk.x.to_hex()); 104 | debug!("{}", &vk1.point.to_hex()); 105 | 106 | let mut vk2 = VerKey::from_sigkey(&sk, ¶ms); 107 | debug!("{}", &vk2.point.to_hex()); 108 | 109 | //assert_eq!(&vk1.point.to_hex(), &vk2.point.to_hex()); 110 | 111 | /*let bs = vk1.to_bytes(); 112 | let bs1 = bs.clone(); 113 | let mut vk3 = VerKey::from(bs1); 114 | assert_eq!(&vk3.point.tostring(), &vk1.point.tostring()); 115 | assert_eq!(&vk3.point.tostring(), &vk2.point.tostring()); 116 | 117 | let mut sk_bytes: [u8; MODBYTES] = [0; MODBYTES]; 118 | sk.x.tobytes(&mut sk_bytes); 119 | let mut s = SigKey::from(sk_bytes.to_vec()); 120 | assert_eq!(&s.x.tostring(), &sk.x.tostring()); 121 | 122 | let bs2: Vec = vk3.into(); 123 | assert_eq!(bs, bs2);*/ 124 | 125 | let bs = vk1.to_bytes(); 126 | let mut vk11 = VerKey::from_bytes(&bs).unwrap(); 127 | // FIXME: Next line fails 128 | //assert_eq!(&vk1.point.to_hex(), &vk11.point.to_hex()); 129 | assert_eq!(vk1.point.to_bytes(), vk11.point.to_bytes()); 130 | 131 | let bs = sk.to_bytes(); 132 | let mut sk1 = SigKey::from_bytes(&bs).unwrap(); 133 | assert_eq!(sk1.x.to_hex(), sk.x.to_hex()); 134 | } 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /bls/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | 3 | // BLS Signatures. 4 | // From: "Dan Boneh, Manu Drijvers, Gregory Neven. Compact Multi-Signatures for Smaller Blockchains". 5 | // Available from: https://eprint.iacr.org/2018/483.pdf 6 | // This link was helpful too https://crypto.stanford.edu/~dabo/pubs/papers/BLSmultisig.html 7 | 8 | // TODO: Add domain separation, for single sig, aggregation sig 9 | // TODO: Add From and Into traits for converting from and to bytes for various structs 10 | // TODO: Support point compression 11 | 12 | extern crate amcl_wrapper; 13 | extern crate rand; 14 | 15 | use amcl_wrapper::extension_field_gt::GT; 16 | 17 | #[cfg(all(feature = "SignatureG1", feature = "SignatureG2"))] 18 | compile_error!("features `SignatureG1` and `SignatureG2` are mutually exclusive"); 19 | 20 | // For feature SignatureG1, signature and message are in G1, verification key in G2 21 | #[cfg(feature = "SignatureG1")] 22 | pub type SignatureGroup = amcl_wrapper::group_elem_g1::G1; 23 | #[cfg(feature = "SignatureG1")] 24 | pub type SignatureGroupVec = amcl_wrapper::group_elem_g1::G1Vector; 25 | #[cfg(feature = "SignatureG1")] 26 | pub type VerkeyGroup = amcl_wrapper::group_elem_g2::G2; 27 | #[cfg(feature = "SignatureG1")] 28 | pub type VerkeyGroupVec = amcl_wrapper::group_elem_g2::G2Vector; 29 | #[cfg(feature = "SignatureG1")] 30 | pub fn ate_2_pairing( 31 | g1: &SignatureGroup, 32 | g2: &VerkeyGroup, 33 | h1: &SignatureGroup, 34 | h2: &VerkeyGroup, 35 | ) -> GT { 36 | GT::ate_2_pairing(g1, g2, h1, h2) 37 | } 38 | #[cfg(feature = "SignatureG1")] 39 | pub fn ate_multi_pairing(elems: Vec<(&SignatureGroup, &VerkeyGroup)>) -> GT { 40 | GT::ate_multi_pairing(elems) 41 | } 42 | 43 | // For feature SignatureG2, signature and message are in G2, verification key in G1 44 | #[cfg(feature = "SignatureG2")] 45 | pub type SignatureGroup = amcl_wrapper::group_elem_g2::G2; 46 | #[cfg(feature = "SignatureG2")] 47 | pub type SignatureGroupVec = amcl_wrapper::group_elem_g2::G2Vector; 48 | #[cfg(feature = "SignatureG2")] 49 | pub type VerkeyGroup = amcl_wrapper::group_elem_g1::G1; 50 | #[cfg(feature = "SignatureG2")] 51 | pub type VerkeyGroupVec = amcl_wrapper::group_elem_g1::G1Vector; 52 | #[cfg(feature = "SignatureG2")] 53 | pub fn ate_2_pairing( 54 | g1: &SignatureGroup, 55 | g2: &VerkeyGroup, 56 | h1: &SignatureGroup, 57 | h2: &VerkeyGroup, 58 | ) -> GT { 59 | GT::ate_2_pairing(g2, g1, h2, h1) 60 | } 61 | #[cfg(feature = "SignatureG2")] 62 | pub fn ate_multi_pairing(elems: Vec<(&SignatureGroup, &VerkeyGroup)>) -> GT { 63 | GT::ate_multi_pairing( 64 | elems 65 | .into_iter() 66 | .map(|(s, v)| (v, s)) 67 | .collect::>(), 68 | ) 69 | } 70 | 71 | #[cfg(test)] 72 | #[macro_use] 73 | extern crate log; 74 | 75 | extern crate serde; 76 | #[macro_use] 77 | extern crate serde_derive; 78 | 79 | extern crate secret_sharing; 80 | 81 | pub mod common; 82 | pub mod multi_sig_fast; 83 | pub mod multi_sig_slow; 84 | pub mod simple; 85 | pub mod threshold_sig; 86 | -------------------------------------------------------------------------------- /bls/src/multi_sig_fast.rs: -------------------------------------------------------------------------------- 1 | use amcl_wrapper::errors::SerzDeserzError; 2 | use amcl_wrapper::extension_field_gt::GT; 3 | use amcl_wrapper::group_elem::GroupElement; 4 | use amcl_wrapper::group_elem_g1::G1; 5 | use amcl_wrapper::group_elem_g2::G2; 6 | 7 | use super::common::{SigKey, VerKey}; 8 | use super::simple::Signature; 9 | use common::Params; 10 | use {ate_2_pairing, SignatureGroup, VerkeyGroup}; 11 | 12 | // This is an older but FASTER way of doing BLS signature aggregation but it IS VULNERABLE to rogue 13 | // public key attack. Use the proof of possession before trusting a new Verkey. 14 | 15 | pub struct ProofOfPossession {} 16 | impl ProofOfPossession { 17 | // Used for domain separation while creating Proof of Possession 18 | const PoP_DOMAIN_PREFIX: [u8; 2] = [2, 2]; 19 | 20 | pub fn generate(verkey: &VerKey, sigkey: &SigKey) -> Signature { 21 | Signature::new( 22 | &[&Self::PoP_DOMAIN_PREFIX, verkey.to_bytes().as_slice()].concat(), 23 | &sigkey, 24 | ) 25 | } 26 | 27 | pub fn verify(proof: &Signature, verkey: &VerKey, params: &Params) -> bool { 28 | proof.verify( 29 | &[&Self::PoP_DOMAIN_PREFIX, verkey.to_bytes().as_slice()].concat(), 30 | verkey, 31 | params, 32 | ) 33 | } 34 | } 35 | 36 | pub struct AggregatedVerKeyFast {} 37 | 38 | impl AggregatedVerKeyFast { 39 | pub fn from_verkeys(ver_keys: Vec<&VerKey>) -> VerKey { 40 | let mut avk = VerkeyGroup::identity(); 41 | for vk in ver_keys { 42 | avk += &vk.point; 43 | } 44 | VerKey { point: avk } 45 | } 46 | } 47 | 48 | pub struct MultiSignatureFast {} 49 | 50 | impl MultiSignatureFast { 51 | pub fn from_sigs(sigs: Vec<&Signature>) -> Signature { 52 | let mut asig = SignatureGroup::identity(); 53 | for s in sigs { 54 | asig += &s.point; 55 | } 56 | Signature { point: asig } 57 | } 58 | 59 | /// An aggregate VerKey is created from `ver_keys`. When verifying signature using the same 60 | /// set of keys frequently generate a verkey once and then use `Signature::verify` 61 | pub fn verify(sig: &Signature, msg: &[u8], ver_keys: Vec<&VerKey>, params: &Params) -> bool { 62 | let avk = AggregatedVerKeyFast::from_verkeys(ver_keys); 63 | sig.verify(msg, &avk, params) 64 | } 65 | 66 | // For verifying multiple multi-signatures from the same signers, 67 | // an aggregated verkey should be created once and then used for each signature verification 68 | } 69 | 70 | #[cfg(test)] 71 | mod tests { 72 | // TODO: Add tests for failure 73 | // TODO: Add more test vectors 74 | use super::*; 75 | use crate::common::Keypair; 76 | use rand::Rng; 77 | use rand::thread_rng; 78 | 79 | #[test] 80 | fn proof_of_possession() { 81 | let mut rng = thread_rng(); 82 | let params = Params::new("test".as_bytes()); 83 | let keypair = Keypair::new(&mut rng, ¶ms); 84 | let sk = keypair.sig_key; 85 | let vk = keypair.ver_key; 86 | 87 | let proof = ProofOfPossession::generate(&vk, &sk); 88 | assert!(ProofOfPossession::verify(&proof, &vk, ¶ms)); 89 | } 90 | 91 | #[test] 92 | fn multi_sign_verify_fast() { 93 | let mut rng = thread_rng(); 94 | let params = Params::new("test".as_bytes()); 95 | let keypair1 = Keypair::new(&mut rng, ¶ms); 96 | let keypair2 = Keypair::new(&mut rng, ¶ms); 97 | let keypair3 = Keypair::new(&mut rng, ¶ms); 98 | let keypair4 = Keypair::new(&mut rng, ¶ms); 99 | let keypair5 = Keypair::new(&mut rng, ¶ms); 100 | 101 | let msg = "Small msg"; 102 | let msg1 = "121220888888822111212"; 103 | let msg2 = "Some message to sign"; 104 | let msg3 = "Some message to sign, making it bigger, ......, still bigger........................, not some entropy, hu2jnnddsssiu8921n ckhddss2222"; 105 | let msg4 = " is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum."; 106 | 107 | for m in vec![msg, msg1, msg2, msg3, msg4] { 108 | let b = m.as_bytes(); 109 | let mut sigs: Vec = Vec::new(); 110 | let mut vks: Vec = Vec::new(); 111 | 112 | for keypair in vec![&keypair1, &keypair2, &keypair3, &keypair4, &keypair5] { 113 | let sig = Signature::new(&b, &keypair.sig_key); 114 | assert!(sig.verify(&b, &keypair.ver_key, ¶ms)); 115 | let v = keypair.ver_key.clone(); 116 | vks.push(v); 117 | sigs.push(sig); 118 | } 119 | 120 | let vks_1: Vec<&VerKey> = vks.iter().map(|v| v).collect(); 121 | let vks_2: Vec<&VerKey> = vks.iter().map(|v| v).collect(); 122 | let sigs: Vec<&Signature> = sigs.iter().map(|s| s).collect(); 123 | let asig = MultiSignatureFast::from_sigs(sigs); 124 | assert!(MultiSignatureFast::verify(&asig, &b, vks_1, ¶ms)); 125 | 126 | let avk = AggregatedVerKeyFast::from_verkeys(vks_2); 127 | assert!(asig.verify(&b, &avk, ¶ms)); 128 | 129 | let bs = asig.to_bytes(); 130 | let sig1 = Signature::from_bytes(&bs).unwrap(); 131 | assert!(sig1.verify(&b, &avk, ¶ms)); 132 | // FIXME: Next line fails, probably something wrong with main amcl codebase. 133 | //assert_eq!(&asig.point.to_hex(), &sig1.point.to_hex()); 134 | 135 | let bs = avk.to_bytes(); 136 | let avk1 = VerKey::from_bytes(&bs).unwrap(); 137 | // FIXME: Next line fails, probably something wrong with main amcl codebase. 138 | //assert_eq!(&avk.point.to_hex(), &avk1.point.to_hex()); 139 | assert_eq!(avk.point.to_bytes(), avk1.point.to_bytes()); 140 | } 141 | } 142 | 143 | #[test] 144 | fn multi_signature_at_infinity() { 145 | let mut rng = thread_rng(); 146 | let params = Params::new("test".as_bytes()); 147 | let keypair1 = Keypair::new(&mut rng, ¶ms); 148 | let keypair2 = Keypair::new(&mut rng, ¶ms); 149 | let msg = "Small msg".as_bytes(); 150 | 151 | let asig = Signature { 152 | point: SignatureGroup::identity(), 153 | }; 154 | let vks: Vec<&VerKey> = vec![&keypair1.ver_key, &keypair2.ver_key]; 155 | assert_eq!(MultiSignatureFast::verify(&asig, &msg, vks, ¶ms), false); 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /bls/src/multi_sig_slow.rs: -------------------------------------------------------------------------------- 1 | use amcl_wrapper::errors::SerzDeserzError; 2 | use amcl_wrapper::extension_field_gt::GT; 3 | use amcl_wrapper::field_elem::{FieldElement, FieldElementVector}; 4 | use amcl_wrapper::group_elem::GroupElement; 5 | use amcl_wrapper::group_elem::GroupElementVector; 6 | use amcl_wrapper::group_elem_g1::G1; 7 | use amcl_wrapper::group_elem_g2::G2; 8 | 9 | use super::common::VerKey; 10 | use super::simple::Signature; 11 | use ate_2_pairing; 12 | use common::{Params, VERKEY_DOMAIN_PREFIX}; 13 | use {SignatureGroup, SignatureGroupVec, VerkeyGroup, VerkeyGroupVec}; 14 | 15 | // This is a newer but SLOWER way of doing BLS signature aggregation. This is NOT VULNERABLE to 16 | // rogue public key attack so does not need proof of possession. 17 | 18 | pub struct AggregatedVerKey {} 19 | 20 | impl AggregatedVerKey { 21 | /// Hashes a verkey with all other verkeys using a Hash function `H:{0, 1}* -> Z_q` 22 | /// Takes a verkey `vk_i` and all verkeys `vk_1, vk_2,...vk_n` (including `vk_i`) and calculates 23 | /// `H(vk_i||vk_1||vk_2...||vk_i||...vk_n)` 24 | pub(crate) fn hashed_verkey_for_aggregation<'a>( 25 | ver_key: &VerKey, 26 | all_ver_key_bytes: impl IntoIterator + 'a)>, 27 | ) -> FieldElement { 28 | // TODO: Sort the verkeys in some order to avoid accidentally passing wrong order of keys 29 | let mut res_vec: Vec = Vec::new(); 30 | 31 | res_vec.extend_from_slice(&ver_key.to_bytes()); 32 | 33 | for vk_bytes in all_ver_key_bytes.into_iter() { 34 | res_vec.extend_from_slice(vk_bytes.as_ref()); 35 | } 36 | Self::hash_verkeys(res_vec.as_slice()) 37 | } 38 | 39 | /// Calculates the aggregated verkey 40 | /// For each `v_i` of the verkeys `vk_1, vk_2,...vk_n` calculate 41 | /// `a_i = vk_i * hashed_verkey_for_aggregation(vk_i, [vk_1, vk_2,...vk_n])` 42 | /// Add all `a_i` 43 | pub fn from_verkeys<'a, T, V>(ver_keys: T) -> VerKey 44 | where 45 | T: IntoIterator, 46 | T::IntoIter: Clone, 47 | V: AsRef + 'a 48 | { 49 | let ver_keys = ver_keys.into_iter(); 50 | // TODO: Sort the verkeys in some order to avoid accidentally passing wrong order of keys 51 | let vk_bytes: Vec<_> = ver_keys.clone().map(|x| x.as_ref().to_bytes()).collect(); 52 | 53 | let (hs, vks): (Vec<_>, Vec<_>) = ver_keys 54 | .map(|vk| ( 55 | AggregatedVerKey::hashed_verkey_for_aggregation(vk.as_ref(), &vk_bytes), 56 | vk.as_ref().point.clone(), 57 | )) 58 | .unzip(); 59 | 60 | let avk = VerkeyGroupVec::from(vks) 61 | .multi_scalar_mul_var_time(&hs.into()) 62 | .unwrap(); 63 | VerKey { point: avk } 64 | } 65 | 66 | /// Hash verkey bytes to field element. H_1 from the paper. 67 | pub(crate) fn hash_verkeys(verkey_bytes: &[u8]) -> FieldElement { 68 | FieldElement::from_msg_hash(&[&VERKEY_DOMAIN_PREFIX, verkey_bytes].concat()) 69 | } 70 | } 71 | 72 | pub struct MultiSignature {} 73 | 74 | impl MultiSignature { 75 | /// The aggregator needs to know of all the signer before it can generate the aggregate signature. 76 | /// Takes individual signatures from each of the signers and their verkey and aggregates the 77 | /// signatures. For each signature `s_i` from signer with verkey `v_i` calculate 78 | /// `a_i = hashed_verkey_for_aggregation(vk_i, [vk_1, vk_2,...vk_n])` 79 | /// `a_si = s_i * a_i` 80 | /// Add all `a_si`. 81 | /// An alternate construction is (as described in the paper) to let signer compute `s_i * a_i` and 82 | /// the aggregator simply adds each signer's output. In that model, signer does more work but in the 83 | /// implemented model, aggregator does more work and the same signer implementation can be used by 84 | /// signers of "slow" and "fast" implementation. 85 | pub fn from_sigs<'a, T, I>(sigs_and_ver_keys: T) -> Signature 86 | where 87 | T: IntoIterator, 88 | T::IntoIter: Clone, 89 | I: AsRef + AsRef + 'a 90 | 91 | { 92 | let sigs_and_ver_keys = sigs_and_ver_keys.into_iter(); 93 | // TODO: Sort the verkeys in some order to avoid accidentally passing wrong order of keys 94 | 95 | let all_ver_key_bytes: Vec<_> = sigs_and_ver_keys 96 | .clone() 97 | .map(|x| AsRef::::as_ref(x).to_bytes()) 98 | .collect(); 99 | 100 | let (hs, sigs): (Vec<_>, Vec<_>) = sigs_and_ver_keys 101 | .map(|x| ( 102 | AggregatedVerKey::hashed_verkey_for_aggregation(x.as_ref(), &all_ver_key_bytes), 103 | AsRef::::as_ref(x).point.clone(), 104 | )) 105 | .unzip(); 106 | 107 | let asig = SignatureGroupVec::from(sigs) 108 | .multi_scalar_mul_var_time(&hs.into()) 109 | .unwrap(); 110 | 111 | Signature { point: asig } 112 | } 113 | 114 | /// An aggregate VerKey is created from `ver_keys`. When verifying signature using the same 115 | /// set of keys frequently generate a verkey once and then use `Signature::verify` 116 | pub fn verify<'a, T, K>(sig: &Signature, msg: &[u8], ver_keys: T, params: &Params) -> bool 117 | where 118 | T: IntoIterator, 119 | T::IntoIter: Clone, 120 | K: AsRef + 'a 121 | { 122 | let avk = AggregatedVerKey::from_verkeys(ver_keys); 123 | sig.verify(msg, &avk, params) 124 | } 125 | 126 | // For verifying multiple aggregate signatures from the same signers, 127 | // an aggregated verkey should be created once and then used for each signature verification 128 | } 129 | 130 | #[cfg(test)] 131 | mod tests { 132 | // TODO: Add tests for failure 133 | // TODO: Add more test vectors 134 | use super::*; 135 | use crate::common::Keypair; 136 | use rand::Rng; 137 | use rand::thread_rng; 138 | 139 | #[test] 140 | fn multi_sign_verify() { 141 | let mut rng = thread_rng(); 142 | let params = Params::new("test".as_bytes()); 143 | let keypair1 = Keypair::new(&mut rng, ¶ms); 144 | let keypair2 = Keypair::new(&mut rng, ¶ms); 145 | let keypair3 = Keypair::new(&mut rng, ¶ms); 146 | let keypair4 = Keypair::new(&mut rng, ¶ms); 147 | let keypair5 = Keypair::new(&mut rng, ¶ms); 148 | 149 | let msg = "Small msg"; 150 | let msg1 = "121220888888822111212"; 151 | let msg2 = "Some message to sign"; 152 | let msg3 = "Some message to sign, making it bigger, ......, still bigger........................, not some entropy, hu2jnnddsssiu8921n ckhddss2222"; 153 | let msg4 = " is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum."; 154 | 155 | for m in vec![msg, msg1, msg2, msg3, msg4] { 156 | let b = m.as_bytes(); 157 | let mut sigs_and_ver_keys: Vec<(Signature, VerKey)> = Vec::new(); 158 | let mut vks: Vec = Vec::new(); 159 | 160 | for keypair in vec![&keypair1, &keypair2, &keypair3, &keypair4, &keypair5] { 161 | let sig = Signature::new(&b, &keypair.sig_key); 162 | assert!(sig.verify(&b, &keypair.ver_key, ¶ms)); 163 | let v = keypair.ver_key.clone(); 164 | vks.push(v); 165 | let v = keypair.ver_key.clone(); 166 | sigs_and_ver_keys.push((sig, v)); 167 | } 168 | 169 | let mut asig = MultiSignature::from_sigs(&sigs_and_ver_keys); 170 | assert!(MultiSignature::verify(&asig, &b, &sigs_and_ver_keys, ¶ms)); 171 | 172 | let mut avk = AggregatedVerKey::from_verkeys(&sigs_and_ver_keys); 173 | assert!(asig.verify(&b, &avk, ¶ms)); 174 | 175 | let bs = asig.to_bytes(); 176 | let mut sig1 = Signature::from_bytes(&bs).unwrap(); 177 | assert!(sig1.verify(&b, &avk, ¶ms)); 178 | // FIXME: Next line fails, probably something wrong with main amcl codebase. 179 | //assert_eq!(&asig.point.to_hex(), &sig1.point.to_hex()); 180 | 181 | let bs = avk.to_bytes(); 182 | let mut avk1 = VerKey::from_bytes(&bs).unwrap(); 183 | // FIXME: Next line fails, probably something wrong with main amcl codebase. 184 | //assert_eq!(&avk.point.to_hex(), &avk1.point.to_hex()); 185 | assert_eq!(avk.point.to_bytes(), avk1.point.to_bytes()); 186 | } 187 | } 188 | 189 | #[test] 190 | fn multi_signature_at_infinity() { 191 | let mut rng = thread_rng(); 192 | let params = Params::new("test".as_bytes()); 193 | let keypair1 = Keypair::new(&mut rng, ¶ms); 194 | let keypair2 = Keypair::new(&mut rng, ¶ms); 195 | let msg = "Small msg".as_bytes(); 196 | 197 | let asig = Signature { 198 | point: SignatureGroup::identity(), 199 | }; 200 | let vks = vec![keypair1.ver_key, keypair2.ver_key]; 201 | assert_eq!(MultiSignature::verify(&asig, &msg, &vks, ¶ms), false); 202 | } 203 | 204 | // TODO: New test that has benchmark for using AggregatedVerKey 205 | } 206 | -------------------------------------------------------------------------------- /bls/src/simple.rs: -------------------------------------------------------------------------------- 1 | use amcl_wrapper::errors::SerzDeserzError; 2 | use amcl_wrapper::extension_field_gt::GT; 3 | use amcl_wrapper::group_elem::{GroupElement, GroupElementVector}; 4 | use amcl_wrapper::group_elem_g1::G1; 5 | use amcl_wrapper::group_elem_g2::G2; 6 | 7 | use super::common::{SigKey, VerKey}; 8 | use amcl_wrapper::field_elem::{FieldElement, FieldElementVector}; 9 | use common::{Params, MESSAGE_DOMAIN_PREFIX}; 10 | use {ate_2_pairing, SignatureGroup, SignatureGroupVec}; 11 | use {ate_multi_pairing, VerkeyGroup}; 12 | 13 | #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] 14 | pub struct Signature { 15 | pub point: SignatureGroup, 16 | } 17 | 18 | impl Signature { 19 | // Signature = H_0(msg) * sk 20 | pub fn new(msg: &[u8], sig_key: &SigKey) -> Self { 21 | let hash_point = Self::hash_message(msg); 22 | let sig = hash_point * &sig_key.x; 23 | // This is different from the paper, the other exponentiation happens in aggregation. 24 | // This avoids the signer to know beforehand of all other participants 25 | Signature { point: sig } 26 | } 27 | 28 | pub fn verify(&self, msg: &[u8], ver_key: &VerKey, params: &Params) -> bool { 29 | // TODO: Check if point exists on curve, maybe use `ECP::new_big` and x cord of verkey 30 | if self.point.is_identity() { 31 | println!("Signature point at infinity"); 32 | return false; 33 | } 34 | let msg_hash_point = Self::hash_message(msg); 35 | // e(self.point, params.g) == e(msg_hash_point, ver_key.point) => 36 | // e(msg_hash_point, ver_key.point) * e(self.point, params.g)^-1 == 1 => 37 | // e(msg_hash_point, ver_key.point) * e(self.point, params.g^-1) == 1 38 | ate_2_pairing( 39 | &msg_hash_point, 40 | &ver_key.point, 41 | &self.point, 42 | ¶ms.g.negation(), 43 | ) 44 | .is_one() 45 | } 46 | 47 | /// Batch verification of signatures. Takes a vector of 3-tuple where each tuple has a message, 48 | /// signature and public key. Messages can be same or different 49 | pub fn batch_verify(msgs_sigs: Vec<(&[u8], &Signature, &VerKey)>, params: &Params) -> bool { 50 | let r = FieldElement::random(); 51 | let r_vec = FieldElementVector::new_vandermonde_vector(&r, msgs_sigs.len()); 52 | let mut sigs = SignatureGroupVec::with_capacity(msgs_sigs.len()); 53 | let mut hs = vec![]; 54 | let mut vs = vec![]; 55 | for (i, (msg, sig, vk)) in msgs_sigs.iter().enumerate() { 56 | sigs.push(sig.point.clone()); 57 | hs.push(Signature::hash_message(msg)); 58 | // The multiplication with &r_vec[i] can be moved to message instead of verkey but 59 | // since verkey is in group G1 by default and operations in G1 are cheaper. 60 | // A better way would be to have code conditional on features such that 61 | // multiplication is moved to message when messages are in G1 and verkey in G2. 62 | vs.push(&vk.point * &r_vec[i]); 63 | } 64 | let aggr_sig = sigs.multi_scalar_mul_var_time(&r_vec).unwrap(); 65 | let mut pairings = hs 66 | .iter() 67 | .zip(vs.iter()) 68 | .map(|(h, v)| (h, v)) 69 | .collect::>(); 70 | let neg_g = params.g.negation(); 71 | pairings.push((&aggr_sig, &neg_g)); 72 | ate_multi_pairing(pairings).is_one() 73 | } 74 | 75 | /// Batch verification of signatures. Takes a vector of 3-tuple where each tuple has a message, 76 | /// signature and public key. Assumes all messages to be distinct 77 | pub fn batch_verify_distinct_msgs( 78 | msgs_sigs: Vec<(&[u8], &Signature, &VerKey)>, 79 | params: &Params, 80 | ) -> bool { 81 | let mut aggr_sig = SignatureGroup::new(); 82 | let mut hs = vec![]; 83 | let mut vs = vec![]; 84 | for (msg, sig, vk) in msgs_sigs { 85 | aggr_sig += &sig.point; 86 | hs.push(Signature::hash_message(msg)); 87 | vs.push(vk); 88 | } 89 | let mut pairings = hs 90 | .iter() 91 | .zip(vs) 92 | .map(|(h, v)| (h, &v.point)) 93 | .collect::>(); 94 | let neg_g = params.g.negation(); 95 | pairings.push((&aggr_sig, &neg_g)); 96 | ate_multi_pairing(pairings).is_one() 97 | } 98 | 99 | pub fn from_bytes(sig_bytes: &[u8]) -> Result { 100 | SignatureGroup::from_bytes(sig_bytes).map(|point| Signature { point }) 101 | } 102 | 103 | pub fn to_bytes(&self) -> Vec { 104 | self.point.to_bytes() 105 | } 106 | 107 | /// Hash message to group element. H_0 from the paper. 108 | pub(crate) fn hash_message(msg: &[u8]) -> SignatureGroup { 109 | SignatureGroup::from_msg_hash(&[&MESSAGE_DOMAIN_PREFIX, msg].concat()) 110 | } 111 | } 112 | 113 | impl AsRef for Signature { 114 | fn as_ref(&self) -> &Signature { &self } 115 | } 116 | 117 | impl AsRef for (Signature, VerKey) { 118 | fn as_ref(&self) -> &Signature { &self.0 } 119 | } 120 | 121 | impl AsRef for (VerKey, Signature) { 122 | fn as_ref(&self) -> &Signature { &self.1 } 123 | } 124 | 125 | impl AsRef for (Signature, VerKey) { 126 | fn as_ref(&self) -> &VerKey { &self.1 } 127 | } 128 | 129 | impl AsRef for (VerKey, Signature) { 130 | fn as_ref(&self) -> &VerKey { &self.0 } 131 | } 132 | 133 | #[cfg(test)] 134 | mod tests { 135 | // TODO: Add tests for failure 136 | // TODO: Add more test vectors 137 | use super::*; 138 | use crate::common::Keypair; 139 | use rand::Rng; 140 | use rand::thread_rng; 141 | use std::time::Instant; 142 | 143 | #[test] 144 | fn sign_verify() { 145 | let mut rng = thread_rng(); 146 | let params = Params::new("test".as_bytes()); 147 | let keypair = Keypair::new(&mut rng, ¶ms); 148 | let sk = keypair.sig_key; 149 | let vk = keypair.ver_key; 150 | 151 | let msg = "Small msg"; 152 | let msg1 = "121220888888822111212"; 153 | let msg2 = "Some message to sign"; 154 | let msg3 = "Some message to sign, making it bigger, ......, still bigger........................, not some entropy, hu2jnnddsssiu8921n ckhddss2222"; 155 | for m in vec![msg, msg1, msg2, msg3] { 156 | let b = m.as_bytes(); 157 | let mut sig = Signature::new(&b, &sk); 158 | assert!(sig.verify(&b, &vk, ¶ms)); 159 | 160 | let bs = sig.to_bytes(); 161 | let sig1 = Signature::from_bytes(&bs).unwrap(); 162 | // FIXME: Next line fails 163 | //assert_eq!(&sig.point.to_hex(), &sig1.point.to_hex()); 164 | assert_eq!(&sig.point.to_bytes(), &sig1.point.to_bytes()); 165 | } 166 | } 167 | 168 | #[test] 169 | fn verification_failure() { 170 | let mut rng = thread_rng(); 171 | let params = Params::new("test".as_bytes()); 172 | let keypair = Keypair::new(&mut rng, ¶ms); 173 | let sk = keypair.sig_key; 174 | let vk = keypair.ver_key; 175 | 176 | let mut msg = "Some msg"; 177 | let sig = Signature::new(&msg.as_bytes(), &sk); 178 | msg = "Other msg"; 179 | assert_eq!(sig.verify(&msg.as_bytes(), &vk, ¶ms), false); 180 | msg = ""; 181 | assert_eq!(sig.verify(&msg.as_bytes(), &vk, ¶ms), false); 182 | } 183 | 184 | #[test] 185 | fn signature_at_infinity() { 186 | let mut rng = thread_rng(); 187 | let params = Params::new("test".as_bytes()); 188 | let keypair = Keypair::new(&mut rng, ¶ms); 189 | let vk = keypair.ver_key; 190 | 191 | let msg = "Small msg".as_bytes(); 192 | let sig = Signature { 193 | point: SignatureGroup::identity(), 194 | }; 195 | assert_eq!(sig.verify(&msg, &vk, ¶ms), false); 196 | } 197 | 198 | #[test] 199 | fn batch_verify() { 200 | let params = Params::new("test".as_bytes()); 201 | let mut keypairs = vec![]; 202 | let mut msgs = vec![]; 203 | let mut sigs = vec![]; 204 | let mut rng = rand::thread_rng(); 205 | let count = 5; 206 | for _ in 0..count { 207 | let keypair = Keypair::new(&mut rng, ¶ms); 208 | let msg = (0..10).map(|_| rng.gen_range(1, 100)).collect::>(); 209 | let sig = Signature::new(&msg, &keypair.sig_key); 210 | sigs.push(sig); 211 | msgs.push(msg); 212 | keypairs.push(keypair); 213 | } 214 | 215 | let start = Instant::now(); 216 | for i in 0..count { 217 | assert!(sigs[i].verify(&msgs[i], &keypairs[i].ver_key, ¶ms)); 218 | } 219 | println!( 220 | "Naive verify for {} sigs takes {:?}", 221 | count, 222 | start.elapsed() 223 | ); 224 | 225 | let start = Instant::now(); 226 | let msgs_sigs = (0..count) 227 | .map(|i| (msgs[i].as_slice(), &sigs[i], &keypairs[i].ver_key)) 228 | .collect::>(); 229 | assert!(Signature::batch_verify(msgs_sigs, ¶ms)); 230 | println!( 231 | "Batch verify for {} sigs takes {:?}", 232 | count, 233 | start.elapsed() 234 | ); 235 | 236 | let start = Instant::now(); 237 | let msgs_sigs = (0..count) 238 | .map(|i| (msgs[i].as_slice(), &sigs[i], &keypairs[i].ver_key)) 239 | .collect::>(); 240 | assert!(Signature::batch_verify_distinct_msgs(msgs_sigs, ¶ms)); 241 | println!( 242 | "Batch verify assuming distinct messages for {} sigs takes {:?}", 243 | count, 244 | start.elapsed() 245 | ); 246 | } 247 | } 248 | -------------------------------------------------------------------------------- /bls/src/threshold_sig.rs: -------------------------------------------------------------------------------- 1 | use crate::{SignatureGroupVec, VerkeyGroupVec}; 2 | use amcl_wrapper::field_elem::{FieldElement, FieldElementVector}; 3 | use amcl_wrapper::group_elem::GroupElementVector; 4 | use common::{Params, SigKey, VerKey}; 5 | use secret_sharing::polynomial::Polynomial; 6 | use secret_sharing::shamir_secret_sharing::get_shared_secret; 7 | use simple::Signature; 8 | use std::collections::{HashMap, HashSet}; 9 | 10 | pub struct Signer { 11 | pub id: usize, 12 | pub sigkey: SigKey, 13 | pub verkey: VerKey, 14 | } 15 | 16 | /// Takes shares for x and generate signing and verification keys 17 | fn keygen_from_shares( 18 | num_signers: usize, 19 | mut x_shares: HashMap, 20 | params: &Params, 21 | ) -> Vec { 22 | let mut signers = vec![]; 23 | for i in 0..num_signers { 24 | let id = i + 1; 25 | let x_i = x_shares.remove(&id).unwrap(); 26 | let g_x_i = ¶ms.g * &x_i; 27 | 28 | signers.push(Signer { 29 | id, 30 | sigkey: SigKey { x: x_i }, 31 | verkey: VerKey { point: g_x_i }, 32 | }) 33 | } 34 | signers 35 | } 36 | 37 | /// Keygen done by trusted party using Shamir secret sharing. Creates signing and verification 38 | /// keys for each signer. The trusted party will know every signer's secret keys and the 39 | /// aggregate secret keys and can create signatures. 40 | /// Outputs 2 items, first is the shared secret and should be destroyed. 41 | /// The second contains the keys, 1 item corresponding to each signer. 42 | pub fn trusted_party_SSS_keygen( 43 | threshold: usize, 44 | total: usize, 45 | params: &Params, 46 | ) -> (FieldElement, Vec) { 47 | let (secret_x, x_shares) = get_shared_secret(threshold, total); 48 | (secret_x, keygen_from_shares(total, x_shares, params)) 49 | } 50 | 51 | pub struct ThresholdScheme {} 52 | 53 | impl ThresholdScheme { 54 | pub fn aggregate_sigs(threshold: usize, sigs: Vec<(usize, Signature)>) -> Signature { 55 | assert!(sigs.len() >= threshold); 56 | let mut s_bases = SignatureGroupVec::with_capacity(threshold); 57 | let mut s_exps = FieldElementVector::with_capacity(threshold); 58 | 59 | let signer_ids = sigs 60 | .iter() 61 | .take(threshold) 62 | .map(|(i, _)| *i) 63 | .collect::>(); 64 | for (id, sig) in sigs.into_iter().take(threshold) { 65 | let l = Polynomial::lagrange_basis_at_0(signer_ids.clone(), id); 66 | s_bases.push(sig.point.clone()); 67 | s_exps.push(l); 68 | } 69 | // theshold signature = sig[i]^l for all i 70 | Signature { 71 | point: s_bases.multi_scalar_mul_const_time(&s_exps).unwrap(), 72 | } 73 | } 74 | 75 | pub fn aggregate_vk(threshold: usize, keys: Vec<(usize, &VerKey)>) -> VerKey { 76 | assert!(keys.len() >= threshold); 77 | 78 | let mut vk_bases = VerkeyGroupVec::with_capacity(threshold); 79 | let mut vk_exps = FieldElementVector::with_capacity(threshold); 80 | 81 | let signer_ids = keys 82 | .iter() 83 | .take(threshold) 84 | .map(|(i, _)| *i) 85 | .collect::>(); 86 | for (id, vk) in keys.into_iter().take(threshold) { 87 | let l = Polynomial::lagrange_basis_at_0(signer_ids.clone(), id); 88 | vk_bases.push(vk.point.clone()); 89 | vk_exps.push(l.clone()); 90 | } 91 | 92 | // threshold verkey = vk_1^l_1 * vk_2^l_2 * ... vk_i^l_i for i in threshold 93 | 94 | VerKey { 95 | point: vk_bases.multi_scalar_mul_var_time(&vk_exps).unwrap(), 96 | } 97 | } 98 | } 99 | 100 | #[cfg(test)] 101 | mod tests { 102 | use super::*; 103 | 104 | fn check_threshold_key_gen( 105 | threshold: usize, 106 | secret_x: FieldElement, 107 | signers: &[Signer], 108 | params: &Params, 109 | ) { 110 | let threshold_vk = ThresholdScheme::aggregate_vk( 111 | threshold, 112 | signers 113 | .iter() 114 | .take(threshold) 115 | .map(|s| (s.id, &s.verkey)) 116 | .collect::>(), 117 | ); 118 | 119 | let expected_vk = ¶ms.g * &secret_x; 120 | assert_eq!(expected_vk, threshold_vk.point); 121 | } 122 | 123 | fn check_signing_on_random_msgs(threshold: usize, signers: &[Signer], params: &Params) { 124 | let msg = FieldElement::random().to_bytes(); 125 | 126 | let mut sigs = vec![]; 127 | for i in 0..threshold { 128 | let sig = Signature::new(&msg, &signers[i].sigkey); 129 | assert!(sig.verify(&msg, &signers[i].verkey, ¶ms)); 130 | sigs.push((signers[i].id, sig)); 131 | } 132 | 133 | let threshold_sig = ThresholdScheme::aggregate_sigs(threshold, sigs); 134 | 135 | let threshold_vk = ThresholdScheme::aggregate_vk( 136 | threshold, 137 | signers 138 | .iter() 139 | .map(|s| (s.id, &s.verkey)) 140 | .collect::>(), 141 | ); 142 | 143 | assert!(threshold_sig.verify(&msg, &threshold_vk, ¶ms)); 144 | } 145 | 146 | fn check_threshold_key_gen_gaps_in_ids( 147 | threshold: usize, 148 | secret_x: FieldElement, 149 | keys_to_aggr: Vec<(usize, &VerKey)>, 150 | params: &Params, 151 | ) { 152 | let threshold_vk = ThresholdScheme::aggregate_vk(threshold, keys_to_aggr); 153 | 154 | let expected_vk = ¶ms.g * &secret_x; 155 | assert_eq!(expected_vk, threshold_vk.point); 156 | } 157 | 158 | #[test] 159 | fn test_verkey_aggregation_shamir_secret_sharing_keygen() { 160 | let threshold = 3; 161 | let total = 5; 162 | let params = Params::new("test".as_bytes()); 163 | 164 | let (secret_x, signers) = trusted_party_SSS_keygen(threshold, total, ¶ms); 165 | 166 | check_threshold_key_gen(threshold, secret_x, &signers, ¶ms) 167 | } 168 | 169 | #[test] 170 | fn test_sign_verify_shamir_secret_sharing_keygen() { 171 | let threshold = 3; 172 | let total = 5; 173 | let params = Params::new("test".as_bytes()); 174 | 175 | let (_, signers) = trusted_party_SSS_keygen(threshold, total, ¶ms); 176 | 177 | check_signing_on_random_msgs(threshold, &signers, ¶ms) 178 | } 179 | 180 | #[test] 181 | fn test_verkey_aggregation_gaps_in_ids_shamir_secret_sharing_keygen() { 182 | let threshold = 3; 183 | let total = 5; 184 | let params = Params::new("test".as_bytes()); 185 | let (secret_x, signers) = trusted_party_SSS_keygen(threshold, total, ¶ms); 186 | 187 | let mut keys = vec![]; 188 | keys.push((signers[0].id, &signers[0].verkey)); 189 | keys.push((signers[2].id, &signers[2].verkey)); 190 | keys.push((signers[4].id, &signers[4].verkey)); 191 | 192 | check_threshold_key_gen_gaps_in_ids(threshold, secret_x, keys, ¶ms); 193 | } 194 | 195 | #[test] 196 | fn test_sign_verify_1() { 197 | // Request signature from 1 threshold group of signers and form aggregate verkey from 198 | // different threshold group of signers. 199 | let threshold = 3; 200 | let total = 6; 201 | let params = Params::new("test".as_bytes()); 202 | let (_, signers) = trusted_party_SSS_keygen(threshold, total, ¶ms); 203 | 204 | let msg = FieldElement::random().to_bytes(); 205 | 206 | // Signers from which signature will be requested. 207 | let mut signer_ids = HashSet::new(); 208 | signer_ids.insert(1); 209 | signer_ids.insert(3); 210 | signer_ids.insert(5); 211 | 212 | let mut sigs = vec![]; 213 | for i in &signer_ids { 214 | let sig = Signature::new(&msg, &signers[*i].sigkey); 215 | assert!(sig.verify(&msg, &signers[*i].verkey, ¶ms)); 216 | sigs.push((signers[*i].id, sig)); 217 | } 218 | 219 | let threshold_sig = ThresholdScheme::aggregate_sigs(threshold, sigs); 220 | 221 | let mut keys = vec![]; 222 | keys.push((signers[1].id, &signers[1].verkey)); // signer id is 2 223 | keys.push((signers[3].id, &signers[3].verkey)); // signer id is 4 224 | keys.push((signers[5].id, &signers[5].verkey)); // signer id is 6 225 | 226 | let threshold_vk = ThresholdScheme::aggregate_vk(threshold, keys); 227 | 228 | assert!(threshold_sig.verify(&msg, &threshold_vk, ¶ms)); 229 | } 230 | 231 | // TODO: Add tests for cases when threshold is not met 232 | } 233 | -------------------------------------------------------------------------------- /delg_cred_cdd/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "delg_cred_cdd" 3 | version = "0.1.0" 4 | authors = ["lovesh "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | rand = "0.6" 9 | log = "*" 10 | failure = "0.1.5" 11 | serde = "1.0" 12 | serde_derive = "1.0" 13 | 14 | [dependencies.amcl_wrapper] 15 | version = "0.1.6" 16 | default-features = false 17 | features = ["bls381"] -------------------------------------------------------------------------------- /delg_cred_cdd/README.md: -------------------------------------------------------------------------------- 1 | [Practical UC-Secure Delegatable Credentials with Attributes and Their Application to Blockchain](https://acmccs.github.io/papers/p683-camenischA.pdf) 2 | 3 | **This implementation is not UC-secure but only implements the delegatable credential part** 4 | 5 | ### Brief description of the API 6 | 1. [Groth1 and Groth2 signatures](src/groth_sig.rs). 7 | - 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. 8 | - Signing keys can be generated by calling `GrothS1::keygen` or `GrothS2::keygen`. Takes the corresponding setup parameters. 9 | - 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. 10 | - 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 11 | 2. [Issuers and delegation](src/issuer.rs). 12 | - 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)`. 13 | - Issuers generate their keys with `EvenLevelIssuer::keygen` or `OddLevelIssuer::keygen`. 14 | - Issuers can delegate by calling `delegate` method that takes the attributes to sign, who to delegate to etc resulting in a credential. 15 | - 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`. 16 | - 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`. 17 | - To verify the correctness of link, call `verify` on it with delegator public key, delegatee public key and setup params. 18 | - 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. 19 | - To verify that all delegations are valid in the chain, call `verify_delegations` on the chain. 20 | 3. [Attribute tokens](src/attribute_token.rs) 21 | - Call `AttributeToken::new` with the `CredChain` and setup parameters to initialize attribute token generation. 22 | - Attribute tokens are generated for all levels of the given chain. To generate attribute token for a subset of the chain, first get a truncated version of the chain by 23 | calling `CredChain::get_truncated_chain` and then use that to create the attribute token. eg. if chain length is 10 and attribute token is 24 | needed for the first 5 levels of the chain, get a truncated chain with `CredChain::get_truncated_chain(5)` and then use the result in `AttributeToken::new` 25 | - Attribute token generation happens in 2 phases. In the commitment phase all commitments are generated and the response phase accepts the challenge. These are intentionally decoupled so that this can be used in a higher level protocol. 26 | - To generate the commitment, call `commitment` method with the indices of the revealed attributes at each level. The indices at each level are a set of integers. 27 | The `commitment` method results in `AttributeTokenComm` object which can be converted to bytes by calling `to_bytes` so that those bytes can be used in challenge computation. Or for testing, `AttributeToken::gen_challenge` can be used that takes `AttributeTokenComm` 28 | - To generate response, call the `response`. 29 | - The verifies with then call `AttributeToken::reconstruct_commitment` to reconstruct the commitment that the prover would have created. He can now hash it into the challenge to compare with the prover's challenge. 30 | - Commitment computation can be sped up by using precomputation of some of the pairings. Precomputation can be done on the setup parameters which can be used for computing commitments 31 | involving any `CredChain` or it can be done on signatures as well which makes those precomputations relevant to that `CredChain` only. 32 | Thus the commitment can be created using 3 methods, either `AttributeToken::commitment` that does not accept any precomputation, 33 | `AttributeToken::commitment_with_precomputation_on_setup_params` that only accepts precomputation done on setup params (using `PrecompOnSetupParams::new`) and 34 | `AttributeToken::commitment_with_precomputation` that accepts precomputation done on setup params (using `PrecompOnSetupParams::new`) and on `CredChain` using `PrecompOnCredChain::new` 35 | 36 | Refer the tests to for details of the API. 37 | 38 | ### Benchmarks 39 | Tests print the timing of various operations. Run tests in release mode to get the timing information. 40 | 41 | ``` 42 | RUST_TEST_THREADS=1 cargo test --release -- --nocapture 43 | ``` 44 | 45 | ### Pending 46 | 1. Add support for verifying the attribute token with a single multi-pairing as suggested in the TODO. -------------------------------------------------------------------------------- /delg_cred_cdd/src/errors.rs: -------------------------------------------------------------------------------- 1 | use failure::Error; 2 | 3 | #[derive(Debug, Fail)] 4 | pub enum DelgError { 5 | #[fail( 6 | display = "Setup parameters valid for {} messages but given {} messages", 7 | expected, given 8 | )] 9 | UnsupportedNoOfMessages { expected: usize, given: usize }, 10 | 11 | #[fail(display = "Expected even level but odd given {}", given)] 12 | ExpectedEvenLevel { given: usize }, 13 | 14 | #[fail(display = "Expected odd level but even given {}", given)] 15 | ExpectedOddLevel { given: usize }, 16 | 17 | #[fail(display = "Expected level {} but given {}", expected, given)] 18 | UnexpectedLevel { expected: usize, given: usize }, 19 | 20 | #[fail( 21 | display = "Number of attributes should be less than {} but given {}", 22 | expected, given 23 | )] 24 | MoreAttributesThanExpected { expected: usize, given: usize }, 25 | 26 | #[fail(display = "Delegatee verkey not found in delegation link")] 27 | VerkeyNotFoundInDelegationLink {}, 28 | 29 | #[fail(display = "No links in the delegation chain")] 30 | ChainEmpty {}, 31 | 32 | #[fail(display = "No odd delegation links in the delegation chain")] 33 | NoOddLinksInChain {}, 34 | 35 | #[fail(display = "No even delegation links in the delegation chain")] 36 | NoEvenLinksInChain {}, 37 | 38 | #[fail( 39 | display = "Requested odd link at index {} but only {} odd links present", 40 | given_index, size 41 | )] 42 | NoOddLinkInChainAtGivenIndex { given_index: usize, size: usize }, 43 | 44 | #[fail( 45 | display = "Requested even link at index {} but only {} even links present", 46 | given_index, size 47 | )] 48 | NoEvenLinkInChainAtGivenIndex { given_index: usize, size: usize }, 49 | 50 | #[fail(display = "Expected {} verkeys but found {}", expected, given)] 51 | IncorrectNumberOfVerkeys { expected: usize, given: usize }, 52 | 53 | #[fail( 54 | display = "Expected {} odd level verkeys but found {}", 55 | expected, given 56 | )] 57 | IncorrectNumberOfOddLevelVerkeys { expected: usize, given: usize }, 58 | 59 | #[fail( 60 | display = "Expected {} even level verkeys but found {}", 61 | expected, given 62 | )] 63 | IncorrectNumberOfEvenLevelVerkeys { expected: usize, given: usize }, 64 | 65 | #[fail( 66 | display = "Same no of bases and exponents required. {} bases and {} exponents", 67 | bases, exponents 68 | )] 69 | UnequalNoOfBasesExponents { bases: usize, exponents: usize }, 70 | 71 | #[fail( 72 | display = "Chain size is {} but expected size at least {}", 73 | actual_size, expected_size 74 | )] 75 | ChainIsShorterThanExpected { 76 | actual_size: usize, 77 | expected_size: usize, 78 | }, 79 | 80 | #[fail(display = "Expected {} `s` commitments but found {}", expected, given)] 81 | IncorrectNumberOfSCommitments { expected: usize, given: usize }, 82 | 83 | #[fail(display = "Expected {} `t` commitments but found {}", expected, given)] 84 | IncorrectNumberOfTCommitments { expected: usize, given: usize }, 85 | 86 | #[fail(display = "Expected {} blinded `r` but found {}", expected, given)] 87 | IncorrectNumberOfBlindedR { expected: usize, given: usize }, 88 | 89 | #[fail( 90 | display = "Expected {} sets of revealed attributes but found {}", 91 | expected, given 92 | )] 93 | IncorrectNumberOfRevealedAttributeSets { expected: usize, given: usize }, 94 | 95 | #[fail( 96 | display = "Number of unrevealed attributes should be less than {} but given {}", 97 | expected, given 98 | )] 99 | MoreUnrevealedAttributesThanExpected { expected: usize, given: usize }, 100 | 101 | #[fail( 102 | display = "Unequal number of commitments and responses for {:?}. {} commitments, {} responses", 103 | entity_type, count_commitments, count_responses 104 | )] 105 | UnequalNoOfCommitmentAndResponses { 106 | count_commitments: usize, 107 | count_responses: usize, 108 | entity_type: String, 109 | }, 110 | 111 | #[fail( 112 | display = "Expected {} odd values but found {} for {:?}", 113 | expected, given, entity_type 114 | )] 115 | IncorrectNumberOfOddValues { 116 | expected: usize, 117 | given: usize, 118 | entity_type: String, 119 | }, 120 | 121 | #[fail( 122 | display = "Expected {} even values but found {} for {:?}", 123 | expected, given, entity_type 124 | )] 125 | IncorrectNumberOfEvenValues { 126 | expected: usize, 127 | given: usize, 128 | entity_type: String, 129 | }, 130 | 131 | #[fail(display = "Error with message {:?}", msg)] 132 | GeneralError { msg: String }, 133 | } 134 | 135 | pub type DelgResult = Result; 136 | -------------------------------------------------------------------------------- /delg_cred_cdd/src/groth_sig.rs: -------------------------------------------------------------------------------- 1 | use crate::errors::{DelgError, DelgResult}; 2 | use amcl_wrapper::extension_field_gt::GT; 3 | use amcl_wrapper::field_elem::{FieldElement, FieldElementVector}; 4 | use amcl_wrapper::group_elem::{GroupElement, GroupElementVector}; 5 | use amcl_wrapper::group_elem_g1::{G1LookupTable, G1Vector, G1}; 6 | use amcl_wrapper::group_elem_g2::{G2Vector, G2}; 7 | 8 | #[derive(Clone, Debug, Serialize, Deserialize)] 9 | pub struct GrothSigkey(pub FieldElement); 10 | 11 | macro_rules! impl_GrothS { 12 | ( $GrothSetupParams:ident, $GrothVerkey:ident, $GrothSig:ident, $GrothS:ident, $vk_group:ident, $msg_group:ident, $GVector:ident ) => { 13 | #[derive(Clone, Debug, Serialize, Deserialize)] 14 | pub struct $GrothSetupParams { 15 | pub g1: G1, 16 | pub g2: G2, 17 | pub y: $GVector, 18 | } 19 | 20 | #[derive(Clone, Debug, Serialize, Deserialize)] 21 | pub struct $GrothVerkey(pub $vk_group); 22 | 23 | #[derive(Clone, Debug, Serialize, Deserialize)] 24 | pub struct $GrothSig { 25 | pub R: $vk_group, 26 | pub S: $msg_group, 27 | pub T: $GVector, 28 | } 29 | 30 | pub struct $GrothS {} 31 | }; 32 | } 33 | 34 | macro_rules! impl_GrothS_setup { 35 | ( $GrothSetupParams:ident, $msg_group:ident, $GVector:ident ) => { 36 | pub fn setup(count_messages: usize, label: &[u8]) -> $GrothSetupParams { 37 | // NUMS for g1 and g2 38 | let g1 = G1::from_msg_hash(&[label, " : g1".as_bytes()].concat()); 39 | let g2 = G2::from_msg_hash(&[label, " : g2".as_bytes()].concat()); 40 | let mut y = $GVector::with_capacity(count_messages); 41 | for i in 0..count_messages { 42 | // // NUMS for y. construct a group element from hashing label||y||i for each i 43 | let yi = $msg_group::from_msg_hash( 44 | &[label, " : y".as_bytes(), i.to_string().as_bytes()].concat(), 45 | ); 46 | y.push(yi); 47 | } 48 | $GrothSetupParams { g1, g2, y } 49 | } 50 | }; 51 | } 52 | 53 | macro_rules! impl_GrothSig_new { 54 | ( $messages:ident, $sk:ident, $y:expr, $g_r:expr, $g_s:expr, $msg_group_vec:ident ) => {{ 55 | if $messages.len() > $y.len() { 56 | return Err(DelgError::UnsupportedNoOfMessages { 57 | expected: $y.len(), 58 | given: $messages.len(), 59 | }); 60 | } 61 | let r = FieldElement::random(); 62 | let r_inv = r.inverse(); 63 | let R = &$g_r * &r; 64 | let S = (&$y[0] + (&$g_s * &$sk.0)) * &r_inv; 65 | let mut T = $msg_group_vec::with_capacity($messages.len()); 66 | for i in 0..$messages.len() { 67 | T.push(&$messages[i] + (&$y[i] * &$sk.0)); 68 | } 69 | T.scale(&r_inv); 70 | Ok(Self { R, S, T }) 71 | }}; 72 | } 73 | 74 | macro_rules! impl_GrothSig_randomize { 75 | ( ) => { 76 | pub fn randomize(&self, r_prime: &FieldElement) -> Self { 77 | let r_prime_inv = r_prime.inverse(); 78 | let R = &self.R * r_prime; 79 | let S = &self.S * &r_prime_inv; 80 | Self { 81 | R, 82 | S, 83 | T: self.T.scaled_by(&r_prime_inv), 84 | } 85 | } 86 | } 87 | } 88 | 89 | impl_GrothS!( 90 | Groth1SetupParams, 91 | Groth1Verkey, 92 | Groth1Sig, 93 | GrothS1, 94 | G2, 95 | G1, 96 | G1Vector 97 | ); 98 | 99 | impl_GrothS!( 100 | Groth2SetupParams, 101 | Groth2Verkey, 102 | Groth2Sig, 103 | GrothS2, 104 | G1, 105 | G2, 106 | G2Vector 107 | ); 108 | 109 | /// Returns tuple of groups elements where the elements are result of scalar multiplication involving the same field element. Uses w-NAF 110 | #[macro_export] 111 | macro_rules! var_time_mul_scl_mul_with_same_field_element { 112 | ( $group:ident, $field_elem:expr, $( $group_elem_table:expr ),* ) => {{ 113 | let wnaf = $field_elem.to_wnaf(5); 114 | ( 115 | $( 116 | $group::wnaf_mul(&$group_elem_table, &wnaf), 117 | )* 118 | ) 119 | }} 120 | } 121 | 122 | impl GrothS1 { 123 | impl_GrothS_setup!(Groth1SetupParams, G1, G1Vector); 124 | 125 | pub fn keygen(setup_params: &Groth1SetupParams) -> (GrothSigkey, Groth1Verkey) { 126 | let sk = FieldElement::random(); 127 | let vk = &setup_params.g2 * &sk; 128 | (GrothSigkey(sk), Groth1Verkey(vk)) 129 | } 130 | } 131 | 132 | impl Groth1Sig { 133 | pub fn new( 134 | messages: &[G1], 135 | sk: &GrothSigkey, 136 | setup_params: &Groth1SetupParams, 137 | ) -> DelgResult { 138 | impl_GrothSig_new!( 139 | messages, 140 | sk, 141 | setup_params.y, 142 | setup_params.g2, 143 | setup_params.g1, 144 | G1Vector 145 | ) 146 | } 147 | 148 | impl_GrothSig_randomize!(); 149 | 150 | pub fn verify( 151 | &self, 152 | messages: &[G1], 153 | verkey: &Groth1Verkey, 154 | setup_params: &Groth1SetupParams, 155 | ) -> DelgResult { 156 | if messages.len() > setup_params.y.len() { 157 | return Err(DelgError::UnsupportedNoOfMessages { 158 | expected: setup_params.y.len(), 159 | given: messages.len(), 160 | }); 161 | } 162 | 163 | // e(S, R) == e(y_0, g2) * (g1, V) => e(y_0, g2) * (g1, V) * e(S, R)^-1 == 1 => e(y_0, g2) * (g1, V) * e(S^-1, R) == 1 164 | let negS = self.S.negation(); 165 | let e0 = GT::ate_multi_pairing(vec![ 166 | (&setup_params.y[0], &setup_params.g2), 167 | (&setup_params.g1, &verkey.0), 168 | (&negS, &self.R), 169 | ]); 170 | if !e0.is_one() { 171 | return Ok(false); 172 | } 173 | 174 | let negR = self.R.negation(); 175 | for i in 0..messages.len() { 176 | // e(T_i, R) == e(m_i, g2) * e(y_i, V) => 1 == e(m_i, g2) * e(y_i, V) * e(T_i, R)^-1 = 1 == e(m_i, g2) * e(y_i, V) * e(T_i, R^-1) 177 | let e = GT::ate_multi_pairing(vec![ 178 | (&messages[i], &setup_params.g2), 179 | (&setup_params.y[i], &verkey.0), 180 | (&self.T[i], &negR), 181 | ]); 182 | if !e.is_one() { 183 | return Ok(false); 184 | } 185 | } 186 | Ok(true) 187 | } 188 | 189 | pub fn verify_fast( 190 | &self, 191 | messages: &[G1], 192 | verkey: &Groth1Verkey, 193 | setup_params: &Groth1SetupParams, 194 | ) -> DelgResult { 195 | // Verify n pairing checks with a single one. 196 | // if a verifier had to check that all 3 values a, b and c are 0, he could pick a random value r in {Z_p}* and check that a + b*r + c*r^2 equals 0 197 | // in a pairing situation if verifier had to check if e(a,b) = 1, e(c, d) = 1 and e(f, g) = 1, pick a random value r in {Z_p}* and check e(a,b) * e(c,d)^r * e(f,g)^{r^2} equals 1 198 | // e(a,b) * e(c,d)^r * e(f,g)^{r^2} = e(a,b) * e(c^r, d) * e(f^{r^2}, g). Exponent moved to 1st element of pairing since computation in group G1 is cheaper 199 | // Now use a single multi-pairing rather than 3 pairings to compute e(a,b) * e(c^r, d) * e(f^{r^2}, g) 200 | // Using the above idea for signature verification => 201 | // e(-S, R)*e(y1, g2)*e(g1, V) * {e(m1, g2)*e(y1, V)*e(T1, -R)}^r * {e(m2, g2)*e(y2, V)*e(T2, -R)}^{r^2} * ... == 1 202 | // e(-S, R)*e(y1, g2)*e(g1, V) * e(m1, g2)^r*e(y1, V)^r*e(T1, -R)^r * e(m2, g2)^{r^2}*e(y2, V)^{r^2}*e(T2, -R)^{r^2} * ... == 1 203 | // e(-S, R)*e(y1, g2)*e(g1, V) * e(m1^r, g2)*e(y1^r, V)*e(T1^r, -R) * e(m2^{r^2}, g1)*e(y2^{r^2}, V)*e(T2^{r^2}, -R) * ... == 1 204 | 205 | if messages.len() > setup_params.y.len() { 206 | return Err(DelgError::UnsupportedNoOfMessages { 207 | expected: setup_params.y.len(), 208 | given: messages.len(), 209 | }); 210 | } 211 | 212 | let r = FieldElement::random(); 213 | let r_vec = FieldElementVector::new_vandermonde_vector(&r, messages.len() + 1); 214 | let negR = self.R.negation(); 215 | let negS = self.S.negation(); 216 | 217 | let mut pairing_elems: Vec<(&G1, &G2)> = vec![ 218 | (&setup_params.y[0], &setup_params.g2), 219 | (&setup_params.g1, &verkey.0), 220 | (&negS, &self.R), 221 | ]; 222 | 223 | let mut temp: Vec<(G1, G1, G1)> = vec![]; 224 | for i in 0..messages.len() { 225 | // The next code block will perform several scalar multiplications with the same field element, i.e. m_i * r, y_i * r, T_i * r 226 | let table_m = G1LookupTable::from(&messages[i]); 227 | let table_y = G1LookupTable::from(&setup_params.y[i]); 228 | let table_T = G1LookupTable::from(&self.T[i]); 229 | // m_i * r, y_i * r, T_i * r 230 | temp.push(var_time_mul_scl_mul_with_same_field_element!( 231 | G1, 232 | r_vec[i + 1], 233 | table_m, 234 | table_y, 235 | table_T 236 | )); 237 | } 238 | 239 | for i in 0..messages.len() { 240 | pairing_elems.push((&temp[i].0, &setup_params.g2)); 241 | pairing_elems.push((&temp[i].1, &verkey.0)); 242 | pairing_elems.push((&temp[i].2, &negR)) 243 | } 244 | 245 | let e = GT::ate_multi_pairing(pairing_elems); 246 | Ok(e.is_one()) 247 | } 248 | } 249 | 250 | impl GrothS2 { 251 | impl_GrothS_setup!(Groth2SetupParams, G2, G2Vector); 252 | 253 | pub fn keygen(setup_params: &Groth2SetupParams) -> (GrothSigkey, Groth2Verkey) { 254 | let sk = FieldElement::random(); 255 | let vk = &setup_params.g1 * &sk; 256 | (GrothSigkey(sk), Groth2Verkey(vk)) 257 | } 258 | } 259 | 260 | impl Groth2Sig { 261 | pub fn new( 262 | messages: &[G2], 263 | sk: &GrothSigkey, 264 | setup_params: &Groth2SetupParams, 265 | ) -> DelgResult { 266 | impl_GrothSig_new!( 267 | messages, 268 | sk, 269 | setup_params.y, 270 | setup_params.g1, 271 | setup_params.g2, 272 | G2Vector 273 | ) 274 | } 275 | 276 | impl_GrothSig_randomize!(); 277 | 278 | pub fn verify( 279 | &self, 280 | messages: &[G2], 281 | verkey: &Groth2Verkey, 282 | setup_params: &Groth2SetupParams, 283 | ) -> DelgResult { 284 | if messages.len() > setup_params.y.len() { 285 | return Err(DelgError::UnsupportedNoOfMessages { 286 | expected: setup_params.y.len(), 287 | given: messages.len(), 288 | }); 289 | } 290 | 291 | // e(R, S) == e(g1, y_0) * (V, g2) => 1 == e(g1, y_0) * (V, g2) * e(R, S)^-1 => 1 == e(g1, y_0) * (V, g2) * e(R^-1, S) 292 | let negR = self.R.negation(); 293 | let e0 = GT::ate_multi_pairing(vec![ 294 | (&setup_params.g1, &setup_params.y[0]), 295 | (&verkey.0, &setup_params.g2), 296 | (&negR, &self.S), 297 | ]); 298 | if !e0.is_one() { 299 | return Ok(false); 300 | } 301 | 302 | for i in 0..messages.len() { 303 | // e(R, T_i) == e(g1, m_i) * e(V, y_i) => 1 == e(g1, m_i) * e(V, y_i) * e(R, T_i)^-1 => 1 == e(g1, m_i) * e(V, y_i) * e(R^-1, T_i) 304 | let e = GT::ate_multi_pairing(vec![ 305 | (&setup_params.g1, &messages[i]), 306 | (&verkey.0, &setup_params.y[i]), 307 | (&negR, &self.T[i]), 308 | ]); 309 | if !e.is_one() { 310 | return Ok(false); 311 | } 312 | } 313 | Ok(true) 314 | } 315 | 316 | pub fn verify_fast( 317 | &self, 318 | messages: &[G2], 319 | verkey: &Groth2Verkey, 320 | setup_params: &Groth2SetupParams, 321 | ) -> DelgResult { 322 | // Verify n pairing checks with a single one. 323 | // if a verifier had to check that all 3 values a, b and c are 0, he could pick a random value r in {Z_p}* and check that a + b*r + c*r^2 equals 0 324 | // in a pairing situation if verifier had to check if e(a,b) = 1, e(c, d) = 1 and e(f, g) = 1, pick a random value r in {Z_p}* and check e(a,b) * e(c,d)^r * e(f,g)^{r^2} equals 1 325 | // e(a,b) * e(c,d)^r * e(f,g)^{r^2} = e(a,b) * e(c^r, d) * e(f^{r^2}, g). Exponent moved to 1st element of pairing since computation in group G1 is cheaper 326 | // Now use a single multi-pairing rather than 3 pairings to compute e(a,b) * e(c^r, d) * e(f^{r^2}, g) 327 | // Using the above idea for signature verification => 328 | // e(-R, S)*e(g1, y1)*e(V, g2) * {e(g1, m1)*e(V, y1)*e(-R, T1)}^r * {e(g1, m2)*e(V, y2)*e(-R, T2)}^{r^2} * ... == 1 329 | // e(-R, S)*e(g1, y1)*e(V, g2) * e(g1, m1)^r*e(V, y1)^r*e(-R, T1)^r * e(g1, m2)^{r^2}*e(V, y2)^{r^2}*e(-R, T2)^{r^2} * ... == 1 330 | // e(-R, S)*e(g1, y1)*e(V, g2) * e(g1^r, m1)*e(V^r, y1)*e(-R^r, T1) * e(g1^{r^2}, m2)*e(V^{r^2}, y2)*e(-R^{r^2}, T2) * ... == 1 331 | 332 | if messages.len() > setup_params.y.len() { 333 | return Err(DelgError::UnsupportedNoOfMessages { 334 | expected: setup_params.y.len(), 335 | given: messages.len(), 336 | }); 337 | } 338 | 339 | let r = FieldElement::random(); 340 | let r_vec = FieldElementVector::new_vandermonde_vector(&r, messages.len() + 1); 341 | let negR = self.R.negation(); 342 | 343 | let mut pairing_elems: Vec<(&G1, &G2)> = vec![ 344 | (&setup_params.g1, &setup_params.y[0]), 345 | (&verkey.0, &setup_params.g2), 346 | (&negR, &self.S), 347 | ]; 348 | 349 | // The next code block will perform several scalar multiplications with the same bases for the same field element (in each iteration), i.e. g1 * r, V * r, R * r 350 | let mut temp: Vec<(G1, G1, G1)> = vec![]; 351 | let table_g1 = G1LookupTable::from(&setup_params.g1); 352 | let table_vk = G1LookupTable::from(&verkey.0); 353 | let table_R = G1LookupTable::from(&negR); 354 | for i in 0..messages.len() { 355 | // g1 * r, V * r, R * r 356 | temp.push(var_time_mul_scl_mul_with_same_field_element!( 357 | G1, 358 | r_vec[i + 1], 359 | table_g1, 360 | table_vk, 361 | table_R 362 | )); 363 | } 364 | 365 | for i in 0..messages.len() { 366 | pairing_elems.push((&temp[i].0, &messages[i])); 367 | pairing_elems.push((&temp[i].1, &setup_params.y[i])); 368 | pairing_elems.push((&temp[i].2, &self.T[i])) 369 | } 370 | 371 | let e = GT::ate_multi_pairing(pairing_elems); 372 | Ok(e.is_one()) 373 | } 374 | } 375 | 376 | #[cfg(test)] 377 | mod tests { 378 | use super::*; 379 | // For benchmarking 380 | use std::time::{Duration, Instant}; 381 | 382 | #[test] 383 | fn test_groth1_sig_verification() { 384 | let count_msgs = 10; 385 | let label = "test".as_bytes(); 386 | let params = GrothS1::setup(count_msgs, label); 387 | assert_eq!(params.y.len(), count_msgs); 388 | let (sk, vk) = GrothS1::keygen(¶ms); 389 | 390 | let msgs = (0..count_msgs).map(|_| G1::random()).collect::>(); 391 | let sig = Groth1Sig::new(msgs.as_slice(), &sk, ¶ms).unwrap(); 392 | 393 | let start = Instant::now(); 394 | assert!(sig.verify(msgs.as_slice(), &vk, ¶ms).unwrap()); 395 | println!("Naive verify takes {:?}", start.elapsed()); 396 | 397 | let start = Instant::now(); 398 | assert!(sig.verify_fast(msgs.as_slice(), &vk, ¶ms).unwrap()); 399 | println!("Fast verify takes {:?}", start.elapsed()); 400 | 401 | let r = FieldElement::random(); 402 | let sig_randomized = sig.randomize(&r); 403 | assert!(sig_randomized 404 | .verify(msgs.as_slice(), &vk, ¶ms) 405 | .unwrap()); 406 | assert!(sig_randomized 407 | .verify_fast(msgs.as_slice(), &vk, ¶ms) 408 | .unwrap()); 409 | } 410 | 411 | #[test] 412 | fn test_groth2_sig_verification() { 413 | let count_msgs = 10; 414 | let label = "test".as_bytes(); 415 | let params = GrothS2::setup(count_msgs, label); 416 | assert_eq!(params.y.len(), count_msgs); 417 | let (sk, vk) = GrothS2::keygen(¶ms); 418 | 419 | let msgs = (0..count_msgs).map(|_| G2::random()).collect::>(); 420 | let sig = Groth2Sig::new(msgs.as_slice(), &sk, ¶ms).unwrap(); 421 | 422 | let start = Instant::now(); 423 | assert!(sig.verify(msgs.as_slice(), &vk, ¶ms).unwrap()); 424 | println!("Naive verify takes {:?}", start.elapsed()); 425 | 426 | let start = Instant::now(); 427 | assert!(sig.verify_fast(msgs.as_slice(), &vk, ¶ms).unwrap()); 428 | println!("Fast verify takes {:?}", start.elapsed()); 429 | 430 | let r = FieldElement::random(); 431 | let sig_randomized = sig.randomize(&r); 432 | assert!(sig_randomized 433 | .verify(msgs.as_slice(), &vk, ¶ms) 434 | .unwrap()); 435 | assert!(sig_randomized 436 | .verify_fast(msgs.as_slice(), &vk, ¶ms) 437 | .unwrap()); 438 | } 439 | } 440 | -------------------------------------------------------------------------------- /delg_cred_cdd/src/issuer.rs: -------------------------------------------------------------------------------- 1 | use crate::errors::{DelgError, DelgResult}; 2 | use crate::groth_sig::{ 3 | Groth1SetupParams, Groth1Sig, Groth1Verkey, Groth2SetupParams, Groth2Sig, Groth2Verkey, 4 | GrothS1, GrothS2, GrothSigkey, 5 | }; 6 | use amcl_wrapper::group_elem::{GroupElement, GroupElementVector}; 7 | use amcl_wrapper::group_elem_g1::{G1LookupTable, G1Vector, G1}; 8 | use amcl_wrapper::group_elem_g2::{G2Vector, G2}; 9 | 10 | pub type Sigkey = GrothSigkey; 11 | pub type EvenLevelVerkey = Groth1Verkey; 12 | pub type OddLevelVerkey = Groth2Verkey; 13 | 14 | // (attributes, signature). The signature is over the attributes and the public key combined by appending public key to the attribute vector. 15 | #[derive(Clone, Debug, Serialize, Deserialize)] 16 | pub struct CredLinkOdd { 17 | pub level: usize, 18 | pub attributes: G1Vector, 19 | pub signature: Groth1Sig, 20 | } 21 | 22 | #[derive(Clone, Debug, Serialize, Deserialize)] 23 | pub struct CredLinkEven { 24 | pub level: usize, 25 | pub attributes: G2Vector, 26 | pub signature: Groth2Sig, 27 | } 28 | 29 | #[derive(Clone, Debug, Serialize, Deserialize)] 30 | pub struct CredChain { 31 | pub odd_links: Vec, 32 | pub even_links: Vec, 33 | } 34 | 35 | #[derive(Clone, Debug, Serialize, Deserialize)] 36 | pub struct EvenLevelIssuer { 37 | pub level: usize, 38 | } 39 | 40 | #[derive(Clone, Debug, Serialize, Deserialize)] 41 | pub struct OddLevelIssuer { 42 | pub level: usize, 43 | } 44 | 45 | pub struct RootIssuer {} 46 | 47 | pub type RootIssuerVerkey = EvenLevelVerkey; 48 | 49 | impl CredLinkOdd { 50 | pub fn attribute_count(&self) -> usize { 51 | self.attributes.len() 52 | } 53 | 54 | pub fn has_verkey(&self, vk: &OddLevelVerkey) -> bool { 55 | self.attributes[self.attributes.len() - 1] == vk.0 56 | } 57 | 58 | pub fn verify( 59 | &self, 60 | delegatee_vk: &OddLevelVerkey, 61 | delegator_vk: &EvenLevelVerkey, 62 | setup_params: &Groth1SetupParams, 63 | ) -> DelgResult { 64 | if self.attributes.len() > setup_params.y.len() { 65 | return Err(DelgError::MoreAttributesThanExpected { 66 | expected: setup_params.y.len(), 67 | given: self.attributes.len(), 68 | }); 69 | } 70 | if !self.has_verkey(delegatee_vk) { 71 | return Err(DelgError::VerkeyNotFoundInDelegationLink {}); 72 | } 73 | /*link.signature 74 | .verify(link.messages.as_slice(), delegator_vk, setup_params)*/ 75 | self.signature 76 | .verify_fast(self.attributes.as_slice(), delegator_vk, setup_params) 77 | } 78 | } 79 | 80 | impl CredLinkEven { 81 | pub fn attribute_count(&self) -> usize { 82 | self.attributes.len() 83 | } 84 | 85 | pub fn has_verkey(&self, vk: &EvenLevelVerkey) -> bool { 86 | self.attributes[self.attributes.len() - 1] == vk.0 87 | } 88 | 89 | pub fn verify( 90 | &self, 91 | delegatee_vk: &EvenLevelVerkey, 92 | delegator_vk: &OddLevelVerkey, 93 | setup_params: &Groth2SetupParams, 94 | ) -> DelgResult { 95 | if self.attributes.len() > setup_params.y.len() { 96 | return Err(DelgError::MoreAttributesThanExpected { 97 | expected: setup_params.y.len(), 98 | given: self.attributes.len(), 99 | }); 100 | } 101 | if !self.has_verkey(delegatee_vk) { 102 | return Err(DelgError::VerkeyNotFoundInDelegationLink {}); 103 | } 104 | /*link.signature 105 | .verify(link.messages.as_slice(), delegator_vk, setup_params)*/ 106 | self.signature 107 | .verify_fast(self.attributes.as_slice(), delegator_vk, setup_params) 108 | } 109 | } 110 | 111 | impl CredChain { 112 | pub fn new() -> Self { 113 | Self { 114 | odd_links: vec![], 115 | even_links: vec![], 116 | } 117 | } 118 | 119 | pub fn odd_size(&self) -> usize { 120 | self.odd_links.len() 121 | } 122 | 123 | pub fn even_size(&self) -> usize { 124 | self.even_links.len() 125 | } 126 | 127 | pub fn size(&self) -> usize { 128 | self.odd_size() + self.even_size() 129 | } 130 | 131 | pub fn get_odd_link(&self, idx: usize) -> DelgResult<&CredLinkOdd> { 132 | if self.odd_size() <= idx { 133 | return Err(DelgError::NoOddLinkInChainAtGivenIndex { 134 | given_index: idx, 135 | size: self.odd_size(), 136 | }); 137 | } 138 | Ok(&self.odd_links[idx]) 139 | } 140 | 141 | pub fn get_even_link(&self, idx: usize) -> DelgResult<&CredLinkEven> { 142 | if self.even_size() <= idx { 143 | return Err(DelgError::NoEvenLinkInChainAtGivenIndex { 144 | given_index: idx, 145 | size: self.even_size(), 146 | }); 147 | } 148 | Ok(&self.even_links[idx]) 149 | } 150 | 151 | pub fn extend_with_odd(&mut self, link: CredLinkOdd) -> DelgResult<()> { 152 | if link.level % 2 == 0 { 153 | return Err(DelgError::ExpectedOddLevel { given: link.level }); 154 | } 155 | if self.odd_size() == 0 && link.level != 1 { 156 | return Err(DelgError::UnexpectedLevel { 157 | expected: 1, 158 | given: link.level, 159 | }); 160 | } else if self.odd_size() != 0 161 | && ((link.level - self.odd_links[self.odd_size() - 1].level) != 2) 162 | { 163 | return Err(DelgError::UnexpectedLevel { 164 | expected: self.odd_links[self.odd_size() - 1].level + 2, 165 | given: link.level, 166 | }); 167 | } 168 | self.odd_links.push(link); 169 | Ok(()) 170 | } 171 | 172 | pub fn extend_with_even(&mut self, link: CredLinkEven) -> DelgResult<()> { 173 | if link.level % 2 != 0 { 174 | return Err(DelgError::ExpectedEvenLevel { given: link.level }); 175 | } 176 | if self.even_size() == 0 && link.level != 2 { 177 | return Err(DelgError::UnexpectedLevel { 178 | expected: 2, 179 | given: link.level, 180 | }); 181 | } else if self.even_size() != 0 182 | && ((link.level - self.even_links[self.even_size() - 1].level) != 2) 183 | { 184 | return Err(DelgError::UnexpectedLevel { 185 | expected: self.even_links[self.even_size() - 1].level + 2, 186 | given: link.level, 187 | }); 188 | } 189 | self.even_links.push(link); 190 | Ok(()) 191 | } 192 | 193 | pub fn verify_last_odd_delegation( 194 | &self, 195 | delegatee_vk: &OddLevelVerkey, 196 | delegator_vk: &EvenLevelVerkey, 197 | setup_params: &Groth1SetupParams, 198 | ) -> DelgResult { 199 | if self.odd_size() == 0 { 200 | return Err(DelgError::NoOddLinksInChain {}); 201 | } 202 | let link = &self.odd_links[self.odd_size() - 1]; 203 | link.verify(delegatee_vk, delegator_vk, setup_params) 204 | } 205 | 206 | pub fn verify_last_even_delegation( 207 | &self, 208 | delegatee_vk: &EvenLevelVerkey, 209 | delegator_vk: &OddLevelVerkey, 210 | setup_params: &Groth2SetupParams, 211 | ) -> DelgResult { 212 | if self.even_size() == 0 { 213 | return Err(DelgError::NoEvenLinksInChain {}); 214 | } 215 | let link = &self.even_links[self.even_size() - 1]; 216 | link.verify(delegatee_vk, delegator_vk, setup_params) 217 | } 218 | 219 | // First verkey of even_level_vks is the root issuer's key 220 | pub fn verify_delegations( 221 | &self, 222 | even_level_vks: Vec<&EvenLevelVerkey>, 223 | odd_level_vks: Vec<&OddLevelVerkey>, 224 | setup_params_1: &Groth1SetupParams, 225 | setup_params_2: &Groth2SetupParams, 226 | ) -> DelgResult { 227 | if self.size() == 0 { 228 | return Err(DelgError::ChainEmpty {}); 229 | } 230 | if (even_level_vks.len() + odd_level_vks.len()) != (self.size() + 1) { 231 | return Err(DelgError::IncorrectNumberOfVerkeys { 232 | expected: self.size() + 1, 233 | given: even_level_vks.len() + odd_level_vks.len(), 234 | }); 235 | } 236 | if even_level_vks.len() != ((self.size() / 2) + 1) { 237 | return Err(DelgError::IncorrectNumberOfEvenLevelVerkeys { 238 | expected: (self.size() / 2) + 1, 239 | given: even_level_vks.len(), 240 | }); 241 | } 242 | if self.size() % 2 == 1 { 243 | if odd_level_vks.len() != ((self.size() / 2) + 1) { 244 | return Err(DelgError::IncorrectNumberOfOddLevelVerkeys { 245 | expected: (self.size() / 2) + 1, 246 | given: odd_level_vks.len(), 247 | }); 248 | } 249 | } else { 250 | if odd_level_vks.len() != (self.size() / 2) { 251 | return Err(DelgError::IncorrectNumberOfOddLevelVerkeys { 252 | expected: self.size() / 2, 253 | given: odd_level_vks.len(), 254 | }); 255 | } 256 | } 257 | 258 | for i in 1..=self.size() { 259 | let r = if i % 2 == 1 { 260 | let idx = i / 2; 261 | let link = &self.odd_links[idx]; 262 | if link.level != i { 263 | return return Err(DelgError::UnexpectedLevel { 264 | expected: i, 265 | given: link.level, 266 | }); 267 | } 268 | link.verify(odd_level_vks[idx], even_level_vks[idx], setup_params_1)? 269 | } else { 270 | let link = &self.even_links[(i / 2) - 1]; 271 | if link.level != i { 272 | return return Err(DelgError::UnexpectedLevel { 273 | expected: i, 274 | given: link.level, 275 | }); 276 | } 277 | link.verify( 278 | even_level_vks[i / 2], 279 | odd_level_vks[(i / 2) - 1], 280 | setup_params_2, 281 | )? 282 | }; 283 | if !r { 284 | return Ok(false); 285 | } 286 | } 287 | Ok(true) 288 | } 289 | 290 | /// Returns a truncated version of the current chain. Does not modify the current chain but clones the links. 291 | pub fn get_truncated(&self, size: usize) -> DelgResult { 292 | if size > self.size() { 293 | return Err(DelgError::ChainIsShorterThanExpected { 294 | actual_size: self.size(), 295 | expected_size: size, 296 | }); 297 | } 298 | let mut new_chain = CredChain::new(); 299 | for i in 1..=size { 300 | if (i % 2) == 1 { 301 | new_chain.odd_links.push(self.odd_links[i / 2].clone()); 302 | } else { 303 | new_chain 304 | .even_links 305 | .push(self.even_links[(i / 2) - 1].clone()); 306 | } 307 | } 308 | Ok(new_chain) 309 | } 310 | } 311 | 312 | impl EvenLevelIssuer { 313 | pub fn new(level: usize) -> DelgResult { 314 | if level % 2 != 0 { 315 | return Err(DelgError::ExpectedEvenLevel { given: level }); 316 | } 317 | Ok(Self { level }) 318 | } 319 | 320 | pub fn keygen(setup_params: &Groth1SetupParams) -> (Sigkey, EvenLevelVerkey) { 321 | GrothS1::keygen(setup_params) 322 | } 323 | 324 | pub fn delegate( 325 | &self, 326 | mut delegatee_attributes: G1Vector, 327 | delegatee_vk: OddLevelVerkey, 328 | sk: &Sigkey, 329 | setup_params: &Groth1SetupParams, 330 | ) -> DelgResult { 331 | if delegatee_attributes.len() >= setup_params.y.len() { 332 | return Err(DelgError::MoreAttributesThanExpected { 333 | expected: setup_params.y.len(), 334 | given: delegatee_attributes.len(), 335 | }); 336 | } 337 | delegatee_attributes.push(delegatee_vk.0); 338 | let signature = Groth1Sig::new(delegatee_attributes.as_slice(), sk, setup_params)?; 339 | Ok(CredLinkOdd { 340 | level: &self.level + 1, 341 | attributes: delegatee_attributes, 342 | signature, 343 | }) 344 | } 345 | } 346 | 347 | impl OddLevelIssuer { 348 | pub fn new(level: usize) -> DelgResult { 349 | if level % 2 == 0 { 350 | return Err(DelgError::ExpectedOddLevel { given: level }); 351 | } 352 | Ok(Self { level }) 353 | } 354 | 355 | pub fn keygen(setup_params: &Groth2SetupParams) -> (Sigkey, OddLevelVerkey) { 356 | GrothS2::keygen(setup_params) 357 | } 358 | 359 | pub fn delegate( 360 | &self, 361 | mut delegatee_attributes: G2Vector, 362 | delegatee_vk: EvenLevelVerkey, 363 | sk: &Sigkey, 364 | setup_params: &Groth2SetupParams, 365 | ) -> DelgResult { 366 | if delegatee_attributes.len() >= setup_params.y.len() { 367 | return Err(DelgError::MoreAttributesThanExpected { 368 | expected: setup_params.y.len(), 369 | given: delegatee_attributes.len(), 370 | }); 371 | } 372 | delegatee_attributes.push(delegatee_vk.0); 373 | let signature = Groth2Sig::new(delegatee_attributes.as_slice(), sk, setup_params)?; 374 | Ok(CredLinkEven { 375 | level: &self.level + 1, 376 | attributes: delegatee_attributes, 377 | signature, 378 | }) 379 | } 380 | } 381 | 382 | impl RootIssuer { 383 | pub fn keygen(setup_params: &Groth1SetupParams) -> (Sigkey, RootIssuerVerkey) { 384 | GrothS1::keygen(setup_params) 385 | } 386 | 387 | pub fn delegate( 388 | mut delegatee_attributes: G1Vector, 389 | delegatee_vk: OddLevelVerkey, 390 | sk: &Sigkey, 391 | setup_params: &Groth1SetupParams, 392 | ) -> DelgResult { 393 | let issuer = EvenLevelIssuer::new(0)?; 394 | issuer.delegate(delegatee_attributes, delegatee_vk, sk, setup_params) 395 | } 396 | } 397 | 398 | #[cfg(test)] 399 | mod tests { 400 | use super::*; 401 | // For benchmarking 402 | use std::time::{Duration, Instant}; 403 | 404 | /// XXX: Need test fixtures 405 | 406 | #[test] 407 | fn test_delegation_level_0_to_level_2() { 408 | let max_attributes = 5; 409 | let label = "test".as_bytes(); 410 | let params1 = GrothS1::setup(max_attributes, label); 411 | let params2 = GrothS2::setup(max_attributes, label); 412 | 413 | let l_0_issuer = EvenLevelIssuer::new(0).unwrap(); 414 | let l_1_issuer = OddLevelIssuer::new(1).unwrap(); 415 | let l_2_issuer = EvenLevelIssuer::new(2).unwrap(); 416 | 417 | let (l_0_issuer_sk, l_0_issuer_vk) = EvenLevelIssuer::keygen(¶ms1); 418 | let (l_1_issuer_sk, l_1_issuer_vk) = OddLevelIssuer::keygen(¶ms2); 419 | let (l_2_issuer_sk, l_2_issuer_vk) = EvenLevelIssuer::keygen(¶ms1); 420 | 421 | let attributes_1: G1Vector = (0..max_attributes - 1) 422 | .map(|_| G1::random()) 423 | .collect::>() 424 | .into(); 425 | let cred_link_1 = l_0_issuer 426 | .delegate( 427 | attributes_1.clone(), 428 | l_1_issuer_vk.clone(), 429 | &l_0_issuer_sk, 430 | ¶ms1, 431 | ) 432 | .unwrap(); 433 | 434 | assert!(cred_link_1 435 | .verify(&l_1_issuer_vk, &l_0_issuer_vk, ¶ms1) 436 | .unwrap()); 437 | 438 | let mut chain_1 = CredChain::new(); 439 | chain_1.extend_with_odd(cred_link_1).unwrap(); 440 | assert_eq!(chain_1.odd_size(), 1); 441 | assert_eq!(chain_1.even_size(), 0); 442 | assert_eq!(chain_1.size(), 1); 443 | assert!(chain_1 444 | .verify_last_odd_delegation(&l_1_issuer_vk, &l_0_issuer_vk, ¶ms1) 445 | .unwrap()); 446 | 447 | let attributes_2: G2Vector = (0..max_attributes - 1) 448 | .map(|_| G2::random()) 449 | .collect::>() 450 | .into(); 451 | let cred_link_2 = l_1_issuer 452 | .delegate( 453 | attributes_2.clone(), 454 | l_2_issuer_vk.clone(), 455 | &l_1_issuer_sk, 456 | ¶ms2, 457 | ) 458 | .unwrap(); 459 | 460 | assert!(cred_link_2 461 | .verify(&l_2_issuer_vk, &l_1_issuer_vk, ¶ms2) 462 | .unwrap()); 463 | 464 | let mut chain_2 = chain_1.clone(); 465 | chain_2.extend_with_even(cred_link_2).unwrap(); 466 | assert_eq!(chain_2.even_size(), 1); 467 | assert_eq!(chain_2.odd_size(), 1); 468 | assert_eq!(chain_2.size(), 2); 469 | 470 | assert!(chain_2 471 | .verify_last_even_delegation(&l_2_issuer_vk, &l_1_issuer_vk, ¶ms2) 472 | .unwrap()); 473 | } 474 | 475 | #[test] 476 | fn test_root_issuer() { 477 | let max_attributes = 5; 478 | let label = "test".as_bytes(); 479 | let params1 = GrothS1::setup(max_attributes, label); 480 | let params2 = GrothS2::setup(max_attributes, label); 481 | 482 | let l_1_issuer = OddLevelIssuer::new(1).unwrap(); 483 | let l_2_issuer = EvenLevelIssuer::new(2).unwrap(); 484 | 485 | let (root_issuer_sk, root_issuer_vk) = RootIssuer::keygen(¶ms1); 486 | let (l_1_issuer_sk, l_1_issuer_vk) = OddLevelIssuer::keygen(¶ms2); 487 | let (l_2_issuer_sk, l_2_issuer_vk) = EvenLevelIssuer::keygen(¶ms1); 488 | 489 | let attributes_1: G1Vector = (0..max_attributes - 1) 490 | .map(|_| G1::random()) 491 | .collect::>() 492 | .into(); 493 | let cred_link_1 = RootIssuer::delegate( 494 | attributes_1.clone(), 495 | l_1_issuer_vk.clone(), 496 | &root_issuer_sk, 497 | ¶ms1, 498 | ) 499 | .unwrap(); 500 | 501 | assert!(cred_link_1 502 | .verify(&l_1_issuer_vk, &root_issuer_vk, ¶ms1) 503 | .unwrap()); 504 | 505 | let mut chain_1 = CredChain::new(); 506 | chain_1.extend_with_odd(cred_link_1).unwrap(); 507 | 508 | let attributes_2: G2Vector = (0..max_attributes - 1) 509 | .map(|_| G2::random()) 510 | .collect::>() 511 | .into(); 512 | let cred_link_2 = l_1_issuer 513 | .delegate( 514 | attributes_2.clone(), 515 | l_2_issuer_vk.clone(), 516 | &l_1_issuer_sk, 517 | ¶ms2, 518 | ) 519 | .unwrap(); 520 | 521 | assert!(cred_link_2 522 | .verify(&l_2_issuer_vk, &l_1_issuer_vk, ¶ms2) 523 | .unwrap()); 524 | } 525 | 526 | #[test] 527 | fn test_delegation_chain_verification() { 528 | let max_attributes = 3; 529 | let label = "test".as_bytes(); 530 | let params1 = GrothS1::setup(max_attributes, label); 531 | let params2 = GrothS2::setup(max_attributes, label); 532 | 533 | let l_0_issuer = EvenLevelIssuer::new(0).unwrap(); 534 | let l_1_issuer = OddLevelIssuer::new(1).unwrap(); 535 | let l_2_issuer = EvenLevelIssuer::new(2).unwrap(); 536 | let l_3_issuer = OddLevelIssuer::new(3).unwrap(); 537 | 538 | let (l_0_issuer_sk, l_0_issuer_vk) = EvenLevelIssuer::keygen(¶ms1); 539 | let (l_1_issuer_sk, l_1_issuer_vk) = OddLevelIssuer::keygen(¶ms2); 540 | let (l_2_issuer_sk, l_2_issuer_vk) = EvenLevelIssuer::keygen(¶ms1); 541 | let (l_3_issuer_sk, l_3_issuer_vk) = OddLevelIssuer::keygen(¶ms2); 542 | let (l_4_issuer_sk, l_4_issuer_vk) = EvenLevelIssuer::keygen(¶ms1); 543 | 544 | let attributes_1: G1Vector = (0..max_attributes - 1) 545 | .map(|_| G1::random()) 546 | .collect::>() 547 | .into(); 548 | let cred_link_1 = l_0_issuer 549 | .delegate( 550 | attributes_1.clone(), 551 | l_1_issuer_vk.clone(), 552 | &l_0_issuer_sk, 553 | ¶ms1, 554 | ) 555 | .unwrap(); 556 | assert!(cred_link_1 557 | .verify(&l_1_issuer_vk, &l_0_issuer_vk, ¶ms1) 558 | .unwrap()); 559 | let mut chain_1 = CredChain::new(); 560 | chain_1.extend_with_odd(cred_link_1).unwrap(); 561 | 562 | let start = Instant::now(); 563 | assert!(chain_1 564 | .verify_delegations( 565 | vec![&l_0_issuer_vk], 566 | vec![&l_1_issuer_vk], 567 | ¶ms1, 568 | ¶ms2 569 | ) 570 | .unwrap()); 571 | println!( 572 | "Verifying delegation chain of length {} takes {:?}", 573 | chain_1.size(), 574 | start.elapsed() 575 | ); 576 | 577 | let attributes_2: G2Vector = (0..max_attributes - 1) 578 | .map(|_| G2::random()) 579 | .collect::>() 580 | .into(); 581 | let cred_link_2 = l_1_issuer 582 | .delegate( 583 | attributes_2.clone(), 584 | l_2_issuer_vk.clone(), 585 | &l_1_issuer_sk, 586 | ¶ms2, 587 | ) 588 | .unwrap(); 589 | assert!(cred_link_2 590 | .verify(&l_2_issuer_vk, &l_1_issuer_vk, ¶ms2) 591 | .unwrap()); 592 | let mut chain_2 = chain_1.clone(); 593 | chain_2.extend_with_even(cred_link_2).unwrap(); 594 | 595 | let start = Instant::now(); 596 | assert!(chain_2 597 | .verify_delegations( 598 | vec![&l_0_issuer_vk, &l_2_issuer_vk], 599 | vec![&l_1_issuer_vk], 600 | ¶ms1, 601 | ¶ms2 602 | ) 603 | .unwrap()); 604 | println!( 605 | "Verifying delegation chain of length {} takes {:?}", 606 | chain_2.size(), 607 | start.elapsed() 608 | ); 609 | 610 | let attributes_3: G1Vector = (0..max_attributes - 1) 611 | .map(|_| G1::random()) 612 | .collect::>() 613 | .into(); 614 | let cred_link_3 = l_2_issuer 615 | .delegate( 616 | attributes_3.clone(), 617 | l_3_issuer_vk.clone(), 618 | &l_2_issuer_sk, 619 | ¶ms1, 620 | ) 621 | .unwrap(); 622 | assert!(cred_link_3 623 | .verify(&l_3_issuer_vk, &l_2_issuer_vk, ¶ms1) 624 | .unwrap()); 625 | let mut chain_3 = chain_2.clone(); 626 | chain_3.extend_with_odd(cred_link_3).unwrap(); 627 | 628 | let start = Instant::now(); 629 | assert!(chain_3 630 | .verify_delegations( 631 | vec![&l_0_issuer_vk, &l_2_issuer_vk], 632 | vec![&l_1_issuer_vk, &l_3_issuer_vk], 633 | ¶ms1, 634 | ¶ms2 635 | ) 636 | .unwrap()); 637 | println!( 638 | "Verifying delegation chain of length {} takes {:?}", 639 | chain_3.size(), 640 | start.elapsed() 641 | ); 642 | 643 | let attributes_4: G2Vector = (0..max_attributes - 1) 644 | .map(|_| G2::random()) 645 | .collect::>() 646 | .into(); 647 | let cred_link_4 = l_3_issuer 648 | .delegate( 649 | attributes_4.clone(), 650 | l_4_issuer_vk.clone(), 651 | &l_3_issuer_sk, 652 | ¶ms2, 653 | ) 654 | .unwrap(); 655 | assert!(cred_link_4 656 | .verify(&l_4_issuer_vk, &l_3_issuer_vk, ¶ms2) 657 | .unwrap()); 658 | let mut chain_4 = chain_3.clone(); 659 | chain_4.extend_with_even(cred_link_4).unwrap(); 660 | 661 | let start = Instant::now(); 662 | assert!(chain_4 663 | .verify_delegations( 664 | vec![&l_0_issuer_vk, &l_2_issuer_vk, &l_4_issuer_vk], 665 | vec![&l_1_issuer_vk, &l_3_issuer_vk], 666 | ¶ms1, 667 | ¶ms2 668 | ) 669 | .unwrap()); 670 | println!( 671 | "Verifying delegation chain of length {} takes {:?}", 672 | chain_4.size(), 673 | start.elapsed() 674 | ); 675 | } 676 | 677 | #[test] 678 | fn test_truncated_delegation_chain() { 679 | let max_attributes = 3; 680 | let label = "test".as_bytes(); 681 | let params1 = GrothS1::setup(max_attributes, label); 682 | let params2 = GrothS2::setup(max_attributes, label); 683 | 684 | let l_0_issuer = EvenLevelIssuer::new(0).unwrap(); 685 | let l_1_issuer = OddLevelIssuer::new(1).unwrap(); 686 | let l_2_issuer = EvenLevelIssuer::new(2).unwrap(); 687 | let l_3_issuer = OddLevelIssuer::new(3).unwrap(); 688 | 689 | let (l_0_issuer_sk, l_0_issuer_vk) = EvenLevelIssuer::keygen(¶ms1); 690 | let (l_1_issuer_sk, l_1_issuer_vk) = OddLevelIssuer::keygen(¶ms2); 691 | let (l_2_issuer_sk, l_2_issuer_vk) = EvenLevelIssuer::keygen(¶ms1); 692 | let (l_3_issuer_sk, l_3_issuer_vk) = OddLevelIssuer::keygen(¶ms2); 693 | let (l_4_issuer_sk, l_4_issuer_vk) = EvenLevelIssuer::keygen(¶ms1); 694 | 695 | let attributes_1: G1Vector = (0..max_attributes - 1) 696 | .map(|_| G1::random()) 697 | .collect::>() 698 | .into(); 699 | let cred_link_1 = l_0_issuer 700 | .delegate( 701 | attributes_1.clone(), 702 | l_1_issuer_vk.clone(), 703 | &l_0_issuer_sk, 704 | ¶ms1, 705 | ) 706 | .unwrap(); 707 | let mut chain_1 = CredChain::new(); 708 | 709 | assert!(chain_1 710 | .verify_delegations(vec![&l_0_issuer_vk], vec![], ¶ms1, ¶ms2) 711 | .is_err()); 712 | 713 | chain_1.extend_with_odd(cred_link_1).unwrap(); 714 | 715 | assert!(chain_1 716 | .verify_delegations( 717 | vec![&l_0_issuer_vk], 718 | vec![&l_1_issuer_vk], 719 | ¶ms1, 720 | ¶ms2 721 | ) 722 | .unwrap()); 723 | 724 | assert!(chain_1.get_truncated(2).is_err()); 725 | 726 | let chain_1_1 = chain_1.get_truncated(1).unwrap(); 727 | assert_eq!(chain_1_1.size(), 1); 728 | assert!(chain_1_1 729 | .verify_delegations( 730 | vec![&l_0_issuer_vk], 731 | vec![&l_1_issuer_vk], 732 | ¶ms1, 733 | ¶ms2 734 | ) 735 | .unwrap()); 736 | 737 | let attributes_2: G2Vector = (0..max_attributes - 1) 738 | .map(|_| G2::random()) 739 | .collect::>() 740 | .into(); 741 | let cred_link_2 = l_1_issuer 742 | .delegate( 743 | attributes_2.clone(), 744 | l_2_issuer_vk.clone(), 745 | &l_1_issuer_sk, 746 | ¶ms2, 747 | ) 748 | .unwrap(); 749 | let mut chain_2 = chain_1.clone(); 750 | chain_2.extend_with_even(cred_link_2).unwrap(); 751 | 752 | assert!(chain_2 753 | .verify_delegations( 754 | vec![&l_0_issuer_vk, &l_2_issuer_vk], 755 | vec![&l_1_issuer_vk], 756 | ¶ms1, 757 | ¶ms2 758 | ) 759 | .unwrap()); 760 | 761 | assert!(chain_2.get_truncated(3).is_err()); 762 | 763 | let chain_2_1 = chain_2.get_truncated(1).unwrap(); 764 | assert_eq!(chain_2_1.size(), 1); 765 | assert!(chain_2_1 766 | .verify_delegations( 767 | vec![&l_0_issuer_vk], 768 | vec![&l_1_issuer_vk], 769 | ¶ms1, 770 | ¶ms2 771 | ) 772 | .unwrap()); 773 | 774 | let chain_2_2 = chain_2.get_truncated(2).unwrap(); 775 | assert_eq!(chain_2_2.size(), 2); 776 | assert!(chain_2_2 777 | .verify_delegations( 778 | vec![&l_0_issuer_vk, &l_2_issuer_vk], 779 | vec![&l_1_issuer_vk], 780 | ¶ms1, 781 | ¶ms2 782 | ) 783 | .unwrap()); 784 | 785 | let attributes_3: G1Vector = (0..max_attributes - 1) 786 | .map(|_| G1::random()) 787 | .collect::>() 788 | .into(); 789 | let cred_link_3 = l_2_issuer 790 | .delegate( 791 | attributes_3.clone(), 792 | l_3_issuer_vk.clone(), 793 | &l_2_issuer_sk, 794 | ¶ms1, 795 | ) 796 | .unwrap(); 797 | let mut chain_3 = chain_2.clone(); 798 | chain_3.extend_with_odd(cred_link_3).unwrap(); 799 | 800 | assert!(chain_3 801 | .verify_delegations( 802 | vec![&l_0_issuer_vk, &l_2_issuer_vk], 803 | vec![&l_1_issuer_vk, &l_3_issuer_vk], 804 | ¶ms1, 805 | ¶ms2 806 | ) 807 | .unwrap()); 808 | 809 | assert!(chain_3.get_truncated(4).is_err()); 810 | 811 | let chain_3_1 = chain_3.get_truncated(1).unwrap(); 812 | assert_eq!(chain_3_1.size(), 1); 813 | assert!(chain_3_1 814 | .verify_delegations( 815 | vec![&l_0_issuer_vk], 816 | vec![&l_1_issuer_vk], 817 | ¶ms1, 818 | ¶ms2 819 | ) 820 | .unwrap()); 821 | 822 | let chain_3_2 = chain_3.get_truncated(2).unwrap(); 823 | assert_eq!(chain_3_2.size(), 2); 824 | assert!(chain_3_2 825 | .verify_delegations( 826 | vec![&l_0_issuer_vk, &l_2_issuer_vk], 827 | vec![&l_1_issuer_vk], 828 | ¶ms1, 829 | ¶ms2 830 | ) 831 | .unwrap()); 832 | 833 | let chain_3_3 = chain_3.get_truncated(3).unwrap(); 834 | assert_eq!(chain_3_3.size(), 3); 835 | assert!(chain_3 836 | .verify_delegations( 837 | vec![&l_0_issuer_vk, &l_2_issuer_vk], 838 | vec![&l_1_issuer_vk, &l_3_issuer_vk], 839 | ¶ms1, 840 | ¶ms2 841 | ) 842 | .unwrap()); 843 | 844 | let attributes_4: G2Vector = (0..max_attributes - 1) 845 | .map(|_| G2::random()) 846 | .collect::>() 847 | .into(); 848 | let cred_link_4 = l_3_issuer 849 | .delegate( 850 | attributes_4.clone(), 851 | l_4_issuer_vk.clone(), 852 | &l_3_issuer_sk, 853 | ¶ms2, 854 | ) 855 | .unwrap(); 856 | let mut chain_4 = chain_3.clone(); 857 | chain_4.extend_with_even(cred_link_4).unwrap(); 858 | 859 | assert!(chain_4 860 | .verify_delegations( 861 | vec![&l_0_issuer_vk, &l_2_issuer_vk, &l_4_issuer_vk], 862 | vec![&l_1_issuer_vk, &l_3_issuer_vk], 863 | ¶ms1, 864 | ¶ms2 865 | ) 866 | .unwrap()); 867 | 868 | assert!(chain_4.get_truncated(5).is_err()); 869 | 870 | let chain_4_1 = chain_4.get_truncated(1).unwrap(); 871 | assert_eq!(chain_4_1.size(), 1); 872 | assert!(chain_4_1 873 | .verify_delegations( 874 | vec![&l_0_issuer_vk], 875 | vec![&l_1_issuer_vk], 876 | ¶ms1, 877 | ¶ms2 878 | ) 879 | .unwrap()); 880 | 881 | let chain_4_2 = chain_4.get_truncated(2).unwrap(); 882 | assert_eq!(chain_4_2.size(), 2); 883 | assert!(chain_4_2 884 | .verify_delegations( 885 | vec![&l_0_issuer_vk, &l_2_issuer_vk], 886 | vec![&l_1_issuer_vk], 887 | ¶ms1, 888 | ¶ms2 889 | ) 890 | .unwrap()); 891 | 892 | let chain_4_3 = chain_4.get_truncated(3).unwrap(); 893 | assert_eq!(chain_4_3.size(), 3); 894 | assert!(chain_4_3 895 | .verify_delegations( 896 | vec![&l_0_issuer_vk, &l_2_issuer_vk], 897 | vec![&l_1_issuer_vk, &l_3_issuer_vk], 898 | ¶ms1, 899 | ¶ms2 900 | ) 901 | .unwrap()); 902 | 903 | let chain_4_4 = chain_4.get_truncated(4).unwrap(); 904 | assert_eq!(chain_4_4.size(), 4); 905 | assert!(chain_4_4 906 | .verify_delegations( 907 | vec![&l_0_issuer_vk, &l_2_issuer_vk, &l_4_issuer_vk], 908 | vec![&l_1_issuer_vk, &l_3_issuer_vk], 909 | ¶ms1, 910 | ¶ms2 911 | ) 912 | .unwrap()); 913 | } 914 | 915 | #[test] 916 | fn test_delegation_chain_extension() { 917 | let max_attributes = 3; 918 | let label = "test".as_bytes(); 919 | let params1 = GrothS1::setup(max_attributes, label); 920 | let params2 = GrothS2::setup(max_attributes, label); 921 | 922 | let l_0_issuer = EvenLevelIssuer::new(0).unwrap(); 923 | let l_1_issuer = OddLevelIssuer::new(1).unwrap(); 924 | let l_2_issuer = EvenLevelIssuer::new(2).unwrap(); 925 | let l_3_issuer = OddLevelIssuer::new(3).unwrap(); 926 | let l_4_issuer = EvenLevelIssuer::new(4).unwrap(); 927 | let l_5_issuer = OddLevelIssuer::new(5).unwrap(); 928 | 929 | let (l_0_issuer_sk, l_0_issuer_vk) = EvenLevelIssuer::keygen(¶ms1); 930 | let (l_1_issuer_sk, l_1_issuer_vk) = OddLevelIssuer::keygen(¶ms2); 931 | let (l_2_issuer_sk, l_2_issuer_vk) = EvenLevelIssuer::keygen(¶ms1); 932 | let (l_3_issuer_sk, l_3_issuer_vk) = OddLevelIssuer::keygen(¶ms2); 933 | let (l_4_issuer_sk, l_4_issuer_vk) = EvenLevelIssuer::keygen(¶ms1); 934 | let (l_5_issuer_sk, l_5_issuer_vk) = OddLevelIssuer::keygen(¶ms2); 935 | let (l_6_issuer_sk, l_6_issuer_vk) = EvenLevelIssuer::keygen(¶ms1); 936 | 937 | let attributes_1: G1Vector = (0..max_attributes - 1) 938 | .map(|_| G1::random()) 939 | .collect::>() 940 | .into(); 941 | let cred_link_1 = l_0_issuer 942 | .delegate( 943 | attributes_1.clone(), 944 | l_1_issuer_vk.clone(), 945 | &l_0_issuer_sk, 946 | ¶ms1, 947 | ) 948 | .unwrap(); 949 | 950 | assert!(cred_link_1 951 | .verify(&l_1_issuer_vk, &l_0_issuer_vk, ¶ms1) 952 | .unwrap()); 953 | 954 | let attributes_2: G2Vector = (0..max_attributes - 1) 955 | .map(|_| G2::random()) 956 | .collect::>() 957 | .into(); 958 | let cred_link_2 = l_1_issuer 959 | .delegate( 960 | attributes_2.clone(), 961 | l_2_issuer_vk.clone(), 962 | &l_1_issuer_sk, 963 | ¶ms2, 964 | ) 965 | .unwrap(); 966 | assert!(cred_link_2 967 | .verify(&l_2_issuer_vk, &l_1_issuer_vk, ¶ms2) 968 | .unwrap()); 969 | 970 | let attributes_3: G1Vector = (0..max_attributes - 1) 971 | .map(|_| G1::random()) 972 | .collect::>() 973 | .into(); 974 | let cred_link_3 = l_2_issuer 975 | .delegate( 976 | attributes_3.clone(), 977 | l_3_issuer_vk.clone(), 978 | &l_2_issuer_sk, 979 | ¶ms1, 980 | ) 981 | .unwrap(); 982 | assert!(cred_link_3 983 | .verify(&l_3_issuer_vk, &l_2_issuer_vk, ¶ms1) 984 | .unwrap()); 985 | 986 | let attributes_4: G2Vector = (0..max_attributes - 1) 987 | .map(|_| G2::random()) 988 | .collect::>() 989 | .into(); 990 | let cred_link_4 = l_3_issuer 991 | .delegate( 992 | attributes_4.clone(), 993 | l_4_issuer_vk.clone(), 994 | &l_3_issuer_sk, 995 | ¶ms2, 996 | ) 997 | .unwrap(); 998 | assert!(cred_link_4 999 | .verify(&l_4_issuer_vk, &l_3_issuer_vk, ¶ms2) 1000 | .unwrap()); 1001 | 1002 | let attributes_5: G1Vector = (0..max_attributes - 1) 1003 | .map(|_| G1::random()) 1004 | .collect::>() 1005 | .into(); 1006 | let cred_link_5 = l_4_issuer 1007 | .delegate( 1008 | attributes_5.clone(), 1009 | l_5_issuer_vk.clone(), 1010 | &l_4_issuer_sk, 1011 | ¶ms1, 1012 | ) 1013 | .unwrap(); 1014 | 1015 | let attributes_6: G2Vector = (0..max_attributes - 1) 1016 | .map(|_| G2::random()) 1017 | .collect::>() 1018 | .into(); 1019 | let cred_link_6 = l_5_issuer 1020 | .delegate( 1021 | attributes_6.clone(), 1022 | l_6_issuer_vk.clone(), 1023 | &l_5_issuer_sk, 1024 | ¶ms2, 1025 | ) 1026 | .unwrap(); 1027 | 1028 | let mut chain_1 = CredChain::new(); 1029 | 1030 | // Make level of odd link even 1031 | let mut morphed_link = cred_link_3.clone(); 1032 | morphed_link.level = 2; 1033 | assert!(chain_1.extend_with_odd(morphed_link).is_err()); 1034 | 1035 | // Try to extend chain of length 0 with odd link of level 3 1036 | assert!(chain_1.extend_with_odd(cred_link_3.clone()).is_err()); 1037 | 1038 | chain_1.extend_with_odd(cred_link_1).unwrap(); 1039 | 1040 | let mut chain_2 = chain_1.clone(); 1041 | 1042 | // Make level of even link odd 1043 | let mut morphed_link = cred_link_2.clone(); 1044 | morphed_link.level = 1; 1045 | assert!(chain_2.extend_with_even(morphed_link).is_err()); 1046 | 1047 | // Try to extend chain with no even links with even link of level 4 1048 | assert!(chain_2.extend_with_even(cred_link_4.clone()).is_err()); 1049 | 1050 | chain_2.extend_with_even(cred_link_2).unwrap(); 1051 | 1052 | let mut chain_3 = chain_2.clone(); 1053 | 1054 | // Try to extend chain last odd link of level 1 with odd link of level 5 1055 | assert!(chain_3.extend_with_odd(cred_link_5).is_err()); 1056 | 1057 | chain_3.extend_with_odd(cred_link_3).unwrap(); 1058 | 1059 | let mut chain_4 = chain_3.clone(); 1060 | 1061 | // Try to extend chain last even link of level 2 with odd link of level 6 1062 | assert!(chain_4.extend_with_even(cred_link_6).is_err()); 1063 | 1064 | chain_4.extend_with_even(cred_link_4).unwrap(); 1065 | } 1066 | } 1067 | -------------------------------------------------------------------------------- /delg_cred_cdd/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | 3 | #[macro_use] 4 | extern crate amcl_wrapper; 5 | 6 | extern crate rand; 7 | #[macro_use] 8 | extern crate failure; 9 | 10 | extern crate serde; 11 | #[macro_use] 12 | extern crate serde_derive; 13 | 14 | pub mod errors; 15 | #[macro_use] 16 | pub mod groth_sig; 17 | #[macro_use] 18 | pub mod attribute_token; 19 | pub mod issuer; 20 | pub mod pok_vc; // TODO: Remove from here a move to a common crate 21 | -------------------------------------------------------------------------------- /delg_cred_cdd/src/pok_vc.rs: -------------------------------------------------------------------------------- 1 | // Proof of knowledge of committed values in a vector Pedersen commitment. 2 | 3 | // `ProverCommitting` will contains vectors of generators and random values. 4 | // `ProverCommitting` has a `commit` method that optionally takes a value as blinding, if not provided, it creates its own. 5 | // `ProverCommitting` has a `finish` method that results in creation of `ProverCommitted` object after consuming `ProverCommitting` 6 | // `ProverCommitted` marks the end of commitment phase and has the final commitment. 7 | // `ProverCommitted` has a method to generate the challenge by hashing all generators and commitment. It is optional 8 | // to use this method as the challenge may come from a super-protocol or from verifier. It takes a vector of bytes that it includes for hashing for computing the challenge 9 | // `ProverCommitted` has a method `gen_proof` to generate proof. It takes the secrets and the challenge to generate responses. 10 | // During response generation `ProverCommitted` is consumed to create `Proof` object containing the commitments and responses. 11 | // `Proof` can then be verified by the verifier. 12 | 13 | /*pub struct ProverCommitting<'a, T: GroupElement> { 14 | gens: Vec<&'a T>, 15 | blindings: Vec, 16 | } 17 | 18 | pub struct ProverCommitted<'a, T: GroupElement> { 19 | gens: Vec<&'a T>, 20 | blindings: Vec, 21 | commitment: T 22 | } 23 | 24 | impl<'a, T> ProverCommitting<'a, T> where T: GroupElement { 25 | pub fn new() -> Self { 26 | Self { 27 | gens: vec![], 28 | blindings: vec![], 29 | } 30 | } 31 | 32 | pub fn commit(&mut self, gen: &'a T, blinding: Option) -> usize { 33 | let blinding = match blinding { 34 | Some(b) => b, 35 | None => FieldElement::random() 36 | }; 37 | let idx = self.gens.len(); 38 | self.gens.push(gen); 39 | self.blindings.push(blinding); 40 | idx 41 | } 42 | 43 | pub fn finish(self) -> ProverCommitted<'a, T> { 44 | // XXX: Need multi-scalar multiplication to be implemented for GroupElementVector. 45 | // XXX: Also implement operator overloading for GroupElement. 46 | unimplemented!() 47 | } 48 | 49 | pub fn get_index(&self, idx: usize) -> Result<(&'a T, &FieldElement), PSError> { 50 | if idx >= self.gens.len() { 51 | return Err(PSError::GeneralError { msg: format!("index {} greater than size {}", idx, self.gens.len()) }); 52 | } 53 | Ok((self.gens[idx], &self.blindings[idx])) 54 | } 55 | }*/ 56 | 57 | #[macro_export] 58 | macro_rules! impl_PoK_VC { 59 | ( $ProverCommitting:ident, $ProverCommitted:ident, $Proof:ident, $group_element:ident, $group_element_vec:ident ) => { 60 | /// Proof of knowledge of messages in a vector commitment. 61 | /// Commit for each message. 62 | #[derive(Clone, Debug, Serialize, Deserialize)] 63 | pub struct $ProverCommitting { 64 | gens: $group_element_vec, 65 | blindings: FieldElementVector, 66 | } 67 | 68 | /// Receive or generate challenge. Compute response and proof 69 | #[derive(Clone, Debug, Serialize, Deserialize)] 70 | pub struct $ProverCommitted { 71 | gens: $group_element_vec, 72 | blindings: FieldElementVector, 73 | commitment: $group_element, 74 | } 75 | 76 | #[derive(Clone, Debug, Serialize, Deserialize)] 77 | pub struct $Proof { 78 | commitment: $group_element, 79 | responses: FieldElementVector, 80 | } 81 | 82 | impl $ProverCommitting { 83 | pub fn new() -> Self { 84 | Self { 85 | gens: $group_element_vec::new(0), 86 | blindings: FieldElementVector::new(0), 87 | } 88 | } 89 | 90 | /// generate a new random blinding if None provided 91 | pub fn commit( 92 | &mut self, 93 | gen: &$group_element, 94 | blinding: Option<&FieldElement>, 95 | ) -> usize { 96 | let blinding = match blinding { 97 | Some(b) => b.clone(), 98 | None => FieldElement::random(), 99 | }; 100 | let idx = self.gens.len(); 101 | self.gens.push(gen.clone()); 102 | self.blindings.push(blinding); 103 | idx 104 | } 105 | 106 | /// Add pairwise product of (`self.gens`, self.blindings). Uses multi-exponentiation. 107 | pub fn finish(self) -> $ProverCommitted { 108 | let commitment = self 109 | .gens 110 | .multi_scalar_mul_const_time(&self.blindings) 111 | .unwrap(); 112 | $ProverCommitted { 113 | gens: self.gens, 114 | blindings: self.blindings, 115 | commitment, 116 | } 117 | } 118 | 119 | pub fn get_index( 120 | &self, 121 | idx: usize, 122 | ) -> Result<(&$group_element, &FieldElement), DelgError> { 123 | if idx >= self.gens.len() { 124 | return Err(DelgError::GeneralError { 125 | msg: format!("index {} greater than size {}", idx, self.gens.len()), 126 | }); 127 | } 128 | Ok((&self.gens[idx], &self.blindings[idx])) 129 | } 130 | } 131 | 132 | impl $ProverCommitted { 133 | /// This step will be done by the main protocol for which this PoK is a sub-protocol 134 | pub fn gen_challenge(&self, mut extra: Vec) -> FieldElement { 135 | let mut bytes = vec![]; 136 | for b in self.gens.as_slice() { 137 | bytes.append(&mut b.to_bytes()); 138 | } 139 | bytes.append(&mut self.commitment.to_bytes()); 140 | bytes.append(&mut extra); 141 | FieldElement::from_msg_hash(&bytes) 142 | } 143 | 144 | /// For each secret, generate a response as self.blinding[i] - challenge*secrets[i]. 145 | pub fn gen_proof( 146 | self, 147 | challenge: &FieldElement, 148 | secrets: &[FieldElement], 149 | ) -> Result<$Proof, DelgError> { 150 | if secrets.len() != self.gens.len() { 151 | return Err(DelgError::UnequalNoOfBasesExponents { 152 | bases: self.gens.len(), 153 | exponents: secrets.len(), 154 | }); 155 | } 156 | let mut responses = FieldElementVector::with_capacity(self.gens.len()); 157 | for i in 0..self.gens.len() { 158 | responses.push(&self.blindings[i] - (challenge * &secrets[i])); 159 | } 160 | Ok($Proof { 161 | commitment: self.commitment, 162 | responses, 163 | }) 164 | } 165 | } 166 | 167 | impl $Proof { 168 | /// Verify that bases[0]^responses[0] * bases[0]^responses[0] * ... bases[i]^responses[i] * commitment^challenge == random_commitment 169 | pub fn verify( 170 | &self, 171 | bases: &[$group_element], 172 | commitment: &$group_element, 173 | challenge: &FieldElement, 174 | ) -> Result { 175 | // bases[0]^responses[0] * bases[0]^responses[0] * ... bases[i]^responses[i] * commitment^challenge == random_commitment 176 | // => 177 | // bases[0]^responses[0] * bases[0]^responses[0] * ... bases[i]^responses[i] * commitment^challenge * random_commitment^-1 == 1 178 | if bases.len() != self.responses.len() { 179 | return Err(DelgError::UnequalNoOfBasesExponents { 180 | bases: bases.len(), 181 | exponents: self.responses.len(), 182 | }); 183 | } 184 | let mut points = $group_element_vec::from(bases); 185 | let mut scalars = self.responses.clone(); 186 | points.push(commitment.clone()); 187 | scalars.push(challenge.clone()); 188 | let pr = points.multi_scalar_mul_var_time(&scalars).unwrap() - &self.commitment; 189 | Ok(pr.is_identity()) 190 | } 191 | } 192 | }; 193 | } 194 | 195 | #[cfg(test)] 196 | #[macro_export] 197 | macro_rules! test_PoK_VC { 198 | ( $n:ident, $ProverCommitting:ident, $ProverCommitted:ident, $Proof:ident, $group_element:ident, $group_element_vec:ident ) => { 199 | let mut gens = $group_element_vec::with_capacity($n); 200 | let mut secrets = FieldElementVector::with_capacity($n); 201 | let mut commiting = $ProverCommitting::new(); 202 | for _ in 0..$n - 1 { 203 | let g = $group_element::random(); 204 | commiting.commit(&g, None); 205 | gens.push(g); 206 | secrets.push(FieldElement::random()); 207 | } 208 | 209 | // Add one of the blindings externally 210 | let g = $group_element::random(); 211 | let r = FieldElement::random(); 212 | commiting.commit(&g, Some(&r)); 213 | let (g_, r_) = commiting.get_index($n - 1).unwrap(); 214 | assert_eq!(g, *g_); 215 | assert_eq!(r, *r_); 216 | gens.push(g); 217 | secrets.push(FieldElement::random()); 218 | 219 | let committed = commiting.finish(); 220 | let commitment = gens.multi_scalar_mul_const_time(&secrets).unwrap(); 221 | let challenge = committed.gen_challenge(commitment.to_bytes()); 222 | let proof = committed.gen_proof(&challenge, secrets.as_slice()).unwrap(); 223 | 224 | assert!(proof 225 | .verify(gens.as_slice(), &commitment, &challenge) 226 | .unwrap()); 227 | // Wrong challenge or commitment fails to verify 228 | assert!(!proof 229 | .verify(gens.as_slice(), &$group_element::random(), &challenge) 230 | .unwrap()); 231 | assert!(!proof 232 | .verify(gens.as_slice(), &commitment, &FieldElement::random()) 233 | .unwrap()); 234 | }; 235 | } 236 | 237 | #[cfg(test)] 238 | pub(crate) mod tests { 239 | use super::*; 240 | // XXX: Error for VC should be independent of PS 241 | use crate::errors::DelgError; 242 | use amcl_wrapper::field_elem::{FieldElement, FieldElementVector}; 243 | use amcl_wrapper::group_elem::{GroupElement, GroupElementVector}; 244 | use amcl_wrapper::group_elem_g1::{G1Vector, G1}; 245 | use amcl_wrapper::group_elem_g2::{G2Vector, G2}; 246 | 247 | #[test] 248 | fn test_PoK_VC_G1() { 249 | // Proof of knowledge of committed values in a vector commitment. The committment lies in group G1. 250 | impl_PoK_VC!(ProverCommittingG1, ProverCommittedG1, ProofG1, G1, G1Vector); 251 | 252 | let n = 5; 253 | test_PoK_VC!( 254 | n, 255 | ProverCommittingG1, 256 | ProverCommittedG1, 257 | ProofG1, 258 | G1, 259 | G1Vector 260 | ); 261 | } 262 | 263 | #[test] 264 | fn test_PoK_VC_G2() { 265 | // Proof of knowledge of committed values in a vector commitment. The committment lies in group G2. 266 | impl_PoK_VC!(ProverCommittingG2, ProverCommittedG2, ProofG2, G2, G2Vector); 267 | 268 | let n = 5; 269 | test_PoK_VC!( 270 | n, 271 | ProverCommittingG2, 272 | ProverCommittedG2, 273 | ProofG2, 274 | G2, 275 | G2Vector 276 | ); 277 | } 278 | } 279 | -------------------------------------------------------------------------------- /musig/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "musig-acml" 3 | version = "0.3.0" 4 | authors = ["Lovesh Harchandani "] 5 | description = "MuSig" 6 | license = "Apache-2.0" 7 | 8 | [dependencies] 9 | rand = "0.6" 10 | lazy_static = "1.3.0" 11 | log = "*" 12 | 13 | [dependencies.amcl_wrapper] 14 | git = "https://github.com/lovesh/amcl_rust_wrapper" 15 | rev = "4ea40f758e9d676937ea3e609d63b37fe9e1df7f" 16 | features = ["secp256k1"] -------------------------------------------------------------------------------- /musig/README.md: -------------------------------------------------------------------------------- 1 | # API 2 | 3 | #### Generate keys 4 | ``` 5 | let keypair = Keypair::new(None); 6 | OR 7 | let rng = EntropyRng::new(); 8 | let keypair = Keypair::new(Some(rng)); 9 | 10 | let my_sk = keypair.sig_key; 11 | let my_vk = keypair.ver_key; 12 | ``` 13 | 14 | #### Sign 15 | Signing is an interactive 3-phase process. 16 | 1. Each signer generates a secret nonce, commits to that nonce and creates a hash of this commitment. In the first phase, signer generates these and shares the hash with other cosigners.. 17 | ```rust 18 | let signer = Signer::new(num_cosigners); // num_cosigners is the total number of signers including the current signer 19 | signer.init_phase_1(); 20 | ``` 21 | Each signer gives a numeric reference starting from 1 to other signers. These references are local to the signer. 22 | On receiving hash `h` from signer referred by `j`, it calls `got_hash` 23 | ```rust 24 | signer.got_hash(h, j).unwrap(); 25 | ``` 26 | 27 | 2. Once a signer has got hash of commitment from **all** other signers, it shares its commitment with other signers. 28 | On receiving commitment `c` from signer referred by `j`, it calls, `got_commitment`. `got_commitment` checks if the hash in phase 1 was for this commitment. 29 | Note that `got_commitment` can only be called if it has got hash from all. This can be checked by calling `is_phase_1_complete` 30 | ```rust 31 | signer.got_commitment(c, j).unwrap(); 32 | ``` 33 | 34 | 3. Once a signer has got commitment from **all** other signers, it generates its signature using `generate_sig`. 35 | Note that `generate_sig` can only be called if it has got commitment from all. This can be checked by calling `is_phase_2_complete` 36 | ```rust 37 | let msg = "Message to sign"; 38 | let msg_b = msg.as_bytes(); 39 | let all_verkeys = vec![my_vk, others_vk, ....]; 40 | let sig = signer.generate_sig(msg_b, &keypair.sig_key, &keypair.ver_key, &all_verkeys).unwrap(); 41 | ``` 42 | `generate_sig` creates an aggregated verification key and the signer's contribution in the aggregated verification key. Both of them don't depend on the nonce or message but are dependent on the cosigner group. 43 | Hence when the same cosigner group is creating many such signatures, it is more efficient to create signatures by computing the aggregate values only once and then reusing them for all subsequent signatures. 44 | ```rust 45 | let L = HashedVerKeys::new(&all_verkeys); 46 | let a = L.hash_with_verkey(&keypair.ver_key); 47 | let sig = Signer::generate_sig_using_aggregated_objs(msg_b, &keypair.sig_key, &nonce, &keypair.ver_key, &aggregate_nonce, &a, &aggregate_verkey); 48 | ``` 49 | 50 | ### Signature Aggregation and Verification 51 | #### Signature Aggregation 52 | Once signers have generated their signatures, the can be aggregated together. 53 | ```rust 54 | let signatures = vec![sig1, sig2]; 55 | let aggr_sig = AggregatedSignature::new(&signatures); 56 | ``` 57 | 58 | #### Aggregate Signature Verification 59 | Anyone possessing all the verification keys can verify the aggregate signature using `verify`. 60 | ```rust 61 | assert!(aggr_sig.verify(msg_b, &all_verkeys)); 62 | ``` 63 | 64 | `verify` will create the aggregated verkey. When many signatures need to be verified using the same cosigner group, it is more efficient to create the aggregated 65 | verkey once and use that to verify signatures. 66 | ```rust 67 | let avk = AggregatedVerKey::new(&all_verkeys); 68 | assert!(aggr_sig.verify_using_aggregated_verkey(b, &avk)); 69 | ``` 70 | 71 | #### Serialization and Deserialization 72 | ``` 73 | let bs: Vec = vec![1, 5, 190, 200, ......] 74 | 75 | let sk = SigKey::from_bytes(&bs); 76 | let sk_bytes = sk.tobytes(); 77 | 78 | let vk = VerKey::from_bytes(&bs); 79 | let vk_bytes = vk.tobytes(); 80 | 81 | Similar for AggregatedVerKey -------------------------------------------------------------------------------- /musig/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate amcl_wrapper; 2 | extern crate rand; 3 | 4 | pub mod musig; 5 | -------------------------------------------------------------------------------- /musig/src/musig.rs: -------------------------------------------------------------------------------- 1 | extern crate rand; 2 | 3 | use amcl_wrapper::constants::MODBYTES; 4 | use amcl_wrapper::errors::SerzDeserzError; 5 | use amcl_wrapper::field_elem::FieldElement; 6 | use amcl_wrapper::group_elem::GroupElement; 7 | use amcl_wrapper::group_elem_g1::G1; 8 | use rand::rngs::EntropyRng; 9 | use rand::RngCore; 10 | 11 | #[derive(Debug, Clone, Copy)] 12 | pub enum MuSigError { 13 | IncorrectCosignerRef(usize), 14 | UnknownCosignerRef(usize), 15 | HashToCommitmentNotPresent(usize), 16 | HashDoesNotMatchCommitment(usize), 17 | Phase1Incomplete(), 18 | Phase2Incomplete(), 19 | DifferentNonceFoundDuringAggregation(G1), 20 | } 21 | 22 | pub struct SigKey { 23 | pub x: FieldElement, 24 | } 25 | 26 | impl SigKey { 27 | pub fn new(rng: Option) -> Self { 28 | match rng { 29 | Some(mut r) => SigKey { 30 | x: FieldElement::random_using_rng(&mut r), 31 | }, 32 | None => SigKey { 33 | x: FieldElement::random(), 34 | }, 35 | } 36 | } 37 | 38 | pub fn from_bytes(sk_bytes: &[u8]) -> Result { 39 | FieldElement::from_bytes(sk_bytes).map(|x| SigKey { x }) 40 | } 41 | 42 | pub fn to_bytes(&self) -> Vec { 43 | self.x.to_bytes() 44 | } 45 | } 46 | 47 | pub struct VerKey { 48 | pub point: G1, 49 | } 50 | 51 | impl Clone for VerKey { 52 | fn clone(&self) -> VerKey { 53 | VerKey { 54 | point: self.point.clone(), 55 | } 56 | } 57 | } 58 | 59 | impl VerKey { 60 | pub fn from_sigkey(sk: &SigKey) -> Self { 61 | VerKey { 62 | point: G1::generator() * sk.x, 63 | } 64 | } 65 | 66 | pub fn from_bytes(vk_bytes: &[u8]) -> Result { 67 | G1::from_bytes(vk_bytes).map(|point| VerKey { point }) 68 | } 69 | 70 | pub fn to_bytes(&self) -> Vec { 71 | self.point.to_bytes() 72 | } 73 | } 74 | 75 | pub struct Keypair { 76 | pub sig_key: SigKey, 77 | pub ver_key: VerKey, 78 | } 79 | 80 | impl Keypair { 81 | pub fn new(rng: Option) -> Self { 82 | let sk = SigKey::new(rng); 83 | let vk = VerKey::from_sigkey(&sk); 84 | Keypair { 85 | sig_key: sk, 86 | ver_key: vk, 87 | } 88 | } 89 | } 90 | 91 | pub struct HashedVerKeys { 92 | pub b: [u8; MODBYTES], 93 | } 94 | 95 | impl HashedVerKeys { 96 | pub fn new(verkeys: &Vec) -> HashedVerKeys { 97 | let mut bytes: Vec = vec![]; 98 | for vk in verkeys { 99 | bytes.extend(vk.to_bytes()); 100 | } 101 | let mut b: [u8; MODBYTES] = [0; MODBYTES]; 102 | b.copy_from_slice(&FieldElement::from_msg_hash(&bytes).to_bytes()); 103 | HashedVerKeys { b } 104 | } 105 | 106 | pub fn hash_with_verkey(&self, verkey: &VerKey) -> FieldElement { 107 | let mut bytes: Vec = vec![]; 108 | bytes.extend(self.b.iter()); 109 | bytes.extend(verkey.to_bytes()); 110 | // TODO: Need domain separation for H_agg 111 | FieldElement::from_msg_hash(&bytes) 112 | } 113 | } 114 | 115 | pub struct AggregatedVerKey { 116 | pub point: G1, 117 | } 118 | 119 | impl Clone for AggregatedVerKey { 120 | fn clone(&self) -> AggregatedVerKey { 121 | AggregatedVerKey { 122 | point: self.point.clone(), 123 | } 124 | } 125 | } 126 | 127 | impl AggregatedVerKey { 128 | pub fn new(verkeys: &Vec) -> Self { 129 | let L = HashedVerKeys::new(verkeys); 130 | Self::new_from_L(verkeys, &L) 131 | } 132 | 133 | pub fn new_from_L(verkeys: &Vec, L: &HashedVerKeys) -> Self { 134 | let mut avk = G1::identity(); 135 | for vk in verkeys { 136 | let a = L.hash_with_verkey(vk); 137 | let point = vk.point * a; 138 | avk += point; 139 | } 140 | AggregatedVerKey { point: avk } 141 | } 142 | 143 | pub fn from_bytes(vk_bytes: &[u8]) -> Result { 144 | G1::from_bytes(vk_bytes).map(|point| AggregatedVerKey { point }) 145 | } 146 | 147 | pub fn to_bytes(&self) -> Vec { 148 | self.point.to_bytes() 149 | } 150 | } 151 | 152 | type Signature = (FieldElement, G1); 153 | 154 | /// `t`, `R` are local (to the current signer) references to the cosigners. 155 | /// The current signer always references himself by index 0. 156 | pub struct Signer { 157 | pub r: FieldElement, 158 | pub R: Vec, 159 | pub t: Vec, 160 | } 161 | 162 | impl Signer { 163 | /// `num_cosigners` is inclusive of the current signer. 164 | pub fn new(num_cosigners: usize) -> Self { 165 | Signer { 166 | r: FieldElement::new(), 167 | // It is cleaner to use Vec of Option and use None for unfilled index rather than identity or zero 168 | R: (0..num_cosigners).map(|_| G1::identity()).collect(), 169 | t: (0..num_cosigners).map(|_| FieldElement::zero()).collect(), 170 | } 171 | } 172 | 173 | /// Signer creates his r, R and t 174 | pub fn init_phase_1(&mut self) { 175 | let r = FieldElement::random(); 176 | let R = G1::generator() * r; 177 | // TODO: Need domain separation for H_com 178 | let t = FieldElement::from_msg_hash(&R.to_bytes()); 179 | self.r = r; 180 | self.R[0] = R; 181 | self.t[0] = t; 182 | } 183 | 184 | /// Process the received `t` from other cosigners 185 | pub fn got_hash(&mut self, t: FieldElement, cosigner_ref: usize) -> Result<(), MuSigError> { 186 | self.validate_cosigner_ref(cosigner_ref)?; 187 | self.t[cosigner_ref] = t; 188 | Ok(()) 189 | } 190 | 191 | /// Process the received `R` from other cosigners 192 | pub fn got_commitment(&mut self, R: G1, cosigner_ref: usize) -> Result<(), MuSigError> { 193 | if !self.is_phase_1_complete() { 194 | return Err(MuSigError::Phase1Incomplete()); 195 | } 196 | self.validate_cosigner_ref(cosigner_ref)?; 197 | let expected_t = FieldElement::from_msg_hash(&R.to_bytes()); 198 | if expected_t != self.t[cosigner_ref] { 199 | return Err(MuSigError::HashDoesNotMatchCommitment(cosigner_ref)); 200 | } 201 | self.R[cosigner_ref] = R; 202 | Ok(()) 203 | } 204 | 205 | pub fn generate_sig( 206 | &self, 207 | msg: &[u8], 208 | sig_key: &SigKey, 209 | verkey: &VerKey, 210 | all_verkeys: &Vec, 211 | ) -> Result { 212 | if !self.is_phase_2_complete() { 213 | return Err(MuSigError::Phase2Incomplete()); 214 | } 215 | let R = Self::compute_aggregated_nonce(&self.R); 216 | 217 | let L = HashedVerKeys::new(all_verkeys); 218 | let a = L.hash_with_verkey(&verkey); 219 | let avk = AggregatedVerKey::new_from_L(all_verkeys, &L); 220 | 221 | Ok(Signer::generate_sig_using_aggregated_objs( 222 | msg, sig_key, &self.r, verkey, R, &a, &avk, 223 | )) 224 | } 225 | 226 | /// Checks if `t`, i.e. hash to commitment from all cosigners is received 227 | pub fn is_phase_1_complete(&self) -> bool { 228 | for t in &self.t { 229 | if t.is_zero() { 230 | return false; 231 | } 232 | } 233 | true 234 | } 235 | 236 | /// Checks if `R`, i.e. commitment from all cosigners is received 237 | pub fn is_phase_2_complete(&self) -> bool { 238 | for R in &self.R { 239 | if R.is_identity() { 240 | return false; 241 | } 242 | } 243 | true 244 | } 245 | 246 | pub fn compute_aggregated_nonce(nonces: &[G1]) -> G1 { 247 | let mut R = G1::identity(); 248 | for n in nonces { 249 | R += *n; 250 | } 251 | R 252 | } 253 | 254 | pub fn compute_challenge(msg: &[u8], aggr_verkey: &[u8], aggr_nonce: &[u8]) -> FieldElement { 255 | // TODO: Need domain separation for H_sig 256 | let mut challenge_bytes: Vec = vec![]; 257 | challenge_bytes.extend(aggr_verkey); 258 | challenge_bytes.extend(aggr_nonce); 259 | challenge_bytes.extend(msg); 260 | FieldElement::from_msg_hash(&challenge_bytes) 261 | } 262 | 263 | fn validate_cosigner_ref(&self, cosigner_ref: usize) -> Result<(), MuSigError> { 264 | if cosigner_ref == 0 { 265 | // Since 0 always references the current signer 266 | return Err(MuSigError::IncorrectCosignerRef(cosigner_ref)); 267 | } 268 | // Does not matter if `self.R.len` is used or `self.t.len` as they have same length 269 | if cosigner_ref >= self.t.len() { 270 | return Err(MuSigError::UnknownCosignerRef(cosigner_ref)); 271 | } 272 | Ok(()) 273 | } 274 | 275 | pub fn generate_sig_using_aggregated_objs( 276 | msg: &[u8], 277 | sig_key: &SigKey, 278 | nonce: &FieldElement, 279 | verkey: &VerKey, 280 | R: G1, 281 | a: &FieldElement, 282 | avk: &AggregatedVerKey, 283 | ) -> Signature { 284 | let challenge = Self::compute_challenge(msg, &avk.to_bytes(), &R.to_bytes()); 285 | 286 | let s = (challenge * a * sig_key.x) + nonce; 287 | (s, R) 288 | } 289 | 290 | /* 291 | 292 | pub fn from_bytes(sig_bytes: &[u8]) -> Result { 293 | FieldElement::from_bytes(sig_bytes).map(|x| Signature { x }) 294 | 295 | } 296 | 297 | pub fn to_bytes(&self) -> Vec { 298 | self.x.to_bytes() 299 | }*/ 300 | } 301 | 302 | pub struct AggregatedSignature { 303 | pub s: FieldElement, 304 | pub R: G1, 305 | } 306 | 307 | impl AggregatedSignature { 308 | pub fn new(signatures: &[Signature]) -> Result { 309 | assert!(signatures.len() > 0); 310 | let mut aggr_sig = signatures[0].0.clone(); 311 | let R = signatures[0].1.clone(); 312 | for sig in signatures.iter().skip(1) { 313 | if sig.1 != R { 314 | return Err(MuSigError::DifferentNonceFoundDuringAggregation(R)); 315 | } 316 | aggr_sig += sig.0 317 | } 318 | Ok(AggregatedSignature { s: aggr_sig, R }) 319 | } 320 | 321 | pub fn verify(&self, msg: &[u8], ver_keys: &Vec) -> bool { 322 | let avk = AggregatedVerKey::new(ver_keys); 323 | self.verify_using_aggregated_verkey(msg, &avk) 324 | } 325 | 326 | pub fn verify_using_aggregated_verkey(&self, msg: &[u8], avk: &AggregatedVerKey) -> bool { 327 | let challenge = Signer::compute_challenge(msg, &avk.to_bytes(), &self.R.to_bytes()); 328 | let lhs = G1::generator() * self.s; 329 | let rhs = &self.R + (&avk.point * &challenge); 330 | lhs == rhs 331 | } 332 | 333 | /*pub fn from_bytes(asig_bytes: &[u8]) -> Result { 334 | FieldElement::from_bytes(asig_bytes).map(|s| AggregatedSignature { s }) 335 | 336 | } 337 | 338 | pub fn to_bytes(&self) -> Vec { 339 | self.s.to_bytes() 340 | }*/ 341 | } 342 | 343 | #[cfg(test)] 344 | mod tests { 345 | use super::*; 346 | 347 | #[test] 348 | fn gen_verkey() { 349 | let sk = SigKey::new(None); 350 | let vk1 = VerKey::from_sigkey(&sk); 351 | let vk2 = VerKey::from_sigkey(&sk); 352 | assert_eq!(&vk1.point.to_hex(), &vk2.point.to_hex()); 353 | 354 | let bs = vk1.to_bytes(); 355 | let vk11 = VerKey::from_bytes(&bs).unwrap(); 356 | assert_eq!(&vk1.point.to_hex(), &vk11.point.to_hex()); 357 | 358 | let bs = sk.to_bytes(); 359 | let sk1 = SigKey::from_bytes(&bs).unwrap(); 360 | assert_eq!(&sk1.x.to_hex(), &sk.x.to_hex()); 361 | } 362 | 363 | #[test] 364 | fn aggr_sign_verify() { 365 | let num_cosigners = 5; 366 | let keypairs: Vec = (0..num_cosigners).map(|_| Keypair::new(None)).collect(); 367 | let verkeys: Vec = keypairs.iter().map(|k| k.ver_key.clone()).collect(); 368 | 369 | let msgs = vec![ 370 | "Small msg", 371 | "121220888888822111212", 372 | "Some message to sign", 373 | "Some message to sign, making it bigger, ......, still bigger........................, not some entropy, hu2jnnddsssiu8921n ckhddss2222", 374 | " is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum." 375 | ]; 376 | 377 | for msg in msgs { 378 | let mut signers: Vec<_> = (0..num_cosigners) 379 | .map(|_| Signer::new(num_cosigners)) 380 | .collect(); 381 | for signer in &mut signers { 382 | signer.init_phase_1(); 383 | } 384 | 385 | // Do phase 1. Each cosigner generates r, t, R and shares t with others. 386 | let ts: Vec = (0..num_cosigners) 387 | .map(|i| signers[i].t[0].clone()) 388 | .collect(); 389 | for i in 0..num_cosigners { 390 | let signer = &mut signers[i]; 391 | let mut k = 1; 392 | for j in 0..num_cosigners { 393 | if i == j { 394 | continue; 395 | } 396 | signer.got_hash(ts[j], k).unwrap(); 397 | k += 1; 398 | } 399 | } 400 | for i in 0..num_cosigners { 401 | assert!(signers[i].is_phase_1_complete()); 402 | } 403 | 404 | // Do phase 2. Each cosigner shares R with others 405 | let Rs: Vec = (0..num_cosigners) 406 | .map(|i| signers[i].R[0].clone()) 407 | .collect(); 408 | for i in 0..num_cosigners { 409 | let signer = &mut signers[i]; 410 | let mut k = 1; 411 | for j in 0..num_cosigners { 412 | if i == j { 413 | continue; 414 | } 415 | signer.got_commitment(Rs[j], k).unwrap(); 416 | k += 1; 417 | } 418 | } 419 | for i in 0..num_cosigners { 420 | assert!(signers[i].is_phase_2_complete()); 421 | } 422 | 423 | let mut signatures: Vec = vec![]; 424 | let msg_b = msg.as_bytes(); 425 | for i in 0..num_cosigners { 426 | let signer = &signers[i]; 427 | let keypair = &keypairs[i]; 428 | let sig = signer 429 | .generate_sig(msg_b, &keypair.sig_key, &keypair.ver_key, &verkeys) 430 | .unwrap(); 431 | signatures.push(sig); 432 | } 433 | let aggr_sig = AggregatedSignature::new(&signatures).unwrap(); 434 | assert!(aggr_sig.verify(msg_b, &verkeys)); 435 | 436 | let verkeys = keypairs.iter().map(|k| k.ver_key.clone()).collect(); 437 | let L = HashedVerKeys::new(&verkeys); 438 | let mut avk = AggregatedVerKey::new(&verkeys); 439 | 440 | let mut signatures: Vec = vec![]; 441 | let R = Signer::compute_aggregated_nonce(&signers[0].R); 442 | for i in 0..num_cosigners { 443 | let keypair = &keypairs[i]; 444 | let a = L.hash_with_verkey(&keypair.ver_key); 445 | let sig = Signer::generate_sig_using_aggregated_objs( 446 | msg_b, 447 | &keypair.sig_key, 448 | &signers[i].r, 449 | &keypair.ver_key, 450 | R, 451 | &a, 452 | &avk, 453 | ); 454 | signatures.push(sig); 455 | } 456 | let aggr_sig = AggregatedSignature::new(&signatures).unwrap(); 457 | assert!(aggr_sig.verify_using_aggregated_verkey(msg_b, &avk)); 458 | 459 | let bs = avk.to_bytes(); 460 | let mut avk_from_bytes = AggregatedVerKey::from_bytes(&bs).unwrap(); 461 | // FIXME: Next line fails, probably something wrong with main amcl codebase. 462 | //assert_eq!(&avk.point.to_hex(), &avk_from_bytes.point.to_hex()); 463 | assert!(aggr_sig.verify_using_aggregated_verkey(msg_b, &avk_from_bytes)); 464 | } 465 | } 466 | } 467 | -------------------------------------------------------------------------------- /ps/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ps_sig" 3 | version = "0.1.1" 4 | authors = ["lovesh "] 5 | edition = "2018" 6 | description = "Pointcheval Sanders signatures" 7 | license = "Apache-2.0" 8 | 9 | [dependencies] 10 | rand = "0.6" 11 | failure = "0.1.5" 12 | serde = "1.0" 13 | serde_derive = "1.0" 14 | 15 | [dependencies.amcl_wrapper] 16 | version = "0.1.6" 17 | default-features = false 18 | features = ["bls381"] 19 | 20 | [features] 21 | default = ["G1G2"] 22 | G1G2 = [] 23 | G2G1 = [] -------------------------------------------------------------------------------- /ps/README.md: -------------------------------------------------------------------------------- 1 | [Short Randomizable signatures](https://eprint.iacr.org/2015/525) by David Pointcheval and Olivier Sanders. 2 | Implementing signature scheme from section 6.1 of the paper as it allows for signing committed messages as well. Demonstrated by test `test_sig_committed_messages`. 3 | Implementing proof of knowledge of a signature from section 6.2 of paper. Demonstrated by test `test_PoK_sig`. 4 | In addition to proof of knowledge, the user can also reveal some of the messages under the signature without revealing all messages or signature. 5 | Demonstrated in test `test_PoK_sig_reveal_messages`. 6 | A more comprehensive test where a user gets signature over a mix of messages where some of them are known while 7 | others are committed to and then a proof of knowledge is done for signature with selectively revealing some messages. Demonstrated in the test `test_scenario_1`. 8 | 9 | 10 | The groups for public key (*_tilde) and signatures can be flipped by compiling with feature `G1G2` or `G2G1`. These features are mutually exclusive. The default feature is `G2G1` meaning signatures are in group G1. 11 | 12 | To run tests with signature in group G1. The proof of knowledge of signatures will involve a multi-exponentiation in group G2. 13 | ``` 14 | cargo test --release --no-default-features --features G2G1 15 | ``` 16 | 17 | To run tests with signature in group G2. The proof of knowledge of signatures will involve a multi-exponentiation in group G1. 18 | ``` 19 | cargo test --release --no-default-features --features G1G2 20 | ``` 21 | 22 | To benchmark, run tests prefixed with `timing` and the time taken for various actions will be printed. 23 | ``` 24 | cargo test --release --no-default-features --features G1G2 timing -- --nocapture 25 | ``` 26 | 27 | or 28 | ``` 29 | cargo test --release --no-default-features --features G2G1 timing -- --nocapture 30 | ``` 31 | 32 | -------------------------------------------------------------------------------- /ps/src/errors.rs: -------------------------------------------------------------------------------- 1 | use failure::Error; 2 | 3 | #[derive(Debug, Fail)] 4 | pub enum PSError { 5 | #[fail( 6 | display = "Verkey has unequal number of Y and Y_tilde elements. Y={} and Y_tilde={}", 7 | y, y_tilde 8 | )] 9 | InvalidVerkey { y: usize, y_tilde: usize }, 10 | 11 | #[fail( 12 | display = "Verkey valid for {} messages but given {} messages", 13 | expected, given 14 | )] 15 | UnsupportedNoOfMessages { expected: usize, given: usize }, 16 | 17 | #[fail( 18 | display = "Same no of bases and exponents required. {} bases and {} exponents", 19 | bases, exponents 20 | )] 21 | UnequalNoOfBasesExponents { bases: usize, exponents: usize }, 22 | 23 | #[fail(display = "Error with message {:?}", msg)] 24 | GeneralError { msg: String }, 25 | } 26 | -------------------------------------------------------------------------------- /ps/src/keys.rs: -------------------------------------------------------------------------------- 1 | use amcl_wrapper::field_elem::FieldElement; 2 | use amcl_wrapper::group_elem::GroupElement; 3 | 4 | use crate::errors::PSError; 5 | use crate::{OtherGroup, SignatureGroup}; 6 | 7 | #[derive(Clone, Debug, Serialize, Deserialize)] 8 | pub struct Sigkey { 9 | pub X: SignatureGroup, 10 | } 11 | 12 | #[derive(Clone, Debug, Serialize, Deserialize)] 13 | pub struct Verkey { 14 | pub g: SignatureGroup, 15 | pub g_tilde: OtherGroup, 16 | pub X_tilde: OtherGroup, 17 | pub Y: Vec, 18 | pub Y_tilde: Vec, 19 | } 20 | 21 | impl Verkey { 22 | pub fn validate(&self) -> Result<(), PSError> { 23 | if self.Y.len() != self.Y_tilde.len() { 24 | return Err(PSError::InvalidVerkey { 25 | y: self.Y.len(), 26 | y_tilde: self.Y_tilde.len(), 27 | }); 28 | } 29 | Ok(()) 30 | } 31 | } 32 | 33 | pub fn keygen(count_messages: usize, label: &[u8]) -> (Sigkey, Verkey) { 34 | // TODO: Take PRNG as argument 35 | let g = SignatureGroup::from_msg_hash(&[label, " : g".as_bytes()].concat()); 36 | let g_tilde = OtherGroup::from_msg_hash(&[label, " : g_tilde".as_bytes()].concat()); 37 | let x = FieldElement::random(); 38 | let mut Y = vec![]; 39 | let mut Y_tilde = vec![]; 40 | let X = &g * &x; 41 | let X_tilde = &g_tilde * &x; 42 | for i in 0..count_messages { 43 | // It is mandatory that all Y and Y_tilde have same discrete log wrt. g and g_tilde respectively. 44 | // But once Y and Y_tilde are generated, y is not needed. 45 | let y = FieldElement::random(); 46 | Y.push(&g * &y); 47 | Y_tilde.push(&g_tilde * &y); 48 | } 49 | ( 50 | Sigkey { X }, 51 | Verkey { 52 | g, 53 | g_tilde, 54 | X_tilde, 55 | Y, 56 | Y_tilde, 57 | }, 58 | ) 59 | } 60 | 61 | #[cfg(test)] 62 | mod tests { 63 | use super::*; 64 | // For benchmarking 65 | use std::time::{Duration, Instant}; 66 | 67 | #[test] 68 | fn test_keygen() { 69 | let count_msgs = 5; 70 | let (sk, vk) = keygen(count_msgs, "test".as_bytes()); 71 | assert!(vk.validate().is_ok()); 72 | assert_eq!(vk.Y.len(), count_msgs); 73 | assert_eq!(vk.Y_tilde.len(), count_msgs); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /ps/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | 3 | #[cfg(all(feature = "G1G2", feature = "G2G1"))] 4 | compile_error!("features `G1G2` and `G2G1` are mutually exclusive"); 5 | 6 | #[macro_use] 7 | extern crate amcl_wrapper; 8 | 9 | use amcl_wrapper::extension_field_gt::GT; 10 | 11 | #[cfg(feature = "G1G2")] 12 | pub type SignatureGroup = amcl_wrapper::group_elem_g2::G2; 13 | #[cfg(feature = "G1G2")] 14 | pub type SignatureGroupVec = amcl_wrapper::group_elem_g2::G2Vector; 15 | #[cfg(feature = "G1G2")] 16 | pub type OtherGroup = amcl_wrapper::group_elem_g1::G1; 17 | #[cfg(feature = "G1G2")] 18 | pub type OtherGroupVec = amcl_wrapper::group_elem_g1::G1Vector; 19 | #[cfg(feature = "G1G2")] 20 | pub fn ate_2_pairing( 21 | g1: &SignatureGroup, 22 | g2: &OtherGroup, 23 | h1: &SignatureGroup, 24 | h2: &OtherGroup, 25 | ) -> GT { 26 | GT::ate_2_pairing(g2, g1, h2, h1) 27 | } 28 | 29 | #[cfg(feature = "G2G1")] 30 | pub type SignatureGroup = amcl_wrapper::group_elem_g1::G1; 31 | #[cfg(feature = "G2G1")] 32 | pub type SignatureGroupVec = amcl_wrapper::group_elem_g1::G1Vector; 33 | #[cfg(feature = "G2G1")] 34 | pub type OtherGroup = amcl_wrapper::group_elem_g2::G2; 35 | #[cfg(feature = "G2G1")] 36 | pub type OtherGroupVec = amcl_wrapper::group_elem_g2::G2Vector; 37 | #[cfg(feature = "G2G1")] 38 | pub fn ate_2_pairing( 39 | g1: &SignatureGroup, 40 | g2: &OtherGroup, 41 | h1: &SignatureGroup, 42 | h2: &OtherGroup, 43 | ) -> GT { 44 | GT::ate_2_pairing(g1, g2, h1, h2) 45 | } 46 | 47 | extern crate rand; 48 | #[macro_use] 49 | extern crate failure; 50 | 51 | extern crate serde; 52 | #[macro_use] 53 | extern crate serde_derive; 54 | 55 | pub mod errors; 56 | pub mod keys; 57 | #[macro_use] 58 | pub mod pok_vc; 59 | pub mod pok_sig; 60 | pub mod signature; 61 | -------------------------------------------------------------------------------- /ps/src/pok_sig.rs: -------------------------------------------------------------------------------- 1 | // Proof of knowledge of signature 2 | 3 | use crate::errors::PSError; 4 | use crate::keys::Verkey; 5 | use crate::signature::Signature; 6 | use crate::{ate_2_pairing, OtherGroup, OtherGroupVec, SignatureGroup, SignatureGroupVec}; 7 | use amcl_wrapper::field_elem::{FieldElement, FieldElementVector}; 8 | use amcl_wrapper::group_elem::{GroupElement, GroupElementVector}; 9 | use amcl_wrapper::group_elem_g1::{G1Vector, G1}; 10 | use amcl_wrapper::group_elem_g2::{G2Vector, G2}; 11 | use std::collections::{HashMap, HashSet}; 12 | 13 | // Implement proof of knowledge of committed values in a vector commitment for `SignatureGroup` and `OtherGroup` 14 | 15 | impl_PoK_VC!( 16 | ProverCommittingSignatureGroup, 17 | ProverCommittedSignatureGroup, 18 | ProofSignatureGroup, 19 | SignatureGroup, 20 | SignatureGroupVec 21 | ); 22 | 23 | impl_PoK_VC!( 24 | ProverCommittingOtherGroup, 25 | ProverCommittedOtherGroup, 26 | ProofOtherGroup, 27 | OtherGroup, 28 | OtherGroupVec 29 | ); 30 | 31 | /* 32 | As section 6.2 describes, for proving knowledge of a signature, the signature sigma is first randomized and also 33 | transformed into a sequential aggregate signature with extra message t for public key g_tilde (and secret key 1). 34 | 1. Say the signature sigma is transformed to sigma_prime = (sigma_prime_1, sigma_prime_2) like step 1 in 6.2 35 | 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. 36 | The verifier now checks whether e(sigma_prime_1, J) == e(sigma_prime_2, g_tilde). Since X_tilde is known, 37 | 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'. 38 | The verifier will then check the pairing e(sigma_prime_1, J'*X_tilde) == e(sigma_prime_2, g_tilde). 39 | 40 | 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 41 | then add the revealed values (raised to the respective generators) to get a final J which will then be used in the pairing check. 42 | */ 43 | #[derive(Clone, Debug, Serialize, Deserialize)] 44 | pub struct PoKOfSignature { 45 | pub secrets: FieldElementVector, 46 | pub sig: Signature, 47 | pub J: OtherGroup, 48 | pub pok_vc: ProverCommittedOtherGroup, 49 | } 50 | 51 | #[derive(Clone, Debug, Serialize, Deserialize)] 52 | pub struct PoKOfSignatureProof { 53 | pub sig: Signature, 54 | pub J: OtherGroup, 55 | pub proof_vc: ProofOtherGroup, 56 | } 57 | 58 | impl PoKOfSignature { 59 | /// Section 6.2 of paper 60 | pub fn init( 61 | sig: &Signature, 62 | vk: &Verkey, 63 | messages: &[FieldElement], 64 | revealed_msg_indices: HashSet, 65 | ) -> Result { 66 | for idx in &revealed_msg_indices { 67 | if *idx >= messages.len() { 68 | return Err(PSError::GeneralError { 69 | msg: format!("Index {} should be less than {}", idx, messages.len()), 70 | }); 71 | } 72 | } 73 | Signature::check_verkey_and_messages_compat(messages, vk)?; 74 | let r = FieldElement::random(); 75 | let t = FieldElement::random(); 76 | 77 | // Transform signature to an aggregate signature on (messages, t) 78 | let sigma_prime_1 = &sig.sigma_1 * &r; 79 | let sigma_prime_2 = (&sig.sigma_2 + (&sig.sigma_1 * &t)) * &r; 80 | 81 | // +1 for `t` 82 | let hidden_msg_count = vk.Y_tilde.len() - revealed_msg_indices.len() + 1; 83 | let mut bases = OtherGroupVec::with_capacity(hidden_msg_count); 84 | let mut exponents = FieldElementVector::with_capacity(hidden_msg_count); 85 | bases.push(vk.g_tilde.clone()); 86 | exponents.push(t.clone()); 87 | for i in 0..vk.Y_tilde.len() { 88 | if revealed_msg_indices.contains(&i) { 89 | continue; 90 | } 91 | bases.push(vk.Y_tilde[i].clone()); 92 | exponents.push(messages[i].clone()); 93 | } 94 | // 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 95 | let J = bases.multi_scalar_mul_const_time(&exponents).unwrap(); 96 | 97 | // For proving knowledge of messages in J. 98 | let mut committing = ProverCommittingOtherGroup::new(); 99 | for b in bases.as_slice() { 100 | committing.commit(b, None); 101 | } 102 | let committed = committing.finish(); 103 | 104 | let sigma_prime = Signature { 105 | sigma_1: sigma_prime_1, 106 | sigma_2: sigma_prime_2, 107 | }; 108 | Ok(Self { 109 | secrets: exponents, 110 | sig: sigma_prime, 111 | J, 112 | pok_vc: committed, 113 | }) 114 | } 115 | 116 | /// Return byte representation of public elements so they can be used for challenge computation 117 | pub fn to_bytes(&self) -> Vec { 118 | let mut bytes = vec![]; 119 | bytes.append(&mut self.sig.to_bytes()); 120 | bytes.append(&mut self.J.to_bytes()); 121 | bytes.append(&mut self.pok_vc.to_bytes()); 122 | bytes 123 | } 124 | 125 | pub fn gen_proof(self, challenge: &FieldElement) -> Result { 126 | let proof_vc = self.pok_vc.gen_proof(challenge, self.secrets.as_slice())?; 127 | Ok(PoKOfSignatureProof { 128 | sig: self.sig, 129 | J: self.J, 130 | proof_vc, 131 | }) 132 | } 133 | } 134 | 135 | impl PoKOfSignatureProof { 136 | pub fn verify( 137 | &self, 138 | vk: &Verkey, 139 | revealed_msgs: HashMap, 140 | challenge: &FieldElement, 141 | ) -> Result { 142 | if self.sig.sigma_1.is_identity() || self.sig.sigma_2.is_identity() { 143 | return Ok(false); 144 | } 145 | 146 | vk.validate()?; 147 | // +1 for `t` 148 | let hidden_msg_count = vk.Y_tilde.len() - revealed_msgs.len() + 1; 149 | let mut bases = OtherGroupVec::with_capacity(hidden_msg_count); 150 | bases.push(vk.g_tilde.clone()); 151 | for i in 0..vk.Y_tilde.len() { 152 | if revealed_msgs.contains_key(&i) { 153 | continue; 154 | } 155 | bases.push(vk.Y_tilde[i].clone()); 156 | } 157 | if !self.proof_vc.verify(bases.as_slice(), &self.J, challenge)? { 158 | return Ok(false); 159 | } 160 | // 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 161 | let mut j; 162 | let J = if revealed_msgs.is_empty() { 163 | &self.J 164 | } else { 165 | j = self.J.clone(); 166 | let mut b = OtherGroupVec::with_capacity(revealed_msgs.len()); 167 | let mut e = FieldElementVector::with_capacity(revealed_msgs.len()); 168 | for (i, m) in revealed_msgs { 169 | b.push(vk.Y_tilde[i].clone()); 170 | e.push(m.clone()); 171 | } 172 | j += b.multi_scalar_mul_var_time(&e).unwrap(); 173 | &j 174 | }; 175 | // e(sigma_1, (J + &X_tilde)) == e(sigma_2, g_tilde) => e(sigma_1, (J + &X_tilde)) * e(-sigma_2, g_tilde) == 1 176 | // Slight optimization possible by precomputing inverse of g_tilde and storing to avoid inverse of sig.sigma_2 177 | let res = ate_2_pairing( 178 | &self.sig.sigma_1, 179 | &(J + &vk.X_tilde), 180 | &(-&self.sig.sigma_2), 181 | &vk.g_tilde, 182 | ); 183 | Ok(res.is_one()) 184 | } 185 | } 186 | 187 | #[cfg(test)] 188 | mod tests { 189 | use super::*; 190 | // For benchmarking 191 | use crate::keys::keygen; 192 | use std::time::{Duration, Instant}; 193 | 194 | impl_PoK_VC!( 195 | ProverCommittingSignatureGroup, 196 | ProverCommittedSignatureGroup, 197 | ProofSignatureGroup, 198 | SignatureGroup, 199 | SignatureGroupVec 200 | ); 201 | 202 | #[test] 203 | fn test_PoK_VC_SignatureGroup() { 204 | let n = 5; 205 | 206 | test_PoK_VC!( 207 | n, 208 | ProverCommittingSignatureGroup, 209 | ProverCommittedSignatureGroup, 210 | ProofSignatureGroup, 211 | SignatureGroup, 212 | SignatureGroupVec 213 | ); 214 | } 215 | 216 | #[test] 217 | fn test_PoK_VC_OtherGroup() { 218 | let n = 5; 219 | 220 | test_PoK_VC!( 221 | n, 222 | ProverCommittingOtherGroup, 223 | ProverCommittedOtherGroup, 224 | ProofOtherGroup, 225 | OtherGroup, 226 | OtherGroupVec 227 | ); 228 | } 229 | 230 | #[test] 231 | fn test_sig_committed_messages() { 232 | let count_msgs = 5; 233 | let committed_msgs = 2; 234 | let (sk, vk) = keygen(count_msgs, "test".as_bytes()); 235 | let msgs = FieldElementVector::random(count_msgs); 236 | let blinding = FieldElement::random(); 237 | 238 | // User commits to messages 239 | // XXX: In production always use multi-scalar multiplication 240 | let mut comm = SignatureGroup::new(); 241 | for i in 0..committed_msgs { 242 | comm += (&vk.Y[i] * &msgs[i]); 243 | } 244 | comm += (&vk.g * &blinding); 245 | 246 | // User and signer engage in a proof of knowledge for the above commitment `comm` 247 | let mut bases = Vec::::new(); 248 | let mut hidden_msgs = Vec::::new(); 249 | for i in 0..committed_msgs { 250 | bases.push(vk.Y[i].clone()); 251 | hidden_msgs.push(msgs[i].clone()); 252 | } 253 | bases.push(vk.g.clone()); 254 | hidden_msgs.push(blinding.clone()); 255 | 256 | // User creates a random commitment, computes challenge and response. The proof of knowledge consists of commitment and responses 257 | let mut committing = ProverCommittingSignatureGroup::new(); 258 | for b in &bases { 259 | committing.commit(b, None); 260 | } 261 | let committed = committing.finish(); 262 | 263 | // Note: The challenge may come from the main protocol 264 | let chal = committed.gen_challenge(comm.to_bytes()); 265 | 266 | let proof = committed.gen_proof(&chal, hidden_msgs.as_slice()).unwrap(); 267 | 268 | // Signer verifies the proof of knowledge. 269 | assert!(proof.verify(bases.as_slice(), &comm, &chal).unwrap()); 270 | 271 | let sig_blinded = Signature::new_with_committed_attributes( 272 | &comm, 273 | &msgs.as_slice()[committed_msgs..count_msgs], 274 | &sk, 275 | &vk, 276 | ) 277 | .unwrap(); 278 | let sig_unblinded = sig_blinded.get_unblinded_signature(&blinding); 279 | assert!(sig_unblinded.verify(msgs.as_slice(), &vk).unwrap()); 280 | } 281 | 282 | #[test] 283 | fn test_PoK_sig() { 284 | let count_msgs = 5; 285 | let (sk, vk) = keygen(count_msgs, "test".as_bytes()); 286 | let msgs = FieldElementVector::random(count_msgs); 287 | let sig = Signature::new(msgs.as_slice(), &sk, &vk).unwrap(); 288 | assert!(sig.verify(msgs.as_slice(), &vk).unwrap()); 289 | 290 | let pok = PoKOfSignature::init(&sig, &vk, msgs.as_slice(), HashSet::new()).unwrap(); 291 | 292 | let chal = pok.pok_vc.gen_challenge(pok.J.to_bytes()); 293 | 294 | let proof = pok.gen_proof(&chal).unwrap(); 295 | 296 | assert!(proof.verify(&vk, HashMap::new(), &chal).unwrap()); 297 | } 298 | 299 | #[test] 300 | fn test_PoK_sig_reveal_messages() { 301 | let count_msgs = 10; 302 | let (sk, vk) = keygen(count_msgs, "test".as_bytes()); 303 | let msgs = FieldElementVector::random(count_msgs); 304 | let sig = Signature::new(msgs.as_slice(), &sk, &vk).unwrap(); 305 | assert!(sig.verify(msgs.as_slice(), &vk).unwrap()); 306 | 307 | let mut revealed_msg_indices = HashSet::new(); 308 | revealed_msg_indices.insert(2); 309 | revealed_msg_indices.insert(4); 310 | revealed_msg_indices.insert(9); 311 | 312 | let pok = 313 | PoKOfSignature::init(&sig, &vk, msgs.as_slice(), revealed_msg_indices.clone()).unwrap(); 314 | 315 | let chal = pok.pok_vc.gen_challenge(pok.J.to_bytes()); 316 | 317 | let proof = pok.gen_proof(&chal).unwrap(); 318 | 319 | let mut revealed_msgs = HashMap::new(); 320 | for i in &revealed_msg_indices { 321 | revealed_msgs.insert(i.clone(), msgs[*i].clone()); 322 | } 323 | assert!(proof.verify(&vk, revealed_msgs.clone(), &chal).unwrap()); 324 | 325 | // Reveal wrong message 326 | let mut revealed_msgs_1 = revealed_msgs.clone(); 327 | revealed_msgs_1.insert(2, FieldElement::random()); 328 | assert!(!proof.verify(&vk, revealed_msgs_1.clone(), &chal).unwrap()); 329 | } 330 | 331 | #[test] 332 | fn timing_pok_signature() { 333 | // Measure time to prove knowledge of signatures, both generation and verification of proof 334 | let iterations = 100; 335 | let count_msgs = 10; 336 | let (sk, vk) = keygen(count_msgs, "test".as_bytes()); 337 | 338 | let msgs = FieldElementVector::random(count_msgs); 339 | let sig = Signature::new(msgs.as_slice(), &sk, &vk).unwrap(); 340 | 341 | let mut total_generating = Duration::new(0, 0); 342 | let mut total_verifying = Duration::new(0, 0); 343 | 344 | for _ in 0..iterations { 345 | let start = Instant::now(); 346 | 347 | let pok = PoKOfSignature::init(&sig, &vk, msgs.as_slice(), HashSet::new()).unwrap(); 348 | 349 | let chal = pok.pok_vc.gen_challenge(pok.J.to_bytes()); 350 | 351 | let proof = pok.gen_proof(&chal).unwrap(); 352 | total_generating += start.elapsed(); 353 | 354 | let start = Instant::now(); 355 | assert!(proof.verify(&vk, HashMap::new(), &chal).unwrap()); 356 | total_verifying += start.elapsed(); 357 | } 358 | 359 | println!( 360 | "Time to create {} proofs is {:?}", 361 | iterations, total_generating 362 | ); 363 | println!( 364 | "Time to verify {} proofs is {:?}", 365 | iterations, total_verifying 366 | ); 367 | } 368 | } 369 | -------------------------------------------------------------------------------- /ps/src/pok_vc.rs: -------------------------------------------------------------------------------- 1 | // Proof of knowledge of committed values in a vector Pedersen commitment. 2 | 3 | // `ProverCommitting` will contains vectors of generators and random values. 4 | // `ProverCommitting` has a `commit` method that optionally takes a value as blinding, if not provided, it creates its own. 5 | // `ProverCommitting` has a `finish` method that results in creation of `ProverCommitted` object after consuming `ProverCommitting` 6 | // `ProverCommitted` marks the end of commitment phase and has the final commitment. 7 | // `ProverCommitted` has a method to generate the challenge by hashing all generators and commitment. It is optional 8 | // to use this method as the challenge may come from a super-protocol or from verifier. It takes a vector of bytes that it includes for hashing for computing the challenge 9 | // `ProverCommitted` has a method `gen_proof` to generate proof. It takes the secrets and the challenge to generate responses. 10 | // During response generation `ProverCommitted` is consumed to create `Proof` object containing the commitments and responses. 11 | // `Proof` can then be verified by the verifier. 12 | 13 | /*pub struct ProverCommitting<'a, T: GroupElement> { 14 | gens: Vec<&'a T>, 15 | blindings: Vec, 16 | } 17 | 18 | pub struct ProverCommitted<'a, T: GroupElement> { 19 | gens: Vec<&'a T>, 20 | blindings: Vec, 21 | commitment: T 22 | } 23 | 24 | impl<'a, T> ProverCommitting<'a, T> where T: GroupElement { 25 | pub fn new() -> Self { 26 | Self { 27 | gens: vec![], 28 | blindings: vec![], 29 | } 30 | } 31 | 32 | pub fn commit(&mut self, gen: &'a T, blinding: Option) -> usize { 33 | let blinding = match blinding { 34 | Some(b) => b, 35 | None => FieldElement::random() 36 | }; 37 | let idx = self.gens.len(); 38 | self.gens.push(gen); 39 | self.blindings.push(blinding); 40 | idx 41 | } 42 | 43 | pub fn finish(self) -> ProverCommitted<'a, T> { 44 | // XXX: Need multi-scalar multiplication to be implemented for GroupElementVector. 45 | // XXX: Also implement operator overloading for GroupElement. 46 | unimplemented!() 47 | } 48 | 49 | pub fn get_index(&self, idx: usize) -> Result<(&'a T, &FieldElement), PSError> { 50 | if idx >= self.gens.len() { 51 | return Err(PSError::GeneralError { msg: format!("index {} greater than size {}", idx, self.gens.len()) }); 52 | } 53 | Ok((self.gens[idx], &self.blindings[idx])) 54 | } 55 | }*/ 56 | 57 | #[macro_export] 58 | macro_rules! impl_PoK_VC { 59 | ( $ProverCommitting:ident, $ProverCommitted:ident, $Proof:ident, $group_element:ident, $group_element_vec:ident ) => { 60 | /// Proof of knowledge of messages in a vector commitment. 61 | /// Commit for each message. 62 | #[derive(Clone, Debug, Serialize, Deserialize)] 63 | pub struct $ProverCommitting { 64 | gens: $group_element_vec, 65 | blindings: FieldElementVector, 66 | } 67 | 68 | /// Receive or generate challenge. Compute response and proof 69 | #[derive(Clone, Debug, Serialize, Deserialize)] 70 | pub struct $ProverCommitted { 71 | gens: $group_element_vec, 72 | blindings: FieldElementVector, 73 | commitment: $group_element, 74 | } 75 | 76 | #[derive(Clone, Debug, Serialize, Deserialize)] 77 | pub struct $Proof { 78 | pub commitment: $group_element, 79 | pub responses: FieldElementVector, 80 | } 81 | 82 | impl $ProverCommitting { 83 | pub fn new() -> Self { 84 | Self { 85 | gens: $group_element_vec::new(0), 86 | blindings: FieldElementVector::new(0), 87 | } 88 | } 89 | 90 | /// generate a new random blinding if None provided 91 | pub fn commit( 92 | &mut self, 93 | gen: &$group_element, 94 | blinding: Option<&FieldElement>, 95 | ) -> usize { 96 | let blinding = match blinding { 97 | Some(b) => b.clone(), 98 | None => FieldElement::random(), 99 | }; 100 | let idx = self.gens.len(); 101 | self.gens.push(gen.clone()); 102 | self.blindings.push(blinding); 103 | idx 104 | } 105 | 106 | /// Add pairwise product of (`self.gens`, self.blindings). Uses multi-exponentiation. 107 | pub fn finish(self) -> $ProverCommitted { 108 | let commitment = self 109 | .gens 110 | .multi_scalar_mul_const_time(&self.blindings) 111 | .unwrap(); 112 | $ProverCommitted { 113 | gens: self.gens, 114 | blindings: self.blindings, 115 | commitment, 116 | } 117 | } 118 | 119 | pub fn get_index( 120 | &self, 121 | idx: usize, 122 | ) -> Result<(&$group_element, &FieldElement), PSError> { 123 | if idx >= self.gens.len() { 124 | return Err(PSError::GeneralError { 125 | msg: format!("index {} greater than size {}", idx, self.gens.len()), 126 | }); 127 | } 128 | Ok((&self.gens[idx], &self.blindings[idx])) 129 | } 130 | } 131 | 132 | impl $ProverCommitted { 133 | pub fn to_bytes(&self) -> Vec { 134 | let mut bytes = vec![]; 135 | for b in self.gens.as_slice() { 136 | bytes.append(&mut b.to_bytes()); 137 | } 138 | bytes.append(&mut self.commitment.to_bytes()); 139 | bytes 140 | } 141 | 142 | /// This step will be done by the main protocol for which this PoK is a sub-protocol 143 | pub fn gen_challenge(&self, mut extra: Vec) -> FieldElement { 144 | let mut bytes = self.to_bytes(); 145 | bytes.append(&mut extra); 146 | FieldElement::from_msg_hash(&bytes) 147 | } 148 | 149 | /// For each secret, generate a response as self.blinding[i] - challenge*secrets[i]. 150 | pub fn gen_proof( 151 | self, 152 | challenge: &FieldElement, 153 | secrets: &[FieldElement], 154 | ) -> Result<$Proof, PSError> { 155 | if secrets.len() != self.gens.len() { 156 | return Err(PSError::UnequalNoOfBasesExponents { 157 | bases: self.gens.len(), 158 | exponents: secrets.len(), 159 | }); 160 | } 161 | let mut responses = FieldElementVector::with_capacity(self.gens.len()); 162 | for i in 0..self.gens.len() { 163 | responses.push(&self.blindings[i] - (challenge * &secrets[i])); 164 | } 165 | Ok($Proof { 166 | commitment: self.commitment, 167 | responses, 168 | }) 169 | } 170 | } 171 | 172 | impl $Proof { 173 | /// Verify that bases[0]^responses[0] * bases[0]^responses[0] * ... bases[i]^responses[i] * commitment^challenge == random_commitment 174 | pub fn verify( 175 | &self, 176 | bases: &[$group_element], 177 | commitment: &$group_element, 178 | challenge: &FieldElement, 179 | ) -> Result { 180 | // bases[0]^responses[0] * bases[0]^responses[0] * ... bases[i]^responses[i] * commitment^challenge == random_commitment 181 | // => 182 | // bases[0]^responses[0] * bases[0]^responses[0] * ... bases[i]^responses[i] * commitment^challenge * random_commitment^-1 == 1 183 | if bases.len() != self.responses.len() { 184 | return Err(PSError::UnequalNoOfBasesExponents { 185 | bases: bases.len(), 186 | exponents: self.responses.len(), 187 | }); 188 | } 189 | let mut points = $group_element_vec::from(bases); 190 | let mut scalars = self.responses.clone(); 191 | points.push(commitment.clone()); 192 | scalars.push(challenge.clone()); 193 | let pr = points.multi_scalar_mul_var_time(&scalars).unwrap() - &self.commitment; 194 | Ok(pr.is_identity()) 195 | } 196 | } 197 | }; 198 | } 199 | 200 | #[cfg(test)] 201 | #[macro_export] 202 | macro_rules! test_PoK_VC { 203 | ( $n:ident, $ProverCommitting:ident, $ProverCommitted:ident, $Proof:ident, $group_element:ident, $group_element_vec:ident ) => { 204 | let mut gens = $group_element_vec::with_capacity($n); 205 | let mut secrets = FieldElementVector::with_capacity($n); 206 | let mut commiting = $ProverCommitting::new(); 207 | for _ in 0..$n - 1 { 208 | let g = $group_element::random(); 209 | commiting.commit(&g, None); 210 | gens.push(g); 211 | secrets.push(FieldElement::random()); 212 | } 213 | 214 | // Add one of the blindings externally 215 | let g = $group_element::random(); 216 | let r = FieldElement::random(); 217 | commiting.commit(&g, Some(&r)); 218 | let (g_, r_) = commiting.get_index($n - 1).unwrap(); 219 | assert_eq!(g, *g_); 220 | assert_eq!(r, *r_); 221 | gens.push(g); 222 | secrets.push(FieldElement::random()); 223 | 224 | let committed = commiting.finish(); 225 | let commitment = gens.multi_scalar_mul_const_time(&secrets).unwrap(); 226 | let challenge = committed.gen_challenge(commitment.to_bytes()); 227 | let proof = committed.gen_proof(&challenge, secrets.as_slice()).unwrap(); 228 | 229 | assert!(proof 230 | .verify(gens.as_slice(), &commitment, &challenge) 231 | .unwrap()); 232 | // Wrong challenge or commitment fails to verify 233 | assert!(!proof 234 | .verify(gens.as_slice(), &$group_element::random(), &challenge) 235 | .unwrap()); 236 | assert!(!proof 237 | .verify(gens.as_slice(), &commitment, &FieldElement::random()) 238 | .unwrap()); 239 | }; 240 | } 241 | 242 | #[cfg(test)] 243 | pub(crate) mod tests { 244 | use super::*; 245 | // XXX: Error for VC should be independent of PS 246 | use crate::errors::PSError; 247 | use amcl_wrapper::field_elem::{FieldElement, FieldElementVector}; 248 | use amcl_wrapper::group_elem::{GroupElement, GroupElementVector}; 249 | use amcl_wrapper::group_elem_g1::{G1Vector, G1}; 250 | use amcl_wrapper::group_elem_g2::{G2Vector, G2}; 251 | 252 | #[test] 253 | fn test_PoK_VC_G1() { 254 | // Proof of knowledge of committed values in a vector commitment. The committment lies in group G1. 255 | impl_PoK_VC!(ProverCommittingG1, ProverCommittedG1, ProofG1, G1, G1Vector); 256 | 257 | let n = 5; 258 | test_PoK_VC!( 259 | n, 260 | ProverCommittingG1, 261 | ProverCommittedG1, 262 | ProofG1, 263 | G1, 264 | G1Vector 265 | ); 266 | } 267 | 268 | #[test] 269 | fn test_PoK_VC_G2() { 270 | // Proof of knowledge of committed values in a vector commitment. The committment lies in group G2. 271 | impl_PoK_VC!(ProverCommittingG2, ProverCommittedG2, ProofG2, G2, G2Vector); 272 | 273 | let n = 5; 274 | test_PoK_VC!( 275 | n, 276 | ProverCommittingG2, 277 | ProverCommittedG2, 278 | ProofG2, 279 | G2, 280 | G2Vector 281 | ); 282 | } 283 | } 284 | -------------------------------------------------------------------------------- /ps/src/signature.rs: -------------------------------------------------------------------------------- 1 | use crate::amcl_wrapper::group_elem::GroupElementVector; 2 | use crate::errors::PSError; 3 | use crate::keys::{Sigkey, Verkey}; 4 | use crate::{ate_2_pairing, OtherGroup, OtherGroupVec, SignatureGroup, SignatureGroupVec}; 5 | use amcl_wrapper::field_elem::{FieldElement, FieldElementVector}; 6 | use amcl_wrapper::group_elem::GroupElement; 7 | 8 | #[derive(Clone, Debug, Serialize, Deserialize)] 9 | pub struct Signature { 10 | pub sigma_1: SignatureGroup, 11 | pub sigma_2: SignatureGroup, 12 | } 13 | 14 | /// Section 6.1 of paper 15 | impl Signature { 16 | /// No committed messages. All messages known to signer. 17 | pub fn new( 18 | messages: &[FieldElement], 19 | sigkey: &Sigkey, 20 | verkey: &Verkey, 21 | ) -> Result { 22 | // TODO: Take PRNG as argument. This will allow deterministic signatures as well 23 | Self::check_verkey_and_messages_compat(messages, verkey)?; 24 | let (sigma_1, sigma_2) = Self::_sign(messages, sigkey, verkey, None); 25 | Ok(Signature { sigma_1, sigma_2 }) 26 | } 27 | 28 | /// 1 or more messages are captured in a commitment `commitment`. The remaining known messages are in `messages`. 29 | /// This is a blind signature. 30 | pub fn new_with_committed_attributes( 31 | commitment: &SignatureGroup, 32 | messages: &[FieldElement], 33 | sigkey: &Sigkey, 34 | verkey: &Verkey, 35 | ) -> Result { 36 | verkey.validate()?; 37 | // There should be commitment to at least one message 38 | if messages.len() >= verkey.Y.len() { 39 | return Err(PSError::UnsupportedNoOfMessages { 40 | expected: messages.len(), 41 | given: verkey.Y.len(), 42 | }); 43 | } 44 | 45 | let (sigma_1, sigma_2) = Self::_sign(messages, sigkey, verkey, Some(commitment)); 46 | Ok(Signature { sigma_1, sigma_2 }) 47 | } 48 | 49 | /// Verify a signature. During proof of knowledge also, this method is used after extending the verkey 50 | pub fn verify(&self, messages: &[FieldElement], verkey: &Verkey) -> Result { 51 | if self.sigma_1.is_identity() || self.sigma_2.is_identity() { 52 | return Ok(false); 53 | } 54 | Self::check_verkey_and_messages_compat(messages, verkey)?; 55 | let mut points = OtherGroupVec::with_capacity(messages.len()); 56 | let mut scalars = FieldElementVector::with_capacity(messages.len()); 57 | for i in 0..messages.len() { 58 | scalars.push(messages[i].clone()); 59 | points.push(verkey.Y_tilde[i].clone()); 60 | } 61 | // pr = X_tilde * Y_tilde[0]^messages[0] * Y_tilde[1]^messages[1] * .... Y_tilde[i]^messages[i] 62 | let pr = &verkey.X_tilde + &points.multi_scalar_mul_var_time(&scalars).unwrap(); 63 | // check e(sigma_1, pr) == e(sigma_2, g_tilde) => e(sigma_1, pr) * e(sigma_2, g_tilde)^-1 == 1 64 | // 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 65 | // inverse in sigma_2 can be avoided since inverse of g_tilde can be precomputed 66 | let res = ate_2_pairing(&self.sigma_1, &pr, &(-&self.sigma_2), &verkey.g_tilde); 67 | Ok(res.is_one()) 68 | } 69 | 70 | /// Once signature on committed attributes (blind signature) is received, the signature needs to be unblinded. 71 | /// Takes the blinding used in the commitment. 72 | pub fn get_unblinded_signature(&self, blinding: &FieldElement) -> Self { 73 | let sigma_1 = self.sigma_1.clone(); 74 | let sigma_1_t = &sigma_1 * blinding; 75 | let sigma_2 = &self.sigma_2 - sigma_1_t; 76 | Self { sigma_1, sigma_2 } 77 | } 78 | 79 | pub fn to_bytes(&self) -> Vec { 80 | let mut bytes = vec![]; 81 | bytes.append(&mut self.sigma_1.to_bytes()); 82 | bytes.append(&mut self.sigma_2.to_bytes()); 83 | bytes 84 | } 85 | 86 | pub fn check_verkey_and_messages_compat( 87 | messages: &[FieldElement], 88 | verkey: &Verkey, 89 | ) -> Result<(), PSError> { 90 | verkey.validate()?; 91 | if messages.len() != verkey.Y.len() { 92 | return Err(PSError::UnsupportedNoOfMessages { 93 | expected: messages.len(), 94 | given: verkey.Y.len(), 95 | }); 96 | } 97 | Ok(()) 98 | } 99 | 100 | pub fn _sign( 101 | messages: &[FieldElement], 102 | sigkey: &Sigkey, 103 | verkey: &Verkey, 104 | commitment: Option<&SignatureGroup>, 105 | ) -> (SignatureGroup, SignatureGroup) { 106 | let u = FieldElement::random(); 107 | // sigma_1 = g^u 108 | let sigma_1 = &verkey.g * &u; 109 | let mut points = SignatureGroupVec::new(0); 110 | let mut scalars = FieldElementVector::new(0); 111 | let offset = verkey.Y.len() - messages.len(); 112 | for i in 0..messages.len() { 113 | scalars.push(messages[i].clone()); 114 | points.push(verkey.Y[offset + i].clone()); 115 | } 116 | // sigma_2 = {X + Y_i^{m_i} + commitment}^u 117 | let mut sigma_2 = &sigkey.X + &points.multi_scalar_mul_const_time(&scalars).unwrap(); 118 | if commitment.is_some() { 119 | sigma_2 += commitment.unwrap() 120 | } 121 | sigma_2 = &sigma_2 * &u; 122 | (sigma_1, sigma_2) 123 | } 124 | } 125 | 126 | #[cfg(test)] 127 | mod tests { 128 | use super::*; 129 | use crate::keys::keygen; 130 | // For benchmarking 131 | use std::time::{Duration, Instant}; 132 | 133 | #[test] 134 | fn test_signature_all_known_messages() { 135 | for i in 0..10 { 136 | let count_msgs = (i % 5) + 1; 137 | let (sk, vk) = keygen(count_msgs, "test".as_bytes()); 138 | let msgs = FieldElementVector::random(count_msgs); 139 | let msgs = msgs.as_slice(); 140 | let sig = Signature::new(msgs, &sk, &vk).unwrap(); 141 | assert!(sig.verify(msgs, &vk).unwrap()); 142 | } 143 | } 144 | 145 | #[test] 146 | fn test_signature_single_committed_message() { 147 | for _ in 0..10 { 148 | let count_msgs = 1; 149 | let (sk, vk) = keygen(count_msgs, "test".as_bytes()); 150 | let msg = FieldElement::random(); 151 | let blinding = FieldElement::random(); 152 | 153 | // commitment = Y[0]^msg * g^blinding 154 | let comm = (&vk.Y[0] * &msg) + (&vk.g * &blinding); 155 | 156 | let sig_blinded = 157 | Signature::new_with_committed_attributes(&comm, &[], &sk, &vk).unwrap(); 158 | let sig_unblinded = sig_blinded.get_unblinded_signature(&blinding); 159 | assert!(sig_unblinded.verify(&[msg], &vk).unwrap()); 160 | } 161 | } 162 | 163 | #[test] 164 | fn test_signature_many_committed_messages() { 165 | for i in 0..10 { 166 | let count_msgs = (i % 5) + 1; 167 | let (sk, vk) = keygen(count_msgs, "test".as_bytes()); 168 | let msgs = FieldElementVector::random(count_msgs); 169 | let blinding = FieldElement::random(); 170 | 171 | // XXX: In production always use multi-scalar multiplication 172 | let mut comm = SignatureGroup::new(); 173 | for i in 0..count_msgs { 174 | comm += (&vk.Y[i] * &msgs[i]); 175 | } 176 | comm += (&vk.g * &blinding); 177 | let sig_blinded = 178 | Signature::new_with_committed_attributes(&comm, &[], &sk, &vk).unwrap(); 179 | let sig_unblinded = sig_blinded.get_unblinded_signature(&blinding); 180 | assert!(sig_unblinded.verify(msgs.as_slice(), &vk).unwrap()); 181 | } 182 | } 183 | 184 | #[test] 185 | fn test_signature_known_and_committed_messages() { 186 | for i in 0..10 { 187 | let count_msgs = (i % 6) + 1; 188 | let committed_msgs = (i % count_msgs) + 1; 189 | let (sk, vk) = keygen(count_msgs, "test".as_bytes()); 190 | let msgs = FieldElementVector::random(count_msgs); 191 | let blinding = FieldElement::random(); 192 | 193 | // XXX: In production always use multi-scalar multiplication 194 | let mut comm = SignatureGroup::new(); 195 | for i in 0..committed_msgs { 196 | comm += (&vk.Y[i] * &msgs[i]); 197 | } 198 | comm += (&vk.g * &blinding); 199 | 200 | let sig_blinded = Signature::new_with_committed_attributes( 201 | &comm, 202 | &msgs.as_slice()[committed_msgs..count_msgs], 203 | &sk, 204 | &vk, 205 | ) 206 | .unwrap(); 207 | let sig_unblinded = sig_blinded.get_unblinded_signature(&blinding); 208 | assert!(sig_unblinded.verify(msgs.as_slice(), &vk).unwrap()); 209 | } 210 | } 211 | 212 | #[test] 213 | fn timing_signature_over_known_and_committed_messages() { 214 | // Measure time to create and verify signatures. Verifying time will include time to unblind the signature as well. 215 | let iterations = 100; 216 | let count_msgs = 10; 217 | let committed_msgs = 3; 218 | let (sk, vk) = keygen(count_msgs, "test".as_bytes()); 219 | let mut total_signing = Duration::new(0, 0); 220 | let mut total_verifying = Duration::new(0, 0); 221 | for _ in 0..iterations { 222 | let msgs = FieldElementVector::random(count_msgs); 223 | let blinding = FieldElement::random(); 224 | // XXX: In production always use multi-scalar multiplication 225 | let mut comm = SignatureGroup::new(); 226 | for i in 0..committed_msgs { 227 | comm += (&vk.Y[i] * &msgs[i]); 228 | } 229 | comm += (&vk.g * &blinding); 230 | 231 | let start = Instant::now(); 232 | let sig_blinded = Signature::new_with_committed_attributes( 233 | &comm, 234 | &msgs.as_slice()[committed_msgs..count_msgs], 235 | &sk, 236 | &vk, 237 | ) 238 | .unwrap(); 239 | total_signing += start.elapsed(); 240 | 241 | let start = Instant::now(); 242 | let sig_unblinded = sig_blinded.get_unblinded_signature(&blinding); 243 | assert!(sig_unblinded.verify(msgs.as_slice(), &vk).unwrap()); 244 | total_verifying += start.elapsed(); 245 | } 246 | 247 | println!( 248 | "Time to create {} signatures is {:?}", 249 | iterations, total_signing 250 | ); 251 | println!( 252 | "Time to verify {} signatures is {:?}", 253 | iterations, total_verifying 254 | ); 255 | } 256 | // TODO: Add tests for negative cases like more messages than supported by public key, etc 257 | } 258 | -------------------------------------------------------------------------------- /ps/tests/scenario.rs: -------------------------------------------------------------------------------- 1 | use amcl_wrapper::field_elem::{FieldElement, FieldElementVector}; 2 | use amcl_wrapper::group_elem::{GroupElement, GroupElementVector}; 3 | use ps_sig::keys::keygen; 4 | use ps_sig::pok_sig::*; 5 | use ps_sig::signature::Signature; 6 | use ps_sig::{OtherGroupVec, SignatureGroup}; 7 | use std::collections::{HashMap, HashSet}; 8 | 9 | #[test] 10 | fn test_scenario_1() { 11 | // User request signer to sign 10 messages where signer knows only 8 messages, the rest 2 are given in a form of commitment. 12 | // Once user gets the signature, it engages in a proof of knowledge of signature with a verifier. 13 | // The user also reveals to the verifier some of the messages. 14 | let count_msgs = 10; 15 | let committed_msgs = 2; 16 | let (sk, vk) = keygen(count_msgs, "test".as_bytes()); 17 | let msgs = FieldElementVector::random(count_msgs); 18 | let blinding = FieldElement::random(); 19 | 20 | // User commits to some messages 21 | let mut comm = SignatureGroup::new(); 22 | for i in 0..committed_msgs { 23 | comm += (&vk.Y[i] * &msgs[i]); 24 | } 25 | comm += (&vk.g * &blinding); 26 | 27 | { 28 | // User and signer engage in a proof of knowledge for the above commitment `comm` 29 | let mut bases = Vec::::new(); 30 | let mut hidden_msgs = Vec::::new(); 31 | for i in 0..committed_msgs { 32 | bases.push(vk.Y[i].clone()); 33 | hidden_msgs.push(msgs[i].clone()); 34 | } 35 | bases.push(vk.g.clone()); 36 | hidden_msgs.push(blinding.clone()); 37 | 38 | // User creates a random commitment, computes challenge and response. The proof of knowledge consists of commitment and responses 39 | let mut committing = ProverCommittingSignatureGroup::new(); 40 | for b in &bases { 41 | committing.commit(b, None); 42 | } 43 | let committed = committing.finish(); 44 | 45 | // Note: The challenge may come from the main protocol 46 | let chal = committed.gen_challenge(comm.to_bytes()); 47 | 48 | let proof = committed.gen_proof(&chal, hidden_msgs.as_slice()).unwrap(); 49 | 50 | // Signer verifies the proof of knowledge. 51 | assert!(proof.verify(bases.as_slice(), &comm, &chal).unwrap()); 52 | } 53 | 54 | // Get signature, unblind it and then verify. 55 | let sig_blinded = Signature::new_with_committed_attributes( 56 | &comm, 57 | &msgs.as_slice()[committed_msgs..count_msgs], 58 | &sk, 59 | &vk, 60 | ) 61 | .unwrap(); 62 | let sig_unblinded = sig_blinded.get_unblinded_signature(&blinding); 63 | assert!(sig_unblinded.verify(msgs.as_slice(), &vk).unwrap()); 64 | 65 | // Do a proof of knowledge of the signature and also reveal some of the messages. 66 | let mut revealed_msg_indices = HashSet::new(); 67 | revealed_msg_indices.insert(4); 68 | revealed_msg_indices.insert(6); 69 | revealed_msg_indices.insert(9); 70 | 71 | let pok = PoKOfSignature::init( 72 | &sig_unblinded, 73 | &vk, 74 | msgs.as_slice(), 75 | revealed_msg_indices.clone(), 76 | ) 77 | .unwrap(); 78 | 79 | let chal = pok.pok_vc.gen_challenge(pok.J.to_bytes()); 80 | 81 | let proof = pok.gen_proof(&chal).unwrap(); 82 | 83 | let mut revealed_msgs = HashMap::new(); 84 | for i in &revealed_msg_indices { 85 | revealed_msgs.insert(i.clone(), msgs[*i].clone()); 86 | } 87 | assert!(proof.verify(&vk, revealed_msgs.clone(), &chal).unwrap()); 88 | } 89 | --------------------------------------------------------------------------------