├── .gitignore ├── .travis.yml ├── Cargo.toml ├── LICENSE ├── README.md ├── benches └── range_proof.rs └── src ├── lib.rs └── proofs ├── inner_product.rs ├── mod.rs ├── range_proof.rs ├── range_proof_wip.rs └── weighted_inner_product.rs /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 6 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 7 | Cargo.lock 8 | 9 | # These are backup files generated by rustfmt 10 | **/*.rs.bk 11 | 12 | .idea 13 | /ipp_explanation/ 14 | bpbench.txt 15 | agg_ver_data.log -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | cache: cargo 3 | rust: stable 4 | virt: lxd 5 | 6 | before_install: 7 | - rustup component add rustfmt clippy 8 | 9 | script: 10 | - cargo build --benches --verbose 11 | - cargo test --verbose 12 | - cargo fmt --all -- --check 13 | - cargo clippy -- -D clippy::all 14 | 15 | deploy: 16 | provider: cargo 17 | token: 18 | secure: "NdYHFns/6o5AxxTTFZGPAWQsSjGw5slOqd6Yt7gDsd0Yx0vOY82a4qyD3ohB7so/u1/sHrk+JUVrwW80SkOcQ9l9Fbp3x0LKlpSkNZHn1xR0b5MFjUOUc6KgJgUhKtQ6zOFBhQGSPwU/TeKAXzQIeYsTI5NOBhlc4CS3HbEcJel//OGFxQzUe2HTE58AZMThHS0BC3cBeVOFcjqY1ztamF6EmBqdaprk0sn3a/BBXZlD2ll+cRtXE07TaVcLjNnaZIzmd9Kl5XFGdBmsBtRFtPKi06IQprF6jMfpIguR18yHqwbzYqaP6J2oJ9WXkGwBwUR9Sic2WsxGQcMYglwJsO9M+3IYCDtpU5TZZ1jn2NJfM0zCojMts+b2J95T7I05eJjXM/qvDDU3+MBYupUpMeAM34tQhI5/7tOb23BLQA+PvmkkgawDNhjyPqZl65rJW0UxektncBzSamVA7AClU7KXHvDnnI5c8qyEZb/+2XRguwCNWfgaZOuEKmltSensa04x7Mx7YnJ2lkxQQIoAG9M56nZ+iRTNm8h/KZtqtmKU3c/SujULoYSc8tEwxY/A4rUkNF6jGIF1akIVJ/xKMhRYI35jg8uN4g2A6/q3hn0+f8E4oZPcYdBrf0bBUsxajUOaCE4roIbWjSYRwq5FSdb7ucxZriNE5wH2ERlH8P0=" 19 | on: 20 | tags: true 21 | condition: '"$TRAVIS_TAG" =~ ^v[0-9].+$' 22 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "bulletproof-kzen" 3 | version = "1.2.1" 4 | authors = [ 5 | "Omer Shlomovits ", 6 | "Suyash Bagad " 7 | ] 8 | license = "GPL-3.0" 9 | description = "Implementation of Bulletproofs and Bulletproofs+ aggregated range proofs with multi-exponent verification" 10 | repository = "https://github.com/ZenGo-X/bulletproofs" 11 | categories = ["cryptography", "algorithms"] 12 | keywords = ["cryptography", "crypto", "zero-knowledge", "bulletproofs"] 13 | 14 | [lib] 15 | name = "bulletproof" 16 | crate-type = ["lib"] 17 | 18 | [dependencies] 19 | itertools = "0.7.8" 20 | serde = "1.0" 21 | serde_derive = "1.0" 22 | curv-kzen = { version = "0.10", default-features = false } 23 | sha2 = "0.9" 24 | generic-array = "0.14" 25 | 26 | [dev-dependencies] 27 | criterion = "0.2" 28 | 29 | [features] 30 | default = ["curv-kzen/rust-gmp-kzen"] 31 | 32 | [[bench]] 33 | name = "range_proof" 34 | path = "benches/range_proof.rs" 35 | harness = false 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Bulletproofs 2 | This library implements [Bulletproofs+](https://eprint.iacr.org/2020/735.pdf) and [Bulletproofs](https://eprint.iacr.org/2017/1066.pdf) aggregated range proofs with multi-exponent verification. The library supports multiple elliptic curves: _secp256k1_ , _ristretto_ , _ed25519_ 3 | 4 | 5 | ## Usage 6 | Control range and batch size using `n,m` variables. Supported range is any number `0 14 | */ 15 | 16 | #![allow(clippy::many_single_char_names, clippy::too_many_arguments)] 17 | 18 | // based on the paper: https://eprint.iacr.org/2017/1066.pdf 19 | #[macro_use] 20 | extern crate serde_derive; 21 | extern crate serde; 22 | 23 | extern crate curv; 24 | extern crate generic_array; 25 | extern crate itertools; 26 | extern crate sha2; 27 | 28 | pub mod proofs; 29 | 30 | #[derive(Copy, PartialEq, Eq, Clone, Debug)] 31 | pub enum Errors { 32 | InnerProductError, 33 | WeightedInnerProdError, 34 | RangeProofError, 35 | } 36 | -------------------------------------------------------------------------------- /src/proofs/inner_product.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | 3 | /* 4 | 5 | Copyright 2018 by Kzen Networks 6 | 7 | This file is part of bulletproof library 8 | (https://github.com/KZen-networks/bulletproof) 9 | 10 | bulletproof is free software: you can redistribute 11 | it and/or modify it under the terms of the GNU General Public 12 | License as published by the Free Software Foundation, either 13 | version 3 of the License, or (at your option) any later version. 14 | 15 | @license GPL-3.0+ 16 | */ 17 | 18 | // based on the paper: https://eprint.iacr.org/2017/1066.pdf 19 | use curv::arithmetic::traits::*; 20 | use curv::cryptographic_primitives::hashing::{Digest, DigestExt}; 21 | use curv::elliptic::curves::{secp256_k1::Secp256k1, Point, Scalar}; 22 | use curv::BigInt; 23 | use sha2::Sha256; 24 | 25 | use Errors::{self, InnerProductError}; 26 | 27 | #[derive(Clone, Debug, Serialize, Deserialize)] 28 | pub struct InnerProductArg { 29 | pub(super) L: Vec>, 30 | pub(super) R: Vec>, 31 | pub(super) a_tag: BigInt, 32 | pub(super) b_tag: BigInt, 33 | } 34 | 35 | impl InnerProductArg { 36 | pub fn prove( 37 | G: &[Point], 38 | H: &[Point], 39 | ux: &Point, 40 | P: &Point, 41 | a: &[BigInt], 42 | b: &[BigInt], 43 | mut L_vec: Vec>, 44 | mut R_vec: Vec>, 45 | ) -> InnerProductArg { 46 | let n = G.len(); 47 | 48 | // All of the input vectors must have the same length. 49 | assert_eq!(G.len(), n); 50 | assert_eq!(H.len(), n); 51 | assert_eq!(a.len(), n); 52 | assert_eq!(b.len(), n); 53 | assert!(n.is_power_of_two()); 54 | 55 | // let mut L_vec = Vec::with_capacity(n); 56 | // let mut R_vec = Vec::with_capacity(n); 57 | if n != 1 { 58 | let n = n / 2; 59 | let (a_L, a_R) = a.split_at(n); 60 | let (b_L, b_R) = b.split_at(n); 61 | let (G_L, G_R) = G.split_at(n); 62 | let (H_L, H_R) = H.split_at(n); 63 | 64 | let c_L = inner_product(a_L, b_R); 65 | let c_R = inner_product(a_R, b_L); 66 | 67 | // Note that no element in vectors a_L and b_R can be 0 68 | // since 0 is an invalid secret key! 69 | // 70 | // L = + + c_L * ux 71 | let c_L_fe = Scalar::::from(&c_L); 72 | let ux_CL: Point = ux * &c_L_fe; 73 | let aL_GR = G_R.iter().zip(a_L).fold(ux_CL, |acc, x| { 74 | if x.1 != &BigInt::zero() { 75 | let aLi = Scalar::::from(x.1); 76 | let aLi_GRi: Point = x.0 * &aLi; 77 | acc + &aLi_GRi 78 | } else { 79 | acc 80 | } 81 | }); 82 | let L = H_L.iter().zip(b_R).fold(aL_GR, |acc, x| { 83 | if x.1 != &BigInt::zero() { 84 | let bRi = Scalar::::from(x.1); 85 | let bRi_HLi: Point = x.0 * &bRi; 86 | acc + &bRi_HLi 87 | } else { 88 | acc 89 | } 90 | }); 91 | 92 | // Note that no element in vectors a_R and b_L can be 0 93 | // since 0 is an invalid secret key! 94 | // 95 | // R = + + c_R * ux 96 | let c_R_fe = Scalar::::from(&c_R); 97 | let ux_CR: Point = ux * &c_R_fe; 98 | let aR_GL = G_L.iter().zip(a_R).fold(ux_CR, |acc, x| { 99 | if x.1 != &BigInt::zero() { 100 | let aRi = Scalar::::from(x.1); 101 | let aRi_GLi: Point = x.0 * &aRi; 102 | acc + &aRi_GLi 103 | } else { 104 | acc 105 | } 106 | }); 107 | let R = H_R.iter().zip(b_L).fold(aR_GL, |acc, x| { 108 | if x.1 != &BigInt::zero() { 109 | let bLi = Scalar::::from(x.1); 110 | let bLi_HRi: Point = x.0 * &bLi; 111 | acc + &bLi_HRi 112 | } else { 113 | acc 114 | } 115 | }); 116 | 117 | let x = Sha256::new().chain_points([&L, &R, ux]).result_scalar(); 118 | let x_bn = x.to_bigint(); 119 | let order = Scalar::::group_order(); 120 | let x_inv_fe = x.invert().unwrap(); 121 | 122 | let a_new = (0..n) 123 | .map(|i| { 124 | let aLx = BigInt::mod_mul(&a_L[i], &x_bn, order); 125 | let aR_minusx = BigInt::mod_mul(&a_R[i], &x_inv_fe.to_bigint(), order); 126 | BigInt::mod_add(&aLx, &aR_minusx, order) 127 | }) 128 | .collect::>(); 129 | // a = &mut a_new[..]; 130 | 131 | let b_new = (0..n) 132 | .map(|i| { 133 | let bRx = BigInt::mod_mul(&b_R[i], &x_bn, order); 134 | let bL_minusx = BigInt::mod_mul(&b_L[i], &x_inv_fe.to_bigint(), order); 135 | BigInt::mod_add(&bRx, &bL_minusx, order) 136 | }) 137 | .collect::>(); 138 | // b = &mut b_new[..]; 139 | 140 | let G_new = (0..n) 141 | .map(|i| { 142 | let GLx_inv = &G_L[i] * &x_inv_fe; 143 | let GRx = &G_R[i] * &x; 144 | GRx + GLx_inv 145 | }) 146 | .collect::>>(); 147 | // G = &mut G_new[..]; 148 | 149 | let H_new = (0..n) 150 | .map(|i| { 151 | let HLx = &H_L[i] * &x; 152 | let HRx_inv = &H_R[i] * &x_inv_fe; 153 | HLx + HRx_inv 154 | }) 155 | .collect::>>(); 156 | // H = &mut H_new[..]; 157 | 158 | L_vec.push(L); 159 | R_vec.push(R); 160 | return InnerProductArg::prove(&G_new, &H_new, ux, P, &a_new, &b_new, L_vec, R_vec); 161 | } 162 | 163 | InnerProductArg { 164 | L: L_vec, 165 | R: R_vec, 166 | a_tag: a[0].clone(), 167 | b_tag: b[0].clone(), 168 | } 169 | } 170 | 171 | pub fn verify( 172 | &self, 173 | g_vec: &[Point], 174 | hi_tag: &[Point], 175 | ux: &Point, 176 | P: &Point, 177 | ) -> Result<(), Errors> { 178 | let G = g_vec; 179 | let H = hi_tag; 180 | let n = G.len(); 181 | 182 | // All of the input vectors must have the same length. 183 | assert_eq!(G.len(), n); 184 | assert_eq!(H.len(), n); 185 | assert!(n.is_power_of_two()); 186 | 187 | if n != 1 { 188 | let n = n / 2; 189 | let (G_L, G_R) = G.split_at(n); 190 | let (H_L, H_R) = H.split_at(n); 191 | 192 | let x = Sha256::new() 193 | .chain_points([&self.L[0], &self.R[0], ux]) 194 | .result_scalar(); 195 | let x_bn = x.to_bigint(); 196 | let order = Scalar::::group_order(); 197 | let x_inv_fe = x.invert().unwrap(); 198 | let x_sq_bn = BigInt::mod_mul(&x_bn, &x_bn, order); 199 | let x_inv_sq_bn = BigInt::mod_mul(&x_inv_fe.to_bigint(), &x_inv_fe.to_bigint(), order); 200 | let x_sq_fe = Scalar::::from(&x_sq_bn); 201 | let x_inv_sq_fe = Scalar::::from(&x_inv_sq_bn); 202 | 203 | let G_new = (0..n) 204 | .map(|i| { 205 | let GLx_inv = &G_L[i] * &x_inv_fe; 206 | let GRx = &G_R[i] * &x; 207 | GRx + GLx_inv 208 | }) 209 | .collect::>>(); 210 | // G = &mut G_new[..]; 211 | 212 | let H_new = (0..n) 213 | .map(|i| { 214 | let HLx = &H_L[i] * &x; 215 | let HRx_inv = &H_R[i] * &x_inv_fe; 216 | HLx + HRx_inv 217 | }) 218 | .collect::>>(); 219 | // H = &mut H_new[..]; 220 | let Lx_sq = &self.L[0] * &x_sq_fe; 221 | let Rx_sq_inv = &self.R[0] * &x_inv_sq_fe; 222 | let P_tag = Lx_sq + Rx_sq_inv + P; 223 | let ip = InnerProductArg { 224 | L: (&self.L[1..]).to_vec(), 225 | R: (&self.R[1..]).to_vec(), 226 | a_tag: self.a_tag.clone(), 227 | b_tag: self.b_tag.clone(), 228 | }; 229 | return ip.verify(&G_new, &H_new, ux, &P_tag); 230 | } 231 | 232 | let a_fe = Scalar::::from(&self.a_tag); 233 | let b_fe = Scalar::::from(&self.b_tag); 234 | let c = &a_fe * &b_fe; 235 | let Ga = &G[0] * &a_fe; 236 | let Hb = &H[0] * &b_fe; 237 | let ux_c = ux * &c; 238 | let P_calc = Ga + Hb + ux_c; 239 | if P.clone() == P_calc { 240 | Ok(()) 241 | } else { 242 | Err(InnerProductError) 243 | } 244 | } 245 | 246 | /// 247 | /// Returns Ok() if the given inner product satisfies the verification equations, 248 | /// else returns `InnerProductError`. 249 | /// 250 | /// Uses a single multiexponentiation (multiscalar multiplication in additive notation) 251 | /// check to verify an inner product proof. 252 | /// 253 | pub fn fast_verify( 254 | &self, 255 | g_vec: &[Point], 256 | hi_tag: &[Point], 257 | ux: &Point, 258 | P: &Point, 259 | ) -> Result<(), Errors> { 260 | let G = g_vec; 261 | let H = hi_tag; 262 | let n = G.len(); 263 | let order = Scalar::::group_order(); 264 | 265 | // All of the input vectors must have the same length. 266 | assert_eq!(G.len(), n); 267 | assert_eq!(H.len(), n); 268 | assert!(n.is_power_of_two()); 269 | 270 | let lg_n = self.L.len(); 271 | assert!( 272 | lg_n <= 64, 273 | "Not compatible for vector sizes greater than 2^64!" 274 | ); 275 | 276 | let mut x_sq_vec: Vec = Vec::with_capacity(lg_n); 277 | let mut x_inv_sq_vec: Vec = Vec::with_capacity(lg_n); 278 | let mut minus_x_sq_vec: Vec = Vec::with_capacity(lg_n); 279 | let mut minus_x_inv_sq_vec: Vec = Vec::with_capacity(lg_n); 280 | let mut allinv = BigInt::one(); 281 | for (Li, Ri) in self.L.iter().zip(self.R.iter()) { 282 | let x: Scalar = Sha256::new().chain_points([Li, Ri, ux]).result_scalar(); 283 | let x_bn = x.to_bigint(); 284 | let x_inv_fe = x.invert().unwrap(); 285 | let x_inv_bn = x_inv_fe.to_bigint(); 286 | let x_sq_bn = BigInt::mod_mul(&x_bn, &x_bn, order); 287 | let x_inv_sq_bn = BigInt::mod_mul(&x_inv_fe.to_bigint(), &x_inv_fe.to_bigint(), order); 288 | 289 | x_sq_vec.push(x_sq_bn.clone()); 290 | x_inv_sq_vec.push(x_inv_sq_bn.clone()); 291 | minus_x_sq_vec.push(BigInt::mod_sub(&BigInt::zero(), &x_sq_bn, order)); 292 | minus_x_inv_sq_vec.push(BigInt::mod_sub(&BigInt::zero(), &x_inv_sq_bn, order)); 293 | allinv *= x_inv_bn; 294 | } 295 | 296 | let mut s: Vec = Vec::with_capacity(n); 297 | s.push(allinv); 298 | for i in 1..n { 299 | let lg_i = 300 | (std::mem::size_of_val(&n) * 8) - 1 - ((i as usize).leading_zeros() as usize); 301 | let k = 1 << lg_i; 302 | // The challenges are stored in "creation order" as [x_k,...,x_1], 303 | // so u_{lg(i)+1} = is indexed by (lg_n-1) - lg_i 304 | let x_lg_i_sq = x_sq_vec[(lg_n - 1) - lg_i].clone(); 305 | s.push(s[i - k].clone() * x_lg_i_sq); 306 | } 307 | 308 | let a_times_s: Vec = (0..n) 309 | .map(|i| BigInt::mod_mul(&s[i], &self.a_tag, order)) 310 | .collect(); 311 | 312 | let b_div_s: Vec = (0..n) 313 | .map(|i| { 314 | let s_inv_i = BigInt::mod_inv(&s[i], order).unwrap(); 315 | BigInt::mod_mul(&s_inv_i, &self.b_tag, order) 316 | }) 317 | .collect(); 318 | 319 | let mut scalars: Vec = Vec::with_capacity(2 * n + 2 * lg_n + 1); 320 | scalars.extend_from_slice(&a_times_s); 321 | scalars.extend_from_slice(&b_div_s); 322 | scalars.extend_from_slice(&minus_x_sq_vec); 323 | scalars.extend_from_slice(&minus_x_inv_sq_vec); 324 | 325 | let mut points: Vec> = Vec::with_capacity(2 * n + 2 * lg_n + 1); 326 | points.extend_from_slice(g_vec); 327 | points.extend_from_slice(hi_tag); 328 | points.extend_from_slice(&self.L); 329 | points.extend_from_slice(&self.R); 330 | 331 | let c = BigInt::mod_mul(&self.a_tag, &self.b_tag, order); 332 | let ux_c = ux * &Scalar::::from(&c); 333 | 334 | let tot_len = points.len(); 335 | 336 | let expect_P = (0..tot_len) 337 | .map(|i| &points[i] * &Scalar::::from(&scalars[i])) 338 | .fold(ux_c, |acc, x| acc + x as Point); 339 | 340 | if *P == expect_P { 341 | Ok(()) 342 | } else { 343 | Err(InnerProductError) 344 | } 345 | } 346 | } 347 | 348 | fn inner_product(a: &[BigInt], b: &[BigInt]) -> BigInt { 349 | assert_eq!( 350 | a.len(), 351 | b.len(), 352 | "inner_product(a,b): lengths of vectors do not match" 353 | ); 354 | let out = BigInt::zero(); 355 | let order = Scalar::::group_order(); 356 | let out = a.iter().zip(b).fold(out, |acc, x| { 357 | let aibi = BigInt::mod_mul(x.0, x.1, order); 358 | BigInt::mod_add(&acc, &aibi, order) 359 | }); 360 | out 361 | } 362 | 363 | #[cfg(test)] 364 | mod tests { 365 | use curv::arithmetic::traits::*; 366 | use curv::cryptographic_primitives::hashing::{Digest, DigestExt}; 367 | use curv::elliptic::curves::secp256_k1::hash_to_curve::generate_random_point; 368 | use curv::elliptic::curves::{secp256_k1::Secp256k1, Point, Scalar}; 369 | use curv::BigInt; 370 | use proofs::inner_product::InnerProductArg; 371 | use sha2::Sha512; 372 | 373 | fn test_helper(n: usize) { 374 | let KZen: &[u8] = &[75, 90, 101, 110]; 375 | let kzen_label = BigInt::from_bytes(KZen); 376 | 377 | let g_vec = (0..n) 378 | .map(|i| { 379 | let kzen_label_i = BigInt::from(i as u32) + &kzen_label; 380 | let hash_i = Sha512::new().chain_bigint(&kzen_label_i).result_bigint(); 381 | generate_random_point(&Converter::to_bytes(&hash_i)) 382 | }) 383 | .collect::>>(); 384 | 385 | // can run in parallel to g_vec: 386 | let h_vec = (0..n) 387 | .map(|i| { 388 | let kzen_label_j = BigInt::from(n as u32) + BigInt::from(i as u32) + &kzen_label; 389 | let hash_j = Sha512::new().chain_bigint(&kzen_label_j).result_bigint(); 390 | generate_random_point(&Converter::to_bytes(&hash_j)) 391 | }) 392 | .collect::>>(); 393 | 394 | let label = BigInt::from(1); 395 | let hash = Sha512::new().chain_bigint(&label).result_bigint(); 396 | let Gx = generate_random_point(&Converter::to_bytes(&hash)); 397 | 398 | let a: Vec<_> = (0..n) 399 | .map(|_| { 400 | let rand = Scalar::::random(); 401 | rand.to_bigint() 402 | }) 403 | .collect(); 404 | 405 | let b: Vec<_> = (0..n) 406 | .map(|_| { 407 | let rand = Scalar::::random(); 408 | rand.to_bigint() 409 | }) 410 | .collect(); 411 | let c = super::inner_product(&a, &b); 412 | 413 | let y = Scalar::::random(); 414 | let order = Scalar::::group_order(); 415 | let yi = (0..n) 416 | .map(|i| BigInt::mod_pow(&y.to_bigint(), &BigInt::from(i as u32), order)) 417 | .collect::>(); 418 | 419 | let yi_inv = (0..n) 420 | .map(|i| { 421 | let yi_fe = Scalar::::from(&yi[i]); 422 | yi_fe.invert().unwrap() 423 | }) 424 | .collect::>>(); 425 | 426 | let hi_tag = (0..n) 427 | .map(|i| &h_vec[i] * &yi_inv[i]) 428 | .collect::>>(); 429 | 430 | // R = + + c * ux 431 | let c_fe = Scalar::::from(&c); 432 | let ux_c: Point = &Gx * &c_fe; 433 | let a_G = (0..n) 434 | .map(|i| { 435 | let ai = Scalar::::from(&a[i]); 436 | &g_vec[i] * &ai 437 | }) 438 | .fold(ux_c, |acc, x: Point| acc + x as Point); 439 | let P = (0..n) 440 | .map(|i| { 441 | let bi = Scalar::::from(&b[i]); 442 | &hi_tag[i] * &bi 443 | }) 444 | .fold(a_G, |acc, x: Point| acc + x as Point); 445 | 446 | let L_vec = Vec::with_capacity(n); 447 | let R_vec = Vec::with_capacity(n); 448 | let ipp = InnerProductArg::prove(&g_vec, &hi_tag, &Gx, &P, &a, &b, L_vec, R_vec); 449 | let verifier = ipp.verify(&g_vec, &hi_tag, &Gx, &P); 450 | assert!(verifier.is_ok()) 451 | } 452 | 453 | fn test_helper_fast_verify(n: usize) { 454 | let KZen: &[u8] = &[75, 90, 101, 110]; 455 | let kzen_label = BigInt::from_bytes(KZen); 456 | 457 | let g_vec = (0..n) 458 | .map(|i| { 459 | let kzen_label_i = BigInt::from(i as u32) + &kzen_label; 460 | let hash_i = Sha512::new().chain_bigint(&kzen_label_i).result_bigint(); 461 | generate_random_point(&Converter::to_bytes(&hash_i)) 462 | }) 463 | .collect::>>(); 464 | 465 | // can run in parallel to g_vec: 466 | let h_vec = (0..n) 467 | .map(|i| { 468 | let kzen_label_j = BigInt::from(n as u32) + BigInt::from(i as u32) + &kzen_label; 469 | let hash_j = Sha512::new().chain_bigint(&kzen_label_j).result_bigint(); 470 | generate_random_point(&Converter::to_bytes(&hash_j)) 471 | }) 472 | .collect::>>(); 473 | 474 | let label = BigInt::from(1); 475 | let hash = Sha512::new().chain_bigint(&label).result_bigint(); 476 | let Gx = generate_random_point(&Converter::to_bytes(&hash)); 477 | 478 | let a: Vec<_> = (0..n) 479 | .map(|_| { 480 | let rand = Scalar::::random(); 481 | rand.to_bigint() 482 | }) 483 | .collect(); 484 | 485 | let b: Vec<_> = (0..n) 486 | .map(|_| { 487 | let rand = Scalar::::random(); 488 | rand.to_bigint() 489 | }) 490 | .collect(); 491 | let c = super::inner_product(&a, &b); 492 | 493 | let y = Scalar::::random(); 494 | let order = Scalar::::group_order(); 495 | let yi = (0..n) 496 | .map(|i| BigInt::mod_pow(&y.to_bigint(), &BigInt::from(i as u32), order)) 497 | .collect::>(); 498 | 499 | let yi_inv = (0..n) 500 | .map(|i| { 501 | let yi_fe = Scalar::::from(&yi[i]); 502 | yi_fe.invert().unwrap() 503 | }) 504 | .collect::>>(); 505 | 506 | let hi_tag = (0..n) 507 | .map(|i| &h_vec[i] * &yi_inv[i]) 508 | .collect::>>(); 509 | 510 | // R = + + c * ux 511 | let c_fe = Scalar::::from(&c); 512 | let ux_c: Point = &Gx * &c_fe; 513 | let a_G = (0..n) 514 | .map(|i| { 515 | let ai = Scalar::::from(&a[i]); 516 | &g_vec[i] * &ai 517 | }) 518 | .fold(ux_c, |acc, x: Point| acc + x as Point); 519 | let P = (0..n) 520 | .map(|i| { 521 | let bi = Scalar::::from(&b[i]); 522 | &hi_tag[i] * &bi 523 | }) 524 | .fold(a_G, |acc, x: Point| acc + x as Point); 525 | 526 | let L_vec = Vec::with_capacity(n); 527 | let R_vec = Vec::with_capacity(n); 528 | let ipp = InnerProductArg::prove(&g_vec, &hi_tag, &Gx, &P, &a, &b, L_vec, R_vec); 529 | let verifier = ipp.fast_verify(&g_vec, &hi_tag, &Gx, &P); 530 | assert!(verifier.is_ok()) 531 | } 532 | 533 | fn test_helper_non_power_2(m: usize, n: usize, a: &[BigInt], b: &[BigInt]) { 534 | let KZen: &[u8] = &[75, 90, 101, 110]; 535 | let kzen_label = BigInt::from_bytes(KZen); 536 | 537 | let g_vec = (0..n) 538 | .map(|i| { 539 | let kzen_label_i = BigInt::from(i as u32) + &kzen_label; 540 | let hash_i = Sha512::new().chain_bigint(&kzen_label_i).result_bigint(); 541 | generate_random_point(&Converter::to_bytes(&hash_i)) 542 | }) 543 | .collect::>>(); 544 | 545 | // can run in parallel to g_vec: 546 | let h_vec = (0..n) 547 | .map(|i| { 548 | let kzen_label_j = BigInt::from(n as u32) + BigInt::from(i as u32) + &kzen_label; 549 | let hash_j = Sha512::new().chain_bigint(&kzen_label_j).result_bigint(); 550 | generate_random_point(&Converter::to_bytes(&hash_j)) 551 | }) 552 | .collect::>>(); 553 | 554 | let label = BigInt::from(1); 555 | let hash = Sha512::new().chain_bigint(&label).result_bigint(); 556 | let Gx = generate_random_point(&Converter::to_bytes(&hash)); 557 | 558 | let c = super::inner_product(a, b); 559 | 560 | let y = Scalar::::random(); 561 | let order = Scalar::::group_order(); 562 | let yi = (0..n) 563 | .map(|i| BigInt::mod_pow(&y.to_bigint(), &BigInt::from(i as u32), order)) 564 | .collect::>(); 565 | 566 | let yi_inv = (0..n) 567 | .map(|i| { 568 | let yi_fe = Scalar::::from(&yi[i]); 569 | yi_fe.invert().unwrap() 570 | }) 571 | .collect::>>(); 572 | 573 | let hi_tag = (0..n) 574 | .map(|i| &h_vec[i] * &yi_inv[i]) 575 | .collect::>>(); 576 | 577 | // R = + + c * ux 578 | let c_fe = Scalar::::from(&c); 579 | 580 | let ux_c: Point = &Gx * &c_fe; 581 | 582 | let a_G = (0..m) 583 | .map(|i| { 584 | let ai = Scalar::::from(&a[i]); 585 | &g_vec[i] * &ai 586 | }) 587 | .fold(ux_c, |acc, x: Point| acc + x as Point); 588 | let P = (0..m) 589 | .map(|i| { 590 | let bi = Scalar::::from(&b[i]); 591 | &hi_tag[i] * &bi 592 | }) 593 | .fold(a_G, |acc, x: Point| acc + x as Point); 594 | 595 | let L_vec = Vec::with_capacity(n); 596 | let R_vec = Vec::with_capacity(n); 597 | let ipp = InnerProductArg::prove(&g_vec, &hi_tag, &Gx, &P, a, b, L_vec, R_vec); 598 | let verifier = ipp.verify(&g_vec, &hi_tag, &Gx, &P); 599 | assert!(verifier.is_ok()) 600 | } 601 | 602 | #[test] 603 | fn make_ipp_32() { 604 | test_helper(32); 605 | } 606 | 607 | #[test] 608 | fn make_ipp_16() { 609 | test_helper(16); 610 | } 611 | #[test] 612 | fn make_ipp_8() { 613 | test_helper(8); 614 | } 615 | 616 | #[test] 617 | fn make_ipp_4() { 618 | test_helper(4); 619 | } 620 | 621 | #[test] 622 | fn make_ipp_2() { 623 | test_helper(2); 624 | } 625 | 626 | #[test] 627 | fn make_ipp_1() { 628 | test_helper(1); 629 | } 630 | 631 | #[test] 632 | fn make_ipp_32_fast_verify() { 633 | test_helper_fast_verify(32); 634 | } 635 | 636 | #[test] 637 | fn make_ipp_16_fast_verify() { 638 | test_helper_fast_verify(16); 639 | } 640 | #[test] 641 | fn make_ipp_8_fast_verify() { 642 | test_helper_fast_verify(8); 643 | } 644 | 645 | #[test] 646 | fn make_ipp_4_fast_verify() { 647 | test_helper_fast_verify(4); 648 | } 649 | 650 | #[test] 651 | fn make_ipp_2_fast_verify() { 652 | test_helper_fast_verify(2); 653 | } 654 | 655 | #[test] 656 | fn make_ipp_1_fast_verify() { 657 | test_helper_fast_verify(1); 658 | } 659 | 660 | #[test] 661 | fn make_ipp_non_power_2() { 662 | // Create random scalar vectors a, b with size non-power of 2 663 | let n: usize = 9; 664 | let mut a: Vec<_> = (0..n) 665 | .map(|_| { 666 | let rand = Scalar::::random(); 667 | rand.to_bigint() 668 | }) 669 | .collect(); 670 | 671 | let mut b: Vec<_> = (0..n) 672 | .map(|_| { 673 | let rand = Scalar::::random(); 674 | rand.to_bigint() 675 | }) 676 | .collect(); 677 | 678 | // next power of 2 679 | let _n: usize = n.next_power_of_two(); 680 | let zero_append_vec = vec![BigInt::zero(); _n - n]; 681 | 682 | // zero-appending at the end of a, b 683 | // let mut padded_a = a.clone(); 684 | a.extend_from_slice(&zero_append_vec); 685 | 686 | // let mut padded_b = b.clone(); 687 | b.extend_from_slice(&zero_append_vec); 688 | 689 | test_helper_non_power_2(n, _n, &a, &b); 690 | } 691 | } 692 | -------------------------------------------------------------------------------- /src/proofs/mod.rs: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright 2018 by Kzen Networks 4 | 5 | This file is part of escrow-recovery library 6 | (https://github.com/KZen-networks/cryptography-utils) 7 | 8 | bulletproof is free software: you can redistribute 9 | it and/or modify it under the terms of the GNU General Public 10 | License as published by the Free Software Foundation, either 11 | version 3 of the License, or (at your option) any later version. 12 | 13 | @license GPL-3.0+ 14 | */ 15 | 16 | // based on the paper: https://eprint.iacr.org/2017/1066.pdf 17 | 18 | pub mod inner_product; 19 | pub mod range_proof; 20 | pub mod range_proof_wip; 21 | pub mod weighted_inner_product; 22 | -------------------------------------------------------------------------------- /src/proofs/range_proof.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | 3 | /* 4 | 5 | Copyright 2018 by Kzen Networks 6 | 7 | This file is part of bulletproof library 8 | (https://github.com/KZen-networks/bulletproof) 9 | 10 | bulletproof is free software: you can redistribute 11 | it and/or modify it under the terms of the GNU General Public 12 | License as published by the Free Software Foundation, either 13 | version 3 of the License, or (at your option) any later version. 14 | 15 | @license GPL-3.0+ 16 | */ 17 | 18 | // based on the paper: https://eprint.iacr.org/2017/1066.pdf 19 | 20 | use curv::arithmetic::traits::*; 21 | use curv::cryptographic_primitives::hashing::{Digest, DigestExt}; 22 | use curv::elliptic::curves::{secp256_k1::Secp256k1, Curve, ECPoint, Point, Scalar}; 23 | use curv::BigInt; 24 | use sha2::Sha256; 25 | 26 | use generic_array::{typenum::Unsigned, GenericArray}; 27 | use itertools::iterate; 28 | use proofs::inner_product::InnerProductArg; 29 | use std::ops::{Shl, Shr}; 30 | use Errors::{self, RangeProofError}; 31 | 32 | #[derive(Clone, Debug, Serialize, Deserialize)] 33 | pub struct RangeProof { 34 | A: Point, 35 | S: Point, 36 | T1: Point, 37 | T2: Point, 38 | tau_x: Scalar, 39 | miu: Scalar, 40 | tx: Scalar, 41 | inner_product_proof: InnerProductArg, 42 | } 43 | 44 | impl RangeProof { 45 | pub fn prove( 46 | g_vec: &[Point], 47 | h_vec: &[Point], 48 | G: &Point, 49 | H: &Point, 50 | mut secret: Vec>, 51 | blinding: &[Scalar], 52 | bit_length: usize, 53 | ) -> RangeProof { 54 | let num_of_proofs = secret.len(); 55 | //num of proofs times bit length 56 | let nm = num_of_proofs * bit_length; 57 | let alpha = Scalar::::random(); 58 | let rho = Scalar::::random(); 59 | 60 | let g_vec = g_vec.to_vec(); 61 | let h_vec = h_vec.to_vec(); 62 | 63 | let mut A = H * α 64 | let mut S = H * ρ 65 | let two = BigInt::from(2); 66 | let one = BigInt::from(1); 67 | let order = Scalar::::group_order(); 68 | 69 | //concat all secrets: 70 | secret.reverse(); 71 | let secret_agg = secret 72 | .iter() 73 | .fold(BigInt::zero(), |acc, x| acc.shl(bit_length) + x.to_bigint()); 74 | 75 | let aL = (0..nm) 76 | .map(|i| { 77 | let shr_secret = secret_agg.clone().shr(i); 78 | shr_secret.modulus(&two) 79 | }) 80 | .collect::>(); 81 | let aR = (0..nm) 82 | .map(|i| BigInt::mod_sub(&aL[i], &one, order)) 83 | .collect::>(); 84 | 85 | let secret_bits = (0..nm) 86 | .map(|i| { 87 | let bignum_bit: BigInt = aL[i].clone() & BigInt::one(); 88 | let byte = BigInt::to_bytes(&bignum_bit); 89 | byte[0] == 1 90 | }) 91 | .collect::>(); 92 | let mut index: usize = 0; 93 | A = g_vec.iter().zip(secret_bits.clone()).fold( 94 | A, 95 | |acc, x| { 96 | if x.1 { 97 | acc + x.0 98 | } else { 99 | acc 100 | } 101 | }, 102 | ); 103 | 104 | A = h_vec 105 | .iter() 106 | .zip(secret_bits) 107 | .fold(A, |acc, x| if !x.1 { acc - x.0 } else { acc }); 108 | 109 | let SR = (0..nm) 110 | .map(|_| Scalar::::random()) 111 | .collect::>>(); 112 | let SL = (0..nm) 113 | .map(|_| Scalar::::random()) 114 | .collect::>>(); 115 | 116 | S = SL.iter().zip(&SR).fold(S, |acc, x| { 117 | let g_vec_i_SLi = &g_vec[index] * x.0; 118 | let h_vec_i_SRi = &h_vec[index] * x.1; 119 | index += 1; 120 | let SRhi_plus_SLgi = h_vec_i_SRi + g_vec_i_SLi; 121 | acc + SRhi_plus_SLgi 122 | }); 123 | 124 | let y = Sha256::new().chain_points([&A, &S]).result_scalar(); 125 | let base_point = Point::::generator(); 126 | let yG: Point = base_point * &y; 127 | let z: Scalar = Sha256::new().chain_points([&yG]).result_scalar(); 128 | let z_bn = z.to_bigint(); 129 | 130 | let one_fe = Scalar::::from(&one); 131 | let yi = iterate(one_fe.clone(), |i| i.clone() * &y) 132 | .take(nm) 133 | .collect::>>(); 134 | 135 | let t2 = (0..nm) 136 | .map(|i| SR[i].clone() * &yi[i] * &SL[i]) 137 | .fold(Scalar::::zero(), |acc, x| acc + x); 138 | let t2 = t2.to_bigint(); 139 | 140 | let two_fe = Scalar::::from(&two); 141 | let vec_2n = iterate(one_fe, |i| i.clone() * &two_fe) 142 | .take(bit_length) 143 | .collect::>>(); 144 | 145 | let t1 = (0..nm) 146 | .map(|i| { 147 | let t1_1 = BigInt::mod_add(&aR[i], &z_bn, order); 148 | let t1_2 = BigInt::mod_mul(&t1_1, &yi[i].to_bigint(), order); 149 | let t1_3 = BigInt::mod_mul(&SL[i].to_bigint(), &t1_2, order); 150 | let t1_4 = BigInt::mod_sub(&aL[i], &z_bn, order); 151 | let t1_5 = BigInt::mod_mul(&SR[i].to_bigint(), &yi[i].to_bigint(), order); 152 | let t1_6 = BigInt::mod_mul(&t1_4, &t1_5, order); 153 | let j = i / bit_length + 2; 154 | let k = i % bit_length; 155 | let z_index = BigInt::mod_pow(&z_bn, &BigInt::from(j as u32), order); 156 | let two_to_the_i = vec_2n[k].clone().to_bigint(); 157 | let t1_7 = BigInt::mod_mul(&z_index, &two_to_the_i, order); 158 | let t1_8 = BigInt::mod_mul(&t1_7, &SL[i].to_bigint(), order); 159 | let t1_68 = BigInt::mod_add(&t1_6, &t1_8, order); 160 | BigInt::mod_add(&t1_3, &t1_68, order) 161 | }) 162 | .fold(BigInt::zero(), |acc, x| BigInt::mod_add(&acc, &x, order)); 163 | 164 | let tau1 = Scalar::::random(); 165 | let tau2 = Scalar::::random(); 166 | let t1_fe = Scalar::::from(&t1); 167 | let t2_fe = Scalar::::from(&t2); 168 | let T1 = G * &t1_fe + H * &tau1; 169 | let T2 = G * &t2_fe + H * &tau2; 170 | 171 | let fs_challenge = Sha256::new().chain_points([&T1, &T2, G, H]).result_scalar(); 172 | let fs_challenge_square = &fs_challenge * &fs_challenge; 173 | let taux_1 = &fs_challenge * &tau1; 174 | let taux_2 = fs_challenge_square * &tau2; 175 | let taux_3 = (0..num_of_proofs) 176 | .map(|i| { 177 | let j = BigInt::mod_add(&two, &BigInt::from(i as u32), order); 178 | let z_j = BigInt::mod_pow(&z_bn, &j, order); 179 | let z_j_fe = Scalar::::from(&z_j); 180 | z_j_fe * &blinding[i] 181 | }) 182 | .fold(taux_2, |acc, x| acc + &x); 183 | let tau_x = taux_1 + &taux_3; 184 | let miu = (rho * &fs_challenge) + α 185 | 186 | let Lp = (0..nm) 187 | .map(|i| { 188 | let Lp_1 = (&SL[i] * &fs_challenge).to_bigint(); 189 | let Lp_2 = BigInt::mod_sub(&aL[i], &z_bn, order); 190 | BigInt::mod_add(&Lp_1, &Lp_2, order) 191 | }) 192 | .collect::>(); 193 | 194 | let Rp = (0..nm) 195 | .map(|i| { 196 | let Rp_1 = (&SR[i] * &fs_challenge).to_bigint(); 197 | 198 | let j = i / bit_length + 2; 199 | let k = i % bit_length; 200 | let z_index = BigInt::mod_pow(&z_bn, &BigInt::from(j as u32), order); 201 | let two_to_the_i = vec_2n[k].clone().to_bigint(); 202 | let Rp_2 = BigInt::mod_mul(&z_index, &two_to_the_i, order); 203 | let Rp_3 = BigInt::mod_add(&BigInt::mod_add(&z_bn, &aR[i], order), &Rp_1, order); 204 | let Rp_4 = BigInt::mod_mul(&yi[i].to_bigint(), &Rp_3, order); 205 | BigInt::mod_add(&Rp_4, &Rp_2, order) 206 | }) 207 | .collect::>(); 208 | let tx = Lp.iter().zip(&Rp).fold(BigInt::zero(), |acc, x| { 209 | let Lp_iRp_i = BigInt::mod_mul(x.0, x.1, order); 210 | BigInt::mod_add(&acc, &Lp_iRp_i, order) 211 | }); 212 | let tx_fe = Scalar::::from(&tx); 213 | 214 | let challenge_x: Scalar = Sha256::new() 215 | .chain_bigint(&tau_x.to_bigint()) 216 | .chain_bigint(&miu.to_bigint()) 217 | .chain_bigint(&tx) 218 | .result_scalar(); 219 | let Gx = G * &challenge_x; 220 | // P' = u^{xc} 221 | let P = &Gx * &tx_fe; 222 | 223 | let yi_inv = (0..nm) 224 | .map(|i| { 225 | // let yi_fe = Scalar::::from(&yi[i]); 226 | // yi_fe.invert() 227 | yi[i].invert().unwrap() 228 | }) 229 | .collect::>>(); 230 | 231 | let hi_tag = (0..nm) 232 | .map(|i| &h_vec[i] * &yi_inv[i]) 233 | .collect::>>(); 234 | 235 | // P' = P' g^l 236 | let P = g_vec.iter().zip(&Lp).fold(P, |acc, x| { 237 | let g_vec_i_lp_i = x.0 * &Scalar::::from(x.1); 238 | acc + g_vec_i_lp_i 239 | }); 240 | // P' = P' h'^r 241 | let P = hi_tag.iter().zip(&Rp).fold(P, |acc, x| { 242 | let h_vec_i_rp_i = x.0 * &Scalar::::from(x.1); 243 | acc + h_vec_i_rp_i 244 | }); 245 | // line 9 246 | // public input : g,h,u^x,P' = g_vec, hi_tag, Gx,P 247 | // private input: a,b = Lp,Rp 248 | let L_vec = Vec::with_capacity(nm); 249 | let R_vec = Vec::with_capacity(nm); 250 | let inner_product_proof = 251 | InnerProductArg::prove(&g_vec, &hi_tag, &Gx, &P, &Lp, &Rp, L_vec, R_vec); 252 | 253 | RangeProof { 254 | A, 255 | S, 256 | T1, 257 | T2, 258 | tau_x, 259 | miu, 260 | tx: tx_fe, 261 | inner_product_proof, 262 | } 263 | } 264 | 265 | pub fn verify( 266 | &self, 267 | g_vec: &[Point], 268 | h_vec: &[Point], 269 | G: &Point, 270 | H: &Point, 271 | ped_com: &[Point], 272 | bit_length: usize, 273 | ) -> Result<(), Errors> { 274 | let num_of_proofs = ped_com.len(); 275 | let nm = num_of_proofs * bit_length; 276 | 277 | let y = Sha256::new() 278 | .chain_points([&self.A, &self.S]) 279 | .result_scalar(); 280 | let base_point = Point::::generator(); 281 | let yG: Point = base_point * &y; 282 | let z: Scalar = Sha256::new().chain_points([&yG]).result_scalar(); 283 | let z_bn = z.to_bigint(); 284 | let order = Scalar::::group_order(); 285 | let z_minus = BigInt::mod_sub(order, &z.to_bigint(), order); 286 | let z_minus_fe = Scalar::::from(&z_minus); 287 | let z_squared = BigInt::mod_pow(&z.to_bigint(), &BigInt::from(2), order); 288 | // delta(x,y): 289 | let one_bn = BigInt::one(); 290 | let one_fe = Scalar::::from(&one_bn); 291 | let yi = iterate(one_fe.clone(), |i| i.clone() * &y) 292 | .take(nm) 293 | .collect::>>(); 294 | 295 | let scalar_mul_yn = yi 296 | .iter() 297 | .fold(Scalar::::zero(), |acc, x| acc + x); 298 | let scalar_mul_yn = scalar_mul_yn.to_bigint(); 299 | let two = BigInt::from(2); 300 | 301 | let two_fe = Scalar::::from(&two); 302 | let vec_2n = iterate(one_fe, |i| i.clone() * &two_fe) 303 | .take(bit_length) 304 | .collect::>>(); 305 | 306 | let scalar_mul_2n = vec_2n 307 | .iter() 308 | .fold(Scalar::::zero(), |acc, x| acc + x); 309 | let scalar_mul_2n = scalar_mul_2n.to_bigint(); 310 | 311 | let z_cubed_scalar_mul_2n = (0..num_of_proofs) 312 | .map(|i| { 313 | let j = BigInt::mod_add(&BigInt::from(3), &BigInt::from(i as u32), order); 314 | let z_j = BigInt::mod_pow(&z_bn, &j, order); 315 | BigInt::mod_mul(&z_j, &scalar_mul_2n, order) 316 | }) 317 | .fold(BigInt::zero(), |acc, x| BigInt::mod_add(&acc, &x, order)); 318 | 319 | let z_minus_zsq = BigInt::mod_sub(&z_bn, &z_squared, order); 320 | let z_minus_zsq_scalar_mul_yn = BigInt::mod_mul(&z_minus_zsq, &scalar_mul_yn, order); 321 | let delta = BigInt::mod_sub(&z_minus_zsq_scalar_mul_yn, &z_cubed_scalar_mul_2n, order); 322 | 323 | let yi_inv = (0..nm) 324 | .map(|i| yi[i].invert().unwrap()) 325 | .collect::>>(); 326 | 327 | let hi_tag = (0..nm) 328 | .map(|i| &h_vec[i] * &yi_inv[i]) 329 | .collect::>>(); 330 | 331 | let fs_challenge = Sha256::new() 332 | .chain_points([&self.T1, &self.T2, G, H]) 333 | .result_scalar(); 334 | let fs_challenge_square = &fs_challenge * &fs_challenge; 335 | 336 | // eq 65: 337 | let Gtx = G * &self.tx; 338 | let Htaux = H * &self.tau_x; 339 | let left_side = Gtx + Htaux; 340 | let delta_fe = Scalar::::from(&delta); 341 | let Gdelta = G * &delta_fe; 342 | let Tx = &self.T1 * &fs_challenge; 343 | let Tx_sq = &self.T2 * &fs_challenge_square; 344 | 345 | let mut vec_ped_zm = (0..num_of_proofs) 346 | .map(|i| { 347 | let z_2_m = BigInt::mod_pow(&z_bn, &BigInt::from((2 + i) as u32), order); 348 | let z_2_m_fe = Scalar::::from(&z_2_m); 349 | &ped_com[i] * &z_2_m_fe 350 | }) 351 | .collect::>>(); 352 | let vec_ped_zm_1 = vec_ped_zm.remove(0); 353 | let ped_com_sum = vec_ped_zm.iter().fold(vec_ped_zm_1, |acc, x| acc + x); 354 | let right_side = ped_com_sum + Gdelta + Tx + Tx_sq; 355 | 356 | let challenge_x = Sha256::new() 357 | .chain_bigint(&self.tau_x.to_bigint()) 358 | .chain_bigint(&self.miu.to_bigint()) 359 | .chain_bigint(&self.tx.to_bigint()) 360 | .result_scalar(); 361 | let Gx = G * &challenge_x; 362 | // P' = u^{xc} 363 | 364 | let P = &Gx * &self.tx; 365 | let minus_miu = BigInt::mod_sub( 366 | Scalar::::group_order(), 367 | &self.miu.to_bigint(), 368 | Scalar::::group_order(), 369 | ); 370 | let minus_miu_fe = Scalar::::from(&minus_miu); 371 | let Hmiu = H * &minus_miu_fe; 372 | let Sx = &self.S * &fs_challenge; 373 | let P = Hmiu + P + self.A.clone() + Sx; 374 | 375 | let P1 = (0..nm) 376 | .map(|i| { 377 | let z_yn = BigInt::mod_mul(&z_bn, &yi[i].to_bigint(), order); 378 | let j = i / bit_length; 379 | let k = i % bit_length; 380 | let z_j = BigInt::mod_pow(&z_bn, &BigInt::from((2 + j) as u32), order); 381 | let z_j_2_n = BigInt::mod_mul(&z_j, &vec_2n[k].to_bigint(), order); 382 | // let z_sq_2n = BigInt::mod_mul(&z_squared, &vec_2n[i], &order); 383 | let zyn_zsq2n = BigInt::mod_add(&z_yn, &z_j_2_n, order); 384 | let zyn_zsq2n_fe = Scalar::::from(&zyn_zsq2n); 385 | &hi_tag[i] * &zyn_zsq2n_fe 386 | }) 387 | .fold(P, |acc, x| acc + x); 388 | 389 | let P = (0..nm) 390 | .map(|i| &g_vec[i] * &z_minus_fe) 391 | .fold(P1, |acc, x| acc + x); 392 | let verify = self.inner_product_proof.verify(g_vec, &hi_tag, &Gx, &P); 393 | if verify.is_ok() && left_side == right_side { 394 | Ok(()) 395 | } else { 396 | Err(RangeProofError) 397 | } 398 | } 399 | 400 | pub fn fast_verify( 401 | &self, 402 | g_vec: &[Point], 403 | h_vec: &[Point], 404 | G: &Point, 405 | H: &Point, 406 | ped_com: &[Point], 407 | bit_length: usize, 408 | ) -> Result<(), Errors> { 409 | let num_of_proofs = ped_com.len(); 410 | let nm = num_of_proofs * bit_length; 411 | 412 | let y = Sha256::new() 413 | .chain_points([&self.A, &self.S]) 414 | .result_scalar(); 415 | let base_point = Point::::generator(); 416 | let yG: Point = base_point * &y; 417 | let z: Scalar = Sha256::new().chain_points([&yG]).result_scalar(); 418 | let z_bn = z.to_bigint(); 419 | let order = Scalar::::group_order(); 420 | let z_minus = BigInt::mod_sub(order, &z.to_bigint(), order); 421 | let z_minus_fe = Scalar::::from(&z_minus); 422 | let z_squared = BigInt::mod_pow(&z.to_bigint(), &BigInt::from(2), order); 423 | // delta(x,y): 424 | let one_bn = BigInt::one(); 425 | let one_fe = Scalar::::from(&one_bn); 426 | let yi = iterate(one_fe.clone(), |i| i.clone() * &y) 427 | .take(nm) 428 | .collect::>>(); 429 | 430 | let scalar_mul_yn = yi 431 | .iter() 432 | .fold(Scalar::::zero(), |acc, x| acc + x); 433 | let scalar_mul_yn = scalar_mul_yn.to_bigint(); 434 | let two = BigInt::from(2); 435 | 436 | let two_fe = Scalar::::from(&two); 437 | let vec_2n = iterate(one_fe, |i| i.clone() * &two_fe) 438 | .take(bit_length) 439 | .collect::>>(); 440 | 441 | let scalar_mul_2n = vec_2n 442 | .iter() 443 | .fold(Scalar::::zero(), |acc, x| acc + x); 444 | let scalar_mul_2n = scalar_mul_2n.to_bigint(); 445 | 446 | let z_cubed_scalar_mul_2n = (0..num_of_proofs) 447 | .map(|i| { 448 | let j = BigInt::mod_add(&BigInt::from(3), &BigInt::from(i as u32), order); 449 | let z_j = BigInt::mod_pow(&z_bn, &j, order); 450 | BigInt::mod_mul(&z_j, &scalar_mul_2n, order) 451 | }) 452 | .fold(BigInt::zero(), |acc, x| BigInt::mod_add(&acc, &x, order)); 453 | 454 | let z_minus_zsq = BigInt::mod_sub(&z_bn, &z_squared, order); 455 | let z_minus_zsq_scalar_mul_yn = BigInt::mod_mul(&z_minus_zsq, &scalar_mul_yn, order); 456 | let delta = BigInt::mod_sub(&z_minus_zsq_scalar_mul_yn, &z_cubed_scalar_mul_2n, order); 457 | 458 | let yi_inv = (0..nm) 459 | .map(|i| yi[i].invert().unwrap()) 460 | .collect::>>(); 461 | 462 | let hi_tag = (0..nm) 463 | .map(|i| &h_vec[i] * &yi_inv[i]) 464 | .collect::>>(); 465 | 466 | let fs_challenge = Sha256::new() 467 | .chain_points([&self.T1, &self.T2, G, H]) 468 | .result_scalar(); 469 | let fs_challenge_square = &fs_challenge * &fs_challenge; 470 | 471 | // eq 65: 472 | let Gtx = G * &self.tx; 473 | let Htaux = H * &self.tau_x; 474 | let left_side = Gtx + Htaux; 475 | let delta_fe = Scalar::::from(&delta); 476 | let Gdelta = G * &delta_fe; 477 | let Tx = &self.T1 * &fs_challenge; 478 | let Tx_sq = &self.T2 * &fs_challenge_square; 479 | 480 | let mut vec_ped_zm = (0..num_of_proofs) 481 | .map(|i| { 482 | let z_2_m = BigInt::mod_pow(&z_bn, &BigInt::from((2 + i) as u32), order); 483 | let z_2_m_fe = Scalar::::from(&z_2_m); 484 | &ped_com[i] * &z_2_m_fe 485 | }) 486 | .collect::>>(); 487 | let vec_ped_zm_1 = vec_ped_zm.remove(0); 488 | let ped_com_sum = vec_ped_zm.iter().fold(vec_ped_zm_1, |acc, x| acc + x); 489 | let right_side = ped_com_sum + Gdelta + Tx + Tx_sq; 490 | 491 | let challenge_x = Sha256::new() 492 | .chain_bigint(&self.tau_x.to_bigint()) 493 | .chain_bigint(&self.miu.to_bigint()) 494 | .chain_bigint(&self.tx.to_bigint()) 495 | .result_scalar(); 496 | let Gx = G * &challenge_x; 497 | // P' = u^{xc} 498 | 499 | let P = &Gx * &self.tx; 500 | let minus_miu = BigInt::mod_sub( 501 | Scalar::::group_order(), 502 | &self.miu.to_bigint(), 503 | Scalar::::group_order(), 504 | ); 505 | let minus_miu_fe = Scalar::::from(&minus_miu); 506 | let Hmiu = H * &minus_miu_fe; 507 | let Sx = &self.S * &fs_challenge; 508 | let P = Hmiu + P + self.A.clone() + Sx; 509 | 510 | let P1 = (0..nm) 511 | .map(|i| { 512 | let z_yn = BigInt::mod_mul(&z_bn, &yi[i].to_bigint(), order); 513 | let j = i / bit_length; 514 | let k = i % bit_length; 515 | let z_j = BigInt::mod_pow(&z_bn, &BigInt::from((2 + j) as u32), order); 516 | let z_j_2_n = BigInt::mod_mul(&z_j, &vec_2n[k].to_bigint(), order); 517 | // let z_sq_2n = BigInt::mod_mul(&z_squared, &vec_2n[i], &order); 518 | let zyn_zsq2n = BigInt::mod_add(&z_yn, &z_j_2_n, order); 519 | let zyn_zsq2n_fe = Scalar::::from(&zyn_zsq2n); 520 | &hi_tag[i] * &zyn_zsq2n_fe 521 | }) 522 | .fold(P, |acc, x| acc + x); 523 | 524 | let P = (0..nm) 525 | .map(|i| &g_vec[i] * &z_minus_fe) 526 | .fold(P1, |acc, x| acc + x); 527 | let verify = self 528 | .inner_product_proof 529 | .fast_verify(g_vec, &hi_tag, &Gx, &P); 530 | if verify.is_ok() && left_side == right_side { 531 | Ok(()) 532 | } else { 533 | Err(RangeProofError) 534 | } 535 | } 536 | 537 | pub fn aggregated_verify( 538 | &self, 539 | g_vec: &[Point], 540 | h_vec: &[Point], 541 | G: &Point, 542 | H: &Point, 543 | ped_com: &[Point], 544 | bit_length: usize, 545 | ) -> Result<(), Errors> { 546 | let n = bit_length; 547 | let m = ped_com.len(); 548 | let nm = m * n; 549 | let lg_nm = self.inner_product_proof.L.len(); 550 | let order = Scalar::::group_order(); 551 | let two = BigInt::from(2); 552 | let one = BigInt::from(1); 553 | let zero = BigInt::zero(); 554 | 555 | // All of the input vectors must have the same length. 556 | assert_eq!(g_vec.len(), nm); 557 | assert_eq!(h_vec.len(), nm); 558 | assert!(nm.is_power_of_two(), "(n*m) must be a power of two!"); 559 | assert!( 560 | lg_nm <= 64, 561 | "Not compatible for vector sizes greater than 2^64!" 562 | ); 563 | 564 | // regenerate challenges y, z, x, x_u from transcript 565 | let y = Sha256::new() 566 | .chain_points([&self.A, &self.S]) 567 | .result_scalar(); 568 | let y_bn = y.to_bigint(); 569 | let y_inv_bn = BigInt::mod_inv(&y_bn, order).unwrap(); 570 | let base_point = Point::::generator(); 571 | let yG: Point = base_point * &y; 572 | let z: Scalar = Sha256::new().chain_points([&yG]).result_scalar(); 573 | let z_bn = z.to_bigint(); 574 | let z_squared = BigInt::mod_pow(&z_bn, &BigInt::from(2), order); 575 | 576 | let challenge_x: Scalar = Sha256::new() 577 | .chain_points([&self.T1, &self.T2, G, H]) 578 | .result_scalar(); 579 | let challenge_x_sq = &challenge_x * &challenge_x; 580 | 581 | let x_u_fe = Sha256::new() 582 | .chain_bigint(&self.tau_x.to_bigint()) 583 | .chain_bigint(&self.miu.to_bigint()) 584 | .chain_bigint(&self.tx.to_bigint()) 585 | .result_scalar(); 586 | 587 | // ux = g^{x_u} 588 | let ux = G * &x_u_fe; 589 | 590 | // generate a random scalar to combine 2 verification equations 591 | let challenge_ver: Scalar = Sha256::new() 592 | .chain_points([&self.A, &self.S, &self.T1, &self.T2, G, H]) 593 | .result_scalar(); 594 | let challenge_ver_bn = challenge_ver.to_bigint(); 595 | 596 | // z2_vec = (z^2, z^3, z^4, ..., z^{m+1}) 597 | let z2_vec = iterate(z_squared.clone(), |i| i.clone() * &z_bn) 598 | .take(m) 599 | .collect::>(); 600 | 601 | // y_vec = (1, y, y^2, ..., y^{nm-1}) 602 | let y_vec = iterate(one.clone(), |i| i.clone() * &y_bn) 603 | .take(nm) 604 | .collect::>(); 605 | 606 | // sum_y_pow = 1 + y + ... + y^{nm} 607 | let sum_y_pow = y_vec 608 | .iter() 609 | .fold(zero.clone(), |acc, x| BigInt::mod_add(&acc, x, order)); 610 | 611 | // vec_2n = (1, 2, 2^2, 2^3, ..., 2^{n}) 612 | let vec_2n = iterate(one.clone(), |i| i.clone() * &two) 613 | .take(n) 614 | .collect::>(); 615 | 616 | // y_inv_vec = (1, y^{-1}, y^{-2}, ..., y^{-(nm-1)}) 617 | let y_inv_vec = iterate(one, |i| i.clone() * &y_inv_bn) 618 | .take(nm) 619 | .collect::>(); 620 | 621 | // d = z^2 d1 + z^3 d2 + ... + z^{m+1} dm 622 | // where dj = (0^{(j-1)n} || 2^{n} || 0^{(m-j)n}) \in \Z_q^{mn} 623 | let d = (0..nm) 624 | .map(|i| { 625 | let k = i % n; 626 | let two_i = vec_2n[k].clone(); 627 | let j = i / n; 628 | let z_j_2 = z2_vec[j].clone(); 629 | BigInt::mod_mul(&two_i, &z_j_2, order) 630 | }) 631 | .collect::>(); 632 | 633 | // sum_d = <1^{mn}, d> 634 | let sum_d = d 635 | .iter() 636 | .fold(zero.clone(), |acc, x| BigInt::mod_add(&acc, x, order)); 637 | 638 | // compute delta(y, z): 639 | let z_minus_zsq = BigInt::mod_sub(&z_bn, &z_squared, order); 640 | let z_minus_zsq_sum_y = BigInt::mod_mul(&z_minus_zsq, &sum_y_pow, order); 641 | let sum_d_z = BigInt::mod_mul(&sum_d, &z_bn, order); 642 | let delta = BigInt::mod_sub(&z_minus_zsq_sum_y, &sum_d_z, order); 643 | 644 | // compute sg and sh vectors (unrolling ipp verification) 645 | let mut x_sq_vec: Vec = Vec::with_capacity(lg_nm); 646 | let mut x_inv_sq_vec: Vec = Vec::with_capacity(lg_nm); 647 | let mut minus_x_sq_vec: Vec = Vec::with_capacity(lg_nm); 648 | let mut minus_x_inv_sq_vec: Vec = Vec::with_capacity(lg_nm); 649 | let mut allinv = BigInt::one(); 650 | for (Li, Ri) in self 651 | .inner_product_proof 652 | .L 653 | .iter() 654 | .zip(self.inner_product_proof.R.iter()) 655 | { 656 | let x: Scalar = Sha256::new().chain_points([Li, Ri, &ux]).result_scalar(); 657 | let x_bn = x.to_bigint(); 658 | let x_inv_fe = x.invert().unwrap(); 659 | let x_inv_bn = x_inv_fe.to_bigint(); 660 | let x_sq_bn = BigInt::mod_mul(&x_bn, &x_bn, order); 661 | let x_inv_sq_bn = BigInt::mod_mul(&x_inv_fe.to_bigint(), &x_inv_fe.to_bigint(), order); 662 | 663 | x_sq_vec.push(x_sq_bn.clone()); 664 | x_inv_sq_vec.push(x_inv_sq_bn.clone()); 665 | minus_x_sq_vec.push(BigInt::mod_sub(&BigInt::zero(), &x_sq_bn, order)); 666 | minus_x_inv_sq_vec.push(BigInt::mod_sub(&BigInt::zero(), &x_inv_sq_bn, order)); 667 | allinv *= x_inv_bn; 668 | } 669 | 670 | let mut s: Vec = Vec::with_capacity(nm); 671 | s.push(allinv); 672 | for i in 1..nm { 673 | let lg_i = 674 | (std::mem::size_of_val(&nm) * 8) - 1 - ((i as usize).leading_zeros() as usize); 675 | let k = 1 << lg_i; 676 | // The challenges are stored in "creation order" as [x_k,...,x_1], 677 | // so u_{lg(i)+1} = is indexed by (lg_n-1) - lg_i 678 | let x_lg_i_sq = x_sq_vec[(lg_nm - 1) - lg_i].clone(); 679 | s.push(s[i - k].clone() * x_lg_i_sq); 680 | } 681 | 682 | let a_times_s: Vec = (0..nm) 683 | .map(|i| BigInt::mod_mul(&s[i], &self.inner_product_proof.a_tag, order)) 684 | .collect(); 685 | 686 | let b_times_sinv: Vec = (0..nm) 687 | .map(|i| { 688 | let s_inv_i = BigInt::mod_inv(&s[i], order).unwrap(); 689 | BigInt::mod_mul(&s_inv_i, &self.inner_product_proof.b_tag, order) 690 | }) 691 | .collect(); 692 | 693 | // exponent of g_vec 694 | let scalar_g_vec: Vec = (0..nm) 695 | .map(|i| BigInt::mod_add(&a_times_s[i], &z_bn, order)) 696 | .collect(); 697 | 698 | // exponent of h_vec 699 | let scalar_h_vec: Vec = (0..nm) 700 | .map(|i| { 701 | let b_sinv_plus_di = BigInt::mod_sub(&b_times_sinv[i], &d[i], order); 702 | let y_inv_b_sinv_plus_di = BigInt::mod_mul(&y_inv_vec[i], &b_sinv_plus_di, order); 703 | BigInt::mod_sub(&y_inv_b_sinv_plus_di, &z_bn, order) 704 | }) 705 | .collect(); 706 | 707 | // exponent of G 708 | let ab = BigInt::mod_mul( 709 | &self.inner_product_proof.a_tag, 710 | &self.inner_product_proof.b_tag, 711 | order, 712 | ); 713 | let ab_minus_tx = BigInt::mod_sub(&ab, &self.tx.to_bigint(), order); 714 | let scalar_G1 = BigInt::mod_mul(&x_u_fe.to_bigint(), &ab_minus_tx, order); 715 | 716 | let delta_minus_tx = BigInt::mod_sub(&delta, &self.tx.to_bigint(), order); 717 | let scalar_G2 = BigInt::mod_mul(&challenge_ver_bn, &delta_minus_tx, order); 718 | 719 | let scalar_G = BigInt::mod_add(&scalar_G1, &scalar_G2, order); 720 | 721 | // exponent of H 722 | let c_times_taux = BigInt::mod_mul(&challenge_ver_bn, &self.tau_x.to_bigint(), order); 723 | let scalar_H = BigInt::mod_sub(&self.miu.to_bigint(), &c_times_taux, order); 724 | 725 | // exponents of A, S 726 | // let scalar_A = BigInt::mod_sub(&zero, &one, &order); 727 | let scalar_S = BigInt::mod_sub(&zero, &challenge_x.to_bigint(), order); 728 | 729 | // exponent of L, R 730 | let scalar_L = minus_x_sq_vec.clone(); 731 | let scalar_R = minus_x_inv_sq_vec.clone(); 732 | 733 | // exponents of commitments 734 | let scalar_coms: Vec = (0..m) 735 | .map(|i| BigInt::mod_mul(&challenge_ver_bn, &z2_vec[i], order)) 736 | .collect(); 737 | 738 | // exponents of T_1, T_2 739 | let scalar_T1 = BigInt::mod_mul(&challenge_ver_bn, &challenge_x.to_bigint(), order); 740 | let scalar_T2 = BigInt::mod_mul(&challenge_ver_bn, &challenge_x_sq.to_bigint(), order); 741 | 742 | // compute concatenated exponent vector 743 | let mut scalars: Vec = Vec::with_capacity(2 * nm + 2 * lg_nm + m + 6); 744 | scalars.extend_from_slice(&scalar_g_vec); 745 | scalars.extend_from_slice(&scalar_h_vec); 746 | scalars.push(scalar_G); 747 | // scalars.push(scalar_H); 748 | // scalars.push(scalar_A); 749 | scalars.push(scalar_S); 750 | scalars.extend_from_slice(&scalar_L); 751 | scalars.extend_from_slice(&scalar_R); 752 | scalars.extend_from_slice(&scalar_coms); 753 | scalars.push(scalar_T1); 754 | scalars.push(scalar_T2); 755 | 756 | // compute concatenated base vector 757 | let mut points: Vec> = Vec::with_capacity(2 * nm + 2 * lg_nm + m + 6); 758 | points.extend_from_slice(g_vec); 759 | points.extend_from_slice(h_vec); 760 | points.push(G.clone()); 761 | // points.push(*H); 762 | // points.push(self.A); 763 | points.push(self.S.clone()); 764 | points.extend_from_slice(&self.inner_product_proof.L); 765 | points.extend_from_slice(&self.inner_product_proof.R); 766 | points.extend_from_slice(ped_com); 767 | points.push(self.T1.clone()); 768 | points.push(self.T2.clone()); 769 | 770 | let H_times_scalar_H = H * &Scalar::::from(&scalar_H); 771 | let tot_len = points.len(); 772 | let lhs = (0..tot_len) 773 | .map(|i| &points[i] * &Scalar::::from(&scalars[i])) 774 | .fold(H_times_scalar_H, |acc, x| acc + x as Point); 775 | 776 | // single multi-exponentiation check 777 | if lhs == self.A { 778 | Ok(()) 779 | } else { 780 | Err(RangeProofError) 781 | } 782 | } 783 | } 784 | 785 | pub fn generate_random_point(bytes: &[u8]) -> Point { 786 | let compressed_point_len = 787 | <::Point as ECPoint>::CompressedPointLength::USIZE; 788 | let truncated = if bytes.len() > compressed_point_len - 1 { 789 | &bytes[0..compressed_point_len - 1] 790 | } else { 791 | &bytes 792 | }; 793 | let mut buffer = GenericArray::< 794 | u8, 795 | <::Point as ECPoint>::CompressedPointLength, 796 | >::default(); 797 | buffer.as_mut_slice()[0] = 0x2; 798 | buffer.as_mut_slice()[1..1 + truncated.len()].copy_from_slice(truncated); 799 | if let Ok(point) = Point::from_bytes(buffer.as_slice()) { 800 | return point; 801 | } 802 | 803 | let bn = BigInt::from_bytes(bytes); 804 | let two = BigInt::from(2); 805 | let bn_times_two = BigInt::mod_mul(&bn, &two, Scalar::::group_order()); 806 | let bytes = BigInt::to_bytes(&bn_times_two); 807 | generate_random_point(&bytes) 808 | } 809 | 810 | #[cfg(test)] 811 | mod tests { 812 | use curv::arithmetic::traits::*; 813 | use curv::cryptographic_primitives::hashing::{Digest, DigestExt}; 814 | use curv::elliptic::curves::{secp256_k1::Secp256k1, Point, Scalar}; 815 | use curv::BigInt; 816 | use sha2::Sha512; 817 | 818 | use curv::elliptic::curves::secp256_k1::hash_to_curve::generate_random_point; 819 | use proofs::range_proof::RangeProof; 820 | 821 | pub fn test_helper(seed: &BigInt, n: usize, m: usize) { 822 | let nm = n * m; 823 | let G = Point::::generator(); 824 | let label = BigInt::from(1); 825 | let hash = Sha512::new().chain_bigint(&label).result_bigint(); 826 | let H = generate_random_point(&Converter::to_bytes(&hash)); 827 | 828 | let g_vec = (0..nm) 829 | .map(|i| { 830 | let kzen_label_i = BigInt::from(i as u32) + seed; 831 | let hash_i = Sha512::new().chain_bigint(&kzen_label_i).result_bigint(); 832 | generate_random_point(&Converter::to_bytes(&hash_i)) 833 | }) 834 | .collect::>>(); 835 | 836 | // can run in parallel to g_vec: 837 | let h_vec = (0..nm) 838 | .map(|i| { 839 | let kzen_label_j = BigInt::from(n as u32) + BigInt::from(i as u32) + seed; 840 | let hash_j = Sha512::new().chain_bigint(&kzen_label_j).result_bigint(); 841 | generate_random_point(&Converter::to_bytes(&hash_j)) 842 | }) 843 | .collect::>>(); 844 | 845 | let range = BigInt::from(2).pow(n as u32); 846 | let v_vec = (0..m) 847 | .map(|_| Scalar::::from(&BigInt::sample_below(&range))) 848 | .collect::>>(); 849 | 850 | let r_vec = (0..m) 851 | .map(|_| Scalar::::random()) 852 | .collect::>>(); 853 | 854 | let ped_com_vec = (0..m) 855 | .map(|i| &*G * &v_vec[i] + &H * &r_vec[i]) 856 | .collect::>>(); 857 | 858 | let range_proof = RangeProof::prove(&g_vec, &h_vec, &G, &H, v_vec, &r_vec, n); 859 | let result = RangeProof::verify(&range_proof, &g_vec, &h_vec, &G, &H, &ped_com_vec, n); 860 | assert!(result.is_ok()); 861 | } 862 | 863 | pub fn test_helper_aggregated(seed: &BigInt, n: usize, m: usize) { 864 | let nm = n * m; 865 | let G = Point::::generator(); 866 | let label = BigInt::from(1); 867 | let hash = Sha512::new().chain_bigint(&label).result_bigint(); 868 | let H = generate_random_point(&Converter::to_bytes(&hash)); 869 | 870 | let g_vec = (0..nm) 871 | .map(|i| { 872 | let kzen_label_i = BigInt::from(i as u32) + seed; 873 | let hash_i = Sha512::new().chain_bigint(&kzen_label_i).result_bigint(); 874 | generate_random_point(&Converter::to_bytes(&hash_i)) 875 | }) 876 | .collect::>>(); 877 | 878 | // can run in parallel to g_vec: 879 | let h_vec = (0..nm) 880 | .map(|i| { 881 | let kzen_label_j = BigInt::from(n as u32) + BigInt::from(i as u32) + seed; 882 | let hash_j = Sha512::new().chain_bigint(&kzen_label_j).result_bigint(); 883 | generate_random_point(&Converter::to_bytes(&hash_j)) 884 | }) 885 | .collect::>>(); 886 | 887 | let range = BigInt::from(2).pow(n as u32); 888 | let v_vec = (0..m) 889 | .map(|_| Scalar::::from(&BigInt::sample_below(&range))) 890 | .collect::>>(); 891 | 892 | let r_vec = (0..m) 893 | .map(|_| Scalar::::random()) 894 | .collect::>>(); 895 | 896 | let ped_com_vec = (0..m) 897 | .map(|i| &*G * &v_vec[i] + &H * &r_vec[i]) 898 | .collect::>>(); 899 | 900 | let range_proof = RangeProof::prove(&g_vec, &h_vec, &G, &H, v_vec, &r_vec, n); 901 | let result = 902 | RangeProof::aggregated_verify(&range_proof, &g_vec, &h_vec, &G, &H, &ped_com_vec, n); 903 | assert!(result.is_ok()); 904 | } 905 | 906 | #[test] 907 | pub fn test_batch_4_range_proof_32() { 908 | let n = 32; 909 | // num of proofs 910 | let m = 4; 911 | let nm = n * m; 912 | let KZen: &[u8] = &[75, 90, 101, 110]; 913 | let kzen_label = BigInt::from_bytes(KZen); 914 | 915 | let G = Point::::generator(); 916 | let label = BigInt::from(1); 917 | let hash = Sha512::new().chain_bigint(&label).result_bigint(); 918 | let H = generate_random_point(&Converter::to_bytes(&hash)); 919 | 920 | let g_vec = (0..nm) 921 | .map(|i| { 922 | let kzen_label_i = BigInt::from(i as u32) + &kzen_label; 923 | let hash_i = Sha512::new().chain_bigint(&kzen_label_i).result_bigint(); 924 | generate_random_point(&Converter::to_bytes(&hash_i)) 925 | }) 926 | .collect::>>(); 927 | 928 | // can run in parallel to g_vec: 929 | let h_vec = (0..nm) 930 | .map(|i| { 931 | let kzen_label_j = BigInt::from(n as u32) + BigInt::from(i as u32) + &kzen_label; 932 | let hash_j = Sha512::new().chain_bigint(&kzen_label_j).result_bigint(); 933 | generate_random_point(&Converter::to_bytes(&hash_j)) 934 | }) 935 | .collect::>>(); 936 | 937 | let range = BigInt::from(2).pow(n as u32); 938 | let v_vec = (0..m) 939 | .map(|_| Scalar::::from(&BigInt::sample_below(&range))) 940 | .collect::>>(); 941 | 942 | let r_vec = (0..m) 943 | .map(|_| Scalar::::random()) 944 | .collect::>>(); 945 | 946 | let ped_com_vec = (0..m) 947 | .map(|i| &*G * &v_vec[i] + &H * &r_vec[i]) 948 | .collect::>>(); 949 | 950 | let range_proof = RangeProof::prove(&g_vec, &h_vec, &G, &H, v_vec, &r_vec, n); 951 | let result = RangeProof::verify(&range_proof, &g_vec, &h_vec, &G, &H, &ped_com_vec, n); 952 | assert!(result.is_ok()); 953 | } 954 | 955 | #[test] 956 | #[should_panic] 957 | pub fn test_batch_4_range_proof_32_out_of_range() { 958 | let n = 32; 959 | // num of proofs 960 | let m = 4; 961 | let nm = n * m; 962 | let KZen: &[u8] = &[75, 90, 101, 110]; 963 | let kzen_label = BigInt::from_bytes(KZen); 964 | 965 | let G = Point::::generator(); 966 | let label = BigInt::from(1); 967 | let hash = Sha512::new().chain_bigint(&label).result_bigint(); 968 | let H = generate_random_point(&Converter::to_bytes(&hash)); 969 | 970 | let g_vec = (0..nm) 971 | .map(|i| { 972 | let kzen_label_i = BigInt::from(i as u32) + &kzen_label; 973 | let hash_i = Sha512::new().chain_bigint(&kzen_label_i).result_bigint(); 974 | generate_random_point(&Converter::to_bytes(&hash_i)) 975 | }) 976 | .collect::>>(); 977 | 978 | // can run in parallel to g_vec: 979 | let h_vec = (0..nm) 980 | .map(|i| { 981 | let kzen_label_j = BigInt::from(n as u32) + BigInt::from(i as u32) + &kzen_label; 982 | let hash_j = Sha512::new().chain_bigint(&kzen_label_j).result_bigint(); 983 | generate_random_point(&Converter::to_bytes(&hash_j)) 984 | }) 985 | .collect::>>(); 986 | 987 | let range = BigInt::from(2).pow(n as u32); 988 | let mut v_vec = (0..m - 1) 989 | .map(|_| Scalar::::from(&BigInt::sample_below(&range))) 990 | .collect::>>(); 991 | 992 | let bad_v = BigInt::from(2).pow(33); 993 | v_vec.push(Scalar::::from(&bad_v)); 994 | 995 | let r_vec = (0..m) 996 | .map(|_| Scalar::::random()) 997 | .collect::>>(); 998 | 999 | let ped_com_vec = (0..m) 1000 | .map(|i| &*G * &v_vec[i] + &H * &r_vec[i]) 1001 | .collect::>>(); 1002 | 1003 | let range_proof = RangeProof::prove(&g_vec, &h_vec, &G, &H, v_vec, &r_vec, n); 1004 | let result = RangeProof::verify(&range_proof, &g_vec, &h_vec, &G, &H, &ped_com_vec, n); 1005 | assert!(result.is_ok()); 1006 | } 1007 | 1008 | #[test] 1009 | pub fn test_batch_2_range_proof_16() { 1010 | let n = 16; 1011 | // num of proofs 1012 | let m = 2; 1013 | let nm = n * m; 1014 | let KZen: &[u8] = &[75, 90, 101, 110]; 1015 | let kzen_label = BigInt::from_bytes(KZen); 1016 | 1017 | let G = Point::::generator(); 1018 | let label = BigInt::from(1); 1019 | let hash = Sha512::new().chain_bigint(&label).result_bigint(); 1020 | let H = generate_random_point(&Converter::to_bytes(&hash)); 1021 | 1022 | let g_vec = (0..nm) 1023 | .map(|i| { 1024 | let kzen_label_i = BigInt::from(i as u32) + &kzen_label; 1025 | let hash_i = Sha512::new().chain_bigint(&kzen_label_i).result_bigint(); 1026 | generate_random_point(&Converter::to_bytes(&hash_i)) 1027 | }) 1028 | .collect::>>(); 1029 | 1030 | // can run in parallel to g_vec: 1031 | let h_vec = (0..nm) 1032 | .map(|i| { 1033 | let kzen_label_j = BigInt::from(n as u32) + BigInt::from(i as u32) + &kzen_label; 1034 | let hash_j = Sha512::new().chain_bigint(&kzen_label_j).result_bigint(); 1035 | generate_random_point(&Converter::to_bytes(&hash_j)) 1036 | }) 1037 | .collect::>>(); 1038 | 1039 | let range = BigInt::from(2).pow(n as u32); 1040 | let v_vec = (0..m) 1041 | .map(|_| Scalar::::from(&BigInt::sample_below(&range))) 1042 | .collect::>>(); 1043 | 1044 | let r_vec = (0..m) 1045 | .map(|_| Scalar::::random()) 1046 | .collect::>>(); 1047 | 1048 | let ped_com_vec = (0..m) 1049 | .map(|i| &*G * &v_vec[i] + &H * &r_vec[i]) 1050 | .collect::>>(); 1051 | 1052 | let range_proof = RangeProof::prove(&g_vec, &h_vec, &G, &H, v_vec, &r_vec, n); 1053 | let result = RangeProof::verify(&range_proof, &g_vec, &h_vec, &G, &H, &ped_com_vec, n); 1054 | assert!(result.is_ok()); 1055 | } 1056 | 1057 | #[test] 1058 | pub fn test_batch_1_range_proof_8() { 1059 | // bit range 1060 | let n = 8; 1061 | // batch size 1062 | let m = 1; 1063 | let nm = n * m; 1064 | // some seed for generating g and h vectors 1065 | let KZen: &[u8] = &[75, 90, 101, 110]; 1066 | let kzen_label = BigInt::from_bytes(KZen); 1067 | 1068 | // G,H - points for pederson commitment: com = vG + rH 1069 | let G = Point::::generator(); 1070 | let label = BigInt::from(1); 1071 | let hash = Sha512::new().chain_bigint(&label).result_bigint(); 1072 | let H = generate_random_point(&Converter::to_bytes(&hash)); 1073 | 1074 | let g_vec = (0..nm) 1075 | .map(|i| { 1076 | let kzen_label_i = BigInt::from(i as u32) + &kzen_label; 1077 | let hash_i = Sha512::new().chain_bigint(&kzen_label_i).result_bigint(); 1078 | generate_random_point(&Converter::to_bytes(&hash_i)) 1079 | }) 1080 | .collect::>>(); 1081 | 1082 | // can run in parallel to g_vec: 1083 | let h_vec = (0..nm) 1084 | .map(|i| { 1085 | let kzen_label_j = BigInt::from(n as u32) + BigInt::from(i as u32) + &kzen_label; 1086 | let hash_j = Sha512::new().chain_bigint(&kzen_label_j).result_bigint(); 1087 | generate_random_point(&Converter::to_bytes(&hash_j)) 1088 | }) 1089 | .collect::>>(); 1090 | 1091 | let range = BigInt::from(2).pow(n as u32); 1092 | let v_vec = (0..m) 1093 | .map(|_| Scalar::::from(&BigInt::sample_below(&range))) 1094 | .collect::>>(); 1095 | 1096 | let r_vec = (0..m) 1097 | .map(|_| Scalar::::random()) 1098 | .collect::>>(); 1099 | 1100 | let ped_com_vec = (0..m) 1101 | .map(|i| &*G * &v_vec[i] + &H * &r_vec[i]) 1102 | .collect::>>(); 1103 | 1104 | let range_proof = RangeProof::prove(&g_vec, &h_vec, &G, &H, v_vec, &r_vec, n); 1105 | let result = RangeProof::verify(&range_proof, &g_vec, &h_vec, &G, &H, &ped_com_vec, n); 1106 | assert!(result.is_ok()); 1107 | } 1108 | 1109 | #[test] 1110 | pub fn test_batch_4_range_proof_64() { 1111 | let KZen: &[u8] = &[75, 90, 101, 110]; 1112 | let kzen_label = BigInt::from_bytes(KZen); 1113 | test_helper(&kzen_label, 64, 4); 1114 | } 1115 | 1116 | #[test] 1117 | pub fn test_agg_batch_4_range_proof_64() { 1118 | let KZen: &[u8] = &[75, 90, 101, 110]; 1119 | let kzen_label = BigInt::from_bytes(KZen); 1120 | test_helper_aggregated(&kzen_label, 64, 4); 1121 | } 1122 | } 1123 | -------------------------------------------------------------------------------- /src/proofs/range_proof_wip.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | 3 | /* 4 | 5 | Copyright 2018 by Kzen Networks 6 | 7 | This file is part of bulletproof library 8 | (https://github.com/KZen-networks/bulletproof) 9 | 10 | bulletproof is free software: you can redistribute 11 | it and/or modify it under the terms of the GNU General Public 12 | License as published by the Free Software Foundation, either 13 | version 3 of the License, or (at your option) any later version. 14 | 15 | @license GPL-3.0+ 16 | */ 17 | 18 | // based on the paper: https://eprint.iacr.org/2020/735.pdf 19 | // This is an implementation of figure 3 - aggregated range proof protocol from the above paper. 20 | // 21 | // Bulletproofs (https://eprint.iacr.org/2017/1066) uses the inner product argument. 22 | // Bulletproofs+ (https://eprint.iacr.org/2020/735.pdf) uses the weighted inner product argument 23 | // which reduces the overall prover communication by ~15% 24 | // 25 | 26 | use curv::arithmetic::traits::*; 27 | use curv::cryptographic_primitives::hashing::{Digest, DigestExt}; 28 | use curv::elliptic::curves::{secp256_k1::Secp256k1, Point, Scalar}; 29 | use curv::BigInt; 30 | use sha2::{Sha256, Sha512}; 31 | 32 | use curv::elliptic::curves::secp256_k1::hash_to_curve::generate_random_point; 33 | use itertools::iterate; 34 | use proofs::weighted_inner_product::WeightedInnerProdArg; 35 | use std::ops::{Shl, Shr}; 36 | use Errors::{self, RangeProofError}; 37 | 38 | #[derive(Clone, Debug, Serialize, Deserialize)] 39 | pub struct StatementRP { 40 | pub g_vec: Vec>, 41 | pub h_vec: Vec>, 42 | pub G: Point, 43 | pub H: Point, 44 | pub bit_length: usize, 45 | } 46 | 47 | impl StatementRP { 48 | pub fn generate_bases( 49 | init_seed: &BigInt, 50 | num_of_proofs: usize, 51 | bit_length: usize, 52 | ) -> StatementRP { 53 | let n = bit_length; 54 | let m = num_of_proofs; 55 | let nm = n * m; 56 | 57 | // G,H - points for pederson commitment: com = vG + rH 58 | let G = Point::::generator().to_point(); 59 | let label = BigInt::mod_sub( 60 | init_seed, 61 | &BigInt::one(), 62 | Scalar::::group_order(), 63 | ); 64 | let hash = Sha512::new().chain_bigint(&label).result_bigint(); 65 | let H = generate_random_point(&Converter::to_bytes(&hash)); 66 | 67 | let g_vec = (0..nm) 68 | .map(|i| { 69 | let kzen_label_i = BigInt::from(i as u32) + init_seed; 70 | let hash_i = Sha512::new().chain_bigint(&kzen_label_i).result_bigint(); 71 | generate_random_point(&Converter::to_bytes(&hash_i)) 72 | }) 73 | .collect::>>(); 74 | 75 | // can run in parallel to g_vec: 76 | let h_vec = (0..nm) 77 | .map(|i| { 78 | let kzen_label_j = BigInt::from(n as u32) + BigInt::from(i as u32) + init_seed; 79 | let hash_j = Sha512::new().chain_bigint(&kzen_label_j).result_bigint(); 80 | generate_random_point(&Converter::to_bytes(&hash_j)) 81 | }) 82 | .collect::>>(); 83 | 84 | StatementRP { 85 | g_vec, 86 | h_vec, 87 | G, 88 | H, 89 | bit_length, 90 | } 91 | } 92 | } 93 | 94 | #[derive(Clone, Debug, Serialize, Deserialize)] 95 | pub struct RangeProofWIP { 96 | A: Point, 97 | weighted_inner_product_proof: WeightedInnerProdArg, 98 | } 99 | 100 | impl RangeProofWIP { 101 | pub fn prove( 102 | stmt: StatementRP, 103 | mut secret: Vec>, 104 | blinding: &[Scalar], 105 | ) -> RangeProofWIP { 106 | let num_of_proofs = secret.len(); 107 | let bit_length = stmt.bit_length; 108 | //num of proofs times bit length 109 | let nm = num_of_proofs * bit_length; 110 | 111 | let g_vec = stmt.g_vec.to_vec(); 112 | let h_vec = stmt.h_vec.to_vec(); 113 | let G = stmt.G; 114 | let H = stmt.H; 115 | 116 | let N = g_vec.len(); 117 | let two = BigInt::from(2); 118 | let one = BigInt::from(1); 119 | let order = Scalar::::group_order(); 120 | 121 | // All of the input vectors must have the same length. 122 | assert_eq!(h_vec.len(), N); 123 | assert!(N.is_power_of_two()); 124 | 125 | //concat all secrets: 126 | secret.reverse(); 127 | let secret_agg = secret 128 | .iter() 129 | .fold(BigInt::zero(), |acc, x| acc.shl(bit_length) + x.to_bigint()); 130 | 131 | let aL = (0..nm) 132 | .map(|i| { 133 | let shr_secret = secret_agg.clone().shr(i); 134 | shr_secret.modulus(&two) 135 | }) 136 | .collect::>(); 137 | let aR = (0..nm) 138 | .map(|i| BigInt::mod_sub(&aL[i], &one, order)) 139 | .collect::>(); 140 | 141 | let secret_bits = (0..nm) 142 | .map(|i| { 143 | let bignum_bit: BigInt = aL[i].clone() & BigInt::one(); 144 | let byte = BigInt::to_bytes(&bignum_bit); 145 | byte[0] == 1 146 | }) 147 | .collect::>(); 148 | 149 | // let mut index: usize = 0; 150 | let alpha = Scalar::::random(); 151 | let mut A = &H * α 152 | A = g_vec.iter().zip(secret_bits.clone()).fold( 153 | A, 154 | |acc, x| { 155 | if x.1 { 156 | acc + x.0 157 | } else { 158 | acc 159 | } 160 | }, 161 | ); 162 | A = h_vec 163 | .iter() 164 | .zip(secret_bits) 165 | .fold(A, |acc, x| if !x.1 { acc - x.0 } else { acc }); 166 | 167 | let y = Sha256::new().chain_points([&A]).result_scalar(); 168 | let y_bn = y.to_bigint(); 169 | let base_point = Point::::generator(); 170 | let yG: Point = base_point * &y; 171 | let z: Scalar = Sha256::new().chain_points([&A, &yG]).result_scalar(); 172 | let z_bn = z.to_bigint(); 173 | let z_sq_bn = BigInt::mod_mul(&z_bn, &z_bn, order); 174 | 175 | // y_vec = (y, y^2, ..., y^{nm}) 176 | let y_powers = iterate(y_bn.clone(), |i| BigInt::mod_mul(i, &y_bn, order)) 177 | .take(nm) 178 | .collect::>(); 179 | let mut y_powers_rev = y_powers.clone(); 180 | y_powers_rev.reverse(); 181 | 182 | // vec_2n = (1, 2, 4, ..., 2^{n-1}) 183 | let vec_2n = iterate(one, |i| i.clone() * &two) 184 | .take(bit_length) 185 | .collect::>(); 186 | 187 | // vec_z2m = (z^2, z^4, ..., z^{2m}) 188 | let vec_z2m = iterate(z_sq_bn.clone(), |i| i.clone() * &z_sq_bn) 189 | .take(num_of_proofs) 190 | .collect::>(); 191 | 192 | // d = z^2 d1 + z^4 d2 + ... + z^{2m} dm 193 | let d = (0..nm) 194 | .map(|i| { 195 | let k = i % bit_length; 196 | let two_i = vec_2n[k].clone(); 197 | let j = i / bit_length; 198 | let z_2j = vec_z2m[j].clone(); 199 | BigInt::mod_mul(&two_i, &z_2j, order) 200 | }) 201 | .collect::>(); 202 | 203 | // compute exponent of h 204 | let y_pow = BigInt::mod_pow(&y_bn, &BigInt::from((nm + 1) as u32), order); 205 | let ip_blinding = (0..num_of_proofs) 206 | .map(|i| BigInt::mod_mul(&blinding[i].to_bigint(), &vec_z2m[i].clone(), order)) 207 | .fold(BigInt::zero(), |acc, x| BigInt::mod_add(&acc, &x, order)); 208 | let scalar_H = BigInt::mod_mul(&ip_blinding, &y_pow, order); 209 | 210 | // compute exponent of g 211 | let ip_secrets = (0..num_of_proofs) 212 | .map(|i| BigInt::mod_mul(&secret[i].to_bigint(), &vec_z2m[i].clone(), order)) 213 | .fold(BigInt::zero(), |acc, x| BigInt::mod_add(&acc, &x, order)); 214 | let scalar1_G = BigInt::mod_mul(&ip_secrets, &y_pow, order); 215 | 216 | let scalar_G = (0..nm) 217 | .map(|i| { 218 | let z_minus_z2 = BigInt::mod_sub(&z_bn, &z_sq_bn, order); 219 | let yi_z_minus_z2 = BigInt::mod_mul(&z_minus_z2, &y_powers[i].clone(), order); 220 | let z_y_pow = BigInt::mod_mul(&z_bn, &y_pow, order); 221 | let di_z_y_pow = BigInt::mod_mul(&d[i], &z_y_pow, order); 222 | BigInt::mod_sub(&yi_z_minus_z2, &di_z_y_pow, order) 223 | }) 224 | .fold(scalar1_G, |acc, x| BigInt::mod_add(&acc, &x, order)); 225 | 226 | // compute exponents of g_vec 227 | let scalars_g_vec = (0..nm) 228 | .map(|_| BigInt::mod_sub(&BigInt::zero(), &z_bn, order)) 229 | .collect::>(); 230 | 231 | // compute exponents of h_vec 232 | let scalars_h_vec = (0..nm) 233 | .map(|i| { 234 | let di_yi_rev = BigInt::mod_mul(&d[i], &y_powers_rev[i].clone(), order); 235 | BigInt::mod_add(&di_yi_rev, &z_bn, order) 236 | }) 237 | .collect::>(); 238 | 239 | let mut A_hat_scalars: Vec = Vec::with_capacity(2 * nm + 2); 240 | A_hat_scalars.extend_from_slice(&scalars_g_vec); 241 | A_hat_scalars.extend_from_slice(&scalars_h_vec); 242 | A_hat_scalars.extend_from_slice(&[scalar_G, scalar_H.clone()]); 243 | 244 | let mut A_hat_bases: Vec> = Vec::with_capacity(2 * nm + 2); 245 | A_hat_bases.extend_from_slice(&g_vec); 246 | A_hat_bases.extend_from_slice(&h_vec); 247 | A_hat_bases.extend_from_slice(&[G.clone(), H.clone()]); 248 | 249 | let A_hat = (0..(2 * nm + 2)) 250 | .map(|i| &A_hat_bases[i] * &Scalar::::from(&A_hat_scalars[i])) 251 | .fold(A.clone(), |acc, x| acc + x as Point); 252 | 253 | // compute aL_hat, aR_hat, alpha_hat 254 | let aL_hat = (0..nm) 255 | .map(|i| BigInt::mod_add(&aL[i], &scalars_g_vec[i], order)) 256 | .collect::>(); 257 | 258 | let aR_hat = (0..nm) 259 | .map(|i| BigInt::mod_add(&aR[i], &scalars_h_vec[i], order)) 260 | .collect::>(); 261 | 262 | let alpha_hat = BigInt::mod_add(&alpha.to_bigint(), &scalar_H, order); 263 | 264 | let L_vec = Vec::with_capacity(nm); 265 | let R_vec = Vec::with_capacity(nm); 266 | let weighted_inner_product_proof = WeightedInnerProdArg::prove( 267 | &g_vec, &h_vec, &G, &H, &A_hat, &aL_hat, &aR_hat, &alpha_hat, &y_bn, L_vec, R_vec, 268 | ); 269 | 270 | RangeProofWIP { 271 | A, 272 | weighted_inner_product_proof, 273 | } 274 | } 275 | 276 | pub fn verify(&self, stmt: StatementRP, ped_com: &[Point]) -> Result<(), Errors> { 277 | let bit_length = stmt.bit_length; 278 | let num_of_proofs = ped_com.len(); 279 | let nm = num_of_proofs * bit_length; 280 | 281 | let g_vec = stmt.g_vec.to_vec(); 282 | let h_vec = stmt.h_vec.to_vec(); 283 | let G = stmt.G; 284 | let H = stmt.H; 285 | 286 | let two = BigInt::from(2); 287 | let one = BigInt::from(1); 288 | let order = Scalar::::group_order(); 289 | 290 | let y = Sha256::new().chain_points([&self.A]).result_scalar(); 291 | let y_bn = y.to_bigint(); 292 | let base_point = Point::::generator(); 293 | let yG: Point = base_point * &y; 294 | let z: Scalar = Sha256::new().chain_points([&self.A, &yG]).result_scalar(); 295 | let z_bn = z.to_bigint(); 296 | let z_sq_bn = BigInt::mod_mul(&z_bn, &z_bn, order); 297 | 298 | // y_vec = (y, y^2, ..., y^{nm}) 299 | let y_powers = iterate(y_bn.clone(), |i| BigInt::mod_mul(i, &y_bn, order)) 300 | .take(nm) 301 | .collect::>(); 302 | let mut y_powers_rev = y_powers.clone(); 303 | y_powers_rev.reverse(); 304 | 305 | // vec_2n = (1, 2, 4, ..., 2^{n-1}) 306 | let vec_2n = iterate(one, |i| i.clone() * &two) 307 | .take(bit_length) 308 | .collect::>(); 309 | 310 | // vec_z2m = (z^2, z^4, ..., z^{2m}) 311 | let vec_z2m = iterate(z_sq_bn.clone(), |i| i.clone() * &z_sq_bn) 312 | .take(num_of_proofs) 313 | .collect::>(); 314 | 315 | // d = z^2 d1 + z^4 d2 + ... + z^{2m} dm 316 | let d = (0..nm) 317 | .map(|i| { 318 | let k = i % bit_length; 319 | let two_i = vec_2n[k].clone(); 320 | let j = i / bit_length; 321 | let z_2j = vec_z2m[j].clone(); 322 | BigInt::mod_mul(&two_i, &z_2j, order) 323 | }) 324 | .collect::>(); 325 | 326 | // compute exponent of g 327 | let y_pow = BigInt::mod_pow(&y_bn, &BigInt::from((nm + 1) as u32), order); 328 | let scalar_G = (0..nm) 329 | .map(|i| { 330 | let z_minus_z2 = BigInt::mod_sub(&z_bn, &z_sq_bn, order); 331 | let yi_z_minus_z2 = BigInt::mod_mul(&z_minus_z2, &y_powers[i].clone(), order); 332 | let z_y_pow = BigInt::mod_mul(&z_bn, &y_pow, order); 333 | let di_z_y_pow = BigInt::mod_mul(&d[i], &z_y_pow, order); 334 | BigInt::mod_sub(&yi_z_minus_z2, &di_z_y_pow, order) 335 | }) 336 | .fold(BigInt::zero(), |acc, x| BigInt::mod_add(&acc, &x, order)); 337 | 338 | // compute exponents of g_vec 339 | let scalars_g_vec = (0..nm) 340 | .map(|_| BigInt::mod_sub(&BigInt::zero(), &z_bn, order)) 341 | .collect::>(); 342 | 343 | // compute exponents of h_vec 344 | let scalars_h_vec = (0..nm) 345 | .map(|i| { 346 | let di_yi_rev = BigInt::mod_mul(&d[i], &y_powers_rev[i].clone(), order); 347 | BigInt::mod_add(&di_yi_rev, &z_bn, order) 348 | }) 349 | .collect::>(); 350 | 351 | // compute product of commitments 352 | let sum_com = (0..num_of_proofs) 353 | .map(|i| { 354 | let y_pow_z2i = BigInt::mod_mul(&y_pow, &vec_z2m[i].clone(), order); 355 | &ped_com[i] * &Scalar::::from(&y_pow_z2i) 356 | }) 357 | .fold(self.A.clone(), |acc, x| acc + x as Point); 358 | 359 | // compute A_hat 360 | let mut A_hat_scalars: Vec = Vec::with_capacity(2 * nm + 2); 361 | A_hat_scalars.extend_from_slice(&scalars_g_vec); 362 | A_hat_scalars.extend_from_slice(&scalars_h_vec); 363 | A_hat_scalars.extend_from_slice(&[scalar_G]); 364 | 365 | let mut A_hat_bases: Vec> = Vec::with_capacity(2 * nm + 2); 366 | A_hat_bases.extend_from_slice(&g_vec); 367 | A_hat_bases.extend_from_slice(&h_vec); 368 | A_hat_bases.extend_from_slice(&[G.clone()]); 369 | 370 | let A_hat = (0..(2 * nm + 1)) 371 | .map(|i| &A_hat_bases[i] * &Scalar::::from(&A_hat_scalars[i])) 372 | .fold(sum_com, |acc, x| acc + x as Point); 373 | 374 | let verify = self 375 | .weighted_inner_product_proof 376 | .fast_verify(&g_vec, &h_vec, &G, &H, &A_hat, &y_bn); 377 | if verify.is_ok() { 378 | Ok(()) 379 | } else { 380 | Err(RangeProofError) 381 | } 382 | } 383 | 384 | /// 385 | /// Verify a wip-based range proof in a using a single multi-exponentiation equation. 386 | /// The final check costs a multi-exponentiation of size (2mn + 2log(mn) + m + 5). 387 | /// 388 | pub fn aggregated_verify( 389 | &self, 390 | stmt: StatementRP, 391 | ped_com: &[Point], 392 | ) -> Result<(), Errors> { 393 | let wip = &self.weighted_inner_product_proof; 394 | let P = &self.A; 395 | 396 | let n = stmt.bit_length; 397 | let m = ped_com.len(); 398 | let nm = m * n; 399 | 400 | let G = &stmt.g_vec[..]; 401 | let H = &stmt.h_vec[..]; 402 | let g = &stmt.G; 403 | let h = &stmt.H; 404 | // let n = stmt.bit_length; 405 | let order = Scalar::::group_order(); 406 | let lg_nm = wip.L.len(); 407 | let two = BigInt::from(2); 408 | let one = BigInt::from(1); 409 | 410 | // All of the input vectors must have the same length. 411 | assert_eq!(G.len(), nm); 412 | assert_eq!(H.len(), nm); 413 | assert!(nm.is_power_of_two(), "(n*m) must be a power of two!"); 414 | assert!( 415 | lg_nm <= 64, 416 | "Not compatible for vector sizes greater than 2^64!" 417 | ); 418 | 419 | // compute challenges 420 | let y = Sha256::new().chain_points([&self.A]).result_scalar(); 421 | let y_bn = y.to_bigint(); 422 | let base_point = Point::::generator(); 423 | let yG: Point = base_point * &y; 424 | let z: Scalar = Sha256::new().chain_points([&self.A, &yG]).result_scalar(); 425 | let z_bn = z.to_bigint(); 426 | let z_sq_bn = BigInt::mod_mul(&z_bn, &z_bn, order); 427 | 428 | // y_vec = (y, y^2, ..., y^{nm}) 429 | let y_powers = iterate(y_bn.clone(), |i| BigInt::mod_mul(i, &y_bn, order)) 430 | .take(nm) 431 | .collect::>(); 432 | let mut y_powers_rev = y_powers.clone(); 433 | y_powers_rev.reverse(); 434 | 435 | // vec_2n = (1, 2, 4, ..., 2^{n-1}) 436 | let vec_2n = iterate(one, |i| i.clone() * &two) 437 | .take(n) 438 | .collect::>(); 439 | 440 | // vec_z2m = (z^2, z^4, ..., z^{2^m}) 441 | let vec_z2m = iterate(z_sq_bn.clone(), |i| i.clone() * &z_sq_bn) 442 | .take(m) 443 | .collect::>(); 444 | 445 | // d = z^2 d1 + z^4 d2 + ... + z^{2^m} dm 446 | // where dj = (0^{(j-1)n} || 2^{n} || 0^{(m-j)n}) \in \Z_q^{mn} 447 | let d = (0..nm) 448 | .map(|i| { 449 | let k = i % n; 450 | let two_i = vec_2n[k].clone(); 451 | let j = i / n; 452 | let z_2j = vec_z2m[j].clone(); 453 | BigInt::mod_mul(&two_i, &z_2j, order) 454 | }) 455 | .collect::>(); 456 | 457 | // compute powers of y_inv 458 | let y_inv = BigInt::mod_inv(&y_bn, order).unwrap(); 459 | let powers_yinv = iterate(y_inv.clone(), |i| i.clone() * y_inv.clone()) 460 | .take(nm) 461 | .collect::>(); 462 | 463 | // compute challenge e 464 | 465 | let e: Scalar = Sha256::new() 466 | .chain_points([&wip.a_tag, &wip.b_tag, g, h]) 467 | .result_scalar(); 468 | let e_bn = e.to_bigint(); 469 | let e_sq_bn = BigInt::mod_mul(&e_bn, &e_bn, order); 470 | 471 | let mut x_sq_vec: Vec = Vec::with_capacity(lg_nm); 472 | let mut minus_e_sq_x_sq_vec: Vec = Vec::with_capacity(lg_nm); 473 | let mut minus_e_sq_x_inv_sq_vec: Vec = Vec::with_capacity(lg_nm); 474 | let mut allinv = BigInt::one(); 475 | let mut all = BigInt::one(); 476 | for (Li, Ri) in wip.L.iter().zip(wip.R.iter()) { 477 | let x: Scalar = Sha256::new().chain_points([Li, Ri, g, h]).result_scalar(); 478 | let x_bn = x.to_bigint(); 479 | let x_inv_fe = x.invert().unwrap(); 480 | let x_inv_bn = x_inv_fe.to_bigint(); 481 | let x_sq_bn = BigInt::mod_mul(&x_bn, &x_bn, order); 482 | let x_inv_sq_bn = BigInt::mod_mul(&x_inv_fe.to_bigint(), &x_inv_fe.to_bigint(), order); 483 | let e_sq_x_sq_bn = BigInt::mod_mul(&e_sq_bn, &x_sq_bn, order); 484 | let e_sq_x_inv_sq_bn = BigInt::mod_mul(&e_sq_bn, &x_inv_sq_bn, order); 485 | 486 | x_sq_vec.push(x_sq_bn.clone()); 487 | minus_e_sq_x_sq_vec.push(BigInt::mod_sub(&BigInt::zero(), &e_sq_x_sq_bn, order)); 488 | minus_e_sq_x_inv_sq_vec.push(BigInt::mod_sub( 489 | &BigInt::zero(), 490 | &e_sq_x_inv_sq_bn, 491 | order, 492 | )); 493 | allinv *= x_inv_bn; 494 | all *= x_bn; 495 | } 496 | 497 | let mut s: Vec = Vec::with_capacity(nm); 498 | let mut sg: Vec = Vec::with_capacity(nm); 499 | let mut sh: Vec = Vec::with_capacity(nm); 500 | s.push(allinv.clone()); 501 | sg.push(allinv); 502 | sh.push(all); 503 | for i in 1..nm { 504 | let lg_i = 505 | (std::mem::size_of_val(&nm) * 8) - 1 - ((i as usize).leading_zeros() as usize); 506 | let k = 1 << lg_i; 507 | // The challenges are stored in "creation order" as [x_k,...,x_1], 508 | // so u_{lg(i)+1} = is indexed by (lg_nm-1) - lg_i 509 | let x_lg_i_sq = x_sq_vec[(lg_nm - 1) - lg_i].clone(); 510 | s.push(s[i - k].clone() * x_lg_i_sq); 511 | let s_inv_i = BigInt::mod_inv(&s[i], order).unwrap(); 512 | let si_yi = BigInt::mod_mul(&s[i], &powers_yinv[i - 1], order); 513 | 514 | sg.push(si_yi); 515 | sh.push(s_inv_i); 516 | } 517 | 518 | // Scalar exponents of LHS 519 | // 520 | // compute exponent of g 521 | let y_pow = BigInt::mod_pow(&y_bn, &BigInt::from((nm + 1) as u32), order); 522 | // ζ(y,z) = (z - z^2)<1^{mn}, y^{mn}> - (z y^{mn+1})<1^{mn}, d_vec> 523 | let zeta = (0..nm) 524 | .map(|i| { 525 | let z_minus_z2 = BigInt::mod_sub(&z_bn, &z_sq_bn, order); 526 | let yi_z_minus_z2 = BigInt::mod_mul(&z_minus_z2, &y_powers[i].clone(), order); 527 | let z_y_pow = BigInt::mod_mul(&z_bn, &y_pow, order); 528 | let di_z_y_pow = BigInt::mod_mul(&d[i], &z_y_pow, order); 529 | BigInt::mod_sub(&yi_z_minus_z2, &di_z_y_pow, order) 530 | }) 531 | .fold(BigInt::zero(), |acc, x| BigInt::mod_add(&acc, &x, order)); 532 | let e_sq_zeta = BigInt::mod_mul(&zeta, &e_sq_bn, order); 533 | let r_times_s = BigInt::mod_mul(&wip.r_prime, &wip.s_prime, order); 534 | let r_times_s_y = BigInt::mod_mul(&r_times_s, &y_bn, order); 535 | let scalar_g = BigInt::mod_sub(&r_times_s_y, &e_sq_zeta, order); 536 | 537 | // exponent of g_vec 538 | let e_rprime = BigInt::mod_mul(&wip.r_prime, &e_bn, order); 539 | let e_sq_z = BigInt::mod_mul(&z_bn, &e_sq_bn, order); 540 | let scalar_g_vec: Vec = (0..nm) 541 | .map(|i| { 542 | let e_rprime_sg_i = BigInt::mod_mul(&e_rprime, &sg[i], order); 543 | BigInt::mod_add(&e_rprime_sg_i, &e_sq_z, order) 544 | }) 545 | .collect(); 546 | 547 | // exponent of h_vec 548 | let e_sprime = BigInt::mod_mul(&wip.s_prime, &e_bn, order); 549 | let scalar_h_vec: Vec = (0..nm) 550 | .map(|i| { 551 | let di_yi_rev = BigInt::mod_mul(&d[i], &y_powers_rev[i].clone(), order); 552 | let di_yi_rev_e_sq = BigInt::mod_mul(&di_yi_rev, &e_sq_bn, order); 553 | let e_sprime_sh_i = BigInt::mod_mul(&e_sprime, &sh[i], order); 554 | let e_sprime_sh_minus_e_sq = BigInt::mod_sub(&e_sprime_sh_i, &e_sq_z, order); 555 | BigInt::mod_sub(&e_sprime_sh_minus_e_sq, &di_yi_rev_e_sq, order) 556 | }) 557 | .collect(); 558 | 559 | // exponent of L, R 560 | let scalar_L = minus_e_sq_x_sq_vec; 561 | let scalar_R = minus_e_sq_x_inv_sq_vec; 562 | 563 | // exponent of P 564 | let minus_e_sq = BigInt::mod_sub(&BigInt::zero(), &e_sq_bn, order); 565 | let scalar_P = minus_e_sq.clone(); 566 | 567 | // exponents of V_j (commitments) 568 | let minus_e_sq_y_pow = BigInt::mod_mul(&minus_e_sq, &y_pow, order); 569 | let scalar_com: Vec = (0..m) 570 | .map(|i| BigInt::mod_mul(&vec_z2m[i], &minus_e_sq_y_pow, order)) 571 | .collect(); 572 | 573 | // exponents of A 574 | let scalar_A = BigInt::mod_sub(&BigInt::zero(), &e_bn, order); 575 | 576 | // compute concatenated exponent vector 577 | let mut scalars: Vec = Vec::with_capacity(2 * nm + 2 * lg_nm + m + 5); 578 | scalars.extend_from_slice(&scalar_g_vec); 579 | scalars.extend_from_slice(&scalar_h_vec); 580 | scalars.push(scalar_g); 581 | scalars.extend_from_slice(&scalar_L); 582 | scalars.extend_from_slice(&scalar_R); 583 | scalars.push(scalar_P); 584 | scalars.extend_from_slice(&scalar_com); 585 | scalars.push(scalar_A); 586 | 587 | // compute concatenated base vector 588 | let mut points: Vec> = Vec::with_capacity(2 * nm + 2 * lg_nm + m + 5); 589 | points.extend_from_slice(G); 590 | points.extend_from_slice(H); 591 | points.push(g.clone()); 592 | points.extend_from_slice(&wip.L); 593 | points.extend_from_slice(&wip.R); 594 | points.push(P.clone()); 595 | points.extend_from_slice(ped_com); 596 | points.push(wip.a_tag.clone()); 597 | 598 | let h_delta_prime = h * &Scalar::::from(&wip.delta_prime); 599 | let tot_len = points.len(); 600 | let lhs = (0..tot_len) 601 | .map(|i| &points[i] * &Scalar::::from(&scalars[i])) 602 | .fold(h_delta_prime, |acc, x| acc + x as Point); 603 | 604 | if lhs == wip.b_tag { 605 | Ok(()) 606 | } else { 607 | Err(RangeProofError) 608 | } 609 | } 610 | } 611 | 612 | #[cfg(test)] 613 | mod tests { 614 | use curv::arithmetic::traits::*; 615 | use curv::elliptic::curves::{secp256_k1::Secp256k1, Point, Scalar}; 616 | use curv::BigInt; 617 | 618 | use proofs::range_proof_wip::{RangeProofWIP, StatementRP}; 619 | 620 | pub fn test_helper(seed: &BigInt, n: usize, m: usize) { 621 | // generate stmt 622 | let stmt = StatementRP::generate_bases(seed, m, n); 623 | 624 | // generate witness 625 | let G = stmt.G.clone(); 626 | let H = stmt.H.clone(); 627 | let range = BigInt::from(2).pow(n as u32); 628 | let v_vec = (0..m) 629 | .map(|_| Scalar::::from(&BigInt::sample_below(&range))) 630 | .collect::>>(); 631 | 632 | let r_vec = (0..m) 633 | .map(|_| Scalar::::random()) 634 | .collect::>>(); 635 | 636 | let ped_com_vec = (0..m) 637 | .map(|i| &G * &v_vec[i] + &H * &r_vec[i]) 638 | .collect::>>(); 639 | 640 | // simulate range proof 641 | let range_proof_wip = RangeProofWIP::prove(stmt.clone(), v_vec, &r_vec); 642 | let result = RangeProofWIP::aggregated_verify(&range_proof_wip, stmt, &ped_com_vec); 643 | assert!(result.is_ok()); 644 | } 645 | 646 | pub fn test_helper_aggregate(seed: &BigInt, n: usize, m: usize) { 647 | // generate stmt 648 | let stmt = StatementRP::generate_bases(seed, m, n); 649 | 650 | // generate witness 651 | let G = stmt.G.clone(); 652 | let H = stmt.H.clone(); 653 | let range = BigInt::from(2).pow(n as u32); 654 | let v_vec = (0..m) 655 | .map(|_| Scalar::::from(&BigInt::sample_below(&range))) 656 | .collect::>>(); 657 | 658 | let r_vec = (0..m) 659 | .map(|_| Scalar::::random()) 660 | .collect::>>(); 661 | 662 | let ped_com_vec = (0..m) 663 | .map(|i| &G * &v_vec[i] + &H * &r_vec[i]) 664 | .collect::>>(); 665 | 666 | // simulate range proof 667 | let range_proof_wip = RangeProofWIP::prove(stmt.clone(), v_vec, &r_vec); 668 | let result = RangeProofWIP::aggregated_verify(&range_proof_wip, stmt, &ped_com_vec); 669 | assert!(result.is_ok()); 670 | } 671 | 672 | #[test] 673 | pub fn test_batch_4_wip_range_proof_32() { 674 | let n = 32; 675 | // num of proofs 676 | let m = 4; 677 | let KZen: &[u8] = &[75, 90, 101, 110]; 678 | let kzen_label = BigInt::from_bytes(KZen); 679 | 680 | let stmt = StatementRP::generate_bases(&kzen_label, m, n); 681 | 682 | // generate witness 683 | let G = stmt.G.clone(); 684 | let H = stmt.H.clone(); 685 | let range = BigInt::from(2).pow(n as u32); 686 | let v_vec = (0..m) 687 | .map(|_| Scalar::::from(&BigInt::sample_below(&range))) 688 | .collect::>>(); 689 | 690 | let r_vec = (0..m) 691 | .map(|_| Scalar::::random()) 692 | .collect::>>(); 693 | 694 | let ped_com_vec = (0..m) 695 | .map(|i| &G * &v_vec[i] + &H * &r_vec[i]) 696 | .collect::>>(); 697 | 698 | let range_proof_wip = RangeProofWIP::prove(stmt.clone(), v_vec, &r_vec); 699 | let result = RangeProofWIP::verify(&range_proof_wip, stmt, &ped_com_vec); 700 | assert!(result.is_ok()); 701 | } 702 | 703 | #[test] 704 | #[should_panic] 705 | pub fn test_batch_4_wip_range_proof_32_out_of_range() { 706 | let n = 32; 707 | // num of proofs 708 | let m = 4; 709 | let KZen: &[u8] = &[75, 90, 101, 110]; 710 | let kzen_label = BigInt::from_bytes(KZen); 711 | 712 | let stmt = StatementRP::generate_bases(&kzen_label, m, n); 713 | 714 | // generate witness 715 | let G = stmt.G.clone(); 716 | let H = stmt.H.clone(); 717 | let range = BigInt::from(2).pow(n as u32); 718 | let mut v_vec = (0..m - 1) 719 | .map(|_| Scalar::::from(&BigInt::sample_below(&range))) 720 | .collect::>>(); 721 | 722 | let bad_v = BigInt::from(2).pow(33); 723 | v_vec.push(Scalar::::from(&bad_v)); 724 | 725 | let r_vec = (0..m) 726 | .map(|_| Scalar::::random()) 727 | .collect::>>(); 728 | 729 | let ped_com_vec = (0..m) 730 | .map(|i| &G * &v_vec[i] + &H * &r_vec[i]) 731 | .collect::>>(); 732 | 733 | let range_proof_wip = RangeProofWIP::prove(stmt.clone(), v_vec, &r_vec); 734 | let result = RangeProofWIP::verify(&range_proof_wip, stmt, &ped_com_vec); 735 | assert!(result.is_ok()); 736 | } 737 | 738 | #[test] 739 | pub fn test_batch_2_wip_range_proof_16() { 740 | let KZen: &[u8] = &[75, 90, 101, 110]; 741 | let kzen_label = BigInt::from_bytes(KZen); 742 | test_helper(&kzen_label, 16, 2); 743 | } 744 | 745 | #[test] 746 | pub fn test_batch_1_wip_range_proof_8() { 747 | let KZen: &[u8] = &[75, 90, 101, 110]; 748 | let kzen_label = BigInt::from_bytes(KZen); 749 | test_helper(&kzen_label, 8, 1); 750 | } 751 | 752 | #[test] 753 | pub fn test_batch_4_wip_range_proof_64() { 754 | let KZen: &[u8] = &[75, 90, 101, 110]; 755 | let kzen_label = BigInt::from_bytes(KZen); 756 | test_helper(&kzen_label, 64, 4); 757 | } 758 | 759 | #[test] 760 | pub fn test_batch_agg_4_wip_range_proof_64() { 761 | let KZen: &[u8] = &[75, 90, 101, 110]; 762 | let kzen_label = BigInt::from_bytes(KZen); 763 | test_helper_aggregate(&kzen_label, 64, 4); 764 | } 765 | } 766 | -------------------------------------------------------------------------------- /src/proofs/weighted_inner_product.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | 3 | /* 4 | 5 | Copyright 2018 by Kzen Networks 6 | 7 | This file is part of bulletproof library 8 | (https://github.com/KZen-networks/bulletproof) 9 | 10 | bulletproof is free software: you can redistribute 11 | it and/or modify it under the terms of the GNU General Public 12 | License as published by the Free Software Foundation, either 13 | version 3 of the License, or (at your option) any later version. 14 | 15 | @license GPL-3.0+ 16 | */ 17 | 18 | // based on the paper: https://eprint.iacr.org/2020/735.pdf 19 | // 20 | // Bulletproofs (https://eprint.iacr.org/2017/1066) uses the inner product argument. 21 | // Bulletproofs+ (https://eprint.iacr.org/2020/735.pdf) uses the weighted inner product argument 22 | // which reduces the overall prover communication by ~15% 23 | // 24 | 25 | use curv::arithmetic::traits::*; 26 | use curv::cryptographic_primitives::hashing::{Digest, DigestExt}; 27 | use curv::elliptic::curves::{secp256_k1::Secp256k1, Point, Scalar}; 28 | use curv::BigInt; 29 | use sha2::Sha256; 30 | 31 | use itertools::iterate; 32 | 33 | use Errors::{self, WeightedInnerProdError}; 34 | 35 | #[derive(Clone, Debug, Serialize, Deserialize)] 36 | pub struct WeightedInnerProdArg { 37 | pub(super) L: Vec>, 38 | pub(super) R: Vec>, 39 | pub(super) a_tag: Point, 40 | pub(super) b_tag: Point, 41 | pub(super) r_prime: BigInt, 42 | pub(super) s_prime: BigInt, 43 | pub(super) delta_prime: BigInt, 44 | } 45 | 46 | impl WeightedInnerProdArg { 47 | pub fn prove( 48 | G: &[Point], 49 | H: &[Point], 50 | g: &Point, 51 | h: &Point, 52 | P: &Point, 53 | a: &[BigInt], 54 | b: &[BigInt], 55 | alpha: &BigInt, 56 | y: &BigInt, 57 | mut L_vec: Vec>, 58 | mut R_vec: Vec>, 59 | ) -> WeightedInnerProdArg { 60 | let n = G.len(); 61 | let order = Scalar::::group_order(); 62 | 63 | // All of the input vectors must have the same length. 64 | assert_eq!(H.len(), n); 65 | assert_eq!(a.len(), n); 66 | assert_eq!(b.len(), n); 67 | assert!(n.is_power_of_two()); 68 | 69 | // compute powers of y 70 | let y_inv = BigInt::mod_inv(y, order).unwrap(); 71 | let powers_y = iterate(y.clone(), |i| i.clone() * y) 72 | .take(n) 73 | .collect::>(); 74 | let powers_yinv = iterate(y_inv.clone(), |i| i.clone() * y_inv.clone()) 75 | .take(n) 76 | .collect::>(); 77 | 78 | // let mut L_vec = Vec::with_capacity(n); 79 | // let mut R_vec = Vec::with_capacity(n); 80 | if n != 1 { 81 | let n = n / 2; 82 | 83 | // we use notation a_L for the left half of vector a and so on 84 | // Note: Bulletproofs+ paper uses (a_1, a_2) for (a_L, a_R) 85 | let (a_L, a_R) = a.split_at(n); 86 | let (b_L, b_R) = b.split_at(n); 87 | let (G_L, G_R) = G.split_at(n); 88 | let (H_L, H_R) = H.split_at(n); 89 | 90 | let yn_aR = (0..n) 91 | .map(|i| BigInt::mod_mul(&powers_y[n - 1], &a_R[i], order)) 92 | .collect::>(); 93 | let yninv_aL = (0..n) 94 | .map(|i| BigInt::mod_mul(&powers_yinv[n - 1], &a_L[i], order)) 95 | .collect::>(); 96 | 97 | let c_L = weighted_inner_product(a_L, b_R, y.clone()); 98 | let c_R = weighted_inner_product(&yn_aR, b_L, y.clone()); 99 | 100 | // Note that no element in vectors a_L and b_R can be 0 101 | // since 0 is an invalid secret key! 102 | // 103 | // L = + + (c_L * g) + (d_L * h) 104 | let c_L_fe = Scalar::::from(&c_L); 105 | let g_cL: Point = g * &c_L_fe; 106 | let d_L_fe = Scalar::::random(); 107 | let h_dL = h * &d_L_fe; 108 | let g_cL_h_dL = g_cL + &h_dL; 109 | let yninv_aL_GR = G_R.iter().zip(yninv_aL).fold(g_cL_h_dL, |acc, x| { 110 | if x.1 != BigInt::zero() { 111 | let aLi = Scalar::::from(&x.1); 112 | let aLi_GRi: Point = x.0 * &aLi; 113 | acc + &aLi_GRi 114 | } else { 115 | acc 116 | } 117 | }); 118 | let L = H_L.iter().zip(b_R).fold(yninv_aL_GR, |acc, x| { 119 | if x.1 != &BigInt::zero() { 120 | let bRi = Scalar::::from(x.1); 121 | let bRi_HLi: Point = x.0 * &bRi; 122 | acc + &bRi_HLi 123 | } else { 124 | acc 125 | } 126 | }); 127 | 128 | // Note that no element in vectors a_R and b_L can be 0 129 | // since 0 is an invalid secret key! 130 | // 131 | // R = + + (c_R * g) + (d_R * h) 132 | let c_R_fe = Scalar::::from(&c_R); 133 | let g_cR: Point = g * &c_R_fe; 134 | let d_R_fe = Scalar::::random(); 135 | let h_dR = h * &d_R_fe; 136 | let g_cR_h_dR = g_cR + &h_dR; 137 | let aR_GL = G_L.iter().zip(yn_aR.clone()).fold(g_cR_h_dR, |acc, x| { 138 | if x.1 != BigInt::zero() { 139 | let aRi = Scalar::::from(&x.1); 140 | let aRi_GLi: Point = x.0 * &aRi; 141 | acc + &aRi_GLi 142 | } else { 143 | acc 144 | } 145 | }); 146 | let R = H_R.iter().zip(b_L).fold(aR_GL, |acc, x| { 147 | if x.1 != &BigInt::zero() { 148 | let bLi = Scalar::::from(x.1); 149 | let bLi_HRi: Point = x.0 * &bLi; 150 | acc + &bLi_HRi 151 | } else { 152 | acc 153 | } 154 | }); 155 | 156 | // the challenges in pre-final rounds are used as [x_1, x_2, ...] 157 | // to avoid confusion with the challenge `e` in last round 158 | let x = Sha256::new().chain_points([&L, &R, g, h]).result_scalar(); 159 | let x_bn = x.to_bigint(); 160 | let x_sq_bn = BigInt::mod_mul(&x_bn, &x_bn, order); 161 | let x_sq_inv_bn = BigInt::mod_inv(&x_sq_bn, order).unwrap(); 162 | let x_inv_fe = x.invert().unwrap(); 163 | 164 | let a_hat = (0..n) 165 | .map(|i| { 166 | let aLx = BigInt::mod_mul(&a_L[i], &x_bn, order); 167 | let aR_minusx = BigInt::mod_mul(&yn_aR[i], &x_inv_fe.to_bigint(), order); 168 | BigInt::mod_add(&aLx, &aR_minusx, order) 169 | }) 170 | .collect::>(); 171 | // a = &mut a_hat[..]; 172 | 173 | let b_hat = (0..n) 174 | .map(|i| { 175 | let bRx = BigInt::mod_mul(&b_R[i], &x_bn, order); 176 | let bL_minusx = BigInt::mod_mul(&b_L[i], &x_inv_fe.to_bigint(), order); 177 | BigInt::mod_add(&bRx, &bL_minusx, order) 178 | }) 179 | .collect::>(); 180 | // b = &mut b_hat[..]; 181 | 182 | let x2_dL = BigInt::mod_mul(&x_sq_bn, &d_L_fe.to_bigint(), order); 183 | let xinv2_dR = BigInt::mod_mul(&x_sq_inv_bn, &d_R_fe.to_bigint(), order); 184 | let x2_dL_xinv2_dR = BigInt::mod_add(&x2_dL, &xinv2_dR, order); 185 | let alpha_hat = BigInt::mod_add(alpha, &x2_dL_xinv2_dR, order); 186 | 187 | let x_yinv = BigInt::mod_mul(&x_bn, &powers_yinv[n - 1], order); 188 | let x_yinv_fe = Scalar::::from(&x_yinv); 189 | let G_hat = (0..n) 190 | .map(|i| { 191 | let GLx_inv = &G_L[i] * &x_inv_fe; 192 | let GRx_yinv = &G_R[i] * &x_yinv_fe; 193 | GRx_yinv + GLx_inv 194 | }) 195 | .collect::>>(); 196 | // G = &mut G_hat[..]; 197 | 198 | let H_hat = (0..n) 199 | .map(|i| { 200 | let HLx = &H_L[i] * &x; 201 | let HRx_inv = &H_R[i] * &x_inv_fe; 202 | HLx + HRx_inv 203 | }) 204 | .collect::>>(); 205 | // H = &mut H_hat[..]; 206 | 207 | L_vec.push(L); 208 | R_vec.push(R); 209 | WeightedInnerProdArg::prove( 210 | &G_hat, &H_hat, g, h, P, &a_hat, &b_hat, &alpha_hat, y, L_vec, R_vec, 211 | ) 212 | } else { 213 | let r = Scalar::::random(); 214 | let r_bn: BigInt = r.to_bigint(); 215 | let s = Scalar::::random(); 216 | let s_bn: BigInt = s.to_bigint(); 217 | let delta = Scalar::::random(); 218 | let delta_bn: BigInt = delta.to_bigint(); 219 | let eta = Scalar::::random(); 220 | let eta_bn: BigInt = eta.to_bigint(); 221 | 222 | // compute A 223 | let Gr = &G[0] * &r; 224 | let Hs = &H[0] * &s; 225 | let a_s = BigInt::mod_mul(&a[0], &s_bn, order); 226 | let a_sy = BigInt::mod_mul(&a_s, y, order); 227 | let b_r = BigInt::mod_mul(&b[0], &r_bn, order); 228 | let b_ry = BigInt::mod_mul(&b_r, y, order); 229 | let a_sy_b_ry = BigInt::mod_add(&a_sy, &b_ry, order); 230 | let g_a_sy_b_ry = g * &Scalar::::from(&a_sy_b_ry); 231 | let h_delta = h * δ 232 | let A = Gr + Hs + g_a_sy_b_ry + h_delta; 233 | 234 | // compute B 235 | let r_s = BigInt::mod_mul(&r_bn, &s_bn, order); 236 | let r_sy = BigInt::mod_mul(y, &r_s, order); 237 | let g_r_sy = g * &Scalar::::from(&r_sy); 238 | let h_eta = h * η 239 | let B = g_r_sy + h_eta; 240 | 241 | // compute challenge e 242 | // let lg_n = L_vec.len(); 243 | let e: Scalar = Sha256::new().chain_points([&A, &B, g, h]).result_scalar(); 244 | let e_bn = e.to_bigint(); 245 | let e_sq_bn = BigInt::mod_mul(&e_bn, &e_bn, order); 246 | 247 | // compute r_prime, s_prime, delta_prime 248 | let ax = BigInt::mod_mul(&a[0], &e_bn, order); 249 | let bx = BigInt::mod_mul(&b[0], &e_bn, order); 250 | let r_prime = BigInt::mod_add(&r_bn, &ax, order); 251 | let s_prime = BigInt::mod_add(&s_bn, &bx, order); 252 | 253 | let deltax = BigInt::mod_mul(&delta_bn, &e_bn, order); 254 | let alpha_x2 = BigInt::mod_mul(alpha, &e_sq_bn, order); 255 | let deltax_alpha_x2 = BigInt::mod_add(&deltax, &alpha_x2, order); 256 | let delta_prime = BigInt::mod_add(&eta_bn, &deltax_alpha_x2, order); 257 | 258 | WeightedInnerProdArg { 259 | L: L_vec, 260 | R: R_vec, 261 | a_tag: A, 262 | b_tag: B, 263 | r_prime, 264 | s_prime, 265 | delta_prime, 266 | } 267 | } 268 | } 269 | 270 | pub fn verify( 271 | &self, 272 | g_vec: &[Point], 273 | hi_tag: &[Point], 274 | g: &Point, 275 | h: &Point, 276 | P: &Point, 277 | y: &BigInt, 278 | ) -> Result<(), Errors> { 279 | let G = g_vec; 280 | let H = hi_tag; 281 | let n = G.len(); 282 | let order = Scalar::::group_order(); 283 | 284 | // All of the input vectors must have the same length. 285 | assert_eq!(H.len(), n); 286 | assert!(n.is_power_of_two()); 287 | 288 | // compute powers of y 289 | let y_inv = BigInt::mod_inv(y, order).unwrap(); 290 | let powers_yinv = iterate(y_inv.clone(), |i| i.clone() * y_inv.clone()) 291 | .take(n) 292 | .collect::>(); 293 | 294 | if n != 1 { 295 | let n = n / 2; 296 | let (G_L, G_R) = G.split_at(n); 297 | let (H_L, H_R) = H.split_at(n); 298 | 299 | let x = Sha256::new() 300 | .chain_points([&self.L[0], &self.R[0], g, h]) 301 | .result_scalar(); 302 | let x_bn = x.to_bigint(); 303 | let order = Scalar::::group_order(); 304 | let x_inv_fe = x.invert().unwrap(); 305 | let x_sq_bn = BigInt::mod_mul(&x_bn, &x_bn, order); 306 | let x_inv_sq_bn = BigInt::mod_mul(&x_inv_fe.to_bigint(), &x_inv_fe.to_bigint(), order); 307 | let x_sq_fe = Scalar::::from(&x_sq_bn); 308 | let x_inv_sq_fe = Scalar::::from(&x_inv_sq_bn); 309 | 310 | let x_yinv = BigInt::mod_mul(&x_bn, &powers_yinv[n - 1], order); 311 | let x_yinv_fe = Scalar::::from(&x_yinv); 312 | let G_hat = (0..n) 313 | .map(|i| { 314 | let GLx_inv = &G_L[i] * &x_inv_fe; 315 | let GRx_yinv = &G_R[i] * &x_yinv_fe; 316 | GRx_yinv + GLx_inv 317 | }) 318 | .collect::>>(); 319 | // G = &mut G_hat[..]; 320 | 321 | let H_hat = (0..n) 322 | .map(|i| { 323 | let HLx = &H_L[i] * &x; 324 | let HRx_inv = &H_R[i] * &x_inv_fe; 325 | HLx + HRx_inv 326 | }) 327 | .collect::>>(); 328 | // H = &mut H_hat[..]; 329 | 330 | let Lx_sq = &self.L[0] * &x_sq_fe; 331 | let Rx_sq_inv = &self.R[0] * &x_inv_sq_fe; 332 | let P_tag = Lx_sq + Rx_sq_inv + P; 333 | 334 | let ip = WeightedInnerProdArg { 335 | L: (&self.L[1..]).to_vec(), 336 | R: (&self.R[1..]).to_vec(), 337 | a_tag: self.a_tag.clone(), 338 | b_tag: self.b_tag.clone(), 339 | r_prime: self.r_prime.clone(), 340 | s_prime: self.s_prime.clone(), 341 | delta_prime: self.delta_prime.clone(), 342 | }; 343 | return ip.verify(&G_hat, &H_hat, g, h, &P_tag, y); 344 | } 345 | 346 | // compute challenge e 347 | 348 | let e = Sha256::new() 349 | .chain_points([&self.a_tag, &self.b_tag, g, h]) 350 | .result_scalar(); 351 | let e_bn = e.to_bigint(); 352 | let e_sq_bn = BigInt::mod_mul(&e_bn, &e_bn, order); 353 | let e_sq_fe = Scalar::::from(&e_sq_bn); 354 | 355 | // left hand side of verification 356 | // LHS = e^2*P + e*A + B 357 | let P_e2 = P * &e_sq_fe; 358 | let Ae = &self.a_tag * &e; 359 | let left = P_e2 + Ae + &self.b_tag; 360 | 361 | // RHS = (er')*G + (es')*H + (r's'y)*g + (delta')*h 362 | let er_prime = BigInt::mod_mul(&e_bn, &self.r_prime, order); 363 | let Ger_prime = &G[0] * &Scalar::::from(&er_prime); 364 | let es_prime = BigInt::mod_mul(&e_bn, &self.s_prime, order); 365 | let Hes_prime = &H[0] * &Scalar::::from(&es_prime); 366 | let rs_prime = BigInt::mod_mul(&self.s_prime, &self.r_prime, order); 367 | let yrs_prime = BigInt::mod_mul(&rs_prime, y, order); 368 | let g_yrs_prime = g * &Scalar::::from(&yrs_prime); 369 | let h_delta_prime = h * &Scalar::::from(&self.delta_prime); 370 | let right = Ger_prime + Hes_prime + g_yrs_prime + h_delta_prime; 371 | 372 | if left == right { 373 | Ok(()) 374 | } else { 375 | Err(WeightedInnerProdError) 376 | } 377 | } 378 | 379 | /// 380 | /// Returns Ok() if the given inner product satisfies the verification equations, 381 | /// else returns `WeightedInnerProdErrorError`. 382 | /// 383 | /// Uses a single multiexponentiation (multiscalar multiplication in additive notation) 384 | /// check to verify an inner product proof. 385 | /// 386 | pub fn fast_verify( 387 | &self, 388 | g_vec: &[Point], 389 | hi_tag: &[Point], 390 | g: &Point, 391 | h: &Point, 392 | P: &Point, 393 | y: &BigInt, 394 | ) -> Result<(), Errors> { 395 | let G = g_vec; 396 | let H = hi_tag; 397 | let n = G.len(); 398 | let order = Scalar::::group_order(); 399 | 400 | // All of the input vectors must have the same length. 401 | assert_eq!(H.len(), n); 402 | assert!(n.is_power_of_two()); 403 | 404 | // compute powers of y 405 | let y_inv = BigInt::mod_inv(y, order).unwrap(); 406 | let powers_yinv = iterate(y_inv.clone(), |i| i.clone() * y_inv.clone()) 407 | .take(n) 408 | .collect::>(); 409 | 410 | let lg_n = self.L.len(); 411 | assert!( 412 | lg_n <= 64, 413 | "Not compatible for vector sizes greater than 2^64!" 414 | ); 415 | 416 | // compute challenge e 417 | let e: Scalar = Sha256::new() 418 | .chain_points([&self.a_tag, &self.b_tag, g, h]) 419 | .result_scalar(); 420 | let e_bn = e.to_bigint(); 421 | let e_sq_bn = BigInt::mod_mul(&e_bn, &e_bn, order); 422 | 423 | let mut x_sq_vec: Vec = Vec::with_capacity(lg_n); 424 | let mut minus_e_sq_x_sq_vec: Vec = Vec::with_capacity(lg_n); 425 | let mut minus_e_sq_x_inv_sq_vec: Vec = Vec::with_capacity(lg_n); 426 | let mut allinv = BigInt::one(); 427 | let mut all = BigInt::one(); 428 | for (Li, Ri) in self.L.iter().zip(self.R.iter()) { 429 | let x: Scalar = Sha256::new().chain_points([Li, Ri, g, h]).result_scalar(); 430 | let x_bn = x.to_bigint(); 431 | let x_inv_fe = x.invert().unwrap(); 432 | let x_inv_bn = x_inv_fe.to_bigint(); 433 | let x_sq_bn = BigInt::mod_mul(&x_bn, &x_bn, order); 434 | let x_inv_sq_bn = BigInt::mod_mul(&x_inv_fe.to_bigint(), &x_inv_fe.to_bigint(), order); 435 | let e_sq_x_sq_bn = BigInt::mod_mul(&e_sq_bn, &x_sq_bn, order); 436 | let e_sq_x_inv_sq_bn = BigInt::mod_mul(&e_sq_bn, &x_inv_sq_bn, order); 437 | 438 | x_sq_vec.push(x_sq_bn.clone()); 439 | minus_e_sq_x_sq_vec.push(BigInt::mod_sub(&BigInt::zero(), &e_sq_x_sq_bn, order)); 440 | minus_e_sq_x_inv_sq_vec.push(BigInt::mod_sub( 441 | &BigInt::zero(), 442 | &e_sq_x_inv_sq_bn, 443 | order, 444 | )); 445 | allinv *= x_inv_bn; 446 | all *= x_bn; 447 | } 448 | 449 | let mut s: Vec = Vec::with_capacity(n); 450 | let mut sg: Vec = Vec::with_capacity(n); 451 | let mut sh: Vec = Vec::with_capacity(n); 452 | s.push(allinv.clone()); 453 | sg.push(allinv); 454 | sh.push(all); 455 | for i in 1..n { 456 | let lg_i = 457 | (std::mem::size_of_val(&n) * 8) - 1 - ((i as usize).leading_zeros() as usize); 458 | let k = 1 << lg_i; 459 | // The challenges are stored in "creation order" as [x_k,...,x_1], 460 | // so u_{lg(i)+1} = is indexed by (lg_n-1) - lg_i 461 | let x_lg_i_sq = x_sq_vec[(lg_n - 1) - lg_i].clone(); 462 | s.push(s[i - k].clone() * x_lg_i_sq); 463 | let s_inv_i = BigInt::mod_inv(&s[i], order).unwrap(); 464 | let si_yi = BigInt::mod_mul(&s[i], &powers_yinv[i - 1], order); 465 | 466 | sg.push(si_yi); 467 | sh.push(s_inv_i); 468 | } 469 | 470 | // Scalar exponent of LHS 471 | let er_times_sg: Vec = (0..n) 472 | .map(|i| { 473 | let e_sg_i = BigInt::mod_mul(&e_bn, &sg[i], order); 474 | BigInt::mod_mul(&self.r_prime, &e_sg_i, order) 475 | }) 476 | .collect(); 477 | let es_times_sg: Vec = (0..n) 478 | .map(|i| { 479 | let e_sh_i = BigInt::mod_mul(&e_bn, &sh[i], order); 480 | BigInt::mod_mul(&self.s_prime, &e_sh_i, order) 481 | }) 482 | .collect(); 483 | let r_times_s = BigInt::mod_mul(&self.r_prime, &self.s_prime, order); 484 | let r_times_s_y = BigInt::mod_mul(&r_times_s, y, order); 485 | 486 | let mut scalars: Vec = Vec::with_capacity(2 * n + 2 * lg_n + 1); 487 | scalars.extend_from_slice(&er_times_sg); 488 | scalars.extend_from_slice(&es_times_sg); 489 | scalars.extend_from_slice(&minus_e_sq_x_sq_vec); 490 | scalars.extend_from_slice(&minus_e_sq_x_inv_sq_vec); 491 | scalars.push(r_times_s_y); 492 | 493 | let mut points: Vec> = Vec::with_capacity(2 * n + 2 * lg_n + 1); 494 | points.extend_from_slice(g_vec); 495 | points.extend_from_slice(hi_tag); 496 | points.extend_from_slice(&self.L); 497 | points.extend_from_slice(&self.R); 498 | points.push(g.clone()); 499 | 500 | let h_delta_prime = h * &Scalar::::from(&self.delta_prime); 501 | let tot_len = points.len(); 502 | let lhs = (0..tot_len) 503 | .map(|i| &points[i] * &Scalar::::from(&scalars[i])) 504 | .fold(h_delta_prime, |acc, x| acc + x as Point); 505 | 506 | let Ae = &self.a_tag * &Scalar::::from(&e_bn); 507 | let Pe_sq = P * &Scalar::::from(&e_sq_bn); 508 | let rhs = Pe_sq + Ae + &self.b_tag; 509 | 510 | if lhs == rhs { 511 | Ok(()) 512 | } else { 513 | Err(WeightedInnerProdError) 514 | } 515 | } 516 | } 517 | 518 | fn weighted_inner_product(a: &[BigInt], b: &[BigInt], y: BigInt) -> BigInt { 519 | assert_eq!( 520 | a.len(), 521 | b.len(), 522 | "weighted_inner_product(a,b): lengths of vectors do not match" 523 | ); 524 | let order = Scalar::::group_order(); 525 | let y_powers = iterate(y.clone(), |i| i.clone() * y.clone()) 526 | .take(a.len()) 527 | .collect::>(); 528 | let n = a.len(); 529 | 530 | (0..n) 531 | .map(|i| { 532 | let aibi = BigInt::mod_mul(&a[i], &b[i], order); 533 | BigInt::mod_mul(&aibi, &y_powers[i], order) 534 | }) 535 | .fold(BigInt::zero(), |acc, x| BigInt::mod_add(&acc, &x, order)) 536 | } 537 | 538 | #[cfg(test)] 539 | mod tests { 540 | use curv::arithmetic::traits::*; 541 | use curv::cryptographic_primitives::hashing::{Digest, DigestExt}; 542 | use curv::elliptic::curves::{secp256_k1::Secp256k1, Point, Scalar}; 543 | use curv::BigInt; 544 | use sha2::{Sha256, Sha512}; 545 | 546 | use curv::elliptic::curves::secp256_k1::hash_to_curve::generate_random_point; 547 | use itertools::iterate; 548 | use proofs::weighted_inner_product::weighted_inner_product; 549 | use proofs::weighted_inner_product::WeightedInnerProdArg; 550 | 551 | fn test_helper(n: usize) { 552 | let KZen: &[u8] = &[75, 90, 101, 110]; 553 | let kzen_label = BigInt::from_bytes(KZen); 554 | 555 | let g_vec = (0..n) 556 | .map(|i| { 557 | let kzen_label_i = BigInt::from(i as u32) + &kzen_label; 558 | let hash_i = Sha512::new().chain_bigint(&kzen_label_i).result_bigint(); 559 | generate_random_point(&Converter::to_bytes(&hash_i)) 560 | }) 561 | .collect::>>(); 562 | 563 | // can run in parallel to g_vec: 564 | let h_vec = (0..n) 565 | .map(|i| { 566 | let kzen_label_j = BigInt::from(n as u32) + BigInt::from(i as u32) + &kzen_label; 567 | let hash_j = Sha512::new().chain_bigint(&kzen_label_j).result_bigint(); 568 | generate_random_point(&Converter::to_bytes(&hash_j)) 569 | }) 570 | .collect::>>(); 571 | 572 | let label = BigInt::from(2); 573 | let hash = Sha512::new().chain_bigint(&label).result_bigint(); 574 | let g = generate_random_point(&Converter::to_bytes(&hash)); 575 | let label = BigInt::from(3); 576 | let hash = Sha512::new().chain_bigint(&label).result_bigint(); 577 | let h = generate_random_point(&Converter::to_bytes(&hash)); 578 | 579 | let a: Vec<_> = (0..n) 580 | .map(|_| { 581 | let rand = Scalar::::random(); 582 | rand.to_bigint() 583 | }) 584 | .collect(); 585 | 586 | let b: Vec<_> = (0..n) 587 | .map(|_| { 588 | let rand = Scalar::::random(); 589 | rand.to_bigint() 590 | }) 591 | .collect(); 592 | 593 | let y_scalar: BigInt = Sha256::new() 594 | .chain(b"Seed string decided by P,V!") 595 | .result_bigint(); 596 | //HSha256::create_hash_from_slice("Seed string decided by P,V!".as_bytes()); 597 | let c = super::weighted_inner_product(&a, &b, y_scalar.clone()); 598 | 599 | let alpha_fe = Scalar::::random(); 600 | let alpha = alpha_fe.to_bigint(); 601 | 602 | let y = Scalar::::random(); 603 | let order = Scalar::::group_order(); 604 | let yi = (0..n) 605 | .map(|i| BigInt::mod_pow(&y.to_bigint(), &BigInt::from(i as u32), order)) 606 | .collect::>(); 607 | 608 | let yi_inv = (0..n) 609 | .map(|i| { 610 | let yi_fe = Scalar::::from(&yi[i]); 611 | yi_fe.invert().unwrap() 612 | }) 613 | .collect::>>(); 614 | 615 | let hi_tag = (0..n) 616 | .map(|i| &h_vec[i] * &yi_inv[i]) 617 | .collect::>>(); 618 | 619 | // R = + + c * g + alpha*h 620 | let c_fe = Scalar::::from(&c); 621 | let g_c: Point = &g * &c_fe; 622 | let h_alpha: Point = &h * &alpha_fe; 623 | let gc_halpha = g_c + h_alpha; 624 | let a_G = (0..n) 625 | .map(|i| { 626 | let ai = Scalar::::from(&a[i]); 627 | &g_vec[i] * &ai 628 | }) 629 | .fold(gc_halpha, |acc, x: Point| { 630 | acc + x as Point 631 | }); 632 | let P = (0..n) 633 | .map(|i| { 634 | let bi = Scalar::::from(&b[i]); 635 | &hi_tag[i] * &bi 636 | }) 637 | .fold(a_G, |acc, x: Point| acc + x as Point); 638 | 639 | let L_vec = Vec::with_capacity(n); 640 | let R_vec = Vec::with_capacity(n); 641 | let ipp = WeightedInnerProdArg::prove( 642 | &g_vec, &hi_tag, &g, &h, &P, &a, &b, &alpha, &y_scalar, L_vec, R_vec, 643 | ); 644 | let verifier = ipp.verify(&g_vec, &hi_tag, &g, &h, &P, &y_scalar); 645 | assert!(verifier.is_ok()) 646 | } 647 | 648 | fn test_helper_fast_verify(n: usize) { 649 | let KZen: &[u8] = &[75, 90, 101, 110]; 650 | let kzen_label = BigInt::from_bytes(KZen); 651 | 652 | let g_vec = (0..n) 653 | .map(|i| { 654 | let kzen_label_i = BigInt::from(i as u32) + &kzen_label; 655 | let hash_i = Sha512::new().chain_bigint(&kzen_label_i).result_bigint(); 656 | generate_random_point(&Converter::to_bytes(&hash_i)) 657 | }) 658 | .collect::>>(); 659 | 660 | // can run in parallel to g_vec: 661 | let h_vec = (0..n) 662 | .map(|i| { 663 | let kzen_label_j = BigInt::from(n as u32) + BigInt::from(i as u32) + &kzen_label; 664 | let hash_j = Sha512::new().chain_bigint(&kzen_label_j).result_bigint(); 665 | generate_random_point(&Converter::to_bytes(&hash_j)) 666 | }) 667 | .collect::>>(); 668 | 669 | let label = BigInt::from(2); 670 | let hash = Sha512::new().chain_bigint(&label).result_bigint(); 671 | let g = generate_random_point(&Converter::to_bytes(&hash)); 672 | let label = BigInt::from(3); 673 | let hash = Sha512::new().chain_bigint(&label).result_bigint(); 674 | let h = generate_random_point(&Converter::to_bytes(&hash)); 675 | 676 | let a: Vec<_> = (0..n) 677 | .map(|_| { 678 | let rand = Scalar::::random(); 679 | rand.to_bigint() 680 | }) 681 | .collect(); 682 | 683 | let b: Vec<_> = (0..n) 684 | .map(|_| { 685 | let rand = Scalar::::random(); 686 | rand.to_bigint() 687 | }) 688 | .collect(); 689 | 690 | let y_scalar: BigInt = Sha256::new() 691 | .chain(b"Seed string decided by P,V!") 692 | .result_bigint(); 693 | let c = super::weighted_inner_product(&a, &b, y_scalar.clone()); 694 | 695 | let alpha_fe = Scalar::::random(); 696 | let alpha = alpha_fe.to_bigint(); 697 | 698 | let y = Scalar::::random(); 699 | let order = Scalar::::group_order(); 700 | let yi = (0..n) 701 | .map(|i| BigInt::mod_pow(&y.to_bigint(), &BigInt::from(i as u32), order)) 702 | .collect::>(); 703 | 704 | let yi_inv = (0..n) 705 | .map(|i| { 706 | let yi_fe = Scalar::::from(&yi[i]); 707 | yi_fe.invert().unwrap() 708 | }) 709 | .collect::>>(); 710 | 711 | let hi_tag = (0..n) 712 | .map(|i| &h_vec[i] * &yi_inv[i]) 713 | .collect::>>(); 714 | 715 | // R = + + c * g + alpha*h 716 | let c_fe = Scalar::::from(&c); 717 | let g_c: Point = &g * &c_fe; 718 | let h_alpha: Point = &h * &alpha_fe; 719 | let gc_halpha = g_c + h_alpha; 720 | let a_G = (0..n) 721 | .map(|i| { 722 | let ai = Scalar::::from(&a[i]); 723 | &g_vec[i] * &ai 724 | }) 725 | .fold(gc_halpha, |acc, x: Point| { 726 | acc + x as Point 727 | }); 728 | let P = (0..n) 729 | .map(|i| { 730 | let bi = Scalar::::from(&b[i]); 731 | &hi_tag[i] * &bi 732 | }) 733 | .fold(a_G, |acc, x: Point| acc + x as Point); 734 | 735 | let L_vec = Vec::with_capacity(n); 736 | let R_vec = Vec::with_capacity(n); 737 | let ipp = WeightedInnerProdArg::prove( 738 | &g_vec, &hi_tag, &g, &h, &P, &a, &b, &alpha, &y_scalar, L_vec, R_vec, 739 | ); 740 | let verifier = ipp.fast_verify(&g_vec, &hi_tag, &g, &h, &P, &y_scalar); 741 | assert!(verifier.is_ok()) 742 | } 743 | 744 | fn test_helper_non_power_2(m: usize, n: usize, a: &[BigInt], b: &[BigInt]) { 745 | let KZen: &[u8] = &[75, 90, 101, 110]; 746 | let kzen_label = BigInt::from_bytes(KZen); 747 | 748 | let g_vec = (0..n) 749 | .map(|i| { 750 | let kzen_label_i = BigInt::from(i as u32) + &kzen_label; 751 | let hash_i = Sha512::new().chain_bigint(&kzen_label_i).result_bigint(); 752 | generate_random_point(&Converter::to_bytes(&hash_i)) 753 | }) 754 | .collect::>>(); 755 | 756 | // can run in parallel to g_vec: 757 | let h_vec = (0..n) 758 | .map(|i| { 759 | let kzen_label_j = BigInt::from(n as u32) + BigInt::from(i as u32) + &kzen_label; 760 | let hash_j = Sha512::new().chain_bigint(&kzen_label_j).result_bigint(); 761 | generate_random_point(&Converter::to_bytes(&hash_j)) 762 | }) 763 | .collect::>>(); 764 | 765 | // generate g, h 766 | let label = BigInt::from(2); 767 | let hash = Sha512::new().chain_bigint(&label).result_bigint(); 768 | let g = generate_random_point(&Converter::to_bytes(&hash)); 769 | let label = BigInt::from(3); 770 | let hash = Sha512::new().chain_bigint(&label).result_bigint(); 771 | let h = generate_random_point(&Converter::to_bytes(&hash)); 772 | 773 | let y_scalar: BigInt = Sha256::new() 774 | .chain(b"Seed string decided by P,V!") 775 | .result_bigint(); 776 | let c = super::weighted_inner_product(a, b, y_scalar.clone()); 777 | 778 | let alpha_fe = Scalar::::random(); 779 | let alpha = alpha_fe.to_bigint(); 780 | 781 | let y = Scalar::::random(); 782 | let order = Scalar::::group_order(); 783 | let yi = (0..n) 784 | .map(|i| BigInt::mod_pow(&y.to_bigint(), &BigInt::from(i as u32), order)) 785 | .collect::>(); 786 | 787 | let yi_inv = (0..n) 788 | .map(|i| { 789 | let yi_fe = Scalar::::from(&yi[i]); 790 | yi_fe.invert().unwrap() 791 | }) 792 | .collect::>>(); 793 | 794 | let hi_tag = (0..n) 795 | .map(|i| &h_vec[i] * &yi_inv[i]) 796 | .collect::>>(); 797 | 798 | // R = + + c * g + alpha*h 799 | let c_fe = Scalar::::from(&c); 800 | let g_c: Point = &g * &c_fe; 801 | let h_alpha: Point = &h * &alpha_fe; 802 | let gc_halpha = g_c + h_alpha; 803 | let a_G = (0..m) 804 | .map(|i| { 805 | let ai = Scalar::::from(&a[i]); 806 | &g_vec[i] * &ai 807 | }) 808 | .fold(gc_halpha, |acc, x: Point| { 809 | acc + x as Point 810 | }); 811 | let P = (0..m) 812 | .map(|i| { 813 | let bi = Scalar::::from(&b[i]); 814 | &hi_tag[i] * &bi 815 | }) 816 | .fold(a_G, |acc, x: Point| acc + x as Point); 817 | 818 | let L_vec = Vec::with_capacity(n); 819 | let R_vec = Vec::with_capacity(n); 820 | let ipp = WeightedInnerProdArg::prove( 821 | &g_vec, &hi_tag, &g, &h, &P, a, b, &alpha, &y_scalar, L_vec, R_vec, 822 | ); 823 | let verifier = ipp.verify(&g_vec, &hi_tag, &g, &h, &P, &y_scalar); 824 | assert!(verifier.is_ok()) 825 | } 826 | 827 | #[test] 828 | fn test_wip() { 829 | let a: Vec = vec![ 830 | BigInt::from(3), 831 | BigInt::from(2), 832 | BigInt::from(1), 833 | BigInt::from(0), 834 | ]; 835 | let b: Vec = vec![ 836 | BigInt::from(1), 837 | BigInt::from(2), 838 | BigInt::from(3), 839 | BigInt::from(4), 840 | ]; 841 | let y = BigInt::from(2); 842 | 843 | let y_powers = iterate(y.clone(), |i| i.clone() * y.clone()) 844 | .take(4) 845 | .collect::>(); 846 | 847 | let expect_y_powers = vec![ 848 | BigInt::from(2), 849 | BigInt::from(4), 850 | BigInt::from(8), 851 | BigInt::from(16), 852 | ]; 853 | assert_eq!(y_powers, expect_y_powers, "Scalar powers of y fails!"); 854 | 855 | let a_weighted_b = weighted_inner_product(&a, &b, y); 856 | assert_eq!( 857 | a_weighted_b, 858 | BigInt::from(46), 859 | "Weighted inner product fails!" 860 | ); 861 | } 862 | 863 | #[test] 864 | fn make_wip_32() { 865 | test_helper(32); 866 | } 867 | 868 | #[test] 869 | fn make_wip_16() { 870 | test_helper(16); 871 | } 872 | #[test] 873 | fn make_wip_8() { 874 | test_helper(8); 875 | } 876 | 877 | #[test] 878 | fn make_wip_4() { 879 | test_helper(4); 880 | } 881 | 882 | #[test] 883 | fn make_wip_2() { 884 | test_helper(2); 885 | } 886 | 887 | #[test] 888 | fn make_wip_1() { 889 | test_helper(1); 890 | } 891 | 892 | #[test] 893 | fn make_wip_32_fast_verify() { 894 | test_helper_fast_verify(32); 895 | } 896 | 897 | #[test] 898 | fn make_wip_16_fast_verify() { 899 | test_helper_fast_verify(16); 900 | } 901 | #[test] 902 | fn make_wip_8_fast_verify() { 903 | test_helper_fast_verify(8); 904 | } 905 | 906 | #[test] 907 | fn make_wip_4_fast_verify() { 908 | test_helper_fast_verify(4); 909 | } 910 | 911 | #[test] 912 | fn make_wip_2_fast_verify() { 913 | test_helper_fast_verify(2); 914 | } 915 | 916 | #[test] 917 | fn make_wip_1_fast_verify() { 918 | test_helper_fast_verify(1); 919 | } 920 | 921 | #[test] 922 | fn make_wip_non_power_2() { 923 | // Create random scalar vectors a, b with size non-power of 2 924 | let n: usize = 9; 925 | let mut a: Vec<_> = (0..n) 926 | .map(|_| { 927 | let rand = Scalar::::random(); 928 | rand.to_bigint() 929 | }) 930 | .collect(); 931 | 932 | let mut b: Vec<_> = (0..n) 933 | .map(|_| { 934 | let rand = Scalar::::random(); 935 | rand.to_bigint() 936 | }) 937 | .collect(); 938 | 939 | // next power of 2 940 | let _n: usize = n.next_power_of_two(); 941 | let zero_append_vec = vec![BigInt::zero(); _n - n]; 942 | 943 | // zero-appending at the end of a, b 944 | a.extend_from_slice(&zero_append_vec); 945 | b.extend_from_slice(&zero_append_vec); 946 | 947 | test_helper_non_power_2(n, _n, &a, &b); 948 | } 949 | } 950 | --------------------------------------------------------------------------------