[
  {
    "path": ".circleci/config.yml",
    "content": "version: 2\njobs:\n  build:\n    docker:\n      - image: circleci/golang:1.14\n\n    working_directory: /go/src/github.com/fentec-project/gofe\n\n    steps:\n      - checkout\n\n      - run:\n          name: Get dependencies\n          command: go get -t -v ./...\n\n      - run:\n          name: Run tests\n          command: go test -v ./..."
  },
  {
    "path": ".gitignore",
    "content": "# IDE files\n.idea\n.vscode\n\n# Vendor directory\nvendor/*/\n\n# Other\n*.swp\n*.swo\n.DS_Store\n\n# Binary\nfentec"
  },
  {
    "path": "AUTHORS.md",
    "content": "# Authors\nA list of code contributors to GoFE library for\nfunctional encryption.\n\n## Maintainer\nThe team from [XLAB d.o.o](https://www.xlab.si/)\n\n## Original authors\n*   Manca Bizjak <manca.bizjak@xlab.si>\n*   Jan Hartman <jan.hartman@xlab.si>\n*   Tilen Marc <tilen.marc@xlab.si>\n*   Miha Stopar <miha.stopar@xlab.si>\n"
  },
  {
    "path": "LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"{}\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright {yyyy} {name of copyright owner}\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License."
  },
  {
    "path": "README.md",
    "content": "# GoFE - Functional Encryption library\n[![Build Status](https://circleci.com/gh/fentec-project/gofe.svg?style=svg)](https://circleci.com/gh/fentec-project/gofe)\n[![GoDoc](https://godoc.org/github.com/fentec-project/gofe?status.svg)](https://godoc.org/github.com/fentec-project/gofe)\n[![Codacy Badge](https://app.codacy.com/project/badge/Grade/3ba91378a50b4446852200cc6391b4e2)](https://www.codacy.com/gh/fentec-project/gofe/dashboard?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=fentec-project/gofe&amp;utm_campaign=Badge_Grade)\n\n<p align=\"center\">\n        <img src=\"GoFE_logo.png\" width=\"160\" />\n</p>\n\nGoFE is a cryptographic library offering different state-of-the-art\nimplementations of functional encryption schemes, specifically FE\nschemes for _linear_ (e.g. _inner products_) and _quadratic polynomials_.\n\nTo quickly get familiar with FE, read a short and very high-level \nintroduction on our [Introductory Wiki page](../../wiki/Introduction-to-FE).\nA more detailed introduction with lots of interactive diagrams can be found on [this blog](https://alicebobstory.com/fe).\n\n<!-- toc -->\n- [Installing GoFE](#installing-gofe)\n- [Using GoFE in your project](#using-gofe-in-your-project)\n    * [Select the FE scheme](#select-the-fe-scheme)\n    * [Configure selected scheme](#configure-selected-scheme)\n    * [Prepare input data](#prepare-input-data)\n    * [Use the scheme (examples)](#use-the-scheme-(examples))\n- [Related work](#related-work)\n    * [Other implementations](#other-implementations)\n    * [Example projects](#example-projects)\n<!-- tocstop -->\n\n### Before using the library\nPlease note that the library is a work in progress and has not yet\nreached a stable release. Code organization and APIs are **not stable**.\nYou can expect them to change at any point.\n\nThe purpose of GoFE is to support research and proof-of-concept\nimplementations. It **should not be used in production**.\n\n## Installing GoFE\nFirst, download and build the library by running either\n`go install github.com/fentec-project/gofe/...` or\n `go get -u -t github.com/fentec-project/gofe/...` from the terminal (note that this also\n downloads and builds all the dependencies of the library).\n Please note that from Go version 1.18 on, `go get` will [no longer build packages](https://golang.org/doc/go-get-install-deprecation),\n and `go install` should be used instead.\n \nTo make sure the library works as expected, navigate to your `$GOPATH/pkg/mod/github.com/fentec-project/gofe` \ndirectory and run `go test -v ./...` . \nIf you are still using Go version below 1.16 or have `GO111MODULE=off` set, navigate to `$GOPATH/src/github.com/fentec-project/gofe` instead.\n\n## Using GoFE in your project\nAfter you have successfully built the library, you can use it in your project.\nInstructions below provide a brief introduction to the most important parts\nof the library, and guide you through a sequence of steps that will quickly\nget your FE example up and running.  \n\n### Select the FE scheme\nYou can choose from the following  set of schemes:\n\n#### Inner product schemes\nYou will need to import packages from `ìnnerprod` directory.\n\nWe organized implementations in two categories based on their security assumptions:\n\n* Schemes with **selective security under chosen-plaintext \nattacks** (s-IND-CPA security):\n    * Scheme by _Abdalla, Bourse, De Caro, Pointcheval_ ([paper](https://eprint.iacr.org/2015/017.pdf)). The scheme can be instantiated from DDH (`simple.DDH`), LWE (`simple.LWE`) primitives.\n    * Ring-LWE scheme based on _Bermudo Mera, Karmakar, Marc, and Soleimanian_ ([paper](https://eprint.iacr.org/2021/046)), see `simple.RingLWE`.\n    * Multi-input scheme based on paper by _Abdalla, Catalano, Fiore, Gay, Ursu_ ([paper](https://eprint.iacr.org/2017/972.pdf)) and instantiated from the scheme in the first point (`simple.DDHMulti`).\n\n* Schemes with stronger **adaptive security under chosen-plaintext attacks** (IND-CPA\nsecurity) or **simulation based security** (SIM-Security for IPE):\n    * Scheme based on paper by _Agrawal, Libert and Stehlé_ ([paper](https://eprint.iacr.org/2015/608.pdf)). It can be instantiated from Damgard DDH (`fullysec.Damgard` - similar to `simple.DDH`, but uses one more group element to achieve full security, similar to how Damgård's encryption scheme is obtained from ElGamal scheme ([paper](https://link.springer.com/chapter/10.1007/3-540-46766-1_36)), LWE (`fullysec.LWE`) and Paillier (`fullysec.Paillier`) primitives.\n    * Multi-input scheme based on paper by _Abdalla, Catalano, Fiore, Gay, Ursu_ ([paper](https://eprint.iacr.org/2017/972.pdf)) and instantiated from the scheme in the first point (`fullysec.DamgardMulti`).\n    * Decentralized scheme based on paper by _Chotard, Dufour Sans, Gay, Phan and Pointcheval_ ([paper](https://eprint.iacr.org/2017/989.pdf)). This scheme does not require a trusted party to generate keys. It is built on pairings (`fullysec.DMCFEClient`).\n    * Decentralized scheme based on paper by _Abdalla, Benhamouda, Kohlweiss, Waldner_  ([paper](https://eprint.iacr.org/2019/020.pdf)). Similarly as above this scheme this scheme does not require a trusted party to generate keys and is based on a general \nprocedure for decentralization of an inner product scheme, in particular the decentralization of a Damgard DDH scheme (`fullysec.DamgardDecMultiClient`).\n    * Function hiding multi-input scheme based on paper by _Datta, Okamoto, Tomida_ ([paper](https://eprint.iacr.org/2018/061.pdf)). This scheme allows clients to encrypt vectors and derive \nfunctional key that allows a decrytor to decrypt an inner product without revealing the ciphertext or the function (`fullysec.FHMultiIPE`).\n    * Function hiding inner product scheme by _Kim, Lewi, Mandal, Montgomery, Roy, Wu_ ([paper](https://eprint.iacr.org/2016/440.pdf)). The scheme allows the decryptor to\ndecrypt the inner product of x and y without reveling (ciphertext) x or (function) y (`fullysec.fhipe`).\n    * Partially function hiding inner product scheme by _Romain Gay_ ([paper](https://eprint.iacr.org/2020/093.pdf)). This scheme\n is a public key inner product scheme that decrypt the inner product of x and y without reveling (ciphertext) x or (function) y. This is\n achieved by limiting the space of vectors that can be encrypted with a public key (`fullysec.partFHIPE`).\n\n#### Quadratic polynomial schemes\nThere are two implemented FE schemes for **quadratic multi-variate polynomials**:\n* First is an efficient symmetric FE scheme by _Dufour Sans, Gay_ and _Pointcheval_ \n([paper](https://eprint.iacr.org/2018/206.pdf)) which is based on\nbilinear pairings, and offers adaptive security under chosen-plaintext\nattacks (IND-CPA security). You will need `SGP` scheme from package `quadratic`.\n* Second is an efficient pubic key FE by _Romain Gay_ ([paper](https://eprint.iacr.org/2020/093.pdf))\nthat is based on the underlying partially function hiding inner product scheme and offers semi-adaptive\nsimulation based security. You will need `quad` scheme from package `quadratic`.\n\n#### Schemes with the attribute based encryption (ABE)\nSchemes are organized under package `abe`.\n\nIt contains four ABE schemes:\n* A ciphertext policy (CP) ABE scheme named FAME by _Agrawal, Chase_ ([paper](https://eprint.iacr.org/2017/807.pdf)) allowing encrypting a\nmessage based on a boolean expression defining a policy which attributes are needed for the decryption. It is implemented in `abe.fame`.\n* A key policy (KP) ABE scheme by _Goyal, Pandey, Sahai, Waters_ ([paper](https://eprint.iacr.org/2006/309.pdf)) allowing a distribution of\nkeys following a boolean expression defining a policy which attributes are needed for the decryption. It is implemented in `abe.gpsw`.\n* A decentralized inner product predicate scheme by _Michalevsky, Joye_ ([paper](https://eprint.iacr.org/2018/753.pdf)) allowing encryption\nwith policy described as a vector, and a decentralized distribution of keys based on users' vectors so that\nonly users with  vectors orthogonal to the encryption vector posses a key that can decrypt the ciphertext. It is implemented in `abe.dippe`.\n* A multi-authority (MA) ciphertext policy (CP) ABE scheme by _Lewko, Waters_ ([paper](https://eprint.iacr.org/2010/351.pdf)) based on a boolean expression defining a policy which attributes are needed for decryption. This scheme is decentralized - the attributes can be spread across multiple different authorites. It is implemented in `abe.ma-abe`.\n\n### Configure selected scheme\nAll GoFE schemes are implemented as Go structs with (at least logically)\nsimilar APIs. So the first thing we need to do is to create a scheme instance\nby instantiating the appropriate struct. For this step, we need to pass in \nsome configuration, e.g. values of parameters for the selected scheme.\n\nLet's say we selected a `simple.DDH` scheme. We create a new scheme instance with:\n````go\nscheme, _ := simple.NewDDH(5, 1024, big.NewInt(1000))\n````\n\nIn the line above, the first argument is length of input vectors **x**\nand **y**, the second argument is bit length of prime modulus _p_\n(because this particular scheme operates in the &#8484;<sub>p</sub> group), and\nthe last argument represents the upper bound for elements of input vectors.\n\nHowever, configuration parameters for different FE schemes vary quite a bit.\nPlease refer to [library documentation](https://godoc.org/github.com/fentec-project/gofe) regarding the meaning of parameters for\n specific schemes. For now, examples and reasonable defaults can be found in \n the test code. \n \nAfter you successfully created a FE scheme instance, you can call its\n methods for:\n* generation of (secret and public) master keys,\n* derivation of functional encryption key,\n* encryption, and\n* decryption. \n\n### Prepare input data\n#### Vectors and matrices\nAll GoFE chemes rely on vectors (or matrices) of big integer (`*big.Int`) \ncomponents. \n\nGoFE schemes use the library's own `Vector` and `Matrix` types. They are implemented\n in the `data` package. A `Vector` is basically a wrapper around `[]*big.Int`\nslice, while a `Matrix` wraps a slice of `Vector`s.\n\nIn general, you only have to worry about providing input data (usually\nvectors **x** and **y**). If you already have your slice of `*big.Int`s \ndefined, you can create a `Vector` by calling\n`data.NewVector` function with your slice as argument, for example:\n````go\n// Let's say you already have your data defined in a slice of *big.Ints\nx := []*big.Int{big.NewInt(0), big.NewInt(1), big.NewInt(2)}\nxVec := data.NewVector(x)\n````\n\nSimilarly, for matrices, you will first have to construct your slice of \n`Vector`s, and pass it to `data.NewMatrix` function: \n````go\nvecs := make([]data.Vector, 3) // a slice of 3 vectors\n// fill vecs\nvecs[0] := []*big.Int{big.NewInt(0), big.NewInt(1), big.NewInt(2)}\nvecs[1] := []*big.Int{big.NewInt(2), big.NewInt(1), big.NewInt(0)}\nvecs[2] := []*big.Int{big.NewInt(1), big.NewInt(1), big.NewInt(1)}\nxMat := data.NewMatrix(vecs)\n````\n\n#### Random data\nTo generate random `*big.Int` values from different probability distributions,\nyou can use one of our several implementations of random samplers. The samplers\nare provided in the `sample` package and all implement `sample.Sampler`\n interface.\n \nYou can quickly construct random vectors and matrices by:\n1. Configuring the sampler of your choice, for example:\n    ````go\n    s := sample.NewUniform(big.NewInt(100)) // will sample uniformly from [0,100)\n    ````\n2. Providing it as an argument to`data.NewRandomVector` or `data.NewRandomMatrix` functions. \n    ````go\n    x, _ := data.NewRandomVector(5, s) // creates a random vector with 5 elements\n    X, _ := data.NewRandomMatrix(2, 3, s) // creates a random 2x3 matrix\n    ````\n    \n## Use the scheme\nTo see how the schemes can be used consult one of the following.\n\n#### Tests\nEvery implemented scheme has an implemented test to verify the correctness\nof the implementation (for example Paillier inner-product scheme implemented in\n`innerprod/fullysec/paillier.go` has a corresponding test in \n`innerprod/fullysec/paillier_test.go`). One can check the appropriate test\nfile to see an example of how the chosen scheme can be used.\n\n#### Examples\nWe give some concrete examples how to use the schemes. \nPlease note that all the examples below omit error management.\n\n##### Using a single input scheme\nThe example below demonstrates how to use single input scheme instances.\nAlthough the example shows how to use the`DDH` from package \n`simple`, the usage is similar for all single input schemes, regardless\nof their security properties (s-IND-CPA or IND-CPA) and instantiation\n (DDH or LWE).\n \nYou will see that three `DDH` structs are instantiated to simulate the\n real-world scenarios where each of the three entities involved in FE\n are on separate machines.\n \n```go\n// Instantiation of a trusted entity that\n// will generate master keys and FE key\nl := 2 // length of input vectors\nbound := big.NewInt(10) // upper bound for input vector coordinates\nmodulusLength := 2048 // bit length of prime modulus p \ntrustedEnt, _ := simple.NewDDHPrecomp(l, modulusLength, bound)\nmsk, mpk, _ := trustedEnt.GenerateMasterKeys()\n\ny := data.NewVector([]*big.Int{big.NewInt(1), big.NewInt(2)})\nfeKey, _ := trustedEnt.DeriveKey(msk, y)\n\n// Simulate instantiation of encryptor \n// Encryptor wants to hide x and should be given\n// master public key by the trusted entity\nenc := simple.NewDDHFromParams(trustedEnt.Params)\nx := data.NewVector([]*big.Int{big.NewInt(3), big.NewInt(4)})\ncipher, _ := enc.Encrypt(x, mpk)\n\n// Simulate instantiation of decryptor that decrypts the cipher \n// generated by encryptor.\ndec := simple.NewDDHFromParams(trustedEnt.Params)\n// decrypt to obtain the result: inner prod of x and y\n// we expect xy to be 11 (e.g. <[1,2],[3,4]>)\nxy, _ := dec.Decrypt(cipher, feKey, y)\n```\n\n##### Using a multi input scheme\nThis example demonstrates how multi input FE schemes can be used.\n \n Here we assume\n that there are `numClients` encryptors (e<sub>i</sub>), each with their corresponding\n input vector x<sub>i</sub>. A trusted entity generates all the master keys needed\n for encryption and distributes appropriate keys to appropriate encryptor. Then, \n encryptor e<sub>i</sub> uses their keys to encrypt their data x<sub>i</sub>.\n The decryptor collects ciphers from all the encryptors. It then relies on the trusted\n  entity to derive a decryption key based on its own set of vectors y<sub>i</sub>. With the\n  derived key, the decryptor is able to compute the result - inner product\nover all vectors, as _Σ <x<sub>i</sub>,y<sub>i</sub>>._\n\n```go\nnumClients := 2           // number of encryptors\nl := 3                    // length of input vectors\nbound := big.NewInt(1000) // upper bound for input vectors\n\n// Simulate collection of input data.\n// X and Y represent matrices of input vectors, where X are collected\n// from numClients encryptors (omitted), and Y is only known by a single decryptor.\n// Encryptor i only knows its own input vector X[i].\nsampler := sample.NewUniform(bound)\nX, _ := data.NewRandomMatrix(numClients, l, sampler)\nY, _ := data.NewRandomMatrix(numClients, l, sampler)\n\n// Trusted entity instantiates scheme instance and generates\n// master keys for all the encryptors. It also derives the FE\n// key derivedKey for the decryptor.\nmodulusLength := 2048\nmultiDDH, _ := simple.NewDDHMultiPrecomp(numClients, l, modulusLength, bound)\npubKey, secKey, _ := multiDDH.GenerateMasterKeys()\nderivedKey, _ := multiDDH.DeriveKey(secKey, Y)\n\n// Different encryptors may reside on different machines.\n// We simulate this with the for loop below, where numClients\n// encryptors are generated.\nencryptors := make([]*simple.DDHMultiClient, numClients)\nfor i := 0; i < numClients; i++ {\n    encryptors[i] = simple.NewDDHMultiClient(multiDDH.Params)\n}\n// Each encryptor encrypts its own input vector X[i] with the\n// keys given to it by the trusted entity.\nciphers := make([]data.Vector, numClients)\nfor i := 0; i < numClients; i++ {\n    cipher, _ := encryptors[i].Encrypt(X[i], pubKey[i], secKey.OtpKey[i])\n    ciphers[i] = cipher\n}\n\n// Ciphers are collected by decryptor, who then computes\n// inner product over vectors from all encryptors.\ndecryptor := simple.NewDDHMultiFromParams(numClients, multiDDH.Params)\nprod, _ = decryptor.Decrypt(ciphers, derivedKey, Y)\n```\nNote that above we instantiate multiple encryptors - in reality,\n different encryptors will be instantiated on different machines. \n \n\n##### Using quadratic polynomial scheme\nIn the example below, we omit instantiation of different entities\n(encryptor and decryptor).\n```go\nl := 2 // length of input vectors\nbound := big.NewInt(10) // Upper bound for coordinates of vectors x, y, and matrix F\n\n// Here we fill our vectors and the matrix F (that represents the\n// quadratic function) with random data from [0, bound).\nsampler := sample.NewUniform(bound)\nF, _ := data.NewRandomMatrix(l, l, sampler)\nx, _ := data.NewRandomVector(l, sampler)\ny, _ := data.NewRandomVector(l, sampler)\n\nsgp := quadratic.NewSGP(l, bound)     // Create scheme instance\nmsk, _ := sgp.GenerateMasterKey()     // Create master secret key\ncipher, _ := sgp.Encrypt(x, y, msk)   // Encrypt input vectors x, y with secret key\nkey, _ := sgp.DeriveKey(msk, F)       // Derive FE key for decryption\ndec, _ := sgp.Decrypt(cipher, key, F) // Decrypt the result to obtain x^T * F * y\n```\n\n##### Using ABE schemes\nLet's say we selected `abe.FAME` scheme. In the example below, we omit instantiation of different entities\n(encryptor and decryptor). Say we want to encrypt the following message `msg` so that only those\nwho own the attributes satisfying a boolean expression 'policy' can decrypt.\n```go\nmsg := \"Attack at dawn!\"\npolicy := \"((0 AND 1) OR (2 AND 3)) AND 5\"\n\ngamma := []string{\"0\", \"2\", \"3\", \"5\"} // owned attributes\n\na := abe.NewFAME() // Create the scheme instance\npubKey, secKey, _ := a.GenerateMasterKeys() // Create a public key and a master secret key\nmsp, _ := abe.BooleanToMSP(policy, false) // The MSP structure defining the policy\ncipher, _ := a.Encrypt(msg, msp, pubKey) // Encrypt msg with policy msp under public key pubKey\nkeys, _ := a.GenerateAttribKeys(gamma, secKey) // Generate keys for the entity with attributes gamma\ndec, _ := a.Decrypt(cipher, keys, pubKey) // Decrypt the message\n```\n\n## Related work\n\n### Other implementations\n\nApart from the GoFE library, there is also a C library called CiFEr that\nimplements many of the same schemes as GoFE, and can be found\n[here](https://github.com/fentec-project/CiFEr).\n\n### Example projects\n\nA few reference uses of the GoFE library are provided:\n* [creating a privacy preserving heatmap](https://github.com/fentec-project/FE-anonymous-heatmap),\n* [evaluating a machine learning function on encrypted data](https://github.com/fentec-project/neural-network-on-encrypted-data),\n* [privacy friendly data analysis on encrypted data](https://github.com/fentec-project/privacy-friendly-analyses).\n"
  },
  {
    "path": "abe/dippe.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage abe\n\nimport (\n\t\"crypto/aes\"\n\tcbc \"crypto/cipher\"\n\t\"crypto/rand\"\n\t\"crypto/sha256\"\n\t\"fmt\"\n\t\"math/big\"\n\t\"strconv\"\n\n\t\"io\"\n\n\t\"github.com/fentec-project/bn256\"\n\t\"github.com/fentec-project/gofe/data\"\n\t\"github.com/fentec-project/gofe/sample\"\n)\n\n// DIPPE represents a Decentralized Inner-Product Predicate Encryption\n// (DIPPE) scheme introduced by Y. Michalevsky and M. Joye in:\n// \"Decentralized Policy-Hiding Attribute-Based Encryption with Receiver Privacy\"\n// https://eprint.iacr.org/2018/753.pdf\ntype DIPPE struct {\n\tsecLevel int\n\tG1ToA    data.MatrixG1\n\tG1ToUA   data.MatrixG1\n\tP        *big.Int // order of the elliptic curve\n}\n\n// DIPPEPubKey represents a public key of an authority in DIPPE scheme.\ntype DIPPEPubKey struct {\n\tG1ToWtA   data.MatrixG1\n\tGToAlphaA data.VectorGT\n\tG2ToSigma *bn256.G2\n}\n\n// DIPPESecKey represents a secret key of an authority in DIPPE scheme.\ntype DIPPESecKey struct {\n\tSigma *big.Int\n\tW     data.Matrix\n\tAlpha data.Vector\n}\n\n// DIPPEAuth represents an authority in DIPPE scheme\ntype DIPPEAuth struct {\n\tID int\n\tSk DIPPESecKey\n\tPk DIPPEPubKey\n}\n\n// DIPPECipher represents a ciphertext in DIPPE scheme\ntype DIPPECipher struct {\n\tC0     data.VectorG1\n\tC      data.MatrixG1\n\tCPrime *bn256.GT\n\tX      data.Vector // policy vector\n\tSymEnc []byte      // symmetric encryption of the message\n\tIv     []byte      // initialization vector for symmetric encryption\n}\n\n// NewDIPPE configures a new instance of the scheme. The input parameter\n// defines the security assumption of the scheme, so called k-Lin assumption,\n// where k is the input.\nfunc NewDIPPE(secLevel int) (*DIPPE, error) {\n\tsampler := sample.NewUniform(bn256.Order)\n\n\tA, err := data.NewRandomMatrix(secLevel+1, secLevel, sampler)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tg1ToA := A.MulG1()\n\n\tU, err := data.NewRandomMatrix(secLevel+1, secLevel+1, sampler)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tUA, err := U.Mul(A)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tUA.Mod(bn256.Order)\n\tg1ToUA := UA.MulG1()\n\n\treturn &DIPPE{secLevel: secLevel,\n\t\tG1ToA:  g1ToA,\n\t\tG1ToUA: g1ToUA,\n\t\tP:      bn256.Order}, nil\n}\n\n// NewDIPPEAuth configures a new authority that will be able to\n// produce decryption keys. If the scheme will have n authorities\n// it is assumed that each will have a different id from [0, n).\nfunc (d *DIPPE) NewDIPPEAuth(id int) (*DIPPEAuth, error) {\n\tsampler := sample.NewUniform(bn256.Order)\n\n\tW, err := data.NewRandomMatrix(d.secLevel+1, d.secLevel+1, sampler)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\talpha, err := data.NewRandomVector(d.secLevel+1, sampler)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tsigma, err := sampler.Sample()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tsk := DIPPESecKey{W: W, Alpha: alpha, Sigma: sigma}\n\n\tg1ToWtA, err := W.Transpose().MatMulMatG1(d.G1ToA)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\talphaAsMatrix := data.Matrix([]data.Vector{alpha})\n\tg1ToAlphaA, err := alphaAsMatrix.MatMulMatG1(d.G1ToA)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tg2 := new(bn256.G2).ScalarBaseMult(big.NewInt(1))\n\tgtToAlphaA := make(data.VectorGT, d.secLevel)\n\tfor i := 0; i < d.secLevel; i++ {\n\t\tgtToAlphaA[i] = bn256.Pair(g1ToAlphaA[0][i], g2)\n\t}\n\n\tg2ToSigma := new(bn256.G2).ScalarMult(g2, sigma)\n\n\tpk := DIPPEPubKey{G1ToWtA: g1ToWtA, GToAlphaA: gtToAlphaA, G2ToSigma: g2ToSigma}\n\n\treturn &DIPPEAuth{ID: id, Sk: sk, Pk: pk}, nil\n}\n\n// Encrypt takes as an input a string message msg, a vector x representing a\n// decryption policy and a slice of public keys of the participating authorities.\n// The i-th coordinate of x corresponds to i-th public key of the authority with\n// id i. It returns an encryption of msg. In case of a failed procedure an\n// error is returned.\nfunc (d *DIPPE) Encrypt(msg string, x data.Vector, pubKeys []*DIPPEPubKey) (*DIPPECipher, error) {\n\t// msg is encrypted using CBC, with a random key that is encapsulated\n\t// with DIPPE\n\t_, keyGt, err := bn256.RandomGT(rand.Reader)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tkeyCBC := sha256.Sum256([]byte(keyGt.String()))\n\n\ta, err := aes.NewCipher(keyCBC[:])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tiv := make([]byte, a.BlockSize())\n\t_, err = io.ReadFull(rand.Reader, iv)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tencrypterCBC := cbc.NewCBCEncrypter(a, iv)\n\n\tmsgByte := []byte(msg)\n\t// message is padded according to pkcs7 standard\n\tpadLen := a.BlockSize() - (len(msgByte) % a.BlockSize())\n\tmsgPad := make([]byte, len(msgByte)+padLen)\n\tcopy(msgPad, msgByte)\n\tfor i := len(msgByte); i < len(msgPad); i++ {\n\t\tmsgPad[i] = byte(padLen)\n\t}\n\n\tsymEnc := make([]byte, len(msgPad))\n\tencrypterCBC.CryptBlocks(symEnc, msgPad)\n\n\t// encapsulate the key with DIPPE\n\tsampler := sample.NewUniform(bn256.Order)\n\ts, err := data.NewRandomVector(d.secLevel, sampler)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tc0 := d.G1ToA.MulVector(s)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tc := make(data.MatrixG1, len(x))\n\tfor i := range x {\n\t\tg1ToXiUA := d.G1ToUA.MulScalar(x[i])\n\t\tg1ToXiUplusWtiA := g1ToXiUA.Add(pubKeys[i].G1ToWtA)\n\t\tc[i] = g1ToXiUplusWtiA.MulVector(s)\n\t}\n\n\tcPrime := new(bn256.GT).ScalarBaseMult(big.NewInt(0))\n\tfor _, e := range pubKeys {\n\t\ttmp := e.GToAlphaA.Dot(s)\n\t\tcPrime.Add(tmp, cPrime)\n\t}\n\tcPrime.Add(keyGt, cPrime)\n\n\treturn &DIPPECipher{C0: c0, C: c, CPrime: cPrime, X: x.Copy(), SymEnc: symEnc, Iv: iv}, nil\n}\n\n// DeriveKeyShare allows an authority to give a partial decryption key. Collecting all\n// such partial keys allows a user to decrypt the message. The input vector v contains\n// an information about the user that will allow him to decrypt iff the inner product\n// v times x = 0 for the policy x. GID is a global identifier of the user and a slice of\n// public keys of the authorities should be given.\nfunc (a *DIPPEAuth) DeriveKeyShare(v data.Vector, pubKeys []*DIPPEPubKey, gid string) (data.VectorG2, error) {\n\tg2ToMu := make(data.VectorG2, a.Sk.W.Rows())\n\tfor i := 0; i < a.Sk.W.Rows(); i++ {\n\t\tg2ToMu[i] = new(bn256.G2).ScalarBaseMult(big.NewInt(0))\n\t}\n\n\tg2ToAlpha := a.Sk.Alpha.MulG2()\n\n\tvar err error\n\tfor j := 0; j < len(pubKeys); j++ {\n\t\tif j == a.ID {\n\t\t\tcontinue\n\t\t}\n\n\t\tyToSigma := new(bn256.G2).ScalarMult(pubKeys[j].G2ToSigma, a.Sk.Sigma)\n\t\tfor i := 0; i < a.Sk.W.Rows(); i++ {\n\t\t\thashed, err := bn256.HashG2(strconv.Itoa(i) + yToSigma.String() + gid + v.String())\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\tif j > a.ID {\n\t\t\t\thashed.Neg(hashed)\n\t\t\t}\n\t\t\tg2ToMu[i] = g2ToMu[i].Add(hashed, g2ToMu[i])\n\t\t}\n\t}\n\n\tg2ToH := make(data.VectorG2, a.Sk.W.Rows())\n\tfor j := range g2ToH {\n\t\tg2ToH[j], err = bn256.HashG2(strconv.Itoa(j) + gid + v.String())\n\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\tg2ToWH, err := a.Sk.W.MatMulVecG2(g2ToH)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tg2ToViWH := g2ToWH.MulScalar(v[a.ID]).Neg()\n\n\treturn g2ToAlpha.Add(g2ToViWH).Add(g2ToMu), nil\n}\n\n// Decrypt accepts the ciphertext, a slice of keys obtained from the authorities,\n// a vector v representing the users decryption allowance, and a global identifier.\n// If the provided keys are correct and the inner product v times x = 0 for the policy\n// x, the message is decrypted, otherwise an error is returned.\nfunc (d *DIPPE) Decrypt(cipher *DIPPECipher, keys []data.VectorG2, v data.Vector, gid string) (string, error) {\n\t// check if the decryption is possible\n\tprod, err := v.Dot(cipher.X)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tif prod.Sign() != 0 {\n\t\treturn \"\", fmt.Errorf(\"insufficient keys\")\n\t}\n\n\t// use DIPPE decryption procedure to get a CBC key\n\t// needed for the decryption of the message\n\tgTToAlphaAS := new(bn256.GT).ScalarBaseMult(big.NewInt(0))\n\n\tones := data.NewConstantMatrix(1, len(keys), big.NewInt(1))\n\tsum, err := ones.MatMulMatG2(data.MatrixG2(keys))\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tfor i, e := range cipher.C0 {\n\t\ttmpGT := bn256.Pair(e, sum[0][i])\n\t\tgTToAlphaAS.Add(gTToAlphaAS, tmpGT)\n\t}\n\n\tvMat := make(data.Matrix, 1)\n\tvMat[0] = v\n\tcSum, err := vMat.MatMulMatG1(cipher.C)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tfor j := range cSum[0] {\n\t\thashed, err := bn256.HashG2(strconv.Itoa(j) + gid + v.String())\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\n\t\ttmpGT := bn256.Pair(cSum[0][j], hashed)\n\t\tgTToAlphaAS.Add(gTToAlphaAS, tmpGT)\n\t}\n\tgTToAlphaAS.Neg(gTToAlphaAS)\n\n\tkeyGt := new(bn256.GT).Add(cipher.CPrime, gTToAlphaAS)\n\n\tkeyCBC := sha256.Sum256([]byte(keyGt.String()))\n\n\ta, err := aes.NewCipher(keyCBC[:])\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tmsgPad := make([]byte, len(cipher.SymEnc))\n\tdecrypter := cbc.NewCBCDecrypter(a, cipher.Iv)\n\tdecrypter.CryptBlocks(msgPad, cipher.SymEnc)\n\n\t// unpad the message\n\tpadLen := int(msgPad[len(msgPad)-1])\n\tif (len(msgPad) - padLen) < 0 {\n\t\treturn \"\", fmt.Errorf(\"failed to decrypt\")\n\t}\n\tmsgByte := msgPad[0:(len(msgPad) - padLen)]\n\n\treturn string(msgByte), nil\n}\n\n// ExactThresholdPolicyVecInit is used for the transformation of the DIPPE\n// scheme into an ABE scheme with an exact threshold. In particular given a\n// slice of attributes, a threshold value and the number of all possible\n// attributes it creates a policy vector that can be used for the DIPPE encryption.\n// The user will be able to decrypt only if he posses exactly the threshold\n// value of the attributes.\nfunc (d DIPPE) ExactThresholdPolicyVecInit(attrib []int, threshold int, numAttrib int) (data.Vector, error) {\n\tpolicyVec := data.NewConstantVector(numAttrib+1, big.NewInt(0))\n\tone := big.NewInt(1)\n\tfor _, e := range attrib {\n\t\tif e > numAttrib {\n\t\t\treturn nil, fmt.Errorf(\"attributes out of range\")\n\t\t}\n\t\tpolicyVec[e].Set(one)\n\t}\n\tpolicyVec[numAttrib].Set(big.NewInt(int64(-threshold)))\n\n\treturn policyVec, nil\n}\n\n// ConjunctionPolicyVecInit is used for the transformation of the DIPPE\n// scheme into an ABE scheme with conjugation policy. In particular given a\n// slice of attributes and the number of all possible attributes it creates\n// a policy vector that can be used for the DIPPE encryption. The user will\n// be able to decrypt only if he posses all the demanded attributes.\nfunc (d DIPPE) ConjunctionPolicyVecInit(attrib []int, numAttrib int) (data.Vector, error) {\n\tpolicyVec := data.NewConstantVector(numAttrib+1, big.NewInt(0))\n\tsampler := sample.NewUniform(bn256.Order)\n\tlast := big.NewInt(0)\n\tfor _, e := range attrib {\n\t\tif e > numAttrib {\n\t\t\treturn nil, fmt.Errorf(\"attributes out of range\")\n\t\t}\n\t\ttmp, err := sampler.Sample()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tpolicyVec[e].Set(tmp)\n\t\tlast.Sub(last, tmp)\n\t}\n\tpolicyVec[numAttrib].Set(last)\n\n\treturn policyVec, nil\n}\n\n// AttributeVecInit given the attributes and the number of all possible\n// attributes creates a vector describing the users allowance. The function is\n// needed in the the transformation of the DIPPE scheme into an ABE scheme\n// with threshold or conjugation.\nfunc (d DIPPE) AttributeVecInit(attrib []int, numAttrib int) (data.Vector, error) {\n\tattribVec := data.NewConstantVector(numAttrib+1, big.NewInt(0))\n\tone := big.NewInt(1)\n\tfor _, e := range attrib {\n\t\tif e > numAttrib {\n\t\t\treturn nil, fmt.Errorf(\"attributes out of range\")\n\t\t}\n\t\tattribVec[e].Set(one)\n\t}\n\tattribVec[numAttrib].Set(one)\n\n\treturn attribVec, nil\n}\n"
  },
  {
    "path": "abe/dippe_test.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage abe_test\n\nimport (\n\t\"testing\"\n\n\t\"math/big\"\n\n\t\"github.com/fentec-project/gofe/abe\"\n\t\"github.com/fentec-project/gofe/data\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestDIPPE(t *testing.T) {\n\t// create a new DIPPE struct, choosing the security parameter\n\td, err := abe.NewDIPPE(3)\n\tif err != nil {\n\t\tt.Fatalf(\"Failed to generate a new scheme: %v\", err)\n\t}\n\tvecLen := 5\n\n\t// create authorities and their public keys\n\tauth := make([]*abe.DIPPEAuth, vecLen)\n\tpubKeys := make([]*abe.DIPPEPubKey, vecLen)\n\tfor i := range auth {\n\t\tauth[i], err = d.NewDIPPEAuth(i)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"Failed to generate a new authority: %v\", err)\n\t\t}\n\t\tpubKeys[i] = &auth[i].Pk\n\t}\n\n\tmsg := \"some message\"\n\n\t// choose a policy vector\n\tpolicyVec := data.Vector([]*big.Int{big.NewInt(1), big.NewInt(-1),\n\t\tbig.NewInt(1), big.NewInt(0), big.NewInt(0)})\n\n\t// encrypt the message with the chosen policy give by a policy vector,\n\tcipher, err := d.Encrypt(msg, policyVec, pubKeys)\n\tif err != nil {\n\t\tt.Fatalf(\"Failed to encrypt: %v\", err)\n\t}\n\n\t// choose a unique user's GID\n\tuserGID := \"someGID\"\n\t// choose user's vector, decryption is possible if and only if\n\t// the users's and policy vector are orthogonal\n\tuserVec := data.Vector([]*big.Int{big.NewInt(0), big.NewInt(1),\n\t\tbig.NewInt(1), big.NewInt(-3), big.NewInt(4)})\n\n\t// authorities generate decryption keys for the user\n\tuserKeys := make([]data.VectorG2, vecLen)\n\tfor i := range auth {\n\t\tuserKeys[i], err = auth[i].DeriveKeyShare(userVec, pubKeys, userGID)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"Failed to generate a user key: %v\", err)\n\t\t}\n\t}\n\n\t// user decrypts using collected keys\n\tdec, err := d.Decrypt(cipher, userKeys, userVec, userGID)\n\tif err != nil {\n\t\tt.Fatalf(\"Failed to decrypt: %v\", err)\n\t}\n\tassert.Equal(t, msg, dec)\n}\n\nfunc TestDIPPE_ABE_threshold(t *testing.T) {\n\t// this test transforms DIPPE scheme into an ABE scheme\n\t// with the exact threshold policy; in threshold policy each user has\n\t// attributes but only the users that have exactly the\n\t// threshold value of specified attributes can decrypt\n\n\t// create a new DIPPE struct, choosing the security parameter\n\td, err := abe.NewDIPPE(3)\n\tif err != nil {\n\t\tt.Fatalf(\"Failed to generate a new scheme: %v\", err)\n\t}\n\t// specify the number of all attributes\n\tnumAttrib := 10\n\n\t// create authorities and their public keys\n\tauth := make([]*abe.DIPPEAuth, numAttrib+1)\n\tpubKeys := make([]*abe.DIPPEPubKey, numAttrib+1)\n\tfor i := range auth {\n\t\tauth[i], err = d.NewDIPPEAuth(i)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"Failed to generate a new authority: %v\", err)\n\t\t}\n\t\tpubKeys[i] = &auth[i].Pk\n\t}\n\n\tmsg := \"some important message\"\n\n\t// choose attributes needed for the exact threshold policy and the\n\t// threshold value\n\tthresholdAttrib := []int{0, 2, 5, 8, 9}\n\texactThreshold := 3\n\t// generate the exact threshold vector (this conversion allows the\n\t// DIPPE scheme to be used as an ABE threshold scheme)\n\tthresholdPolicyVec, err := d.ExactThresholdPolicyVecInit(thresholdAttrib, exactThreshold, numAttrib)\n\tif err != nil {\n\t\tt.Fatalf(\"Failed to generate threshold vector: %v\", err)\n\t}\n\n\t// encrypt the message with the chosen threshold policy\n\tthresholdCipher, err := d.Encrypt(msg, thresholdPolicyVec, pubKeys)\n\tif err != nil {\n\t\tt.Fatalf(\"Failed to encrypt: %v\", err)\n\t}\n\n\t// choose a unique user's GID\n\tthresholdUserGID := \"thresholdGID\"\n\n\t// choose the attributes possessed by the users\n\tthresholdUserAttrib := []int{0, 1, 5, 7, 9}\n\n\t// generate user's vector\n\tthresholdUserVec, err := d.AttributeVecInit(thresholdUserAttrib, numAttrib)\n\tif err != nil {\n\t\tt.Fatalf(\"Failed to generate attributes vector: %v\", err)\n\t}\n\n\t// authorities generate decryption keys for the user\n\tthresholdUserKeys := make([]data.VectorG2, len(auth))\n\tfor i := range auth {\n\t\tthresholdUserKeys[i], err = auth[i].DeriveKeyShare(thresholdUserVec, pubKeys, thresholdUserGID)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"Failed to generate a user key: %v\", err)\n\t\t}\n\t}\n\n\t// user decrypts using collected keys\n\tdec, err := d.Decrypt(thresholdCipher, thresholdUserKeys, thresholdUserVec, thresholdUserGID)\n\tif err != nil {\n\t\tt.Fatalf(\"Failed to decrypt: %v\", err)\n\t}\n\tassert.Equal(t, msg, dec)\n}\n\nfunc TestDIPPE_ABE_conjugation(t *testing.T) {\n\t// this test transforms DIPPE scheme into an ABE scheme\n\t// with the conjugation policy; in the conjugation policy\n\t// the user must have all the specified attributes to be\n\t// able to decrypt\n\n\t// create a new DIPPE struct, choosing the security parameter\n\td, err := abe.NewDIPPE(3)\n\tif err != nil {\n\t\tt.Fatalf(\"Failed to generate a new scheme: %v\", err)\n\t}\n\t// specify the number of all attributes\n\tnumAttrib := 10\n\n\t// create authorities and their public keys\n\tauth := make([]*abe.DIPPEAuth, numAttrib+1)\n\tpubKeys := make([]*abe.DIPPEPubKey, numAttrib+1)\n\tfor i := range auth {\n\t\tauth[i], err = d.NewDIPPEAuth(i)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"Failed to generate a new authority: %v\", err)\n\t\t}\n\t\tpubKeys[i] = &auth[i].Pk\n\t}\n\n\tmsg := \"some important message\"\n\n\t// choose attributes needed for the conjunction policy\n\tconjunctAttrib := []int{1, 2, 3, 7}\n\t// generate the conjunction vector (this conversion allows the\n\t// DIPPE scheme to be used as an ABE conjunction scheme)\n\tconjunctPolicyVec, err := d.ConjunctionPolicyVecInit(conjunctAttrib, numAttrib)\n\tif err != nil {\n\t\tt.Fatalf(\"Failed to generate conjucnction vector: %v\", err)\n\t}\n\n\t// encrypt the message with the chosen conjunction policy\n\tconjunctCipher, err := d.Encrypt(msg, conjunctPolicyVec, pubKeys)\n\tif err != nil {\n\t\tt.Fatalf(\"Failed to encrypt: %v\", err)\n\t}\n\n\t// choose a unique user's GID\n\tconjunctUserGID := \"conjunctionGID\"\n\n\t// choose the attributes possessed by the user\n\tconjunctUserAttrib := []int{0, 1, 2, 3, 7, 9}\n\n\t// generate user's vector\n\tconjunctUserVec, err := d.AttributeVecInit(conjunctUserAttrib, numAttrib)\n\tif err != nil {\n\t\tt.Fatalf(\"Failed to generate attributes vector: %v\", err)\n\t}\n\n\t// authorities generate decryption keys for the user\n\tconjunctUserKeys := make([]data.VectorG2, len(auth))\n\tfor i := range auth {\n\t\tconjunctUserKeys[i], err = auth[i].DeriveKeyShare(conjunctUserVec, pubKeys, conjunctUserGID)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"Failed to generate a user key: %v\", err)\n\t\t}\n\t}\n\n\t// user decrypts using collected keys\n\tdec, err := d.Decrypt(conjunctCipher, conjunctUserKeys, conjunctUserVec, conjunctUserGID)\n\tif err != nil {\n\t\tt.Fatalf(\"Failed to decrypt: %v\", err)\n\t}\n\tassert.Equal(t, msg, dec)\n}\n"
  },
  {
    "path": "abe/doc.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// Package abe includes schemes allowing attribute based encryption.\npackage abe\n"
  },
  {
    "path": "abe/fame.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage abe\n\nimport (\n\t\"math/big\"\n\n\t\"fmt\"\n\t\"strconv\"\n\n\t\"crypto/aes\"\n\tcbc \"crypto/cipher\"\n\t\"crypto/rand\"\n\t\"crypto/sha256\"\n\n\t\"io\"\n\n\t\"github.com/fentec-project/bn256\"\n\t\"github.com/fentec-project/gofe/data\"\n\t\"github.com/fentec-project/gofe/sample\"\n)\n\n// This is a ciphertext policy (CP) attribute based (ABE) scheme based\n// on Shashank Agrawal, Melissa Chase:\n// \"FAME: Fast Attribute-based Message Encryption\"\n//\n// This scheme enables encryption based on a boolean expression\n// determining which attributes are needed for an entity to be able\n// to decrypt. Moreover, secret keys are generated, where each key\n// is connected to some attribute, such that only a set of keys whose\n// attributes are sufficient can decrypt the massage.\n// This scheme is a PUBLIC-KEY scheme - no master secret key is needed\n// to encrypt the messages.\n//\n\n// FAME represents a FAME scheme.\ntype FAME struct {\n\tP *big.Int // order of the elliptic curve\n}\n\n// NewFAME configures a new instance of the scheme.\nfunc NewFAME() *FAME {\n\treturn &FAME{P: bn256.Order}\n}\n\n// FAMESecKey represents a master secret key of a FAME scheme.\ntype FAMESecKey struct {\n\tPartInt [4]*big.Int\n\tPartG1  [3]*bn256.G1\n}\n\n// FAMEPubKey represents a public key of a FAME scheme.\ntype FAMEPubKey struct {\n\tPartG2 [2]*bn256.G2\n\tPartGT [2]*bn256.GT\n}\n\n// GenerateMasterKeys generates a new set of public keys, needed\n// for encrypting data, and master secret keys needed for generating\n// keys for decrypting.\nfunc (a *FAME) GenerateMasterKeys() (*FAMEPubKey, *FAMESecKey, error) {\n\tsampler := sample.NewUniformRange(big.NewInt(1), a.P)\n\tval, err := data.NewRandomVector(7, sampler)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tpartInt := [4]*big.Int{val[0], val[1], val[2], val[3]}\n\tpartG1 := [3]*bn256.G1{new(bn256.G1).ScalarBaseMult(val[4]),\n\t\tnew(bn256.G1).ScalarBaseMult(val[5]),\n\t\tnew(bn256.G1).ScalarBaseMult(val[6])}\n\tpartG2 := [2]*bn256.G2{new(bn256.G2).ScalarBaseMult(val[0]),\n\t\tnew(bn256.G2).ScalarBaseMult(val[1])}\n\ttmp1 := new(big.Int).Mod(new(big.Int).Add(new(big.Int).Mul(val[0], val[4]), val[6]), a.P)\n\ttmp2 := new(big.Int).Mod(new(big.Int).Add(new(big.Int).Mul(val[1], val[5]), val[6]), a.P)\n\tpartGT := [2]*bn256.GT{new(bn256.GT).ScalarBaseMult(tmp1),\n\t\tnew(bn256.GT).ScalarBaseMult(tmp2)}\n\n\treturn &FAMEPubKey{PartG2: partG2, PartGT: partGT},\n\t\t&FAMESecKey{PartInt: partInt, PartG1: partG1}, nil\n}\n\n// FAMECipher represents a ciphertext of a FAME scheme.\ntype FAMECipher struct {\n\tCt0     [3]*bn256.G2\n\tCt      [][3]*bn256.G1\n\tCtPrime *bn256.GT\n\tMsp     *MSP\n\tSymEnc  []byte // symmetric encryption of the message\n\tIv      []byte // initialization vector for symmetric encryption\n}\n\n// Encrypt takes as an input a message msg represented as an element of an elliptic\n// curve, a MSP struct representing the decryption policy, and a public key pk. It\n// returns an encryption of the message. In case of a failed procedure an error\n// is returned. Note that safety of the encryption is only proved if the mapping\n// msp.RowToAttrib from the rows of msp.Mat to attributes is injective.\nfunc (a *FAME) Encrypt(msg string, msp *MSP, pk *FAMEPubKey) (*FAMECipher, error) {\n\tif len(msp.Mat) == 0 || len(msp.Mat[0]) == 0 {\n\t\treturn nil, fmt.Errorf(\"empty msp matrix\")\n\t}\n\n\tattrib := make(map[string]bool)\n\tfor _, i := range msp.RowToAttrib {\n\t\tif attrib[i] {\n\t\t\treturn nil, fmt.Errorf(\"some attributes correspond to\" +\n\t\t\t\t\"multiple rows of the MSP struct, the scheme is not secure\")\n\t\t}\n\t\tattrib[i] = true\n\t}\n\n\t// msg is encrypted using CBC, with a random key that is encapsulated\n\t// with FAME\n\t_, keyGt, err := bn256.RandomGT(rand.Reader)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tkeyCBC := sha256.Sum256([]byte(keyGt.String()))\n\n\tc, err := aes.NewCipher(keyCBC[:])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tiv := make([]byte, c.BlockSize())\n\t_, err = io.ReadFull(rand.Reader, iv)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tencrypterCBC := cbc.NewCBCEncrypter(c, iv)\n\n\tmsgByte := []byte(msg)\n\n\t// message is padded according to pkcs7 standard\n\tpadLen := c.BlockSize() - (len(msgByte) % c.BlockSize())\n\tmsgPad := make([]byte, len(msgByte)+padLen)\n\tcopy(msgPad, msgByte)\n\tfor i := len(msgByte); i < len(msgPad); i++ {\n\t\tmsgPad[i] = byte(padLen)\n\t}\n\n\tsymEnc := make([]byte, len(msgPad))\n\tencrypterCBC.CryptBlocks(symEnc, msgPad)\n\n\t// encapsulate the key with FAME\n\tsampler := sample.NewUniform(a.P)\n\ts, err := data.NewRandomVector(2, sampler)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tct0 := [3]*bn256.G2{new(bn256.G2).ScalarMult(pk.PartG2[0], s[0]),\n\t\tnew(bn256.G2).ScalarMult(pk.PartG2[1], s[1]),\n\t\tnew(bn256.G2).ScalarBaseMult(new(big.Int).Add(s[0], s[1]))}\n\n\tct := make([][3]*bn256.G1, len(msp.Mat))\n\tfor i := 0; i < len(msp.Mat); i++ {\n\t\tfor l := 0; l < 3; l++ {\n\t\t\ths1, err := bn256.HashG1(msp.RowToAttrib[i] + \" \" + strconv.Itoa(l) + \" 0\")\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\ths1.ScalarMult(hs1, s[0])\n\n\t\t\ths2, err := bn256.HashG1(msp.RowToAttrib[i] + \" \" + strconv.Itoa(l) + \" 1\")\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\ths2.ScalarMult(hs2, s[1])\n\n\t\t\tct[i][l] = new(bn256.G1).Add(hs1, hs2)\n\t\t\tfor j := 0; j < len(msp.Mat[0]); j++ {\n\t\t\t\ths1, err = bn256.HashG1(\"0 \" + strconv.Itoa(j) + \" \" + strconv.Itoa(l) + \" 0\")\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t\ths1.ScalarMult(hs1, s[0])\n\n\t\t\t\ths2, err = bn256.HashG1(\"0 \" + strconv.Itoa(j) + \" \" + strconv.Itoa(l) + \" 1\")\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t\ths2.ScalarMult(hs2, s[1])\n\n\t\t\t\thsToM := new(bn256.G1).Add(hs1, hs2)\n\t\t\t\tpow := new(big.Int).Set(msp.Mat[i][j])\n\t\t\t\tif pow.Sign() == -1 {\n\t\t\t\t\tpow.Neg(pow)\n\t\t\t\t\thsToM.ScalarMult(hsToM, pow)\n\t\t\t\t\thsToM.Neg(hsToM)\n\t\t\t\t} else {\n\t\t\t\t\thsToM.ScalarMult(hsToM, pow)\n\t\t\t\t}\n\t\t\t\tct[i][l].Add(ct[i][l], hsToM)\n\t\t\t}\n\t\t}\n\t}\n\n\tctPrime := new(bn256.GT).ScalarMult(pk.PartGT[0], s[0])\n\tctPrime.Add(ctPrime, new(bn256.GT).ScalarMult(pk.PartGT[1], s[1]))\n\tctPrime.Add(ctPrime, keyGt)\n\n\treturn &FAMECipher{Ct0: ct0, Ct: ct, CtPrime: ctPrime, Msp: msp, SymEnc: symEnc, Iv: iv}, nil\n}\n\n// FAMEAttribKeys represents keys corresponding to attributes possessed by\n// an entity and used for decrypting in a FAME scheme.\ntype FAMEAttribKeys struct {\n\tK0        [3]*bn256.G2\n\tK         [][3]*bn256.G1\n\tKPrime    [3]*bn256.G1\n\tAttribToI map[string]int\n}\n\n// GenerateAttribKeys given a set of attributes gamma and the master secret key\n// generates keys that can be used for the decryption of any ciphertext encoded\n// with a policy for which attributes gamma are sufficient.\nfunc (a *FAME) GenerateAttribKeys(gamma []string, sk *FAMESecKey) (*FAMEAttribKeys, error) {\n\tsampler := sample.NewUniform(a.P)\n\tr, err := data.NewRandomVector(2, sampler)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tsigma, err := data.NewRandomVector(len(gamma), sampler)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tpow0 := new(big.Int).Mul(sk.PartInt[2], r[0])\n\tpow0.Mod(pow0, a.P)\n\tpow1 := new(big.Int).Mul(sk.PartInt[3], r[1])\n\tpow1.Mod(pow1, a.P)\n\tpow2 := new(big.Int).Add(r[0], r[1])\n\tpow2.Mod(pow2, a.P)\n\n\tk0 := [3]*bn256.G2{new(bn256.G2).ScalarBaseMult(pow0),\n\t\tnew(bn256.G2).ScalarBaseMult(pow1),\n\t\tnew(bn256.G2).ScalarBaseMult(pow2)}\n\n\ta0Inv := new(big.Int).ModInverse(sk.PartInt[0], a.P)\n\ta1Inv := new(big.Int).ModInverse(sk.PartInt[1], a.P)\n\taInv := [2]*big.Int{a0Inv, a1Inv}\n\n\tk := make([][3]*bn256.G1, len(gamma))\n\tattribToI := make(map[string]int)\n\tfor i, y := range gamma {\n\t\tk[i] = [3]*bn256.G1{new(bn256.G1), new(bn256.G1), new(bn256.G1)}\n\t\tgSigma := new(bn256.G1).ScalarBaseMult(sigma[i])\n\t\tfor t := 0; t < 2; t++ {\n\t\t\ths0, err := bn256.HashG1(y + \" 0 \" + strconv.Itoa(t))\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\ths0.ScalarMult(hs0, pow0)\n\t\t\ths1, err := bn256.HashG1(y + \" 1 \" + strconv.Itoa(t))\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\ths1.ScalarMult(hs1, pow1)\n\t\t\ths2, err := bn256.HashG1(y + \" 2 \" + strconv.Itoa(t))\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\ths2.ScalarMult(hs2, pow2)\n\n\t\t\tk[i][t].Add(hs0, hs1)\n\t\t\tk[i][t].Add(k[i][t], hs2)\n\t\t\tk[i][t].Add(k[i][t], gSigma)\n\t\t\tk[i][t].ScalarMult(k[i][t], aInv[t])\n\t\t}\n\n\t\tk[i][2].ScalarBaseMult(sigma[i])\n\t\tk[i][2].Neg(k[i][2])\n\n\t\tattribToI[y] = i\n\t}\n\n\tsigmaPrime, err := sampler.Sample()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tgSigmaPrime := new(bn256.G1).ScalarBaseMult(sigmaPrime)\n\n\tk2 := [3]*bn256.G1{new(bn256.G1), new(bn256.G1), new(bn256.G1)}\n\tfor t := 0; t < 2; t++ {\n\t\ths0, err := bn256.HashG1(\"0 0 0 \" + strconv.Itoa(t))\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\ths0.ScalarMult(hs0, pow0)\n\t\ths1, err := bn256.HashG1(\"0 0 1 \" + strconv.Itoa(t))\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\ths1.ScalarMult(hs1, pow1)\n\t\ths2, err := bn256.HashG1(\"0 0 2 \" + strconv.Itoa(t))\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\ths2.ScalarMult(hs2, pow2)\n\n\t\tk2[t].Add(hs0, hs1)\n\t\tk2[t].Add(k2[t], hs2)\n\t\tk2[t].Add(k2[t], gSigmaPrime)\n\t\tk2[t].ScalarMult(k2[t], aInv[t])\n\t\tk2[t].Add(k2[t], sk.PartG1[t])\n\t}\n\n\tk2[2].ScalarBaseMult(sigmaPrime)\n\tk2[2].Neg(k2[2])\n\tk2[2].Add(k2[2], sk.PartG1[2])\n\n\treturn &FAMEAttribKeys{K0: k0, K: k, KPrime: k2, AttribToI: attribToI}, nil\n}\n\n// Decrypt takes as an input a cipher and an FAMEAttribKeys and tries to decrypt\n// the cipher. This is possible only if the set of possessed attributes (and\n// corresponding keys FAMEAttribKeys) suffices the encryption policy of the\n// cipher. If this is not possible, an error is returned.\nfunc (a *FAME) Decrypt(cipher *FAMECipher, key *FAMEAttribKeys, pk *FAMEPubKey) (string, error) {\n\t// find out which attributes are owned\n\tattribMap := make(map[string]bool)\n\tfor k := range key.AttribToI {\n\t\tattribMap[k] = true\n\t}\n\n\tcountAttrib := 0\n\tfor i := 0; i < len(cipher.Msp.Mat); i++ {\n\t\tif attribMap[cipher.Msp.RowToAttrib[i]] {\n\t\t\tcountAttrib++\n\t\t}\n\t}\n\n\t// create a matrix of needed keys\n\tpreMatForKey := make([]data.Vector, countAttrib)\n\tctForKey := make([][3]*bn256.G1, countAttrib)\n\trowToAttrib := make([]string, countAttrib)\n\tcountAttrib = 0\n\tfor i := 0; i < len(cipher.Msp.Mat); i++ {\n\t\tif attribMap[cipher.Msp.RowToAttrib[i]] {\n\t\t\tpreMatForKey[countAttrib] = cipher.Msp.Mat[i]\n\t\t\tctForKey[countAttrib] = cipher.Ct[i]\n\t\t\trowToAttrib[countAttrib] = cipher.Msp.RowToAttrib[i]\n\t\t\tcountAttrib++\n\t\t}\n\t}\n\n\tmatForKey, err := data.NewMatrix(preMatForKey)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"the provided cipher is faulty\")\n\t}\n\n\t// matForKey may have a len of 0 if there is a single condition\n\tif len(matForKey) == 0 {\n\t\treturn \"\", fmt.Errorf(\"provided key is not sufficient for decryption\")\n\t}\n\n\t// get a combination alpha of keys needed to decrypt\n\t// matForKey may have a len of 0 if there is a single condition\n\tif len(matForKey) == 0 {\n\t\treturn \"\", fmt.Errorf(\"provided key is not sufficient for decryption\")\n\t}\n\toneVec := data.NewConstantVector(len(matForKey[0]), big.NewInt(0))\n\toneVec[0].SetInt64(1)\n\talpha, err := data.GaussianEliminationSolver(matForKey.Transpose(), oneVec, a.P)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"provided key is not sufficient for decryption\")\n\t}\n\n\t// get a CBC key needed for the decryption of msg\n\tkeyGt := new(bn256.GT).Set(cipher.CtPrime)\n\n\tctProd := new([3]*bn256.G1)\n\tkeyProd := new([3]*bn256.G1)\n\tfor j := 0; j < 3; j++ {\n\t\tctProd[j] = new(bn256.G1).ScalarBaseMult(big.NewInt(0))\n\t\tkeyProd[j] = new(bn256.G1).ScalarBaseMult(big.NewInt(0))\n\t\tfor i, e := range rowToAttrib {\n\t\t\tctProd[j].Add(ctProd[j], new(bn256.G1).ScalarMult(ctForKey[i][j], alpha[i]))\n\t\t\tkeyProd[j].Add(keyProd[j], new(bn256.G1).ScalarMult(key.K[key.AttribToI[e]][j], alpha[i]))\n\t\t}\n\t\tkeyProd[j].Add(keyProd[j], key.KPrime[j])\n\t\tctPairing := bn256.Pair(ctProd[j], key.K0[j])\n\t\tkeyPairing := bn256.Pair(keyProd[j], cipher.Ct0[j])\n\t\tkeyPairing.Neg(keyPairing)\n\t\tkeyGt.Add(keyGt, ctPairing)\n\t\tkeyGt.Add(keyGt, keyPairing)\n\t}\n\n\tkeyCBC := sha256.Sum256([]byte(keyGt.String()))\n\n\tc, err := aes.NewCipher(keyCBC[:])\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tmsgPad := make([]byte, len(cipher.SymEnc))\n\tdecrypter := cbc.NewCBCDecrypter(c, cipher.Iv)\n\tdecrypter.CryptBlocks(msgPad, cipher.SymEnc)\n\n\t// unpad the message\n\tpadLen := int(msgPad[len(msgPad)-1])\n\tif (len(msgPad) - padLen) < 0 {\n\t\treturn \"\", fmt.Errorf(\"failed to decrypt\")\n\t}\n\tmsgByte := msgPad[0:(len(msgPad) - padLen)]\n\n\treturn string(msgByte), nil\n}\n"
  },
  {
    "path": "abe/fame_test.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage abe_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/fentec-project/gofe/abe\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestFAME(t *testing.T) {\n\t// create a new FAME struct with the universe of attributes\n\t// denoted by integer\n\ta := abe.NewFAME()\n\n\t// generate a public key and a secret key for the scheme\n\tpubKey, secKey, err := a.GenerateMasterKeys()\n\tif err != nil {\n\t\tt.Fatalf(\"Failed to generate master keys: %v\", err)\n\t}\n\n\t// create a message to be encrypted\n\tmsg := \"Attack at dawn!\"\n\n\t// create a msp struct out of a boolean expression representing the\n\t// policy specifying which attributes are needed to decrypt the ciphertext;\n\t// the boolean expression is a string of attributes joined by AND and OR\n\t// hence the names of the attributes should not include \"AND\" or \"OR\"\n\t// as a substring and '(' or ')' as a character\n\n\t// note that safety of the encryption is only proved if the mapping\n\t// msp.RowToAttrib from the rows of msp.Mat to attributes is injective, i.e.\n\t// only boolean expressions in which each attribute appears at most once\n\t// are allowed - if expressions with multiple appearances of an attribute\n\t// are needed, then this attribute can be split into more sub-attributes\n\tmsp, err := abe.BooleanToMSP(\"((0 AND 1) OR (2 AND 3)) AND 5\", false)\n\tif err != nil {\n\t\tt.Fatalf(\"Failed to generate the policy: %v\", err)\n\t}\n\n\t// encrypt the message msg with the decryption policy specified by the\n\t// msp structure\n\tcipher, err := a.Encrypt(msg, msp, pubKey)\n\tif err != nil {\n\t\tt.Fatalf(\"Failed to encrypt: %v\", err)\n\t}\n\n\t// define a set of attributes (a subset of the universe of attributes)\n\t// that an entity possesses\n\tgamma := []string{\"0\", \"2\", \"3\", \"5\"}\n\n\t// generate keys for decryption for an entity with\n\t// attributes gamma\n\tkeys, err := a.GenerateAttribKeys(gamma, secKey)\n\tif err != nil {\n\t\tt.Fatalf(\"Failed to generate keys: %v\", err)\n\t}\n\n\t// decrypt the ciphertext with the keys of an entity\n\t// that has sufficient attributes\n\tmsgCheck, err := a.Decrypt(cipher, keys, pubKey)\n\tif err != nil {\n\t\tt.Fatalf(\"Failed to decrypt: %v\", err)\n\t}\n\tassert.Equal(t, msg, msgCheck)\n\n\t// define a set of attributes (a subset of the universe of attributes)\n\t// that an entity possesses\n\tgammaInsuff := []string{\"1\", \"3\", \"5\"}\n\n\t// generate keys for decryption for an entity with\n\t// attributes gammaInsuff\n\tkeysInsuff, err := a.GenerateAttribKeys(gammaInsuff, secKey)\n\tif err != nil {\n\t\tt.Fatalf(\"Failed to generate keys: %v\", err)\n\t}\n\n\t// try to decrypt the ciphertext with the keys of an entity\n\t// that has insufficient attributes\n\t_, err = a.Decrypt(cipher, keysInsuff, pubKey)\n\tassert.Error(t, err)\n\n\tmspSingleCondition, err := abe.BooleanToMSP(\"0\", false)\n\tif err != nil {\n\t\tt.Fatalf(\"Failed to generate the policy: %v\", err)\n\t}\n\n\t// encrypt the message msg with the decryption policy specified by the\n\t// msp structure\n\tcipherSingleCondition, err := a.Encrypt(msg, mspSingleCondition, pubKey)\n\tif err != nil {\n\t\tt.Fatalf(\"Failed to encrypt: %v\", err)\n\t}\n\n\tmsgCheckSingleCondition, err := a.Decrypt(cipherSingleCondition, keys, pubKey)\n\tif err != nil {\n\t\tt.Fatalf(\"Failed to decrypt: %v\", err)\n\t}\n\tassert.Equal(t, msg, msgCheckSingleCondition)\n\n\t_, err = a.Decrypt(cipherSingleCondition, keysInsuff, pubKey)\n\tassert.Error(t, err)\n\n\t// test with Single UUID\n\tmspSingleUUID, err := abe.BooleanToMSP(\"123e4567-e89b-12d3-a456-426655440000\", false)\n\n\tif err != nil {\n\t\tt.Fatalf(\"Failed to generate the policy: %v\", err)\n\t}\n\n\tcipherSingleUUID, err := a.Encrypt(msg, mspSingleUUID, pubKey)\n\tif err != nil {\n\t\tt.Fatalf(\"Failed to encrypt: %v\", err)\n\t}\n\n\t// define a set of attributes (a subset of the universe of attributes)\n\t// that an entity possesses\n\tgammaUUID := []string{\"123e4567-e89b-12d3-a456-426655440000\", \"123e4567-e89b-12d3-a456-4266554400001\"}\n\n\t// generate keys for decryption for an entity with\n\t// attributes gamma\n\tkeysUUID, err := a.GenerateAttribKeys(gammaUUID, secKey)\n\tif err != nil {\n\t\tt.Fatalf(\"Failed to generate keys: %v\", err)\n\t}\n\n\t// decrypt the ciphertext with the keys of an entity\n\t// that has sufficient attributes\n\tmsgCheckSingleUUID, err := a.Decrypt(cipherSingleUUID, keysUUID, pubKey)\n\tif err != nil {\n\t\tt.Fatalf(\"Failed to decrypt: %v\", err)\n\t}\n\tassert.Equal(t, msg, msgCheckSingleUUID)\n\n\t// define a set of attributes (a subset of the universe of attributes)\n\t// that an entity possesses\n\tgammaInsuffUUID := []string{\"123e4567-e89b-12d3-a456-426655440099\"}\n\n\t// generate keys for decryption for an entity with\n\t// attributes gammaInsuff\n\tkeysInsuffUUID, err := a.GenerateAttribKeys(gammaInsuffUUID, secKey)\n\tif err != nil {\n\t\tt.Fatalf(\"Failed to generate keys: %v\", err)\n\t}\n\n\t// try to decrypt the ciphertext with the keys of an entity\n\t// that has insufficient attributes\n\t_, err = a.Decrypt(cipherSingleUUID, keysInsuffUUID, pubKey)\n\tassert.Error(t, err)\n\n\t//\n\t// test with Multi UUID\n\tmspMultiUUID, err := abe.BooleanToMSP(\"123e4567-e89b-12d3-a456-426655440000 OR 123e4567-e89b-12d3-a456-426655440001\", false)\n\tif err != nil {\n\t\tt.Fatalf(\"Failed to generate the policy: %v\", err)\n\t}\n\n\tcipherMultiUUID, err := a.Encrypt(msg, mspMultiUUID, pubKey)\n\tif err != nil {\n\t\tt.Fatalf(\"Failed to encrypt: %v\", err)\n\t}\n\n\t// decrypt the ciphertext with the keys of an entity\n\t// that has sufficient attributes\n\tmsgCheckMultiUUID, err := a.Decrypt(cipherMultiUUID, keysUUID, pubKey)\n\tif err != nil {\n\t\tt.Fatalf(\"Failed to decrypt: %v\", err)\n\t}\n\tassert.Equal(t, msg, msgCheckMultiUUID)\n\n\t// try to decrypt the ciphertext with the keys of an entity\n\t// that has insufficient attributes\n\t_, err = a.Decrypt(cipherMultiUUID, keysInsuffUUID, pubKey)\n\tassert.Error(t, err)\n}\n"
  },
  {
    "path": "abe/gpsw.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage abe\n\nimport (\n\t\"crypto/aes\"\n\tcbc \"crypto/cipher\"\n\t\"crypto/rand\"\n\t\"crypto/sha256\"\n\t\"fmt\"\n\t\"math/big\"\n\n\t\"io\"\n\n\t\"strconv\"\n\n\t\"github.com/fentec-project/bn256\"\n\t\"github.com/fentec-project/gofe/data\"\n\t\"github.com/fentec-project/gofe/sample\"\n)\n\n// This is a key policy (KP) attribute based (ABE) scheme based on\n// Goyal, Pandey, Sahai, Waters:\n// \"Attribute-Based Encryption for Fine-Grained Access Control of\n// Encrypted Data\"\n//\n// We abbreviated it GPSW scheme to honor the authors. This scheme\n// enables encrypting data associated with a set of attributes and\n// generating keys associated with boolean expressions determining the\n// policy. A user that owns such a key can decrypt the ciphertext\n// only if the attributes associated to the ciphertext satisfy the\n//policy associated to the key.\n// This scheme is a PUBLIC-KEY scheme - no master secret key is needed\n// to encrypt the messages.\n\n// GPSWParams represents configuration parameters for the GPSW ABE-scheme instance.\ntype GPSWParams struct {\n\tL int      // number of attributes\n\tP *big.Int // order of the elliptic curve\n}\n\n// GPSW represents an GPSW ABE-scheme.\ntype GPSW struct {\n\tParams *GPSWParams\n}\n\n// NewGPSW configures a new instance of the scheme.\n// It accepts l the number of attributes possibly used in\n// the scheme. Attributes' names will be considered as\n// elements of a set {0, 1,..., l-1}.\nfunc NewGPSW(l int) *GPSW {\n\treturn &GPSW{Params: &GPSWParams{\n\t\tL: l,           // number of attributes in the whole universe\n\t\tP: bn256.Order, // the order of the pairing groups\n\t}}\n}\n\n// GPSWPubKey represents a public key of the GPSW ABE-scheme.\ntype GPSWPubKey struct {\n\tT data.VectorG2\n\tY *bn256.GT\n}\n\n// GenerateMasterKeys generates a new set of public keys, needed\n// for encrypting data, and secret keys needed for generating keys\n// for decryption.\nfunc (a *GPSW) GenerateMasterKeys() (*GPSWPubKey, data.Vector, error) {\n\tsampler := sample.NewUniform(a.Params.P)\n\tsk, err := data.NewRandomVector(a.Params.L+1, sampler)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\tt := sk[:a.Params.L].MulG2()\n\ty := new(bn256.GT).ScalarBaseMult(sk[a.Params.L])\n\n\treturn &GPSWPubKey{T: t, Y: y}, sk, nil\n}\n\n// GPSWCipher represents a ciphertext of the GPSW ABE-scheme.\ntype GPSWCipher struct {\n\tGamma     []int         // the set of attributes that can be used for policy of decryption\n\tAttribToI map[int]int   // a map that connects the attributes in gamma with elements of e\n\tE0        *bn256.GT     // the first part of the encryption\n\tE         data.VectorG2 // the second part of the encryption\n\tSymEnc    []byte        // symmetric encryption of the message\n\tIv        []byte        // initialization vector for symmetric encryption\n}\n\n// Encrypt takes as an input a message msg given as a string, gamma a set (slice)\n// of attributes that will be associated with the encryption and a public\n// key pk. It returns an encryption of msg. In case of a failed procedure an\n// error is returned.\nfunc (a *GPSW) Encrypt(msg string, gamma interface{}, pk *GPSWPubKey) (*GPSWCipher, error) {\n\tvar gammaI []int\n\tswitch gamma.(type) {\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"attributes should be of type []int or []string of integers\")\n\tcase []int:\n\t\tgammaI = gamma.([]int)\n\tcase []string:\n\t\tgammaI = make([]int, len(gamma.([]string)))\n\t\tfor i, e := range gamma.([]string) {\n\t\t\tatt, err := strconv.Atoi(e)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tgammaI[i] = att\n\t\t}\n\t}\n\n\t// msg is encrypted using CBC, with a random key that is encapsulated\n\t// with GPSW\n\t_, keyGt, err := bn256.RandomGT(rand.Reader)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tkeyCBC := sha256.Sum256([]byte(keyGt.String()))\n\n\tc, err := aes.NewCipher(keyCBC[:])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tiv := make([]byte, c.BlockSize())\n\t_, err = io.ReadFull(rand.Reader, iv)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tencrypterCBC := cbc.NewCBCEncrypter(c, iv)\n\n\tmsgByte := []byte(msg)\n\t// message is padded according to pkcs7 standard\n\tpadLen := c.BlockSize() - (len(msgByte) % c.BlockSize())\n\tmsgPad := make([]byte, len(msgByte)+padLen)\n\tcopy(msgPad, msgByte)\n\tfor i := len(msgByte); i < len(msgPad); i++ {\n\t\tmsgPad[i] = byte(padLen)\n\t}\n\n\tsymEnc := make([]byte, len(msgPad))\n\tencrypterCBC.CryptBlocks(symEnc, msgPad)\n\n\t// encapsulate the key with GPSW\n\tsampler := sample.NewUniform(a.Params.P)\n\ts, err := sampler.Sample()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\te0 := new(bn256.GT).Add(keyGt, new(bn256.GT).ScalarMult(pk.Y, s))\n\te := make(data.VectorG2, len(gammaI))\n\tattribToI := make(map[int]int)\n\tfor i, el := range gammaI {\n\t\te[i] = new(bn256.G2).ScalarMult(pk.T[el], s)\n\t\tattribToI[el] = i\n\t}\n\n\treturn &GPSWCipher{Gamma: gammaI,\n\t\tAttribToI: attribToI,\n\t\tE0:        e0,\n\t\tE:         e,\n\t\tSymEnc:    symEnc,\n\t\tIv:        iv}, nil\n}\n\n// GPSWKey represents a key structure for decrypting a ciphertext. It includes\n// a msp structure (policy) associated with the key and a vector D representing\n// the main part of the key.\ntype GPSWKey struct {\n\tMsp         *MSP\n\tD           data.VectorG1\n}\n\n// GeneratePolicyKey given a monotone span program (MSP) msp and the vector of secret\n// keys produces an ABE key associated with the policy given by MSP. In particular,\n// this key can be used to decrypt any cipertext associated with attributes that\n// satisfy given policy.\nfunc (a *GPSW) GeneratePolicyKey(msp *MSP, sk data.Vector) (*GPSWKey, error) {\n\tif len(msp.Mat) == 0 || len(msp.Mat[0]) == 0 {\n\t\treturn nil, fmt.Errorf(\"empty msp matrix\")\n\t}\n\tif len(sk) != (a.Params.L + 1) {\n\t\treturn nil, fmt.Errorf(\"the secret key has wrong length\")\n\t}\n\n\tu, err := getSum(sk[a.Params.L], a.Params.P, len(msp.Mat[0]))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tkey := make(data.VectorG1, len(msp.Mat))\n\n\tfor i := 0; i < len(msp.Mat); i++ {\n\t\tattrib, err := strconv.Atoi(msp.RowToAttrib[i])\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif 0 > attrib || a.Params.L <= attrib {\n\t\t\treturn nil, fmt.Errorf(\"attributes of msp not in the universe of a\")\n\t\t}\n\n\t\ttMapIInv := new(big.Int).ModInverse(sk[attrib], a.Params.P)\n\t\tmatTimesU, err := msp.Mat[i].Dot(u)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tpow := new(big.Int).Mul(tMapIInv, matTimesU)\n\t\tpow.Mod(pow, a.Params.P)\n\t\tkey[i] = new(bn256.G1).ScalarBaseMult(pow)\n\t}\n\n\treturn &GPSWKey{Msp: msp, D: key}, nil\n}\n\n// getSum is a helping function that given integers y, p and d generates a\n// random d dimensional vector over Z_p whose entries sum to y in Z_p.\nfunc getSum(y *big.Int, p *big.Int, d int) (data.Vector, error) {\n\tsampler := sample.NewUniform(p)\n\tret, err := data.NewRandomVector(d, sampler)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tsum := big.NewInt(0)\n\tfor i := 0; i < d-1; i++ {\n\t\tsum.Add(sum, ret[i])\n\t\tsum.Mod(sum, p)\n\t}\n\tret[d-1] = new(big.Int).Sub(y, sum)\n\tret[d-1].Mod(ret[d-1], p)\n\n\treturn ret, nil\n}\n\n// Decrypt takes as an input a cipher and an GPSWKey key and tries to decrypt\n// the cipher. If the GPSWKey is properly generated, this is possible if and\n// only if the set of attributes associated with the ciphertext satisfies the\n// policy (boolean expression) of the key. This is if and only if the\n// rows of the msp matrix in the key associated with the attributes of the\n// ciphertext span the vector [1, 1,..., 1]. If this is not possible, an\n//error is returned.\nfunc (a *GPSW) Decrypt(cipher *GPSWCipher, key *GPSWKey) (string, error) {\n\t// get intersection of gamma and attributes used in the key policy\n\tgammaMap := make(map[int]bool)\n\tfor _, e := range cipher.Gamma {\n\t\tgammaMap[e] = true\n\t}\n\tintersection := make([]int, 0)\n\tmat := make(data.Matrix, 0)\n\td := make(data.VectorG1, 0)\n\tfor i := 0; i < len(key.Msp.Mat); i++ {\n\t\tattrib, err := strconv.Atoi(key.Msp.RowToAttrib[i])\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\t\tif gammaMap[attrib] {\n\t\t\tintersection = append(intersection, attrib)\n\t\t\tmat = append(mat, key.Msp.Mat[i])\n\t\t\td = append(d, key.D[i])\n\t\t}\n\t}\n\n\t// get a combination alpha of keys needed to decrypt\n\tones := data.NewConstantVector(len(mat[0]), big.NewInt(1))\n\talpha, err := data.GaussianEliminationSolver(mat.Transpose(), ones, a.Params.P)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"the provided key is not sufficient for the decryption\")\n\t}\n\n\t// get a CBC key needed for the decryption of msg\n\tkeyGt := new(bn256.GT).Set(cipher.E0)\n\tfor i := 0; i < len(alpha); i++ {\n\t\tpair := bn256.Pair(d[i], cipher.E[cipher.AttribToI[intersection[i]]])\n\t\tpair.ScalarMult(pair, alpha[i])\n\t\tpair.Neg(pair)\n\t\tkeyGt.Add(keyGt, pair)\n\t}\n\n\tkeyCBC := sha256.Sum256([]byte(keyGt.String()))\n\n\tc, err := aes.NewCipher(keyCBC[:])\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tmsgPad := make([]byte, len(cipher.SymEnc))\n\tdecrypter := cbc.NewCBCDecrypter(c, cipher.Iv)\n\tdecrypter.CryptBlocks(msgPad, cipher.SymEnc)\n\n\t// unpad the message\n\tpadLen := int(msgPad[len(msgPad)-1])\n\tif (len(msgPad) - padLen) < 0 {\n\t\treturn \"\", fmt.Errorf(\"failed to decrypt\")\n\t}\n\tmsgByte := msgPad[0:(len(msgPad) - padLen)]\n\n\treturn string(msgByte), nil\n}\n"
  },
  {
    "path": "abe/gpsw_test.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage abe_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/fentec-project/gofe/abe\"\n\t\"github.com/fentec-project/gofe/data\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestGPSW(t *testing.T) {\n\t// create a new GPSW struct with the universe of l possible\n\t// attributes (attributes are denoted by the integers in [0, l))\n\tl := 10\n\ta := abe.NewGPSW(l)\n\n\t// generate a public key and a secret key for the scheme\n\tpubKey, secKey, err := a.GenerateMasterKeys()\n\tif err != nil {\n\t\tt.Fatalf(\"Failed to generate master keys: %v\", err)\n\t}\n\n\t// create two messages to be encrypted\n\tmsg1 := \"Attack at dawn!\"\n\tmsg2 := \"More chocolate!\"\n\n\t// define a set of attributes (a subset of the universe of attributes)\n\t// that will be associated with the encryptions\n\tgamma1 := []int{0, 4, 5} // could be given also as []string{\"0\", \"4\", \"5\"}\n\tgamma2 := []int{0, 1, 4} // could be given also as []string{\"0\", \"1\", \"4\"}\n\n\t// encrypt the first message with associated attributes gamma1\n\tcipher1, err := a.Encrypt(msg1, gamma1, pubKey)\n\tif err != nil {\n\t\tt.Fatalf(\"Failed to encrypt: %v\", err)\n\t}\n\n\t// encrypt the second message with associated attributes gamma2\n\tcipher2, err := a.Encrypt(msg2, gamma2, pubKey)\n\tif err != nil {\n\t\tt.Fatalf(\"Failed to encrypt: %v\", err)\n\t}\n\n\t// create a msp struct out of a boolean expression representing the\n\t// policy specifying which attributes are needed to decrypt the ciphertext;\n\t// the boolean expression is a string of attributes joined by AND and OR\n\t// where attributes are integers from the interval [0, l)\n\n\t// note that the safety of the encryption is only proved if the mapping\n\t// msp.RowToAttrib from the rows of msp.Mat to attributes is injective, i.e.\n\t// only boolean expressions in which each attribute appears at most once\n\t// are allowed - if expressions with multiple appearances of an attribute\n\t// are needed, then this attribute can be split into more sub-attributes\n\tmsp, err := abe.BooleanToMSP(\"(1 OR 4) AND (2 OR (0 AND 5))\", true)\n\tif err != nil {\n\t\tt.Fatalf(\"Failed to generate the policy: %v\", err)\n\t}\n\n\t// generate a key for decryption that correspond to provided msp struct,\n\t// i.e. a key that can decrypt a message iff the attributes associated\n\t// with the ciphertext satisfy the boolean expression\n\tabeKey, err := a.GeneratePolicyKey(msp, secKey)\n\tif err != nil {\n\t\tt.Fatalf(\"Failed to generate keys: %v\", err)\n\t}\n\n\t// test if error is returned when a bad Msp struct is given\n\temptyMsp := &abe.MSP{Mat: make(data.Matrix, 0), RowToAttrib: make([]string, 0)}\n\t_, err = a.GeneratePolicyKey(emptyMsp, secKey)\n\tassert.Error(t, err)\n\n\t// decrypt the first ciphertext with abeKey\n\tmsgCheck, err := a.Decrypt(cipher1, abeKey)\n\tif err != nil {\n\t\tt.Fatalf(\"Failed to decrypt: %v\", err)\n\t}\n\tassert.Equal(t, msg1, msgCheck)\n\n\t// try to decrypt the second ciphertext but fail with abeKey\n\t_, err = a.Decrypt(cipher2, abeKey)\n\tassert.Error(t, err)\n}\n"
  },
  {
    "path": "abe/ma-abe.go",
    "content": "/*\n * Copyright (c) 2021 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage abe\n\nimport (\n    \"crypto/aes\"\n    cbc \"crypto/cipher\"\n    \"crypto/rand\"\n    \"crypto/sha256\"\n    \"fmt\"\n    \"math/big\"\n    \"io\"\n    \"github.com/fentec-project/bn256\"\n    \"github.com/fentec-project/gofe/data\"\n    \"github.com/fentec-project/gofe/sample\"\n)\n\n// This is a ciphertext policy (CP) multi-authority (MA) attribute based\n// encryption (ABE) scheme based on the paper \"Decentralizing Attribute-Based\n// Encryption\" by Allison Lewko and Brent Waters, accessible at\n// (https://eprint.iacr.org/2010/351.pdf).\n//\n// This scheme enables encryption based on a boolean expression determining\n// which attributes are needed for an entity to be able to decrypt, where the\n// attributes can be spread across many different authorities, eliminating the\n// need for a central authority. Secret keys, each connected to a single\n// attribute, are generated by the relevant authorities, such that only a set\n// of keys whose attributes are sufficient according to the boolean formula can\n// decrypt the message.\n\n// MAABE represents a MAABE scheme.\ntype MAABE struct {\n    P *big.Int\n    G1 *bn256.G1\n    G2 *bn256.G2\n    Gt *bn256.GT\n}\n\n// NewMAABE configures a new instance of the scheme.\nfunc NewMAABE() *MAABE {\n    gen1 := new(bn256.G1).ScalarBaseMult(big.NewInt(1))\n    gen2 := new(bn256.G2).ScalarBaseMult(big.NewInt(1))\n    return &MAABE{\n            P: bn256.Order,\n            G1: gen1,\n            G2: gen2,\n            Gt: bn256.Pair(gen1, gen2),\n    }\n}\n\n// MAABEPubKey represents a public key for an authority.\ntype MAABEPubKey struct {\n    Attribs []string\n    EggToAlpha map[string]*bn256.GT\n    GToY map[string]*bn256.G2\n}\n\n// MAABESecKey represents a secret key for an authority.\ntype MAABESecKey struct {\n    Attribs []string\n    Alpha map[string]*big.Int\n    Y map[string]*big.Int\n}\n\n// MAABEAuth represents an authority in the MAABE scheme.\ntype MAABEAuth struct {\n    ID string\n    Maabe *MAABE\n    Pk *MAABEPubKey\n    Sk *MAABESecKey\n}\n\n// NewMAABEAuth configures a new instance of an authority and generates its\n// public and secret keys for the given set of attributes. In case of a failed\n// procedure an error is returned.\nfunc (a *MAABE) NewMAABEAuth(id string, attribs []string) (*MAABEAuth, error) {\n    numattrib := len(attribs)\n    // sanity checks\n    if numattrib == 0 {\n        return nil, fmt.Errorf(\"empty set of authority attributes\")\n    }\n    if len(id) == 0 {\n        return nil, fmt.Errorf(\"empty id string\")\n    }\n    // rand generator\n    sampler := sample.NewUniform(a.P)\n    // generate seckey\n    alphaI, err := data.NewRandomVector(numattrib, sampler)\n    if err != nil {\n        return nil, err\n    }\n    yI, err := data.NewRandomVector(numattrib, sampler)\n    if err != nil {\n        return nil, err\n    }\n    alpha := make(map[string]*big.Int)\n    y := make(map[string]*big.Int)\n    for i, at := range attribs {\n        alpha[at] = alphaI[i]\n        y[at] = yI[i]\n    }\n    // generate pubkey\n    eggToAlpha := make(map[string]*bn256.GT)\n    gToY := make(map[string]*bn256.G2)\n    for _, at := range attribs {\n        eggToAlpha[at] = new(bn256.GT).ScalarMult(a.Gt, alpha[at])\n        gToY[at] = new(bn256.G2).ScalarMult(a.G2, y[at])\n    }\n    sk := &MAABESecKey{Attribs: attribs, Alpha: alpha, Y: y}\n    pk := &MAABEPubKey{Attribs: attribs, EggToAlpha: eggToAlpha, GToY: gToY}\n    return &MAABEAuth{\n        ID: id,\n        Maabe: a,\n        Pk: pk,\n        Sk: sk,\n    }, nil\n}\n\n// PubKeys is a getter function that returns a copy of the authority's public\n// keys.\nfunc (auth *MAABEAuth) PubKeys() *MAABEPubKey {\n    newEggToAlpha := make(map[string]*bn256.GT)\n    newGToY := make(map[string]*bn256.G2)\n    newAttribs := make([]string, len(auth.Pk.Attribs))\n    copy(newAttribs, auth.Pk.Attribs)\n    for at, gt := range auth.Pk.EggToAlpha {\n        newEggToAlpha[at] = new(bn256.GT).Set(gt)\n    }\n    for at, g2 := range auth.Pk.GToY {\n        newGToY[at] = new(bn256.G2).Set(g2)\n    }\n    return &MAABEPubKey{\n        Attribs: newAttribs,\n        EggToAlpha: newEggToAlpha,\n        GToY: newGToY,\n    }\n}\n\n// AddAttribute generates public and secret keys for a new attribute that is\n// given as input. In case of a failed procedure an error is returned, and nil\n// otherwise.\nfunc (auth *MAABEAuth) AddAttribute(attrib string) error {\n    // sanity checks\n    if len(attrib) == 0 {\n        return fmt.Errorf(\"attribute cannot be an empty string\")\n    }\n    if auth.Maabe == nil {\n        return fmt.Errorf(\"MAABE struct cannot be nil\")\n    }\n    // attribute should not already exist, separate function\n    if auth.Sk.Alpha[attrib] != nil || auth.Sk.Y[attrib] != nil {\n        return fmt.Errorf(\"attribute already exists\")\n    }\n    // generate secret key\n    sampler := sample.NewUniform(auth.Maabe.P)\n    skVals, err := data.NewRandomVector(2, sampler)\n    if err != nil {\n        return err\n    }\n    alpha := skVals[0]\n    y := skVals[1]\n    // generate public key\n    eggToAlpha := new(bn256.GT).ScalarMult(auth.Maabe.Gt, alpha)\n    gToY := new(bn256.G2).ScalarMult(auth.Maabe.G2, y)\n    // add keys to authority\n    auth.Sk.Alpha[attrib] = alpha\n    auth.Sk.Y[attrib] = y\n    auth.Pk.EggToAlpha[attrib] = eggToAlpha\n    auth.Pk.GToY[attrib] = gToY\n    auth.Sk.Attribs = append(auth.Sk.Attribs, attrib)\n    auth.Pk.Attribs = append(auth.Pk.Attribs, attrib)\n    return nil\n}\n\n// RegenerateKey generates public and secret keys for an already existing\n// attribute that is given as input. In case of a failed procedure an error is\n// returned. It is meant to be used in case only a part of the authority's\n// secret keys get compromised. Note that the new public keys have to be\n// distributed and messages that were encrypted with a policy that contains\n// this attribute have to also be reencrypted.\nfunc (auth *MAABEAuth) RegenerateKey(attrib string) error {\n    // sanity checks\n    if len(attrib) == 0 {\n        return fmt.Errorf(\"attribute cannot be an empty string\")\n    }\n    if auth.Maabe == nil {\n        return fmt.Errorf(\"MAABE struct cannot be nil\")\n    }\n    // attribute must already exist\n    if auth.Sk.Alpha[attrib] == nil || auth.Sk.Y[attrib] == nil {\n        return fmt.Errorf(\"attribute does not exist yet\")\n    }\n    // generate secret key\n    sampler := sample.NewUniform(auth.Maabe.P)\n    skVals, err := data.NewRandomVector(2, sampler)\n    if err != nil {\n        return err\n    }\n    alpha := skVals[0]\n    y := skVals[1]\n    // generate public key\n    eggToAlpha := new(bn256.GT).ScalarMult(auth.Maabe.Gt, alpha)\n    gToY := new(bn256.G2).ScalarMult(auth.Maabe.G2, y)\n    // add keys to authority\n    auth.Sk.Alpha[attrib] = alpha\n    auth.Sk.Y[attrib] = y\n    auth.Pk.EggToAlpha[attrib] = eggToAlpha\n    auth.Pk.GToY[attrib] = gToY\n    return nil\n}\n\n// MAABECipher represents a ciphertext of a MAABE scheme.\ntype MAABECipher struct {\n    C0 *bn256.GT\n    C1x map[string]*bn256.GT\n    C2x map[string]*bn256.G2\n    C3x map[string]*bn256.G2\n    Msp *MSP\n    SymEnc []byte // symmetric encryption of the string message\n    Iv []byte // initialization vector for symmetric encryption\n}\n\n// Encrypt takes an input message in string form, a MSP struct representing the\n// decryption policy and a list of public keys of the relevant authorities. It\n// returns a ciphertext consisting of an AES encrypted message with the secret\n// key encrypted according to the MAABE scheme. In case of a failed procedure\n// an error is returned.\nfunc (a *MAABE) Encrypt(msg string, msp *MSP, pks []*MAABEPubKey) (*MAABECipher, error) {\n    // sanity checks\n    if len(msp.Mat) == 0 || len(msp.Mat[0]) == 0 {\n        return nil, fmt.Errorf(\"empty msp matrix\")\n    }\n    mspRows := msp.Mat.Rows()\n    mspCols := msp.Mat.Cols()\n    attribs := make(map[string]bool)\n    for _, i := range msp.RowToAttrib {\n        if attribs[i] {\n            return nil, fmt.Errorf(\"some attributes correspond to\" +\n            \"multiple rows of the MSP struct, the scheme is not secure\")\n        }\n        attribs[i] = true\n    }\n    if len(msg) == 0 {\n        return nil, fmt.Errorf(\"message cannot be empty\")\n    }\n    // msg is encrypted with AES-CBC with a random key that is encrypted with\n    // MA-ABE\n    // generate secret key\n    _, symKey, err := bn256.RandomGT(rand.Reader)\n    if err != nil {\n        return nil, err\n    }\n    // generate new AES-CBC params\n    keyCBC := sha256.Sum256([]byte(symKey.String()))\n    cipherAES, err := aes.NewCipher(keyCBC[:])\n    if err != nil {\n        return nil, err\n    }\n    iv := make([]byte, cipherAES.BlockSize())\n    _, err = io.ReadFull(rand.Reader, iv)\n    if err != nil {\n        return nil, err\n    }\n    encrypterCBC := cbc.NewCBCEncrypter(cipherAES, iv)\n    // interpret msg as a byte array and pad it according to PKCS7 standard\n    msgByte := []byte(msg)\n    padLen := cipherAES.BlockSize() - (len(msgByte) % cipherAES.BlockSize())\n    msgPad := make([]byte, len(msgByte) + padLen)\n    copy(msgPad, msgByte)\n    for i := len(msgByte); i < len(msgPad); i++ {\n        msgPad[i] = byte(padLen)\n    }\n    // encrypt data\n    symEnc := make([]byte, len(msgPad))\n    encrypterCBC.CryptBlocks(symEnc, msgPad)\n\n    // now encrypt symKey with MA-ABE\n    // rand generator\n    sampler := sample.NewUniform(a.P)\n    // pick random vector v with random s as first element\n    v, err := data.NewRandomVector(mspCols, sampler)\n    if err != nil {\n        return nil, err\n    }\n    s := v[0]\n    if err != nil {\n        return nil, err\n    }\n    lambdaI, err := msp.Mat.MulVec(v)\n    if err != nil {\n        return nil, err\n    }\n    if len(lambdaI) != mspRows {\n        return nil, fmt.Errorf(\"wrong lambda len\")\n    }\n    lambda := make(map[string]*big.Int)\n    for i, at := range msp.RowToAttrib {\n        lambda[at] = lambdaI[i]\n    }\n    // pick random vector w with 0 as first element\n    w, err := data.NewRandomVector(mspCols, sampler)\n    if err != nil {\n        return nil, err\n    }\n    w[0] = big.NewInt(0)\n    omegaI, err := msp.Mat.MulVec(w)\n    if err != nil {\n        return nil, err\n    }\n    if len(omegaI) != mspRows {\n        return nil, fmt.Errorf(\"wrong omega len\")\n    }\n    omega := make(map[string]*big.Int)\n    for i, at := range msp.RowToAttrib {\n        omega[at] = omegaI[i]\n    }\n    // calculate ciphertext\n    c0 := new(bn256.GT).Add(symKey, new(bn256.GT).ScalarMult(a.Gt, s))\n    c1 := make(map[string]*bn256.GT)\n    c2 := make(map[string]*bn256.G2)\n    c3 := make(map[string]*bn256.G2)\n    // get randomness\n    rI, err := data.NewRandomVector(mspRows, sampler)\n    r := make(map[string]*big.Int)\n    for i, at := range msp.RowToAttrib {\n        r[at] = rI[i]\n    }\n    if err != nil {\n        return nil, err\n    }\n    for _, at := range msp.RowToAttrib {\n        // find the correct pubkey\n        foundPK := false\n        for _, pk := range pks {\n            if pk.EggToAlpha[at] != nil {\n                // CAREFUL: negative numbers do not play well with ScalarMult\n                signLambda := lambda[at].Cmp(big.NewInt(0))\n                signOmega := omega[at].Cmp(big.NewInt(0))\n                var tmpLambda *bn256.GT\n                var tmpOmega *bn256.G2\n                if signLambda >= 0 {\n                    tmpLambda = new(bn256.GT).ScalarMult(a.Gt, lambda[at])\n                } else {\n                    tmpLambda = new(bn256.GT).ScalarMult(new(bn256.GT).Neg(a.Gt), new(big.Int).Abs(lambda[at]))\n                }\n                if signOmega >= 0 {\n                    tmpOmega = new(bn256.G2).ScalarMult(a.G2, omega[at])\n                } else {\n                    tmpOmega = new(bn256.G2).ScalarMult(new(bn256.G2).Neg(a.G2), new(big.Int).Abs(omega[at]))\n                }\n                c1[at] = new(bn256.GT).Add(tmpLambda, new(bn256.GT).ScalarMult(pk.EggToAlpha[at], r[at]))\n                c2[at] = new(bn256.G2).ScalarMult(a.G2, r[at])\n                c3[at] = new(bn256.G2).Add(new(bn256.G2).ScalarMult(pk.GToY[at], r[at]), tmpOmega)\n                foundPK = true\n                break\n            }\n        }\n        if !foundPK {\n            return nil, fmt.Errorf(\"attribute not found in any pubkey\")\n        }\n    }\n    return &MAABECipher{\n        C0: c0,\n        C1x: c1,\n        C2x: c2,\n        C3x: c3,\n        Msp: msp,\n        SymEnc: symEnc,\n        Iv: iv,\n    }, nil\n}\n\n// MAABEKey represents a key corresponding to an attribute possessed by an\n// entity. They are issued by the relevant authorities and are used for\n// decryption in a MAABE scheme.\ntype MAABEKey struct {\n    Gid string\n    Attrib string\n    Key *bn256.G1\n}\n\n// GenerateAttribKeys generates a list of attribute keys for the given user\n// (represented by its Global ID) that possesses the given list of attributes.\n// In case of a failed procedure an error is returned. The relevant authority\n// has to check that the entity actually possesses the attributes via some\n// other channel.\nfunc (auth *MAABEAuth) GenerateAttribKeys(gid string, attribs []string) ([]*MAABEKey, error) {\n    // sanity checks\n    if len(gid) == 0 {\n        return nil, fmt.Errorf(\"GID cannot be empty\")\n    }\n    if len(attribs) == 0 {\n        return nil, fmt.Errorf(\"attribute cannot be empty\")\n    }\n    if auth.Maabe == nil {\n        return nil, fmt.Errorf(\"ma-abe scheme cannot be nil\")\n    }\n    hash, err := bn256.HashG1(gid)\n    if err != nil {\n        return nil, err\n    }\n    ks := make([]*MAABEKey, len(attribs))\n    for i, at := range attribs {\n        var k *bn256.G1\n        if auth.Sk.Alpha[at] != nil && auth.Sk.Y[at] != nil {\n            k = new(bn256.G1).Add(new(bn256.G1).ScalarMult(auth.Maabe.G1, auth.Sk.Alpha[at]), new(bn256.G1).ScalarMult(hash, auth.Sk.Y[at]))\n            ks[i] = &MAABEKey{\n                Gid: gid,\n                Attrib: at,\n                Key: k,\n            }\n        } else {\n            return nil, fmt.Errorf(\"attribute not found in secret key\")\n        }\n    }\n    return ks, nil\n}\n\n// Decrypt takes a ciphertext in a MAABE scheme and a set of attribute keys\n// belonging to the same entity, and attempts to decrypt the cipher. This is\n// possible only if the set of possessed attributes/keys suffices the\n// decryption policy of the ciphertext. In case this is not possible or\n// something goes wrong an error is returned.\nfunc (a * MAABE) Decrypt(ct *MAABECipher, ks []*MAABEKey) (string, error) {\n    // sanity checks\n    if len(ks) == 0 {\n        return \"\", fmt.Errorf(\"empty set of attribute keys\")\n    }\n    gid := ks[0].Gid\n    for _, k := range ks {\n        if k.Gid != gid {\n            return \"\", fmt.Errorf(\"not all GIDs are the same\")\n        }\n    }\n    // get hashed GID\n    hash, err := bn256.HashG1(gid)\n    if err != nil {\n        return \"\", err\n    }\n    // find out which attributes are valid and extract them\n    goodMatRows := make([]data.Vector, 0)\n    goodAttribs := make([]string, 0)\n    aToK := make(map[string]*MAABEKey)\n    for _, k := range ks {\n        aToK[k.Attrib] = k\n    }\n    for i, at := range ct.Msp.RowToAttrib {\n        if aToK[at] != nil {\n            goodMatRows = append(goodMatRows, ct.Msp.Mat[i])\n            goodAttribs = append(goodAttribs, at)\n        }\n    }\n    goodMat, err := data.NewMatrix(goodMatRows)\n    if err != nil {\n        return \"\", err\n    }\n    //choose consts c_x, such that \\sum c_x A_x = (1,0,...,0)\n    // if they don't exist, keys are not ok\n    goodCols := goodMat.Cols()\n    if goodCols == 0 {\n        return \"\", fmt.Errorf(\"no good matrix columns, most likely the keys contain no valid attribute\")\n    }\n    one := data.NewConstantVector(goodCols, big.NewInt(0))\n    one[0] = big.NewInt(1)\n    c, err := data.GaussianEliminationSolver(goodMat.Transpose(), one, a.P)\n    if err != nil {\n        return \"\", err\n    }\n    cx := make(map[string]*big.Int)\n    for i, at := range goodAttribs {\n        cx[at] = c[i]\n    }\n    // compute intermediate values\n    eggLambda := make(map[string]*bn256.GT)\n    for _, at := range goodAttribs {\n        if ct.C1x[at] != nil && ct.C2x[at] != nil && ct.C3x[at] != nil {\n            num := new(bn256.GT).Add(ct.C1x[at], bn256.Pair(hash, ct.C3x[at]))\n            den := new(bn256.GT).Neg(bn256.Pair(aToK[at].Key, ct.C2x[at]))\n            eggLambda[at] = new(bn256.GT).Add(num, den)\n        } else {\n            return \"\", fmt.Errorf(\"attribute %s not in ciphertext dicts\", at)\n        }\n    }\n    eggs := new(bn256.GT).ScalarBaseMult(big.NewInt(0))\n    for _, at := range goodAttribs {\n        if eggLambda[at] != nil {\n            sign := cx[at].Cmp(big.NewInt(0))\n            if sign == 1 {\n                eggs.Add(eggs, new(bn256.GT).ScalarMult(eggLambda[at], cx[at]))\n            } else if sign == -1 {\n                eggs.Add(eggs, new(bn256.GT).ScalarMult(new(bn256.GT).Neg(eggLambda[at]), new(big.Int).Abs(cx[at])))\n            }\n        } else {\n            return \"\", fmt.Errorf(\"missing intermediate result\")\n        }\n    }\n    // calculate key for symmetric encryption\n    symKey := new(bn256.GT).Add(ct.C0, new(bn256.GT).Neg(eggs))\n    // now decrypt message with it\n    keyCBC := sha256.Sum256([]byte(symKey.String()))\n    cipherAES, err := aes.NewCipher(keyCBC[:])\n    if err != nil {\n        return \"\", err\n    }\n    msgPad := make([]byte, len(ct.SymEnc))\n    decrypter := cbc.NewCBCDecrypter(cipherAES, ct.Iv)\n    decrypter.CryptBlocks(msgPad, ct.SymEnc)\n    // unpad the message\n    padLen := int(msgPad[len(msgPad)-1])\n    if (len(msgPad) - padLen) < 0 {\n        return \"\", fmt.Errorf(\"failed to decrypt\")\n    }\n    msgByte := msgPad[0:(len(msgPad) - padLen)]\n    return string(msgByte), nil\n}\n"
  },
  {
    "path": "abe/ma-abe_test.go",
    "content": "package abe_test\n\nimport (\n    \"testing\"\n    \"github.com/fentec-project/gofe/abe\"\n    \"github.com/stretchr/testify/assert\"\n)\n\nfunc TestMAABE(t *testing.T) {\n    // create new MAABE struct with Global Parameters\n    maabe := abe.NewMAABE()\n\n    // create three authorities, each with two attributes\n    attribs1 := []string{\"auth1:at1\", \"auth1:at2\"}\n    attribs2 := []string{\"auth2:at1\", \"auth2:at2\"}\n    attribs3 := []string{\"auth3:at1\", \"auth3:at2\"}\n    auth1, err:= maabe.NewMAABEAuth(\"auth1\", attribs1)\n    if err != nil {\n        t.Fatalf(\"Failed generation authority %s: %v\\n\", \"auth1\", err)\n    }\n    auth2, err:= maabe.NewMAABEAuth(\"auth2\", attribs2)\n    if err != nil {\n        t.Fatalf(\"Failed generation authority %s: %v\\n\", \"auth2\", err)\n    }\n    auth3, err:= maabe.NewMAABEAuth(\"auth3\", attribs3)\n    if err != nil {\n        t.Fatalf(\"Failed generation authority %s: %v\\n\", \"auth3\", err)\n    }\n\n    // create a msp struct out of the boolean formula\n    msp, err := abe.BooleanToMSP(\"((auth1:at1 AND auth2:at1) OR (auth1:at2 AND auth2:at2)) OR (auth3:at1 AND auth3:at2)\", false)\n    if err != nil {\n        t.Fatalf(\"Failed to generate the policy: %v\\n\", err)\n    }\n\n    // define the set of all public keys we use\n    pks := []*abe.MAABEPubKey{auth1.PubKeys(), auth2.PubKeys(), auth3.PubKeys()}\n\n    // choose a message\n    msg := \"Attack at dawn!\"\n\n    // encrypt the message with the decryption policy in msp\n    ct, err := maabe.Encrypt(msg, msp, pks)\n    if err != nil {\n        t.Fatalf(\"Failed to encrypt: %v\\n\", err)\n    }\n\n    // also check for empty message\n    msgEmpty := \"\"\n    _, err = maabe.Encrypt(msgEmpty, msp, pks)\n    assert.Error(t, err)\n\n    // use a pub keyring that is too small\n    pksSmall := []*abe.MAABEPubKey{auth1.PubKeys()}\n    _, err = maabe.Encrypt(msg, msp, pksSmall)\n    assert.Error(t, err)\n\n    // choose a single user's Global ID\n    gid := \"gid1\"\n\n    // authority 1 issues keys to user\n    keys1, err := auth1.GenerateAttribKeys(gid, attribs1)\n    if err != nil {\n        t.Fatalf(\"Failed to generate attribute keys: %v\\n\", err)\n    }\n    key11, key12 := keys1[0], keys1[1]\n    // authority 2 issues keys to user\n    keys2, err := auth2.GenerateAttribKeys(gid, attribs2)\n    if err != nil {\n        t.Fatalf(\"Failed to generate attribute keys: %v\\n\", err)\n    }\n    key21, key22 := keys2[0], keys2[1]\n    // authority 3 issues keys to user\n    keys3, err := auth3.GenerateAttribKeys(gid, attribs3)\n    if err != nil {\n        t.Fatalf(\"Failed to generate attribute keys: %v\\n\", err)\n    }\n    key31, key32 := keys3[0], keys3[1]\n\n    // try and generate key for an attribute that does not belong to the\n    // authority (or does not exist)\n    _, err = auth3.GenerateAttribKeys(gid, []string{\"auth3:at3\"})\n    assert.Error(t, err)\n\n    // user tries to decrypt with different key combos\n    ks1 := []*abe.MAABEKey{key11, key21, key31} // ok\n    ks2 := []*abe.MAABEKey{key12, key22, key32} // ok\n    ks3 := []*abe.MAABEKey{key11, key22} // not ok\n    ks4 := []*abe.MAABEKey{key12, key21} // not ok\n    ks5 := []*abe.MAABEKey{key31, key32} // ok\n\n    // try to decrypt all messages\n    msg1, err := maabe.Decrypt(ct, ks1)\n    if err != nil {\n        t.Fatalf(\"Error decrypting with keyset 1: %v\\n\", err)\n    }\n    assert.Equal(t, msg, msg1)\n\n    msg2, err := maabe.Decrypt(ct, ks2)\n    if err != nil {\n        t.Fatalf(\"Error decrypting with keyset 2: %v\\n\", err)\n    }\n    assert.Equal(t, msg, msg2)\n\n    _, err = maabe.Decrypt(ct, ks3)\n    assert.Error(t, err)\n\n    _, err = maabe.Decrypt(ct, ks4)\n    assert.Error(t, err)\n\n    msg5, err := maabe.Decrypt(ct, ks5)\n    if err != nil {\n        t.Fatalf(\"Error decrypting with keyset 5: %v\\n\", err)\n    }\n    assert.Equal(t, msg, msg5)\n\n    // generate keys with a different GID\n    gid2 := \"gid2\"\n    // authority 1 issues keys to user\n    foreignKeys, err := auth1.GenerateAttribKeys(gid2, []string{\"auth1:at1\"})\n    if err != nil {\n        t.Fatalf(\"Failed to generate attribute key for %s: %v\\n\", \"auth1:at1\", err)\n    }\n    foreignKey11 := foreignKeys[0]\n    // join two users who have sufficient attributes together, but not on their\n    // own\n    ks6 := []*abe.MAABEKey{foreignKey11, key21}\n    // try and decrypt\n    _, err = maabe.Decrypt(ct, ks6)\n    assert.Error(t, err)\n\n    // add a new attribute to some authority\n    err = auth3.AddAttribute(\"auth3:at3\")\n    if err != nil {\n        t.Fatalf(\"Error adding attribute: %v\\n\", err)\n    }\n    // now try to generate the key\n    _, err = auth3.GenerateAttribKeys(gid, []string{\"auth3:at3\"})\n    if err != nil {\n        t.Fatalf(\"Error generating key for new attribute: %v\\n\", err)\n    }\n\n    // regenerate a compromised key for some authority\n    err = auth1.RegenerateKey(\"auth1:at2\")\n    if err != nil {\n        t.Fatalf(\"Error regenerating key: %v\\n\", err)\n    }\n    // regenerate attrib key for that key and republish pubkey\n    keysNew, err := auth1.GenerateAttribKeys(gid, []string{\"auth1:at2\"})\n    if err != nil {\n        t.Fatalf(\"Error generating attrib key for regenerated key: %v\\n\", err)\n    }\n    key12New := keysNew[0]\n    pks = []*abe.MAABEPubKey{auth1.Pk, auth2.Pk, auth3.Pk}\n    // reencrypt msg\n    ctNew, err := maabe.Encrypt(msg, msp, pks)\n    if err != nil {\n        t.Fatalf(\"Failed to encrypt with new keys\")\n    }\n    ks7 := []*abe.MAABEKey{key12New, key22}\n    // decrypt reencrypted msg\n    msg7, err := maabe.Decrypt(ctNew, ks7)\n    if err != nil {\n        t.Fatalf(\"Failed to decrypt with regenerated keys: %v\\n\", err)\n    }\n    assert.Equal(t, msg, msg7)\n}\n\n"
  },
  {
    "path": "abe/policy.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage abe\n\nimport (\n\t\"math/big\"\n\t\"strings\"\n\n\t\"fmt\"\n\n\t\"github.com/fentec-project/gofe/data\"\n)\n\n// MSP represents a monotone span program (MSP) describing a policy defining which\n// attributes are needed to decrypt the ciphertext. It includes a matrix\n// mat and a mapping from the rows of the mat to attributes. A MSP policy\n// allows decryption of an entity with a set of attributes A if an only if all the\n// rows of the matrix mapped to an element of A span the vector [1, 0,..., 0] (or\n// vector [1, 1,..., 1] depending on the use case).\ntype MSP struct {\n\tP           *big.Int\n\tMat         data.Matrix\n\tRowToAttrib []string\n}\n\n// BooleanToMSP takes as an input a boolean expression (without a NOT gate) as\n// a string where attributes are joined by AND and OR gates. It outputs a\n// msp structure representing the expression, i.e. a matrix whose rows\n// correspond to attributes used in the expression and with the property that a\n// boolean expression assigning 1 to some attributes is satisfied iff the\n// corresponding rows span a vector [1, 1,..., 1] or vector [1, 0,..., 0]\n// depending if parameter convertToOnes is set to true or false. Additionally a\n// vector is produced whose i-th entry indicates to which attribute the i-th row\n// corresponds.\n// Example: BooleanToMSP(\"attrib1 AND (attrib2 OR attrib3)\", true)\n// The names of the attributes should not include \"AND\" or \"OR\" as\n// a substring and '(' or ')' as a character, otherwise the function\n// will not work properly.\nfunc BooleanToMSP(boolExp string, convertToOnes bool) (*MSP, error) {\n\t// by the Lewko-Waters algorithm we obtain a MSP struct with the property\n\t// that is the the boolean expression is satisfied if and only if the corresponding\n\t// rows of the msp matrix span the vector [1, 0,..., 0]\n\tvec := make(data.Vector, 1)\n\tvec[0] = big.NewInt(1)\n\tmsp, _, err := booleanToMSPIterative(boolExp, vec, 1)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// if convertToOnes is set to true convert the matrix to such a MSP\n\t// struct so that the boolean expression is satisfied iff the\n\t// corresponding rows span the vector [1, 1,..., 1]\n\tif convertToOnes {\n\t\t// create an invertible matrix that maps [1, 0,..., 0] to [1,1,...,1]\n\t\tinvMat := make(data.Matrix, len(msp.Mat[0]))\n\t\tfor i := 0; i < len(msp.Mat[0]); i++ {\n\t\t\tinvMat[i] = make(data.Vector, len(msp.Mat[0]))\n\t\t\tfor j := 0; j < len(msp.Mat[0]); j++ {\n\t\t\t\tif i == 0 || j == i {\n\t\t\t\t\tinvMat[i][j] = big.NewInt(1)\n\t\t\t\t} else {\n\t\t\t\t\tinvMat[i][j] = big.NewInt(0)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t//change the msp matrix by multiplying with it the matrix invMat\n\t\tmsp.Mat, err = msp.Mat.Mul(invMat)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\treturn msp, nil\n}\n\n// booleanToMspIterative iteratively builds a msp structure by splitting the expression\n// into two parts separated by an AND or OR gate, generating a msp structure on each of\n// them, and joining both structures together. The structure is such the the boolean expression\n// assigning 1 to some attributes is satisfied iff the corresponding rows span a vector\n// [1, 0,..., 0]. The algorithm is known as Lewko-Waters algorithm, see Appendix G in\n// https://eprint.iacr.org/2010/351.pdf.\nfunc booleanToMSPIterative(boolExp string, vec data.Vector, c int) (*MSP, int, error) {\n\tboolExp = strings.TrimSpace(boolExp)\n\tnumBrc := 0\n\tvar boolExp1 string\n\tvar boolExp2 string\n\tvar c1 int\n\tvar cOut int\n\tvar msp1 *MSP\n\tvar msp2 *MSP\n\tvar err error\n\tfound := false\n\n\t// find the main AND or OR gate and iteratively call the function on\n\t// both the sub-expressions\n\tfor i, e := range boolExp {\n\t\tif e == '(' {\n\t\t\tnumBrc++\n\t\t\tcontinue\n\t\t}\n\t\tif e == ')' {\n\t\t\tnumBrc--\n\t\t\tcontinue\n\t\t}\n\t\tif numBrc == 0 && i < len(boolExp)-3 && boolExp[i:i+3] == \"AND\" {\n\t\t\tboolExp1 = boolExp[:i]\n\t\t\tboolExp2 = boolExp[i+3:]\n\t\t\tvec1, vec2 := makeAndVecs(vec, c)\n\t\t\tmsp1, c1, err = booleanToMSPIterative(boolExp1, vec1, c+1)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, 0, err\n\t\t\t}\n\t\t\tmsp2, cOut, err = booleanToMSPIterative(boolExp2, vec2, c1)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, 0, err\n\t\t\t}\n\t\t\tfound = true\n\t\t\tbreak\n\t\t}\n\t\tif numBrc == 0 && i < len(boolExp)-2 && boolExp[i:i+2] == \"OR\" {\n\t\t\tboolExp1 = boolExp[:i]\n\t\t\tboolExp2 = boolExp[i+2:]\n\t\t\tmsp1, c1, err = booleanToMSPIterative(boolExp1, vec, c)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, 0, err\n\t\t\t}\n\t\t\tmsp2, cOut, err = booleanToMSPIterative(boolExp2, vec, c1)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, 0, err\n\t\t\t}\n\t\t\tfound = true\n\t\t\tbreak\n\t\t}\n\t}\n\n\t// If the AND or OR gate is not found then there are two options,\n\t// either the whole expression is in brackets, or the the expression\n\t// is only one attribute. It neither of both is true, then\n\t// an error is returned while converting the expression into an\n\t// attribute\n\tif !found {\n\t\tif boolExp[0] == '(' && boolExp[len(boolExp)-1] == ')' {\n\t\t\tboolExp = boolExp[1:(len(boolExp) - 1)]\n\t\t\treturn booleanToMSPIterative(boolExp, vec, c)\n\t\t}\n\n\t\tif strings.Contains(boolExp, \"(\") || strings.Contains(boolExp, \")\") {\n\t\t\treturn nil, 0, fmt.Errorf(\"bad boolean expression or attributes contain ( or )\")\n\t\t}\n\n\t\tmat := make(data.Matrix, 1)\n\t\tmat[0] = make(data.Vector, c)\n\t\tfor i := 0; i < c; i++ {\n\t\t\tif i < len(vec) {\n\t\t\t\tmat[0][i] = new(big.Int).Set(vec[i])\n\t\t\t} else {\n\t\t\t\tmat[0][i] = big.NewInt(0)\n\t\t\t}\n\t\t}\n\n\t\trowToAttribS := make([]string, 1)\n\t\trowToAttribS[0] = boolExp\n\t\treturn &MSP{Mat: mat, RowToAttrib: rowToAttribS}, c, nil\n\n\t}\n\t// otherwise we join the two msp structures into one\n\tmat := make(data.Matrix, len(msp1.Mat)+len(msp2.Mat))\n\tfor i := 0; i < len(msp1.Mat); i++ {\n\t\tmat[i] = make(data.Vector, cOut)\n\t\tfor j := 0; j < len(msp1.Mat[0]); j++ {\n\t\t\tmat[i][j] = msp1.Mat[i][j]\n\t\t}\n\t\tfor j := len(msp1.Mat[0]); j < cOut; j++ {\n\t\t\tmat[i][j] = big.NewInt(0)\n\t\t}\n\t}\n\tfor i := 0; i < len(msp2.Mat); i++ {\n\t\tmat[i+len(msp1.Mat)] = msp2.Mat[i]\n\t}\n\trowToAttribS := append(msp1.RowToAttrib, msp2.RowToAttrib...)\n\n\treturn &MSP{Mat: mat, RowToAttrib: rowToAttribS}, cOut, nil\n}\n\n// makeAndVecs is a helping structure that given a vector and and counter\n// creates two new vectors used whenever an AND gate is found in a iterative\n// step of BooleanToMsp\nfunc makeAndVecs(vec data.Vector, c int) (data.Vector, data.Vector) {\n\tvec1 := data.NewConstantVector(c+1, big.NewInt(0))\n\tvec2 := data.NewConstantVector(c+1, big.NewInt(0))\n\tfor i := 0; i < len(vec); i++ {\n\t\tvec2[i].Set(vec[i])\n\t}\n\tvec1[c] = big.NewInt(-1)\n\tvec2[c] = big.NewInt(1)\n\n\treturn vec1, vec2\n}\n"
  },
  {
    "path": "abe/policy_test.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage abe\n\nimport (\n\t\"math/big\"\n\t\"testing\"\n\n\t\"github.com/fentec-project/gofe/data\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestBooleanToMsp(t *testing.T) {\n\t// create as msp struct out of a boolean expression\n\tp := big.NewInt(7)\n\tmsp, err := BooleanToMSP(\"1 AND (((6 OR 7) AND (8 OR 9)) OR ((2 AND 3) OR (4 AND 5)))\", true)\n\tif err != nil {\n\t\tt.Fatalf(\"Error while processing a boolean expression: %v\", err)\n\t}\n\n\t// check if having attributes 1, 7 and 9 satisfies the expression, i.e. entries 0, 2, 4\n\t// of a msp matrix span vector [1, 1,..., 1], using Gaussian elimination\n\tv := make(data.Vector, len(msp.Mat[0]))\n\tfor i := 0; i < len(v); i++ {\n\t\tv[i] = big.NewInt(1)\n\t}\n\tm := make(data.Matrix, 3)\n\tm[0] = msp.Mat[0]\n\tm[1] = msp.Mat[2]\n\tm[2] = msp.Mat[4]\n\n\tx, err := data.GaussianEliminationSolver(m.Transpose(), v, p)\n\tif err != nil {\n\t\tt.Fatalf(\"Error finding a vector: %v\", err)\n\t}\n\tassert.NotNil(t, x)\n\n\t// check if an error is generated if the boolean expression is not in a correct form\n\t_, err = BooleanToMSP(\"1 AND ((6 OR 7) AND (8 OR 9)) OR ((2 AND 3) OR (4 AND 5)))\", true)\n\tassert.Error(t, err)\n}\n"
  },
  {
    "path": "data/doc.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// Package data defines basic mathematical structures used\n// throughout the library.\npackage data\n"
  },
  {
    "path": "data/matrix.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage data\n\nimport (\n\t\"fmt\"\n\t\"math/big\"\n\n\t\"github.com/fentec-project/bn256\"\n\t\"github.com/fentec-project/gofe/sample\"\n)\n\n// Matrix wraps a slice of Vector elements. It represents a row-major.\n// order matrix.\n//\n// The j-th element from the i-th vector of the matrix can be obtained\n// as m[i][j].\ntype Matrix []Vector\n\n// NewMatrix accepts a slice of Vector elements and\n// returns a new Matrix instance.\n// It returns error if not all the vectors have the same number of elements.\nfunc NewMatrix(vectors []Vector) (Matrix, error) {\n\tl := -1\n\tnewVectors := make([]Vector, len(vectors))\n\n\tif len(vectors) > 0 {\n\t\tl = len(vectors[0])\n\t}\n\tfor i, v := range vectors {\n\t\tif len(v) != l {\n\t\t\treturn nil, fmt.Errorf(\"all vectors should be of the same length\")\n\t\t}\n\t\tnewVectors[i] = NewVector(v)\n\t}\n\n\treturn Matrix(newVectors), nil\n}\n\n// NewRandomMatrix returns a new Matrix instance\n// with random elements sampled by the provided sample.Sampler.\n// Returns an error in case of sampling failure.\nfunc NewRandomMatrix(rows, cols int, sampler sample.Sampler) (Matrix, error) {\n\tmat := make([]Vector, rows)\n\n\tfor i := 0; i < rows; i++ {\n\t\tvec, err := NewRandomVector(cols, sampler)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tmat[i] = vec\n\t}\n\n\treturn NewMatrix(mat)\n}\n\n// NewRandomDetMatrix returns a new Matrix instance\n// with random elements sampled by a pseudo-random\n// number generator. Elements are sampled from [0, max) and key\n// determines the pseudo-random generator.\nfunc NewRandomDetMatrix(rows, cols int, max *big.Int, key *[32]byte) (Matrix, error) {\n\tl := rows * cols\n\tv, err := NewRandomDetVector(l, max, key)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tmat := make([]Vector, rows)\n\tfor i := 0; i < rows; i++ {\n\t\tmat[i] = NewVector(v[(i * cols):((i + 1) * cols)])\n\t}\n\n\treturn NewMatrix(mat)\n}\n\n// NewConstantMatrix returns a new Matrix instance\n// with all elements set to constant c.\nfunc NewConstantMatrix(rows, cols int, c *big.Int) Matrix {\n\tmat := make([]Vector, rows)\n\tfor i := 0; i < rows; i++ {\n\t\tmat[i] = NewConstantVector(cols, c)\n\t}\n\n\treturn mat\n}\n\n// Copy creates a new Matrix with the same values.\nfunc (m Matrix) Copy() Matrix {\n\tmat := make(Matrix, m.Rows())\n\tfor i := 0; i < m.Rows(); i++ {\n\t\tmat[i] = m[i].Copy()\n\t}\n\n\treturn mat\n}\n\n// Rows returns the number of rows of matrix m.\nfunc (m Matrix) Rows() int {\n\treturn len(m)\n}\n\n// Cols returns the number of columns of matrix m.\nfunc (m Matrix) Cols() int {\n\tif len(m) != 0 {\n\t\treturn len(m[0])\n\t}\n\n\treturn 0\n}\n\n// DimsMatch returns a bool indicating whether matrices\n// m and other have the same dimensions.\nfunc (m Matrix) DimsMatch(other Matrix) bool {\n\treturn m.Rows() == other.Rows() && m.Cols() == other.Cols()\n}\n\n// GetCol returns i-th column of matrix m as a vector.\n// It returns error if i >= the number of m's columns.\nfunc (m Matrix) GetCol(i int) (Vector, error) {\n\tif i >= m.Cols() {\n\t\treturn nil, fmt.Errorf(\"column index exceeds matrix dimensions\")\n\t}\n\n\tcolumn := make([]*big.Int, m.Rows())\n\tfor j := 0; j < m.Rows(); j++ {\n\t\tcolumn[j] = m[j][i]\n\t}\n\n\treturn NewVector(column), nil\n}\n\n// Transpose transposes matrix m and returns\n// the result in a new Matrix.\nfunc (m Matrix) Transpose() Matrix {\n\ttransposed := make([]Vector, m.Cols())\n\tfor i := 0; i < m.Cols(); i++ {\n\t\ttransposed[i], _ = m.GetCol(i)\n\t}\n\n\tmT, _ := NewMatrix(transposed)\n\n\treturn mT\n}\n\n// CheckBound checks whether all matrix elements are strictly\n// smaller than the provided bound.\n// It returns error if at least one element is >= bound.\nfunc (m Matrix) CheckBound(bound *big.Int) error {\n\tfor _, v := range m {\n\t\terr := v.CheckBound(bound)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// CheckDims checks whether dimensions of matrix m match\n// the provided rows and cols arguments.\nfunc (m Matrix) CheckDims(rows, cols int) bool {\n\treturn m.Rows() == rows && m.Cols() == cols\n}\n\n// Mod applies the element-wise modulo operation on matrix m.\n// The result is returned in a new Matrix.\nfunc (m Matrix) Mod(modulo *big.Int) Matrix {\n\tvectors := make([]Vector, m.Rows())\n\n\tfor i, v := range m {\n\t\tvectors[i] = v.Mod(modulo)\n\t}\n\n\tmatrix, _ := NewMatrix(vectors)\n\n\treturn matrix\n}\n\n// Apply applies an element-wise function f to matrix m.\n// The result is returned in a new Matrix.\nfunc (m Matrix) Apply(f func(*big.Int) *big.Int) Matrix {\n\tres := make(Matrix, len(m))\n\n\tfor i, vi := range m {\n\t\tres[i] = vi.Apply(f)\n\t}\n\n\treturn res\n}\n\n// Dot calculates the dot product (inner product) of matrices m and other,\n// which we define as the sum of the dot product of rows of both matrices.\n// It returns an error if m and other have different dimensions.\nfunc (m Matrix) Dot(other Matrix) (*big.Int, error) {\n\tif !m.DimsMatch(other) {\n\t\treturn nil, fmt.Errorf(\"matrices mismatch in dimensions\")\n\t}\n\n\tr := new(big.Int)\n\n\tfor i := 0; i < m.Rows(); i++ {\n\t\tprod, err := m[i].Dot(other[i])\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tr = r.Add(r, prod)\n\t}\n\n\treturn r, nil\n}\n\n// Add adds matrices m and other.\n// The result is returned in a new Matrix.\n// Error is returned if m and other have different dimensions.\nfunc (m Matrix) Add(other Matrix) (Matrix, error) {\n\tif !m.DimsMatch(other) {\n\t\treturn nil, fmt.Errorf(\"matrices mismatch in dimensions\")\n\t}\n\n\tvectors := make([]Vector, m.Rows())\n\n\tfor i, v := range m {\n\t\tvectors[i] = v.Add(other[i])\n\t}\n\n\tmatrix, err := NewMatrix(vectors)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn matrix, nil\n}\n\n// Sub adds matrices m and other.\n// The result is returned in a new Matrix.\n// Error is returned if m and other have different dimensions.\nfunc (m Matrix) Sub(other Matrix) (Matrix, error) {\n\tif !m.DimsMatch(other) {\n\t\treturn nil, fmt.Errorf(\"matrices mismatch in dimensions\")\n\t}\n\n\tvecs := make([]Vector, m.Rows())\n\n\tfor i, v := range m {\n\t\tvecs[i] = v.Sub(other[i])\n\t}\n\n\treturn NewMatrix(vecs)\n}\n\n// Mul multiplies matrices m and other.\n// The result is returned in a new Matrix.\n// Error is returned if m and other have different dimensions.\nfunc (m Matrix) Mul(other Matrix) (Matrix, error) {\n\tif m.Cols() != other.Rows() {\n\t\treturn nil, fmt.Errorf(\"cannot multiply matrices\")\n\t}\n\n\tprod := make([]Vector, m.Rows())\n\tfor i := 0; i < m.Rows(); i++ {\n\t\tprod[i] = make([]*big.Int, other.Cols())\n\t\tfor j := 0; j < other.Cols(); j++ {\n\t\t\totherCol, _ := other.GetCol(j)\n\t\t\tprod[i][j], _ = m[i].Dot(otherCol)\n\t\t}\n\t}\n\n\treturn NewMatrix(prod)\n}\n\n// MulScalar multiplies elements of matrix m by a scalar x.\n// The result is returned in a new Matrix.\nfunc (m Matrix) MulScalar(x *big.Int) Matrix {\n\treturn m.Apply(func(i *big.Int) *big.Int {\n\t\treturn new(big.Int).Mul(i, x)\n\t})\n}\n\n// MulVec multiplies matrix m and vector v.\n// It returns the resulting vector.\n// Error is returned if the number of columns of m differs from the number\n// of elements of v.\nfunc (m Matrix) MulVec(v Vector) (Vector, error) {\n\tif m.Cols() != len(v) {\n\t\treturn nil, fmt.Errorf(\"cannot multiply matrix by a vector\")\n\t}\n\n\tres := make(Vector, m.Rows())\n\tfor i, row := range m {\n\t\tres[i], _ = row.Dot(v)\n\t}\n\n\treturn res, nil\n}\n\n// MulXMatY calculates the function x^T * m * y, where x and y are\n// vectors.\nfunc (m Matrix) MulXMatY(x, y Vector) (*big.Int, error) {\n\tt, err := m.MulVec(y)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tv, err := t.Dot(x)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn v, nil\n}\n\n// Minor returns a matrix obtained from m by removing row i and column j.\n// It returns an error if i >= number of rows of m, or if j >= number of\n// columns of m.\nfunc (m Matrix) Minor(i int, j int) (Matrix, error) {\n\tif i >= m.Rows() || j >= m.Cols() {\n\t\treturn nil, fmt.Errorf(\"cannot obtain minor - out of bounds\")\n\t}\n\tmat := make(Matrix, m.Rows()-1)\n\tfor k := 0; k < m.Rows(); k++ {\n\t\tif k == i {\n\t\t\tcontinue\n\t\t}\n\t\tvec := make(Vector, 0, len(m[0])-1)\n\t\tvec = append(vec, m[k][:j]...)\n\t\tvec = append(vec, m[k][j+1:]...)\n\t\tif k < i {\n\t\t\tmat[k] = vec\n\t\t} else {\n\t\t\tmat[k-1] = vec\n\t\t}\n\t}\n\n\treturn NewMatrix(mat)\n}\n\n// Determinant returns the determinant of matrix m.\n// It returns an error if the determinant does not exist.\nfunc (m Matrix) Determinant() (*big.Int, error) {\n\tif m.Rows() == 1 {\n\t\treturn new(big.Int).Set(m[0][0]), nil\n\t}\n\tdet := big.NewInt(0)\n\tsign := big.NewInt(1)\n\tfor i := 0; i < m.Rows(); i++ {\n\t\tminor, err := m.Minor(0, i)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tvalue, err := minor.Determinant()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tvalue.Mul(value, m[0][i])\n\t\tvalue.Mul(value, sign)\n\t\tsign.Neg(sign)\n\t\tdet.Add(det, value)\n\t}\n\n\treturn det, nil\n}\n\n// InverseMod returns the inverse matrix of m in the group Z_p.\n// Note that as we consider only matrix with integers,\n// the inverse exists only in Z_p.\n//\n// It returns an error in case matrix is not invertible.\nfunc (m Matrix) InverseMod(p *big.Int) (Matrix, error) {\n\tmat := make(Matrix, m.Rows())\n\tdet, err := m.Determinant()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdet.Mod(det, p)\n\tif det.Cmp(big.NewInt(0)) == 0 {\n\t\treturn nil, fmt.Errorf(\"matrix non-invertable\")\n\t}\n\tinvDet := new(big.Int).ModInverse(det, p)\n\tif m.Rows() == 1 {\n\t\tmat[0] = Vector{invDet}\n\t\treturn mat, nil\n\t}\n\tsign := new(big.Int)\n\tminusOne := big.NewInt(-1)\n\tfor i := 0; i < m.Rows(); i++ {\n\t\trow := make(Vector, m.Cols())\n\t\tfor j := 0; j < m.Cols(); j++ {\n\t\t\tminor, err := m.Minor(i, j)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tvalue, err := minor.Determinant()\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tvalue.Mod(value, p)\n\t\t\tsign.Exp(minusOne, big.NewInt(int64(i+j)), nil)\n\t\t\tvalue.Mul(value, sign)\n\t\t\tvalue.Mul(value, invDet)\n\t\t\tvalue.Mod(value, p)\n\t\t\trow[j] = value\n\t\t}\n\t\tmat[i] = row\n\t}\n\tco, err := NewMatrix(mat)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn co.Transpose(), nil\n}\n\n// MulG1 calculates m * [bn256.G1] and returns the\n// result in a new MatrixG1 instance.\nfunc (m Matrix) MulG1() MatrixG1 {\n\tprod := make(MatrixG1, len(m))\n\tfor i := range prod {\n\t\tprod[i] = m[i].MulG1()\n\t}\n\n\treturn prod\n}\n\n// MulG2 calculates m * [bn256.G1] and returns the\n// result in a new MatrixG2 instance.\nfunc (m Matrix) MulG2() MatrixG2 {\n\tprod := make(MatrixG2, len(m))\n\tfor i := range prod {\n\t\tprod[i] = m[i].MulG2()\n\t}\n\n\treturn prod\n}\n\n// MatMulMatG1 multiplies m and other in the sense that\n// if other is t * [bn256.G1] for some matrix t, then the\n// function returns m * t * [bn256.G1] where m * t is a\n// matrix multiplication.\nfunc (m Matrix) MatMulMatG1(other MatrixG1) (MatrixG1, error) {\n\tif m.Cols() != other.Rows() {\n\t\treturn nil, fmt.Errorf(\"cannot multiply matrices\")\n\t}\n\n\tprod := make(MatrixG1, m.Rows())\n\tfor i := 0; i < m.Rows(); i++ {\n\t\tprod[i] = make([]*bn256.G1, other.Cols())\n\t\tfor j := 0; j < other.Cols(); j++ {\n\t\t\tprod[i][j] = new(bn256.G1).ScalarBaseMult(big.NewInt(0))\n\t\t\tfor k := 0; k < m.Cols(); k++ {\n\t\t\t\tmik := new(big.Int).Set(m[i][k])\n\t\t\t\tokj := new(bn256.G1).Set(other[k][j])\n\t\t\t\tif m[i][k].Sign() == -1 {\n\t\t\t\t\tokj.Neg(okj)\n\t\t\t\t\tmik.Neg(mik)\n\t\t\t\t}\n\t\t\t\ttmp := new(bn256.G1).ScalarMult(okj, mik)\n\t\t\t\tprod[i][j].Add(tmp, prod[i][j])\n\t\t\t}\n\t\t}\n\t}\n\n\treturn prod, nil\n}\n\n// MatMulMatG2 multiplies m and other in the sense that\n// if other is t * [bn256.G2] for some matrix t, then the\n// function returns m * t * [bn256.G2] where m * t is a\n// matrix multiplication.\nfunc (m Matrix) MatMulMatG2(other MatrixG2) (MatrixG2, error) {\n\tif m.Cols() != other.Rows() {\n\t\treturn nil, fmt.Errorf(\"cannot multiply matrices\")\n\t}\n\n\tprod := make(MatrixG2, m.Rows())\n\tfor i := 0; i < m.Rows(); i++ {\n\t\tprod[i] = make([]*bn256.G2, other.Cols())\n\t\tfor j := 0; j < other.Cols(); j++ {\n\t\t\tprod[i][j] = new(bn256.G2).ScalarBaseMult(big.NewInt(0))\n\t\t\tfor k := 0; k < m.Cols(); k++ {\n\t\t\t\tmik := new(big.Int).Set(m[i][k])\n\t\t\t\tokj := new(bn256.G2).Set(other[k][j])\n\t\t\t\tif m[i][k].Sign() == -1 {\n\t\t\t\t\tokj.Neg(okj)\n\t\t\t\t\tmik.Neg(mik)\n\t\t\t\t}\n\t\t\t\ttmp := new(bn256.G2).ScalarMult(okj, mik)\n\t\t\t\tprod[i][j].Add(tmp, prod[i][j])\n\t\t\t}\n\t\t}\n\t}\n\n\treturn prod, nil\n}\n\n// MatMulVecG2 multiplies m and other in the sense that\n// if other is t * [bn256.G2] for some vector t, then the\n// function returns m * t * [bn256.G2] where m * t is a\n// matrix-vector multiplication.\nfunc (m Matrix) MatMulVecG2(other VectorG2) (VectorG2, error) {\n\tif m.Cols() != len(other) {\n\t\treturn nil, fmt.Errorf(\"dimensions don't fit\")\n\t}\n\n\tprod := make(VectorG2, m.Rows())\n\tfor j := 0; j < m.Rows(); j++ {\n\t\tprod[j] = new(bn256.G2).ScalarBaseMult(big.NewInt(0))\n\t\tfor k := 0; k < m.Cols(); k++ {\n\t\t\tmjk := new(big.Int).Set(m[j][k])\n\t\t\tok := new(bn256.G2).Set(other[k])\n\t\t\tif m[j][k].Sign() == -1 {\n\t\t\t\tok.Neg(ok)\n\t\t\t\tmjk.Neg(mjk)\n\t\t\t}\n\t\t\ttmp := new(bn256.G2).ScalarMult(ok, mjk)\n\t\t\tprod[j].Add(tmp, prod[j])\n\t\t}\n\t}\n\n\treturn prod, nil\n}\n\n// GaussianElimination uses Gaussian elimination to transform a matrix\n// into an equivalent upper triangular form\nfunc (m Matrix) GaussianElimination(p *big.Int) (Matrix, error) {\n\tif m.Rows() == 0 || m.Cols() == 0 {\n\t\treturn nil, fmt.Errorf(\"the matrix should not be empty\")\n\t}\n\n\t// we copy matrix m into res and v into u\n\tres := make(Matrix, m.Rows())\n\tfor i := 0; i < m.Rows(); i++ {\n\t\tres[i] = make(Vector, m.Cols())\n\t\tfor j := 0; j < m.Cols(); j++ {\n\t\t\tres[i][j] = new(big.Int).Set(m[i][j])\n\t\t}\n\t}\n\n\t// res and u are transformed to be in the upper triangular form\n\th, k := 0, 0\n\tfor h < m.Rows() && k < res.Cols() {\n\t\tzero := true\n\t\tfor i := h; i < m.Rows(); i++ {\n\t\t\tif res[i][k].Sign() != 0 {\n\t\t\t\tres[h], res[i] = res[i], res[h]\n\t\t\t\tzero = false\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif zero {\n\t\t\tk++\n\t\t\tcontinue\n\t\t}\n\t\tmHKInv := new(big.Int).ModInverse(res[h][k], p)\n\t\tfor i := h + 1; i < m.Rows(); i++ {\n\t\t\tf := new(big.Int).Mul(mHKInv, res[i][k])\n\t\t\tres[i][k] = big.NewInt(0)\n\t\t\tfor j := k + 1; j < res.Cols(); j++ {\n\t\t\t\tres[i][j].Sub(res[i][j], new(big.Int).Mul(f, res[h][j]))\n\t\t\t\tres[i][j].Mod(res[i][j], p)\n\t\t\t}\n\t\t}\n\t\tk++\n\t\th++\n\t}\n\n\treturn res, nil\n}\n\n// InverseModGauss returns the inverse matrix of m in the group Z_p.\n// The algorithm uses Gaussian elimination. It returns the determinant\n// as well. In case the matrix is not invertible it returns an error.\nfunc (m Matrix) InverseModGauss(p *big.Int) (Matrix, *big.Int, error) {\n\tif m.Rows() == 0 || m.Cols() == 0 {\n\t\treturn nil, nil, fmt.Errorf(\"the matrix should not be empty\")\n\t}\n\tif m.Rows() != m.Cols() {\n\t\treturn nil, nil, fmt.Errorf(\"the number of rows must equal the number of columns\")\n\t}\n\n\t// we copy matrix m into matExt and extend it with identity\n\tmatExt := make(Matrix, m.Rows())\n\tfor i := 0; i < m.Rows(); i++ {\n\t\tmatExt[i] = make(Vector, m.Cols()*2)\n\t\tfor j := 0; j < m.Cols(); j++ {\n\t\t\tmatExt[i][j] = new(big.Int).Set(m[i][j])\n\t\t}\n\t\tfor j := m.Cols(); j < 2*m.Cols(); j++ {\n\t\t\tif i+m.Cols() == j {\n\t\t\t\tmatExt[i][j] = big.NewInt(1)\n\t\t\t} else {\n\t\t\t\tmatExt[i][j] = big.NewInt(0)\n\t\t\t}\n\n\t\t}\n\t}\n\n\ttriang, err := matExt.GaussianElimination(p)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\t// check if the inverse can be computed\n\tdet := big.NewInt(1)\n\tfor i := 0; i < matExt.Rows(); i++ {\n\t\tdet.Mul(det, triang[i][i])\n\t\tdet.Mod(det, p)\n\t}\n\tif det.Sign() == 0 {\n\t\treturn nil, det, fmt.Errorf(\"matrix non-invertable\")\n\t}\n\n\t// use the upper triangular form to obtain the solution\n\tmatInv := make(Matrix, m.Rows())\n\tfor k := 0; k < m.Rows(); k++ {\n\t\tmatInv[k] = make(Vector, m.Cols())\n\t\tfor i := m.Rows() - 1; i >= 0; i-- {\n\t\t\tfor j := m.Rows() - 1; j >= 0; j-- {\n\t\t\t\tif matInv[k][j] == nil {\n\t\t\t\t\ttmpSum, _ := triang[i][j+1 : m.Cols()].Dot(matInv[k][j+1:])\n\t\t\t\t\tmatInv[k][j] = new(big.Int).Sub(triang[i][m.Cols()+k], tmpSum)\n\t\t\t\t\tmHKInv := new(big.Int).ModInverse(triang[i][j], p)\n\t\t\t\t\tmatInv[k][j].Mul(matInv[k][j], mHKInv)\n\t\t\t\t\tmatInv[k][j].Mod(matInv[k][j], p)\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn matInv.Transpose(), det, nil\n}\n\n// DeterminantGauss returns the determinant of matrix m using Gaussian\n// elimination. It returns an error if the determinant does not exist.\nfunc (m Matrix) DeterminantGauss(p *big.Int) (*big.Int, error) {\n\tif m.Rows() != m.Cols() {\n\t\treturn nil, fmt.Errorf(\"number of rows must equal number of columns\")\n\t}\n\ttriang, err := m.GaussianElimination(p)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tret := big.NewInt(1)\n\tfor i := 0; i < m.Cols(); i++ {\n\t\tret.Mul(ret, triang[i][i])\n\t\tret.Mod(ret, p)\n\t}\n\n\treturn ret, nil\n}\n\n// GaussianEliminationSolver solves a vector equation mat * x = v and finds vector x,\n// using Gaussian elimination. Arithmetic operations are considered to be over\n// Z_p, where p should be a prime number. If such x does not exist, then the\n// function returns an error.\nfunc GaussianEliminationSolver(mat Matrix, v Vector, p *big.Int) (Vector, error) {\n\tif mat.Rows() == 0 || mat.Cols() == 0 {\n\t\treturn nil, fmt.Errorf(\"the matrix should not be empty\")\n\t}\n\tif mat.Rows() != len(v) {\n\t\treturn nil, fmt.Errorf(fmt.Sprintf(\"dimensions should match: \"+\n\t\t\t\"rows of the matrix %d, length of the vector %d\", mat.Rows(), len(v)))\n\t}\n\n\t// we copy matrix mat into m and v into u\n\tcpMat := make([]Vector, mat.Rows())\n\tu := make(Vector, mat.Rows())\n\tfor i := 0; i < mat.Rows(); i++ {\n\t\tcpMat[i] = make(Vector, mat.Cols())\n\t\tfor j := 0; j < mat.Cols(); j++ {\n\t\t\tcpMat[i][j] = new(big.Int).Set(mat[i][j])\n\t\t}\n\t\tu[i] = new(big.Int).Set(v[i])\n\t}\n\tm, _ := NewMatrix(cpMat) // error is impossible to happen\n\n\t// m and u are transformed to be in the upper triangular form\n\tret := make(Vector, mat.Cols())\n\th, k := 0, 0\n\tfor h < mat.Rows() && k < mat.Cols() {\n\t\tzero := true\n\t\tfor i := h; i < mat.Rows(); i++ {\n\t\t\tif m[i][k].Sign() != 0 {\n\t\t\t\tm[h], m[i] = m[i], m[h]\n\n\t\t\t\tu[h], u[i] = u[i], u[h]\n\t\t\t\tzero = false\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif zero {\n\t\t\tret[k] = big.NewInt(0)\n\t\t\tk++\n\t\t\tcontinue\n\t\t}\n\t\tmHKInv := new(big.Int).ModInverse(m[h][k], p)\n\t\tfor i := h + 1; i < mat.Rows(); i++ {\n\t\t\tf := new(big.Int).Mul(mHKInv, m[i][k])\n\t\t\tm[i][k] = big.NewInt(0)\n\t\t\tfor j := k + 1; j < mat.Cols(); j++ {\n\t\t\t\tm[i][j].Sub(m[i][j], new(big.Int).Mul(f, m[h][j]))\n\t\t\t\tm[i][j].Mod(m[i][j], p)\n\t\t\t}\n\t\t\tu[i].Sub(u[i], new(big.Int).Mul(f, u[h]))\n\t\t\tu[i].Mod(u[i], p)\n\t\t}\n\t\tk++\n\t\th++\n\t}\n\n\tfor i := h; i < mat.Rows(); i++ {\n\t\tif u[i].Sign() != 0 {\n\t\t\treturn nil, fmt.Errorf(\"no solution\")\n\t\t}\n\t}\n\tfor j := k; j < mat.Cols(); j++ {\n\t\tret[j] = big.NewInt(0)\n\t}\n\n\t// use the upper triangular form to obtain the solution\n\tfor i := h - 1; i >= 0; i-- {\n\t\tfor j := k - 1; j >= 0; j-- {\n\t\t\tif ret[j] == nil {\n\t\t\t\ttmpSum, _ := m[i][j+1:].Dot(ret[j+1:])\n\t\t\t\tret[j] = new(big.Int).Sub(u[i], tmpSum)\n\t\t\t\tmHKInv := new(big.Int).ModInverse(m[i][j], p)\n\t\t\t\tret[j].Mul(ret[j], mHKInv)\n\t\t\t\tret[j].Mod(ret[j], p)\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\n\treturn ret, nil\n}\n\n// Tensor creates a tensor product of matrices m and other.\n// The result is returned in a new Matrix.\nfunc (m Matrix) Tensor(other Matrix) Matrix {\n\tprod := make(Matrix, m.Rows()*other.Rows())\n\tfor i := 0; i < prod.Rows(); i++ {\n\t\tprod[i] = make(Vector, m.Cols()*other.Cols())\n\t\tfor j := 0; j < len(prod[i]); j++ {\n\t\t\tprod[i][j] = new(big.Int).Mul(m[i/other.Rows()][j/other.Cols()], other[i%other.Rows()][j%other.Cols()])\n\t\t}\n\t}\n\n\treturn prod\n}\n\n// ToVec creates a vector whose entries are entries of m\n// ordered as m_11, m_12,..., m_21, m_22,..., m_kl.\nfunc (m Matrix) ToVec() Vector {\n\tres := make(Vector, m.Rows()*m.Cols())\n\tfor i := 0; i < m.Rows(); i++ {\n\t\tfor j := 0; j < m.Cols(); j++ {\n\t\t\tres[m.Cols()*i+j] = new(big.Int).Set(m[i][j])\n\t\t}\n\t}\n\n\treturn res\n}\n\n// JoinCols joins matrices m and other in a new Matrix\n// with columns from both matrices.\nfunc (m Matrix) JoinCols(other Matrix) (Matrix, error) {\n\tif m.Rows() != other.Rows() {\n\t\treturn nil, fmt.Errorf(\"dimensions do not fit\")\n\t}\n\n\tres := make(Matrix, m.Rows())\n\tfor i := 0; i < m.Rows(); i++ {\n\t\tres[i] = make(Vector, m.Cols()+other.Cols())\n\t\tfor j := 0; j < m.Cols()+other.Cols(); j++ {\n\t\t\tif j < m.Cols() {\n\t\t\t\tres[i][j] = new(big.Int).Set(m[i][j])\n\t\t\t} else {\n\t\t\t\tres[i][j] = new(big.Int).Set(other[i][j-m.Cols()])\n\t\t\t}\n\t\t}\n\t}\n\n\treturn res, nil\n}\n\n// JoinRows joins matrices m and other in a new Matrix\n// with rows from both matrices.\nfunc (m Matrix) JoinRows(other Matrix) (Matrix, error) {\n\tif m.Cols() != other.Cols() {\n\t\treturn nil, fmt.Errorf(\"dimensions do not fit\")\n\t}\n\n\tres := make(Matrix, m.Rows()+other.Rows())\n\tfor i := 0; i < res.Rows(); i++ {\n\t\tres[i] = make(Vector, m.Cols())\n\t\tfor j := 0; j < m.Cols(); j++ {\n\t\t\tif i < m.Rows() {\n\t\t\t\tres[i][j] = new(big.Int).Set(m[i][j])\n\t\t\t} else {\n\t\t\t\tres[i][j] = new(big.Int).Set(other[i-m.Rows()][j])\n\t\t\t}\n\t\t}\n\t}\n\n\treturn res, nil\n}\n\n// Identity returns the identity matrix with given dimensions.\nfunc Identity(rows, cols int) Matrix {\n\tres := NewConstantMatrix(rows, cols, big.NewInt(0))\n\tfor i := 0; i < rows && i < cols; i++ {\n\t\tres[i][i].SetInt64(1)\n\t}\n\n\treturn res\n}\n"
  },
  {
    "path": "data/matrix_bn256.go",
    "content": "package data\n\nimport (\n\t\"math/big\"\n\n\t\"github.com/fentec-project/bn256\"\n)\n\n// MatrixG1 wraps a slice of VectorG1 elements. It represents a row-major.\n// order matrix.\n//\n// The j-th element from the i-th vector of the matrix can be obtained\n// as m[i][j].\ntype MatrixG1 []VectorG1\n\n// Rows returns the number of rows of matrixG1 m.\nfunc (m MatrixG1) Rows() int {\n\treturn len(m)\n}\n\n// Cols returns the number of columns of matrixG1 m.\nfunc (m MatrixG1) Cols() int {\n\tif len(m) != 0 {\n\t\treturn len(m[0])\n\t}\n\n\treturn 0\n}\n\n// Add sums matrices m and other componentwise.\n// It returns the result in a new MatrixG1 instance.\nfunc (m MatrixG1) Add(other MatrixG1) MatrixG1 {\n\tsum := make(MatrixG1, len(m))\n\tfor i := range sum {\n\t\tsum[i] = m[i].Add(other[i])\n\t}\n\n\treturn sum\n}\n\n// MulScalar multiplies matrix m by a scalar s.\n// It returns the result in a new MatrixG1 instance.\nfunc (m MatrixG1) MulScalar(s *big.Int) MatrixG1 {\n\tout := make(MatrixG1, m.Rows())\n\tfor i := range out {\n\t\tout[i] = m[i].MulScalar(s)\n\t}\n\n\treturn out\n}\n\n// MulVector multiplies matrix m by a vector v, i.e if\n// m is t * [bn256.G1] for some matrix t, then the result\n// is (t * v) [bn256.G1]\nfunc (m MatrixG1) MulVector(v Vector) VectorG1 {\n\tout := make(VectorG1, m.Rows())\n\tfor i := range out {\n\t\tout[i] = new(bn256.G1).ScalarBaseMult(big.NewInt(0))\n\t\tfor k := 0; k < m.Cols(); k++ {\n\t\t\tmik := new(bn256.G1).Set(m[i][k])\n\t\t\tvk := new(big.Int).Set(v[k])\n\t\t\tif v[k].Sign() == -1 {\n\t\t\t\tvk.Neg(vk)\n\t\t\t\tmik.Neg(mik)\n\t\t\t}\n\t\t\ttmp := new(bn256.G1).ScalarMult(mik, vk)\n\t\t\tout[i].Add(tmp, out[i])\n\t\t}\n\t}\n\n\treturn out\n}\n\n// MatrixG2 wraps a slice of VectorG2 elements. It represents a row-major.\n// order matrix.\n//\n// The j-th element from the i-th vector of the matrix can be obtained\n// as m[i][j].\ntype MatrixG2 []VectorG2\n\n// Rows returns the number of rows of matrixG2 m.\nfunc (m MatrixG2) Rows() int {\n\treturn len(m)\n}\n\n// Cols returns the number of columns of matrixG2 m.\nfunc (m MatrixG2) Cols() int {\n\tif len(m) != 0 {\n\t\treturn len(m[0])\n\t}\n\n\treturn 0\n}\n\n// MulScalar multiplies matrix m by a scalar s\nfunc (m MatrixG2) MulScalar(s *big.Int) MatrixG2 {\n\tout := make(MatrixG2, m.Rows())\n\tfor i := range out {\n\t\tout[i] = m[i].MulScalar(s)\n\t}\n\n\treturn out\n}\n\n// MulVector multiplies matrix m by a vector v, i.e if\n// m is t * [bn256.G2] for some matrix t, then the result\n// is (t * v) [bn256.G2]\nfunc (m MatrixG2) MulVector(v Vector) VectorG2 {\n\tout := make(VectorG2, m.Rows())\n\tfor i := range out {\n\t\tout[i] = new(bn256.G2).ScalarBaseMult(big.NewInt(0))\n\t\tfor k := 0; k < m.Cols(); k++ {\n\t\t\tmik := new(bn256.G2).Set(m[i][k])\n\t\t\tvk := new(big.Int).Set(v[k])\n\t\t\tif v[k].Sign() == -1 {\n\t\t\t\tvk.Neg(vk)\n\t\t\t\tmik.Neg(mik)\n\t\t\t}\n\t\t\ttmp := new(bn256.G2).ScalarMult(mik, vk)\n\t\t\tout[i].Add(tmp, out[i])\n\t\t}\n\t}\n\n\treturn out\n}\n"
  },
  {
    "path": "data/matrix_test.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage data\n\nimport (\n\t\"math/big\"\n\t\"testing\"\n\n\t\"github.com/fentec-project/gofe/sample\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestMatrix(t *testing.T) {\n\trows, cols := 5, 3\n\tbound := new(big.Int).Exp(big.NewInt(2), big.NewInt(20), big.NewInt(0))\n\tsampler := sample.NewUniform(bound)\n\n\tx, err := NewRandomMatrix(rows, cols, sampler)\n\tif err != nil {\n\t\tt.Fatalf(\"Error during random generation: %v\", err)\n\t}\n\n\ty, err := NewRandomMatrix(rows, cols, sampler)\n\tif err != nil {\n\t\tt.Fatalf(\"Error during random generation: %v\", err)\n\t}\n\n\tadd, err := x.Add(y)\n\n\tif err != nil {\n\t\tt.Fatalf(\"Error during matrix addition: %v\", err)\n\t}\n\n\tmodulo := big.NewInt(int64(104729))\n\tmod := x.Mod(modulo)\n\n\tfor i := 0; i < rows; i++ {\n\t\tfor j := 0; j < cols; j++ {\n\t\t\tassert.Equal(t, new(big.Int).Add(x[i][j], y[i][j]), add[i][j], \"coordinates should sum correctly\")\n\t\t\tassert.Equal(t, new(big.Int).Mod(x[i][j], modulo), mod[i][j], \"coordinates should mod correctly\")\n\t\t}\n\t}\n\n\tsampler = sample.NewUniform(big.NewInt(256))\n\tvar key [32]byte\n\tfor i := range key {\n\t\tr, _ := sampler.Sample()\n\t\tkey[i] = byte(r.Int64())\n\t}\n\n\t_, err = NewRandomDetMatrix(100, 100, big.NewInt(5), &key)\n\tassert.Equal(t, err, nil)\n}\n\nfunc TestMatrix_Rows(t *testing.T) {\n\tm, _ := NewRandomMatrix(2, 3, sample.NewUniform(big.NewInt(10)))\n\tassert.Equal(t, 2, m.Rows())\n}\n\nfunc TestMatrix_Cols(t *testing.T) {\n\tm, _ := NewRandomMatrix(2, 3, sample.NewUniform(big.NewInt(10)))\n\tassert.Equal(t, 3, m.Cols())\n}\n\nfunc TestMatrix_Empty(t *testing.T) {\n\tvar m Matrix\n\tassert.Equal(t, 0, m.Rows())\n\tassert.Equal(t, 0, m.Cols())\n}\n\nfunc TestMatrix_DimsMatch(t *testing.T) {\n\tsampler := sample.NewUniform(big.NewInt(10))\n\tm1, _ := NewRandomMatrix(2, 3, sampler)\n\tm2, _ := NewRandomMatrix(2, 3, sampler)\n\tm3, _ := NewRandomMatrix(2, 4, sampler)\n\tm4, _ := NewRandomMatrix(3, 3, sampler)\n\n\tassert.True(t, m1.DimsMatch(m2))\n\tassert.False(t, m1.DimsMatch(m3))\n\tassert.False(t, m1.DimsMatch(m4))\n}\n\nfunc TestMatrix_CheckDims(t *testing.T) {\n\tsampler := sample.NewUniform(big.NewInt(10))\n\tm, _ := NewRandomMatrix(2, 2, sampler)\n\n\tassert.True(t, m.CheckDims(2, 2))\n\tassert.False(t, m.CheckDims(2, 3))\n\tassert.False(t, m.CheckDims(3, 2))\n\tassert.False(t, m.CheckDims(3, 3))\n}\n\nfunc TestMatrix_Dot(t *testing.T) {\n\tm1 := Matrix{\n\t\tVector{big.NewInt(1), big.NewInt(2)},\n\t\tVector{big.NewInt(3), big.NewInt(4)},\n\t}\n\tm2 := Matrix{\n\t\tVector{big.NewInt(4), big.NewInt(3)},\n\t\tVector{big.NewInt(2), big.NewInt(1)},\n\t}\n\tmismatched := Matrix{\n\t\tVector{big.NewInt(1), big.NewInt(2)},\n\t}\n\n\tdot, _ := m1.Dot(m2)\n\t_, err := m1.Dot(mismatched)\n\n\tassert.Equal(t, big.NewInt(20), dot, \"dot product of matrices does not work correctly\")\n\tassert.Error(t, err, \"expected an error to because of dimension mismatch\")\n}\n\nfunc TestMatrix_MulScalar(t *testing.T) {\n\tone := big.NewInt(1)\n\ttwo := big.NewInt(2)\n\tm := Matrix{\n\t\tVector{one, one, one},\n\t\tVector{one, one, one},\n\t}\n\tmTimesTwo := Matrix{\n\t\tVector{two, two, two},\n\t\tVector{two, two, two},\n\t}\n\n\tassert.Equal(t, m.MulScalar(two), mTimesTwo)\n}\n\nfunc TestMatrix_MulVec(t *testing.T) {\n\tm := Matrix{\n\t\tVector{big.NewInt(1), big.NewInt(2), big.NewInt(3)},\n\t\tVector{big.NewInt(4), big.NewInt(5), big.NewInt(6)},\n\t}\n\tv := Vector{big.NewInt(2), big.NewInt(2), big.NewInt(2)}\n\tvMismatched := Vector{big.NewInt(1)}\n\n\tmvExpected := Vector{big.NewInt(12), big.NewInt(30)}\n\tmv, _ := m.MulVec(v)\n\t_, err := m.MulVec(vMismatched)\n\n\tassert.Equal(t, mvExpected, mv, \"product of matrix and vector does not work correctly\")\n\tassert.Error(t, err, \"expected an error to because of dimension mismatch\")\n}\n\nfunc TestMatrix_Mul(t *testing.T) {\n\tm1 := Matrix{\n\t\tVector{big.NewInt(1), big.NewInt(2), big.NewInt(3)},\n\t\tVector{big.NewInt(4), big.NewInt(5), big.NewInt(6)},\n\t}\n\tm2 := Matrix{\n\t\tVector{big.NewInt(1), big.NewInt(2)},\n\t\tVector{big.NewInt(3), big.NewInt(4)},\n\t\tVector{big.NewInt(5), big.NewInt(6)},\n\t}\n\tmismatched := Matrix{Vector{big.NewInt(1)}}\n\n\tprodExpected := Matrix{\n\t\tVector{big.NewInt(22), big.NewInt(28)},\n\t\tVector{big.NewInt(49), big.NewInt(64)},\n\t}\n\tprod, _ := m1.Mul(m2)\n\t_, err := m1.Mul(mismatched)\n\n\tassert.Equal(t, prodExpected, prod, \"product of matrices does not work correctly\")\n\tassert.Error(t, err, \"expected an error to because of dimension mismatch\")\n}\n\nfunc TestMatrix_Determinant(t *testing.T) {\n\tm := Matrix{\n\t\tVector{big.NewInt(1), big.NewInt(1), big.NewInt(1)},\n\t\tVector{big.NewInt(4), big.NewInt(5), big.NewInt(6)},\n\t\tVector{big.NewInt(4), big.NewInt(4), big.NewInt(3)},\n\t}\n\tp := big.NewInt(7)\n\n\tdet1, err := m.Determinant()\n\tif err != nil {\n\t\tt.Fatalf(\"Error during computation of determinant: %v\", err)\n\t}\n\tdet1.Mod(det1, p)\n\n\tdet2, err := m.DeterminantGauss(p)\n\tif err != nil {\n\t\tt.Fatalf(\"Error during computation of determinant: %v\", err)\n\t}\n\n\tassert.Equal(t, det1, det2, \"computed determinants are not equal\")\n}\n\nfunc TestMatrix_InverseMod(t *testing.T) {\n\tm := Matrix{\n\t\tVector{big.NewInt(1), big.NewInt(1), big.NewInt(1)},\n\t\tVector{big.NewInt(4), big.NewInt(5), big.NewInt(6)},\n\t\tVector{big.NewInt(4), big.NewInt(4), big.NewInt(3)},\n\t}\n\tp := big.NewInt(7)\n\n\tmInv1, err := m.InverseMod(p)\n\tif err != nil {\n\t\tt.Fatalf(\"Error during computation of inverse: %v\", err)\n\t}\n\n\tmInv2, _, err := m.InverseModGauss(p)\n\tif err != nil {\n\t\tt.Fatalf(\"Error during computation of inverse: %v\", err)\n\t}\n\tfor i := 0; i < m.Rows(); i++ {\n\t\tfor j := 0; j < m.Cols(); j++ {\n\t\t\tassert.Equal(t, mInv1[i][j].Cmp(mInv2[i][j]), 0, \"computed inverses are not equal\")\n\t\t}\n\n\t}\n}\n\nfunc TestMatrix_GaussianElimintaion(t *testing.T) {\n\t// create instances mat, xTest and v for which mat * xTest = v\n\t// as a matrix vector multiplication over Z_p\n\tp := big.NewInt(17)\n\tsampler := sample.NewUniform(p)\n\tmat, err := NewRandomMatrix(100, 50, sampler)\n\tif err != nil {\n\t\tt.Fatalf(\"Error during matrix generation: %v\", err)\n\t}\n\n\txTest, err := NewRandomVector(50, sampler)\n\tif err != nil {\n\t\tt.Fatalf(\"Error during vector generation: %v\", err)\n\t}\n\n\tv, err := mat.MulVec(xTest)\n\tif err != nil {\n\t\tt.Fatalf(\"Error in generating a test vector: %v\", err)\n\t}\n\tv = v.Mod(p)\n\n\t// test the Gaussian elimination algorithm that given v and mat\n\t// finds x such that mat * x = v\n\tx, err := GaussianEliminationSolver(mat, v, p)\n\tif err != nil {\n\t\tt.Fatalf(\"Error in Gaussian elimination: %v\", err)\n\t}\n\n\t// test if the obtained x is correct\n\tvCheck, err := mat.MulVec(x)\n\tif err != nil {\n\t\tt.Fatalf(\"Error obtainig a check value: %v\", err)\n\t}\n\tvCheck = vCheck.Mod(p)\n\tassert.Equal(t, v, vCheck)\n\n\t// test if errors are returned if the inputs have a wrong form\n\tvWrong, err := NewRandomVector(101, sampler)\n\tif err != nil {\n\t\tt.Fatalf(\"Error during vector generation: %v\", err)\n\t}\n\t_, err = GaussianEliminationSolver(mat, vWrong, p)\n\tassert.Error(t, err)\n\n\tmatWrong := make(Matrix, 0)\n\t_, err = GaussianEliminationSolver(matWrong, v, p)\n\tassert.Error(t, err)\n}\n\nfunc TestMatrix_Tensor(t *testing.T) {\n\tm1 := Matrix{\n\t\tVector{big.NewInt(1), big.NewInt(2)},\n\t\tVector{big.NewInt(3), big.NewInt(4)},\n\t}\n\tm2 := Matrix{\n\t\tVector{big.NewInt(1), big.NewInt(2)},\n\t}\n\n\tprodExpected := Matrix{\n\t\tVector{big.NewInt(1), big.NewInt(2), big.NewInt(2), big.NewInt(4)},\n\t\tVector{big.NewInt(3), big.NewInt(6), big.NewInt(4), big.NewInt(8)},\n\t}\n\tprod := m1.Tensor(m2)\n\n\tassert.Equal(t, prodExpected, prod, \"tensor product of matrices does not work correctly\")\n}\n"
  },
  {
    "path": "data/vector.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage data\n\nimport (\n\t\"fmt\"\n\t\"math/big\"\n\n\t\"github.com/fentec-project/bn256\"\n\t\"github.com/fentec-project/gofe/sample\"\n\t\"golang.org/x/crypto/salsa20\"\n)\n\n// Vector wraps a slice of *big.Int elements.\ntype Vector []*big.Int\n\n// NewVector returns a new Vector instance.\nfunc NewVector(coordinates []*big.Int) Vector {\n\treturn Vector(coordinates)\n}\n\n// NewRandomVector returns a new Vector instance\n// with random elements sampled by the provided sample.Sampler.\n// Returns an error in case of sampling failure.\nfunc NewRandomVector(len int, sampler sample.Sampler) (Vector, error) {\n\tvec := make([]*big.Int, len)\n\tvar err error\n\n\tfor i := 0; i < len; i++ {\n\t\tvec[i], err = sampler.Sample()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\treturn NewVector(vec), nil\n}\n\n// NewRandomDetVector returns a new Vector instance\n// with (deterministic) random elements sampled by a pseudo-random\n// number generator. Elements are sampled from [0, max) and key\n// determines the pseudo-random generator.\nfunc NewRandomDetVector(len int, max *big.Int, key *[32]byte) (Vector, error) {\n\tif max.Cmp(big.NewInt(2)) < 0 {\n\t\treturn nil, fmt.Errorf(\"upper bound on samples should be at least 2\")\n\t}\n\n\tmaxBits := new(big.Int).Sub(max, big.NewInt(1)).BitLen()\n\tmaxBytes := (maxBits + 7) / 8\n\tover := uint((8 * maxBytes) - maxBits)\n\n\tlTimesMaxBytes := len * maxBytes\n\tnonce := make([]byte, 8) // nonce is initialized to zeros\n\tret := make([]*big.Int, len)\n\n\tfor i := 3; true; i++ {\n\t\tin := make([]byte, i*lTimesMaxBytes) // input is initialized to zeros\n\n\t\tout := make([]byte, i*lTimesMaxBytes)\n\n\t\tsalsa20.XORKeyStream(out, in, nonce, key)\n\n\t\tj := 0\n\t\tk := 0\n\t\tfor j < (i * lTimesMaxBytes) {\n\t\t\tout[j] = out[j] >> over\n\t\t\tret[k] = new(big.Int).SetBytes(out[j:(j + maxBytes)])\n\t\t\tif ret[k].Cmp(max) < 0 {\n\t\t\t\tk++\n\t\t\t}\n\t\t\tif k == len {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj += maxBytes\n\n\t\t}\n\t\tif k == len {\n\t\t\tbreak\n\t\t}\n\t}\n\n\treturn NewVector(ret), nil\n}\n\n// NewConstantVector returns a new Vector instance\n// with all elements set to constant c.\nfunc NewConstantVector(len int, c *big.Int) Vector {\n\tvec := make([]*big.Int, len)\n\tfor i := 0; i < len; i++ {\n\t\tvec[i] = new(big.Int).Set(c)\n\t}\n\n\treturn vec\n}\n\n// Copy creates a new vector with the same values\n// of the entries.\nfunc (v Vector) Copy() Vector {\n\tnewVec := make(Vector, len(v))\n\n\tfor i, c := range v {\n\t\tnewVec[i] = new(big.Int).Set(c)\n\t}\n\n\treturn newVec\n}\n\n// MulScalar multiplies vector v by a given scalar x.\n// The result is returned in a new Vector.\nfunc (v Vector) MulScalar(x *big.Int) Vector {\n\tres := make(Vector, len(v))\n\tfor i, vi := range v {\n\t\tres[i] = new(big.Int).Mul(x, vi)\n\t}\n\n\treturn res\n}\n\n// Mod performs modulo operation on vector's elements.\n// The result is returned in a new Vector.\nfunc (v Vector) Mod(modulo *big.Int) Vector {\n\tnewCoords := make([]*big.Int, len(v))\n\n\tfor i, c := range v {\n\t\tnewCoords[i] = new(big.Int).Mod(c, modulo)\n\t}\n\n\treturn NewVector(newCoords)\n}\n\n// CheckBound checks whether the absolute values of all vector elements\n// are strictly smaller than the provided bound.\n// It returns error if at least one element's absolute value is >= bound.\nfunc (v Vector) CheckBound(bound *big.Int) error {\n\tabs := new(big.Int)\n\tfor _, c := range v {\n\t\tabs.Abs(c)\n\t\tif abs.Cmp(bound) > 0 {\n\t\t\treturn fmt.Errorf(\"all coordinates of a vector should not be greater than bound\")\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// Apply applies an element-wise function f to vector v.\n// The result is returned in a new Vector.\nfunc (v Vector) Apply(f func(*big.Int) *big.Int) Vector {\n\tres := make(Vector, len(v))\n\n\tfor i, vi := range v {\n\t\tres[i] = f(vi)\n\t}\n\n\treturn res\n}\n\n// Neg returns -v for given vector v.\n// The result is returned in a new Vector.\nfunc (v Vector) Neg() Vector {\n\tneg := make([]*big.Int, len(v))\n\tfor i, c := range v {\n\t\tneg[i] = new(big.Int).Neg(c)\n\t}\n\n\treturn neg\n}\n\n// Add adds vectors v and other.\n// The result is returned in a new Vector.\nfunc (v Vector) Add(other Vector) Vector {\n\tsum := make([]*big.Int, len(v))\n\n\tfor i, c := range v {\n\t\tsum[i] = new(big.Int).Add(c, other[i])\n\t}\n\n\treturn NewVector(sum)\n}\n\n// Sub subtracts vectors v and other.\n// The result is returned in a new Vector.\nfunc (v Vector) Sub(other Vector) Vector {\n\tsub := make([]*big.Int, len(v))\n\tfor i, c := range v {\n\t\tsub[i] = new(big.Int).Sub(c, other[i])\n\t}\n\n\treturn sub\n}\n\n// Dot calculates the dot product (inner product) of vectors v and other.\n// It returns an error if vectors have different numbers of elements.\nfunc (v Vector) Dot(other Vector) (*big.Int, error) {\n\tprod := big.NewInt(0)\n\n\tif len(v) != len(other) {\n\t\treturn nil, fmt.Errorf(\"vectors should be of same length\")\n\t}\n\n\tfor i, c := range v {\n\t\tprod = prod.Add(prod, new(big.Int).Mul(c, other[i]))\n\t}\n\n\treturn prod, nil\n}\n\n// MulAsPolyInRing multiplies vectors v and other as polynomials\n// in the ring of polynomials R = Z[x]/((x^n)+1), where n is length of\n// the vectors. Note that the input vector [1, 2, 3] represents a\n// polynomial Z[x] = x²+2x+3.\n// It returns a new polynomial with degree <= n-1.\n//\n// If vectors differ in size, error is returned.\nfunc (v Vector) MulAsPolyInRing(other Vector) (Vector, error) {\n\tif len(v) != len(other) {\n\t\treturn nil, fmt.Errorf(\"vectors must have the same length\")\n\t}\n\tn := len(v)\n\n\t// Result will be a polynomial with the degree <= n-1\n\tprod := new(big.Int)\n\tres := make(Vector, n)\n\n\t// Over all degrees, beginning at lowest degree\n\tfor i := 0; i < n; i++ {\n\t\tres[i] = big.NewInt(0)\n\t\t// Handle products with degrees < n\n\t\tfor j := 0; j <= i; j++ {\n\t\t\tprod.Mul(v[i-j], other[j]) // Multiply coefficients\n\t\t\tres[i].Add(res[i], prod)\n\t\t}\n\t\t// Handle products with degrees >= n\n\t\tfor j := i + 1; j < n; j++ {\n\t\t\tprod.Mul(v[n+i-j], other[j]) // Multiply coefficients\n\t\t\tprod.Neg(prod)               // Negate, because x^n = -1\n\t\t\tres[i].Add(res[i], prod)\n\t\t}\n\t}\n\n\treturn res, nil\n}\n\n// MulG1 calculates bn256.G1 * v (also g1^v in multiplicative notation)\n// and returns the result (v[0] * bn256.G1, ... , v[n-1] * bn256.G1) in a\n// VectorG1 instance.\nfunc (v Vector) MulG1() VectorG1 {\n\tprod := make(VectorG1, len(v))\n\tfor i := range prod {\n\t\tvi := new(big.Int).Abs(v[i])\n\t\tprod[i] = new(bn256.G1).ScalarBaseMult(vi)\n\t\tif v[i].Sign() == -1 {\n\t\t\tprod[i].Neg(prod[i])\n\t\t}\n\t}\n\n\treturn prod\n}\n\n// MulVecG1 calculates g1 * v (also g1^v in multiplicative notation)\n// and returns the result (v[0] * g1[0], ... , v[n-1] * g1[n-1]) in a\n// VectorG1 instance.\nfunc (v Vector) MulVecG1(g1 VectorG1) VectorG1 {\n\tzero := big.NewInt(0)\n\n\tprod := make(VectorG1, len(v))\n\tfor i := range prod {\n\t\tvi := new(big.Int).Set(v[i])\n\t\tg1i := new(bn256.G1).Set(g1[i])\n\t\tif vi.Cmp(zero) == -1 {\n\t\t\tg1i.Neg(g1i)\n\t\t\tvi.Neg(vi)\n\t\t}\n\t\tprod[i] = new(bn256.G1).ScalarMult(g1i, vi)\n\t}\n\n\treturn prod\n}\n\n// MulG2 calculates bn256.G2 * v (also g2^v in multiplicative notation)\n// and returns the result (v[0] * bn256.G2, ... , v[n-1] * bn256.G2) in a\n// VectorG2 instance.\nfunc (v Vector) MulG2() VectorG2 {\n\tprod := make(VectorG2, len(v))\n\tfor i := range prod {\n\t\tvi := new(big.Int).Abs(v[i])\n\t\tprod[i] = new(bn256.G2).ScalarBaseMult(vi)\n\t\tif v[i].Sign() == -1 {\n\t\t\tprod[i].Neg(prod[i])\n\t\t}\n\t}\n\n\treturn prod\n}\n\n// MulVecG2 calculates g2 * v (also g2^v in multiplicative notation)\n// and returns the result (v[0] * g2[0], ... , v[n-1] * g2[n-1]) in a\n// VectorG2 instance.\nfunc (v Vector) MulVecG2(g2 VectorG2) VectorG2 {\n\tzero := big.NewInt(0)\n\n\tprod := make(VectorG2, len(v))\n\tfor i := range prod {\n\t\tvi := new(big.Int).Set(v[i])\n\t\tg2i := new(bn256.G2).Set(g2[i])\n\t\tif vi.Cmp(zero) == -1 {\n\t\t\tg2i.Neg(g2i)\n\t\t\tvi.Neg(vi)\n\t\t}\n\t\tprod[i] = new(bn256.G2).ScalarMult(g2i, vi)\n\t}\n\n\treturn prod\n}\n\n// String produces a string representation of a vector.\nfunc (v Vector) String() string {\n\tvStr := \"\"\n\tfor _, yi := range v {\n\t\tvStr = vStr + \" \" + yi.String()\n\t}\n\treturn vStr\n}\n\n// Tensor creates a tensor product of vectors v and other.\n// The result is returned in a new Vector.\nfunc (v Vector) Tensor(other Vector) Vector {\n\tprod := make(Vector, len(v)*len(other))\n\tfor i := 0; i < len(prod); i++ {\n\t\tprod[i] = new(big.Int).Mul(v[i/len(other)], other[i%len(other)])\n\t}\n\n\treturn prod\n}\n"
  },
  {
    "path": "data/vector_bn256.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage data\n\nimport (\n\t\"math/big\"\n\n\t\"github.com/fentec-project/bn256\"\n)\n\n// VectorG1 wraps a slice of elements from elliptic curve BN256.G1 group.\ntype VectorG1 []*bn256.G1\n\n// Add sums vectors v1 and v2 (also v1 * v2 in multiplicative notation).\n// It returns the result in a new VectorG1 instance.\nfunc (v VectorG1) Add(other VectorG1) VectorG1 {\n\tsum := make(VectorG1, len(v))\n\tfor i := range sum {\n\t\tsum[i] = new(bn256.G1).Add(v[i], other[i])\n\t}\n\n\treturn sum\n}\n\n// Neg returns a new VectorG1 instance with\n// values -v in the additive notation.\nfunc (v VectorG1) Neg() VectorG1 {\n\tneg := make(VectorG1, len(v))\n\tfor i := range neg {\n\t\tneg[i] = new(bn256.G1).Neg(v[i])\n\t}\n\n\treturn neg\n}\n\n// Copy produces a new copy of vector v.\nfunc (v VectorG1) Copy() VectorG1 {\n\tcp := make(VectorG1, len(v))\n\tfor i := range cp {\n\t\tcp[i] = new(bn256.G1).Set(v[i])\n\t}\n\n\treturn cp\n}\n\n// MulScalar multiplies s * v (in additive notation).\nfunc (v VectorG1) MulScalar(s *big.Int) VectorG1 {\n\tsTmp := new(big.Int).Set(s)\n\tout := v.Copy()\n\tif s.Sign() == -1 {\n\t\tsTmp.Neg(s)\n\t\tout = out.Neg()\n\t}\n\n\tfor i := range out {\n\t\tout[i].ScalarMult(out[i], sTmp)\n\t}\n\n\treturn out\n}\n\n// VectorG2 wraps a slice of elements from elliptic curve BN256.G2 group.\ntype VectorG2 []*bn256.G2\n\n// Add sums vectors v1 and v2 (also v1 * v2 in multiplicative notation).\n// It returns the result in a new VectorG2 instance.\nfunc (v VectorG2) Add(other VectorG2) VectorG2 {\n\tsum := make(VectorG2, len(v))\n\tfor i := range sum {\n\t\tsum[i] = new(bn256.G2).Add(v[i], other[i])\n\t}\n\n\treturn sum\n}\n\n// Neg returns a new VectorG1 instance with\n// values -v in the additive notation.\nfunc (v VectorG2) Neg() VectorG2 {\n\tneg := make(VectorG2, len(v))\n\tfor i := range neg {\n\t\tneg[i] = new(bn256.G2).Neg(v[i])\n\t}\n\n\treturn neg\n}\n\n// Copy produces a new copy of vector v.\nfunc (v VectorG2) Copy() VectorG2 {\n\tcp := make(VectorG2, len(v))\n\tfor i := range cp {\n\t\tcp[i] = new(bn256.G2).Set(v[i])\n\t}\n\n\treturn cp\n}\n\n// MulScalar multiplies s * v (in additive notation).\nfunc (v VectorG2) MulScalar(s *big.Int) VectorG2 {\n\tsTmp := new(big.Int).Set(s)\n\tout := v.Copy()\n\tif s.Sign() == -1 {\n\t\tsTmp.Neg(s)\n\t\tout = out.Neg()\n\t}\n\n\tfor i := range out {\n\t\tout[i].ScalarMult(out[i], sTmp)\n\t}\n\n\treturn out\n}\n\n// VectorGT wraps a slice of elements from pairing BN256.GT group.\ntype VectorGT []*bn256.GT\n\n// Dot multiplies v = (v_1,...,v_n) and other = (o_1,...,o_n) to\n// return v1 * o_1 + ... + v_n *o_n (in additive notation)\nfunc (v VectorGT) Dot(other Vector) *bn256.GT {\n\tprod := new(bn256.GT).ScalarBaseMult(big.NewInt(0))\n\n\tfor i, c := range v {\n\t\tprod.Add(prod, new(bn256.GT).ScalarMult(c, other[i]))\n\t}\n\n\treturn prod\n}\n"
  },
  {
    "path": "data/vector_test.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage data\n\nimport (\n\t\"math/big\"\n\t\"testing\"\n\n\t\"github.com/fentec-project/gofe/sample\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestVector(t *testing.T) {\n\tl := 3\n\tbound := new(big.Int).Exp(big.NewInt(2), big.NewInt(20), big.NewInt(0))\n\tsampler := sample.NewUniform(bound)\n\n\tx, err := NewRandomVector(l, sampler)\n\tif err != nil {\n\t\tt.Fatalf(\"Error during random generation: %v\", err)\n\t}\n\n\ty, err := NewRandomVector(l, sampler)\n\tif err != nil {\n\t\tt.Fatalf(\"Error during random generation: %v\", err)\n\t}\n\n\tadd := x.Add(y)\n\tmul, err := x.Dot(y)\n\n\tif err != nil {\n\t\tt.Fatalf(\"Error during vector multiplication: %v\", err)\n\t}\n\n\tmodulo := int64(104729)\n\tmod := x.Mod(big.NewInt(modulo))\n\n\tinnerProd := big.NewInt(0)\n\tfor i := 0; i < 3; i++ {\n\t\tassert.Equal(t, new(big.Int).Add(x[i], y[i]), add[i], \"coordinates should sum correctly\")\n\t\tinnerProd = innerProd.Add(innerProd, new(big.Int).Mul(x[i], y[i]))\n\t\tassert.Equal(t, new(big.Int).Mod(x[i], big.NewInt(modulo)), mod[i], \"coordinates should mod correctly\")\n\t}\n\n\tassert.Equal(t, innerProd, mul, \"inner product should calculate correctly\")\n\n\tsampler = sample.NewUniform(big.NewInt(256))\n\tvar key [32]byte\n\tfor i := range key {\n\t\tr, _ := sampler.Sample()\n\t\tkey[i] = byte(r.Int64())\n\t}\n\n\t_, err = NewRandomDetVector(100, big.NewInt(5), &key)\n\tassert.Equal(t, err, nil)\n}\n\nfunc TestVector_MulAsPolyInRing(t *testing.T) {\n\tp1 := Vector{big.NewInt(0), big.NewInt(1), big.NewInt(2)}\n\tp2 := Vector{big.NewInt(2), big.NewInt(1), big.NewInt(0)}\n\tprod, _ := p1.MulAsPolyInRing(p2)\n\n\tassert.Equal(t, prod, Vector{big.NewInt(-2), big.NewInt(2), big.NewInt(5)})\n}\n\nfunc TestVecor_Tensor(t *testing.T) {\n\tv1 := Vector{big.NewInt(1), big.NewInt(2)}\n\n\tv2 := Vector{big.NewInt(1), big.NewInt(2)}\n\n\tprodExpected := Vector{big.NewInt(1), big.NewInt(2), big.NewInt(2), big.NewInt(4)}\n\tprod := v1.Tensor(v2)\n\n\tassert.Equal(t, prodExpected, prod, \"tensor product of vectors does not work correctly\")\n}\n"
  },
  {
    "path": "doc.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// Package gofe provides implementations of functional encryption\n// schemes for linear and quadratic polynomials.\npackage gofe\n"
  },
  {
    "path": "go.mod",
    "content": "module github.com/fentec-project/gofe\n\ngo 1.17\n\nrequire (\n\tgithub.com/fentec-project/bn256 v0.0.0-20190726093940-0d0fc8bfeed0\n\tgithub.com/pkg/errors v0.9.1\n\tgithub.com/stretchr/testify v1.7.0\n\tgolang.org/x/crypto v0.0.0-20211115234514-b4de73f9ece8\n)\n\nrequire (\n\tgithub.com/davecgh/go-spew v1.1.0 // indirect\n\tgithub.com/pmezard/go-difflib v1.0.0 // indirect\n\tgolang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 // indirect\n\tgopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect\n)\n"
  },
  {
    "path": "go.sum",
    "content": "github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=\ngithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/fentec-project/bn256 v0.0.0-20190726093940-0d0fc8bfeed0 h1:mkWVpEiA+MMlWxElUXRqTVSH9eETZvqJ21NZTaDaMiI=\ngithub.com/fentec-project/bn256 v0.0.0-20190726093940-0d0fc8bfeed0/go.mod h1:llEBqR6SDQxLj2lH10BjIYPrcoqDAFv6mhsqvHfIzlI=\ngithub.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=\ngithub.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=\ngithub.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngolang.org/x/crypto v0.0.0-20211115234514-b4de73f9ece8 h1:5QRxNnVsaJP6NAse0UdkRgL3zHMvCRRkrDVLNdNpdy4=\ngolang.org/x/crypto v0.0.0-20211115234514-b4de73f9ece8/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=\ngolang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=\ngolang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4=\ngolang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=\ngolang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=\ngopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\n"
  },
  {
    "path": "innerprod/doc.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// Package innerprod includes functional encryption schemes for inner\n// products.\n//\n// Based on security assumptions, the schemes are organized into\n// subpackages simple (s-IND-CPA security), and fullysec\n// (e.g. \"fully secure\", offering adaptive IND-CPA security).\n//\n// Note that in both packages you will find single input as\n// well as multi input schemes. Construction of all multi input\n// schemes is based on the work of Abdalla et. al (see paper:\n// https://eprint.iacr.org/2017/972.pdf)\npackage innerprod\n"
  },
  {
    "path": "innerprod/fullysec/damgard.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage fullysec\n\nimport (\n\t\"fmt\"\n\t\"math/big\"\n\n\t\"github.com/fentec-project/gofe/data\"\n\t\"github.com/fentec-project/gofe/internal\"\n\t\"github.com/fentec-project/gofe/internal/dlog\"\n\t\"github.com/fentec-project/gofe/internal/keygen\"\n\t\"github.com/fentec-project/gofe/sample\"\n)\n\n// DamgardParams includes public parameters for the Damgard inner\n// product scheme.\n// L (int): The length of vectors to be encrypted.\n// Bound (int): The value by which coordinates of vectors x and y are bounded.\n// G (int): Generator of a cyclic group Z_P: G**(Q) = 1 (mod P).\n// H (int): Generator of a cyclic group Z_P: H**(Q) = 1 (mod P).\n// P (int): Modulus - we are operating in a cyclic group Z_P.\n// Q (int): Multiplicative order of G and H.\ntype DamgardParams struct {\n\tL     int\n\tBound *big.Int\n\tG     *big.Int\n\tH     *big.Int\n\tP     *big.Int\n\tQ     *big.Int\n}\n\n// Damgard represents a scheme instantiated from the DDH assumption\n// based on DDH variant of:\n// Agrawal, Shweta, Libert, and Stehle:\n// \"Fully secure functional encryption for inner products,\n// from standard assumptions\".\ntype Damgard struct {\n\tParams *DamgardParams\n}\n\n// NewDamgard configures a new instance of the scheme.\n// It accepts the length of input vectors l, the bit length of the\n// modulus (we are operating in the Z_p group), and a bound by which\n// coordinates of input vectors are bounded.\n//\n// It returns an error in case the scheme could not be properly\n// configured, or if precondition l * bound² is >= order of the cyclic\n// group.\nfunc NewDamgard(l, modulusLength int, bound *big.Int) (*Damgard, error) {\n\tkey, err := keygen.NewElGamal(modulusLength)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tzero := big.NewInt(0)\n\tone := big.NewInt(1)\n\ttwo := big.NewInt(2)\n\n\tbSquared := new(big.Int).Exp(bound, two, nil)\n\tprod := new(big.Int).Mul(big.NewInt(int64(2*l)), bSquared)\n\tif prod.Cmp(key.Q) > 0 {\n\t\treturn nil, fmt.Errorf(\"2 * l * bound^2 should be smaller than group order\")\n\t}\n\n\th := new(big.Int)\n\tfor {\n\t\tsampler := sample.NewUniformRange(two, key.Q)\n\t\tr, err := sampler.Sample()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\t// h generated in the following way is always a generator with order q\n\t\th.Exp(key.G, r, key.P)\n\n\t\t// additional checks to avoid some known attacks\n\t\tif new(big.Int).Mod(new(big.Int).Sub(key.P, one), h).Cmp(zero) == 0 {\n\t\t\tcontinue\n\t\t}\n\t\thInv := new(big.Int).ModInverse(h, key.P)\n\t\tif new(big.Int).Mod(new(big.Int).Sub(key.P, one), hInv).Cmp(zero) == 0 {\n\t\t\tcontinue\n\t\t}\n\t\tbreak\n\t}\n\n\treturn &Damgard{\n\t\tParams: &DamgardParams{\n\t\t\tL:     l,\n\t\t\tBound: bound,\n\t\t\tG:     key.G,\n\t\t\tH:     h,\n\t\t\tP:     key.P,\n\t\t\tQ:     key.Q,\n\t\t},\n\t}, nil\n}\n\n// NewDamgardPrecomp configures a new instance of the scheme based on\n// precomputed prime numbers and generators.\n// It accepts the length of input vectors l, the bit length of the\n// modulus (we are operating in the Z_p group), and a bound by which\n// coordinates of input vectors are bounded. The modulus length should\n// be one of values 1024, 1536, 2048, 2560, 3072, or 4096. The precomputed\n// prime numbers and generators were simply obtained by running NewDamgard\n// function.\n//\n// It returns an error in case the scheme could not be properly\n// configured, or if precondition l * bound² is >= order of the cyclic\n// group.\nfunc NewDamgardPrecomp(l, modulusLength int, bound *big.Int) (*Damgard, error) {\n\tone := big.NewInt(1)\n\ttwo := big.NewInt(2)\n\tg := new(big.Int)\n\th := new(big.Int)\n\tp := new(big.Int)\n\n\tif modulusLength == 1024 {\n\t\tg.SetString(\"34902160241479276675539633849372382885917193816560610471607073855548755350834003692485735908635894317735639518678334280193650806072183057417077181724192674928134805218882803812978345229222559213790765817899845072682155064387311523738581388872686127675360979304234957611566801734164757915959042140104663977828\", 10)\n\t\th.SetString(\"15420637599119437909472314391464117244272797175081469344935256550115202257944676665553901111021364396888996244331294748348639524453606317448549098209774792643437849812948134158610698367936877182339463164515756739059909678247548635902607622196992717889883047826579537373927574110724167611850755082659113353814\", 10)\n\t\tp.SetString(\"166211269243229118758738154756726384542659478479960313411107431885216572625212662756677338184675400324411541201832214281445670912135683272416408753424543622705770319923251281963485084208425069817917631106045349238686234860629044433560424091289406000897029571960128048529362925472176997104870527051276406995203\", 10)\n\t} else if modulusLength == 1536 {\n\t\tg.SetString(\"676416913692519694440150163403654362412279108516867264953779609011365998625435399420336578530015558254310139891236630566729665914687641028600402606957815727025192669238117788115237116562468680376464346714542467465836552396661693422160454402926392749202926871877212792118140354124110927269910674002861908621272286950597240072605316784317536178700101838123530590145680002962405974024190384775185108002307650499125333676880320808656556635493186351335151559453463208\", 10)\n\t\th.SetString(\"162435356591098080112923949933138473281129080012462876365242296621510003247926800168810467125425312741356845555051398168995345221821254788094709212569083281560861934370026731898947082535853089500762419810631794616608702382341836751059467526394750733484031555507059435514454850206195181859188711511695415306637351122791298103837179337333322817996915750092675310561842474481585085713281105392293555407844591189296291324552036671109998940504540100161197823599243891\", 10)\n\t\tp.SetString(\"1851297899986638926486011430658634631676522135433726749065856232802142091866650774719879427474637700607873256035038534449089405369134066444876856913629831069906506096279113968447116822488133963417347136141052507685108634240736100862550194947326287783557220764070479431781692630708747550712729778398000353165406458520850089303530985563143326919073190605085889925484113854496074216626577246143598303709289292397203458923541841135799203967503522114881404128535647507\", 10)\n\t} else if modulusLength == 2048 {\n\t\tg.SetString(\"4006960929413042209594165215465319088439374252008797022450541422457034721098828647078778605657155669917104962611933792130890703423519992986737966991597160684973795472419962788730248050852176194215699504914899438223683843401963466624139534923052671383315398134823370041633710463630745156269175253639670460050105594663691338308037509280576148624454011047879615100156717631945194107791315234171086603775159708325087759679758438868772220133433497821899045165244202228696902434100209752952701657306825368599999359102329396520012735146260911352901326915877502873633420811221206110021993351144711002138373506576799781061829\", 10)\n\t\th.SetString(\"16531397285674350767314702525644915041456240916042269006661016218466751820121367708744665988146094312460459686332899317211264306268688887145182608791297975910105233621322826639428591684097281721326762853220049531036892964645338402521408932284623118973840687103995270506055864839392780688919921574729334863152272712825111303515621796552988450890438067795005159750945818303100847992123152427222482913524403644261704298722743429153705746979942035168013929376597721413830914117313871470498590418693493905967182265847426629997026054543887503362398742858491325979767814095393383666927420156454285653125386823358683247619671\", 10)\n\t\tp.SetString(\"28884237504713658990682089080899862128005980675308910325841161962760155725037929764087367167449843609136681034352509183117742758446654629096509285354423361556493020266963222508540306384896802796001914743293196010488452478370041404523014215612960481024232879327123268440037633547483165934132901270561772860319969916305482525766132307669097012989986613879246932730824899649301621408341438037745468033187743673001187803377254713546325789438300798311106106322698517805307792059495696632070953526611920926003483451787562399452650878943515646786958216714025307572678422373120397225912926110031401983688860264234966561627699\", 10)\n\t} else if modulusLength == 2560 {\n\t\tg.SetString(\"283408881721750179985507845260248881237898607313021593637913985490973593382472548378053368228310040484438920416918021737085067966444840449068073874437662089659563355479608930182263107110969154912883370207053052795964658868443319273167870311282045348396320159912742394374241864712808383029954025256232806465551969466207671603658677963161975454703127476120201164519187150268352527923664649275471494757270139533433456630363925187498055211365480086561354743681517539297815712218419607006668655891574362066382949706266666189227897710299445185100212256741698216505337617571970963008519334554537811591236478130526432239803909461119767954934793813410765013072006162612226471775059215628326278458577643374735250370115470812597459244082296191871275203831471332697557979904062571849\", 10)\n\t\th.SetString(\"60603226626244984946015074611399313803245697048858823305998791050960516381707120286785720252208953282756722645401890645185550185014757676697220190895358672768431707069471110996253922983573984124316810681408685350886144002884260922773441021522086311309748129811838078781339054390074111039635714653119513182362870864625376495724028601281359016299631376501745572486338940082085075668612842777510700862160795716160806125722301037965086971367697165162183431144060195434995026056781565232838274115314469024436666926374971029865332455354830888647688402585402990945621351542202067894748432776518006655843916388537951718725340446233164828852013369347111758769617449735121060447630493643403400643959220152005725907208460642317320745167072023561550218217956652950353398499254599742\", 10)\n\t\tp.SetString(\"403126381462544353337185732949672984701995200694926494258456907009253008321275627278199160008680481542251933923210212978304159426174307419863781623411302777276318286800690060166638633211627521530173324015527027650548199185539205697958056639406116068885574865579676651743820636201007864067569576455725489531113260031526605827601510665037511961715114944815619491261828558745083975042855063688267346905844510423020844412350570902289599734320004108557140241966071165594059732527795488131297017205383953304055105007982366596746708951250486384299368612656872813778220074826250625689603663742175288397398948456522281031888042417278385238985218731264092285591879578299600853004336936458454638992426900228708418575870946630137618851131144232868141478901063119847104013555395370887\", 10)\n\t} else if modulusLength == 3072 {\n\t\tg.SetString(\"3696261717511684685041982088526264061294500298114921057816954458306445697150348237912729036967670872345042594238223317055749478029025374644864924550052402546275985983344583674703146236623453822520422465163020824494790581472736649085281450730460445260696087738043872307629635997875332076478424042345012004769107421873566499123042621978973433575500345010912635742477932006291250637245855027695943163956584173316781442078828050076620331751405548730676363847526959436516279320074682721438642683731766682502490935962962293815202487144775533102010333956118641968798500514719248831145108532912211817219793191951880318961073149276914867129023978524587935704313755469570162971499124682746476415187933097132047611840762510892175328320025164466873845777990557296853549970943298347924080102740724512079409979152285019931666423541870247789529268168448010024121369388707140296446100906359619586133848407970098685310317291828335700424602208\", 10)\n\t\th.SetString(\"567649039783047480227338473928434756096941793851205367034019596755160950347349183458824085567577717539018304618223485608741105961797110596645149404693961630602136531678036354529574048049387247758318737991227930011620451360293879761672154747784975220369021073972313352929486325631485787131058176462649454317449501920846554754923439009414476391939400343349482311343015897922534760972817588470659148393369453541539857229554365836585067664597417625404552690944486027240221141785988408230137708791844568226402922187996696503785944931820332617839757682381094642917330498053626106798012177968190876620737530689308284333593333125689734905825145119037797011061634852469676220493758348073580817216823443614368951436342741042435481507815482798733572408751161565276006768858533125203508129436766572987021821650216162035709837972268600512594452400036134765839973589301700524293661567605165762293059122431279400652446300525682001019196136\", 10)\n\t\tp.SetString(\"4387756306134544957818467663802660683665166110605728231080818705443663402154316615145921798856363268744945754470238000282108344905251127487705736550297997444150840902348669718478564904142834154197029830975532074167513046443903186309497214496864577129616824062991068960005865144004932069025136224356325248036029606434443391988386519658751798077031844645051726026696307027395796695909035405241040411794836124123435225690961994089776517262574417789067836840997650095451062948856617211542724543995145259735683916440579956961657374517806591607068842498749297993409884001044324428640569001916341503645559748760311343179943896427393009949062735145363544745972252566600994034655540841225414736222780096833045470605544717177880459300618917961703559234544541206877026518430276932498602360341258899345739335298856394124351357206871568254540730107127298623178526868418799471896060015463201459762913197633841160710893895836663035998106119\", 10)\n\t} else if modulusLength == 4096 {\n\t\tg.SetString(\"51665588681810560577916524923861643358980285220048008212528567741884121491554604183472728540139463099618903178110360757930742372390027135064809646425064896539133721148335557788263239281487173350543811713890328584918216783142094297306639941000480756707312457878765754357205186485080839623690156744636468433787780205323460166423447602447200754978133176713947189000663528355089645281397174452923418212485422962705227706103188302892660448134233848971142570881089940852441776074246332915421265800026335300100610273942459340241610730244726628211914068945587128124478812632725838440727321816905181830592204023095726270782834020990986443265625389712733369116937470448592846480352222814297792606318850361699893703272484112273500581408730519942517586496563772194165844831300501908379990979449691597045730512107756238377635183257797115883839801779086058652272455400286891699445584526719648220045380141260347316315487340493029966105973850214850475440630205768783542021741101804842248602349004364816943429122368563644935802417389995380389429997320053299323220481603252879925927515844929958940305561718295197935926645561977544440676439150126025681320050786964708227836328341875446457912905977470123640014345655062829575775837287500880054558386787\", 10)\n\t\th.SetString(\"653735051824112393106801492829043654983094810153936916566419297234893790474265474662670688710073348877202869152643983800310336936407217572878666006904653566429370273243928900524622200126090143285935697025102272467307580256707629199315519492688020243538476473287317884073943557740453015512750672402070439254723909940895097629630953500504933411614006835509266155433485165683944804036549172274160941459059251790260424550107135346982158930124883878553492540634625536558325828876220292338217093182644187426663586499630969144324838282516931412124575753931891717246058395623268249929461243359978135742469252500443989584744702727780893623276815417727584978028391169715443458364712495037724857002997953369015075369014382917440895283545982020768248209480534141352756164681807291197719347396848885385564846533227145898299352065862788210851139899108807494649254246247909836864209696565581846420881131639054554828603682225473062422081030815891806059849482326467150974089876248055494734946134244334370720707623963134127685862797676223995758737312498339183154611067568296397353652230198967761004520297654249905695573112921297631619886554083093006856350790194488256889122557656064371766221432744243315870629759094828247037312561620044735468234281300\", 10)\n\t\tp.SetString(\"1022249395832567838406986294560330159176972202126664245047364146720891252715766488477689126342364655087193411078517616569887825896401401223927363505007778278205623713273194552498760148834874746839752870298152746450585455651115247220867383465863156721401567161663838310658875672995951663020449772454232797368263754624173026584111779206080723120076751471597509403139249260220696195263597156452889920392585797464801375940661326779247976331028637271512085826066667631423502199894046717721786935806581428328491087482664043743281068318459302242239861275878019857365021173868449409246193470959347916848019032536247915451026158871684654213802886886213841729258073333569276986893577214659899227179735448593265633219968622571880602115519942763955551007919826002851866939641065270816032435114864853636918330698605282572789904941484540512478406984407320963402583009124880812235841866246441862987563989772424040933513333746472128494254253767426962063553015635240386636751473945937412527996558505231385625318878887383161350102080329744822052478052004574860361461762694379860797225344866320388590336321515376486033237159694567932935601775209663052272120524337888258857351777348841323194553467226791591208931619058871750498804369190487499494069660723\", 10)\n\t} else {\n\t\treturn nil, fmt.Errorf(\"modulus length should be one of values 1024, 1536, 2048, 2560, 3072, or 4096\")\n\t}\n\n\tq := new(big.Int).Sub(p, one)\n\tq.Div(q, two)\n\n\tbSquared := new(big.Int).Exp(bound, two, nil)\n\tprod := new(big.Int).Mul(big.NewInt(int64(2*l)), bSquared)\n\tif prod.Cmp(q) > 0 {\n\t\treturn nil, fmt.Errorf(\"2 * l * bound^2 should be smaller than group order\")\n\t}\n\n\treturn &Damgard{\n\t\tParams: &DamgardParams{\n\t\t\tL:     l,\n\t\t\tBound: bound,\n\t\t\tG:     g,\n\t\t\tH:     h,\n\t\t\tP:     p,\n\t\t\tQ:     q,\n\t\t},\n\t}, nil\n}\n\n// NewDamgardFromParams takes configuration parameters of an existing\n// Damgard scheme instance, and reconstructs the scheme with same configuration\n// parameters. It returns a new Damgard instance.\nfunc NewDamgardFromParams(params *DamgardParams) *Damgard {\n\treturn &Damgard{\n\t\tParams: params,\n\t}\n}\n\n// DamgardSecKey is a secret key for Damgard scheme.\ntype DamgardSecKey struct {\n\tS data.Vector\n\tT data.Vector\n}\n\n// GenerateMasterKeys generates a master secret key and master\n// public key for the scheme. It returns an error in case master keys\n// could not be generated.\nfunc (d *Damgard) GenerateMasterKeys() (*DamgardSecKey, data.Vector, error) {\n\t// both part of masterSecretKey\n\tmskS := make(data.Vector, d.Params.L)\n\tmskT := make(data.Vector, d.Params.L)\n\n\tmasterPubKey := make([]*big.Int, d.Params.L)\n\tsampler := sample.NewUniformRange(big.NewInt(2), d.Params.Q)\n\n\tfor i := 0; i < d.Params.L; i++ {\n\t\ts, err := sampler.Sample()\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\t\tmskS[i] = s\n\n\t\tt, err := sampler.Sample()\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\t\tmskT[i] = t\n\n\t\ty1 := new(big.Int).Exp(d.Params.G, s, d.Params.P)\n\t\ty2 := new(big.Int).Exp(d.Params.H, t, d.Params.P)\n\n\t\tmasterPubKey[i] = new(big.Int).Mod(new(big.Int).Mul(y1, y2), d.Params.P)\n\t}\n\n\treturn &DamgardSecKey{S: mskS, T: mskT}, masterPubKey, nil\n}\n\n// DamgardDerivedKey is a functional encryption key for Damgard scheme.\ntype DamgardDerivedKey struct {\n\tKey1 *big.Int\n\tKey2 *big.Int\n}\n\n// DeriveKey takes master secret key and input vector y, and returns the\n// functional encryption key. In case the key could not be derived, it\n// returns an error.\nfunc (d *Damgard) DeriveKey(masterSecKey *DamgardSecKey, y data.Vector) (*DamgardDerivedKey, error) {\n\tif err := y.CheckBound(d.Params.Bound); err != nil {\n\t\treturn nil, err\n\t}\n\n\tkey1, err := masterSecKey.S.Dot(y)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tkey2, err := masterSecKey.T.Dot(y)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tk1 := new(big.Int).Mod(key1, d.Params.Q)\n\tk2 := new(big.Int).Mod(key2, d.Params.Q)\n\n\treturn &DamgardDerivedKey{Key1: k1, Key2: k2}, nil\n}\n\n// Encrypt encrypts input vector x with the provided master public key.\n// It returns a ciphertext vector. If encryption failed, error is returned.\nfunc (d *Damgard) Encrypt(x, masterPubKey data.Vector) (data.Vector, error) {\n\tif err := x.CheckBound(d.Params.Bound); err != nil {\n\t\treturn nil, err\n\t}\n\n\tsampler := sample.NewUniformRange(big.NewInt(2), d.Params.Q)\n\tr, err := sampler.Sample()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tciphertext := make([]*big.Int, len(x)+2)\n\t// c = g^r\n\t// dd = h^r\n\tc := new(big.Int).Exp(d.Params.G, r, d.Params.P)\n\tciphertext[0] = c\n\tdd := new(big.Int).Exp(d.Params.H, r, d.Params.P)\n\tciphertext[1] = dd\n\n\tfor i := 0; i < len(x); i++ {\n\t\t// e_i = h_i^r * g^x_i\n\t\t// e_i = mpk[i]^r * g^x_i\n\t\tt1 := new(big.Int).Exp(masterPubKey[i], r, d.Params.P)\n\t\tt2 := internal.ModExp(d.Params.G, x[i], d.Params.P)\n\t\tct := new(big.Int).Mod(new(big.Int).Mul(t1, t2), d.Params.P)\n\t\tciphertext[i+2] = ct\n\t}\n\n\treturn data.NewVector(ciphertext), nil\n}\n\n// Decrypt accepts the encrypted vector, functional encryption key, and\n// a plaintext vector y. It returns the inner product of x and y.\n// If decryption failed, error is returned.\nfunc (d *Damgard) Decrypt(cipher data.Vector, key *DamgardDerivedKey, y data.Vector) (*big.Int, error) {\n\tif err := y.CheckBound(d.Params.Bound); err != nil {\n\t\treturn nil, err\n\t}\n\n\tnum := big.NewInt(1)\n\tfor i, ct := range cipher[2:] {\n\t\tt1 := internal.ModExp(ct, y[i], d.Params.P)\n\t\tnum = num.Mod(new(big.Int).Mul(num, t1), d.Params.P)\n\t}\n\n\tt1 := new(big.Int).Exp(cipher[0], key.Key1, d.Params.P)\n\tt2 := new(big.Int).Exp(cipher[1], key.Key2, d.Params.P)\n\n\tdenom := new(big.Int).Mod(new(big.Int).Mul(t1, t2), d.Params.P)\n\tdenomInv := new(big.Int).ModInverse(denom, d.Params.P)\n\tr := new(big.Int).Mod(new(big.Int).Mul(num, denomInv), d.Params.P)\n\n\tbSquared := new(big.Int).Exp(d.Params.Bound, big.NewInt(2), big.NewInt(0))\n\tbound := new(big.Int).Mul(big.NewInt(int64(d.Params.L)), bSquared)\n\n\tcalc, err := dlog.NewCalc().InZp(d.Params.P, d.Params.Q)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tcalc = calc.WithNeg()\n\n\tres, err := calc.WithBound(bound).BabyStepGiantStep(r, d.Params.G)\n\treturn res, err\n}\n"
  },
  {
    "path": "innerprod/fullysec/damgard_dec_multi.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage fullysec\n\nimport (\n\t\"crypto/sha256\"\n\t\"fmt\"\n\t\"math/big\"\n\n\t\"github.com/fentec-project/gofe/data\"\n\t\"github.com/fentec-project/gofe/sample\"\n)\n\n// DamgardDecMultiClient represents a client in a decentralized\n// multi client variant of the underlying multi client (dmagard_multi)\n// scheme based. The decentralization is based on\n// Abdalla, Benhamouda, Kohlweiss,and Waldner:\n// \"Decentralizing Inner-Product Functional Encryption\".\n// The participants in the scheme are clients without a central authority.\n// They interactively generate private keys for each client so that client i\n// can encrypt vector x_i. The scheme allows the clients to interactively\n// generate a key_Y, depending on a matrix Y with rows y_i, so that\n// given key_y and the ciphertext the decryptor can compute value\n// Σ_i <x_i, y_i> (sum of dot products).\ntype DamgardDecMultiClient struct {\n\t// number of encryptors\n\tIdx int\n\t*DamgardMulti\n\tClientPubKey *big.Int\n\tClientSecKey *big.Int\n\tShare        data.Matrix\n}\n\n// NewDamgardDecMultiClient configures a new client in the decentralized scheme\n// based on a underlying DamgardMulti scheme.\n// It accepts the identification of the client (an integer from [0, numClients))\n// and the underlying DamgardMulti scheme (which contains all the shared parameters)\n//\n// It returns an error in case the scheme cannot be properly initialized.\nfunc NewDamgardDecMultiClient(idx int, damgardMulti *DamgardMulti) (*DamgardDecMultiClient, error) {\n\tsampler := sample.NewUniform(damgardMulti.Params.Q)\n\tsec, err := sampler.Sample()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"could not generate random value\")\n\t}\n\tpub := new(big.Int).Exp(damgardMulti.Params.G, sec, damgardMulti.Params.P)\n\n\treturn &DamgardDecMultiClient{\n\t\tIdx:          idx,\n\t\tDamgardMulti: damgardMulti,\n\t\tClientPubKey: pub,\n\t\tClientSecKey: sec,\n\t}, nil\n}\n\n// SetShare sets a shared key for client c, based on the public keys of all the\n// clients involved in the scheme. It assumes that Idx of a client indicates\n// which is the corresponding public key in pubKeys. Shared keys are such that\n// each client has a random key but all the shared keys sum to 0.\nfunc (c *DamgardDecMultiClient) SetShare(pubKeys []*big.Int) error {\n\tc.Share = data.NewConstantMatrix(c.NumClients, c.Params.L, big.NewInt(0))\n\tvar add data.Matrix\n\tvar err error\n\tfor k := 0; k < len(pubKeys); k++ {\n\t\tif k == c.Idx {\n\t\t\tcontinue\n\t\t}\n\t\tsharedNum := new(big.Int).Exp(pubKeys[k], c.ClientSecKey, c.Params.P)\n\t\tsharedKey := sha256.Sum256([]byte(sharedNum.String()))\n\n\t\tadd, err = data.NewRandomDetMatrix(c.NumClients, c.Params.L, c.Params.Q, &sharedKey)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif k < c.Idx {\n\t\t\tc.Share, err = c.Share.Add(add)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t} else {\n\t\t\tc.Share, err = c.Share.Sub(add)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\tc.Share = c.Share.Mod(c.Params.Q)\n\t}\n\n\treturn nil\n}\n\n// DamgardDecMultiSecKey is a secret key that each client has.\ntype DamgardDecMultiSecKey struct {\n\tsk     *DamgardSecKey\n\tpk     data.Vector\n\tOtpKey data.Vector\n}\n\n// GenerateKeys generates the secret key for each client.\n//\n// It returns an error in case master keys could not be generated.\nfunc (c *DamgardDecMultiClient) GenerateKeys() (*DamgardDecMultiSecKey, error) {\n\tmasterSecretKey, masterPublicKey, err := c.Damgard.GenerateMasterKeys()\n\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error in master key generation\")\n\t}\n\n\totpVector, err := data.NewRandomVector(c.Damgard.Params.L,\n\t\tsample.NewUniform(c.Damgard.Params.Q))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error in random vector generation\")\n\t}\n\n\treturn &DamgardDecMultiSecKey{sk: masterSecretKey,\n\t\tpk:     masterPublicKey,\n\t\tOtpKey: otpVector}, nil\n}\n\n// Encrypt generates a ciphertext from the input vector x\n// with the provided secret key.\n// If encryption failed, error is returned.\nfunc (c *DamgardDecMultiClient) Encrypt(x data.Vector, key *DamgardDecMultiSecKey) (data.Vector, error) {\n\tif err := x.CheckBound(c.Params.Bound); err != nil {\n\t\treturn nil, err\n\t}\n\n\txAddOtp := x.Add(key.OtpKey)\n\totpModulo := xAddOtp.Mod(c.Params.Q)\n\n\treturn c.Damgard.Encrypt(otpModulo, key.pk)\n}\n\n// DamgardDecMultiDerivedKeyPart is functional encryption key for decentralized\n// Damgrad Scheme.\ntype DamgardDecMultiDerivedKeyPart struct {\n\tKeyPart    *DamgardDerivedKey\n\tOTPKeyPart *big.Int\n}\n\n// DeriveKeyShare is run by a client. It takes a secret key and\n// a matrix y comprised of input vectors, and returns a part of\n// the functional encryption key.\n// In case the key could not be derived, it returns an error.\nfunc (c *DamgardDecMultiClient) DeriveKeyShare(secKey *DamgardDecMultiSecKey, y data.Matrix) (*DamgardDecMultiDerivedKeyPart, error) {\n\tif err := y.CheckBound(c.Damgard.Params.Bound); err != nil {\n\t\treturn nil, err\n\t}\n\n\tyPart := data.NewVector(y[c.Idx])\n\tz1, err := secKey.OtpKey.Dot(yPart)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tz2, err := c.Share.Dot(y)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tzPart := new(big.Int).Add(z1, z2)\n\tzPart.Mod(zPart, c.Damgard.Params.Q)\n\tkey, err := c.Damgard.DeriveKey(secKey.sk, yPart)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &DamgardDecMultiDerivedKeyPart{key, zPart}, nil\n}\n\n// DamgardDecMultiDec represents a decryptor for the decentralized variant of the\n// underlying multi input Damgard scheme.\ntype DamgardDecMultiDec struct {\n\t*DamgardMulti\n}\n\n// NewDamgardDecMultiDec takes the underlying DamgardMulti and instantiates a\n// new DamgardDecMultiDec struct.\nfunc NewDamgardDecMultiDec(damgardMulti *DamgardMulti) *DamgardDecMultiDec {\n\treturn &DamgardDecMultiDec{\n\t\tDamgardMulti: NewDamgardMultiFromParams(damgardMulti.NumClients, damgardMulti.Bound, damgardMulti.Params),\n\t}\n}\n\n// Decrypt accepts an array of ciphertexts comprised of encrypted vectors,\n// an array of partial functional encryption keys, and a matrix y representing\n// the inner-product vectors. It returns the sum of inner products.\n// If decryption failed, an error is returned.\nfunc (dc *DamgardDecMultiDec) Decrypt(cipher []data.Vector, partKeys []*DamgardDecMultiDerivedKeyPart, y data.Matrix) (*big.Int, error) {\n\tif err := y.CheckBound(dc.Params.Bound); err != nil {\n\t\treturn nil, err\n\t}\n\tif len(cipher) != len(partKeys) {\n\t\treturn nil, fmt.Errorf(\"the number of keys does not match the number of ciphertexts\")\n\t}\n\n\tkeys := make([]*DamgardDerivedKey, len(partKeys))\n\tz := big.NewInt(0)\n\tfor i := 0; i < len(partKeys); i++ {\n\t\tz.Add(z, partKeys[i].OTPKeyPart)\n\t\tkeys[i] = partKeys[i].KeyPart\n\t}\n\tz.Mod(z, dc.Params.Q)\n\tkey := &DamgardMultiDerivedKey{Keys: keys,\n\t\tZ: z,\n\t}\n\n\treturn dc.DamgardMulti.Decrypt(cipher, key, y)\n}\n"
  },
  {
    "path": "innerprod/fullysec/damgard_dec_multi_test.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage fullysec_test\n\nimport (\n\t\"math/big\"\n\t\"testing\"\n\n\t\"github.com/fentec-project/gofe/data\"\n\t\"github.com/fentec-project/gofe/innerprod/fullysec\"\n\t\"github.com/fentec-project/gofe/sample\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc testFullySecDamgardDecMultiFromParam(t *testing.T, param damgardTestParam) {\n\t// choose parameters\n\tnumOfClients := 10\n\tl := 2\n\tbound := big.NewInt(1024)\n\tsampler := sample.NewUniformRange(new(big.Int).Add(new(big.Int).Neg(bound), big.NewInt(1)), bound)\n\n\t// create a (non-decentralized) multi-input scheme as the underlying scheme\n\t// for the decentralization\n\tvar damgardMulti *fullysec.DamgardMulti\n\tvar err error\n\tif param.precomputed {\n\t\t// modulusLength defines the security of the scheme, the higher the better\n\t\tdamgardMulti, err = fullysec.NewDamgardMultiPrecomp(numOfClients, l, param.modulusLength, bound)\n\t} else {\n\t\tdamgardMulti, err = fullysec.NewDamgardMulti(numOfClients, l, param.modulusLength, bound)\n\t}\n\tassert.NoError(t, err)\n\n\t// we simulate different independent, decentralized clients and\n\t// we collect all of their public keys\n\tclients := make([]*fullysec.DamgardDecMultiClient, numOfClients)\n\tpubKeys := make([]*big.Int, numOfClients)\n\tfor i := 0; i < numOfClients; i++ {\n\t\tclients[i], err = fullysec.NewDamgardDecMultiClient(i, damgardMulti)\n\t\tassert.NoError(t, err)\n\t\tpubKeys[i] = clients[i].ClientPubKey\n\t}\n\n\t// each client makes a private partial key out of the public keys and\n\t// create its own secret key for the encryption of a vector\n\tsecKeys := make([]*fullysec.DamgardDecMultiSecKey, numOfClients)\n\tfor i := 0; i < numOfClients; i++ {\n\t\terr = clients[i].SetShare(pubKeys)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"Error during share generation: %v\", err)\n\t\t}\n\n\t\tsecKeys[i], err = clients[i].GenerateKeys()\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"Error during secret keys generation: %v\", err)\n\t\t}\n\t}\n\n\t// each client encrypts its own vector x_i\n\tciphertexts := make([]data.Vector, numOfClients)\n\tcollectedX := make([]data.Vector, numOfClients) // for checking whether encrypt/decrypt works properly\n\tfor i := 0; i < numOfClients; i++ {\n\t\tx, err := data.NewRandomVector(l, sampler) // x possessed and chosen by encryptors[i]\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"Error during random vector generation: %v\", err)\n\t\t}\n\t\tcollectedX[i] = x\n\n\t\tc, err := clients[i].Encrypt(x, secKeys[i])\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"Error during encryption: %v\", err)\n\t\t}\n\t\tciphertexts[i] = c\n\t}\n\n\t// pick a matrix that represent the collection of inner-product vectors y_i\n\ty, err := data.NewRandomMatrix(numOfClients, l, sampler)\n\tassert.NoError(t, err)\n\n\tpartKeys := make([]*fullysec.DamgardDecMultiDerivedKeyPart, numOfClients)\n\tfor i := 0; i < numOfClients; i++ {\n\t\tpartKeys[i], err = clients[i].DeriveKeyShare(secKeys[i], y)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"Error during derivation of key: %v\", err)\n\t\t}\n\t}\n\n\t// we simulate the decryptor\n\tdecryptor := fullysec.NewDamgardDecMultiDec(damgardMulti)\n\n\t// decryptor decrypts the value\n\txy, err := decryptor.Decrypt(ciphertexts, partKeys, y)\n\tif err != nil {\n\t\tt.Fatalf(\"Error during decryption: %v\", err)\n\t}\n\n\t// we check if the decrypted value is correct\n\txMatrix, err := data.NewMatrix(collectedX)\n\tif err != nil {\n\t\tt.Fatalf(\"Error during collection of vectors to be encrypted: %v\", err)\n\t}\n\txyCheck, err := xMatrix.Dot(y)\n\tif err != nil {\n\t\tt.Fatalf(\"Error during inner product calculation: %v\", err)\n\t}\n\tassert.Equal(t, xy.Cmp(xyCheck), 0, \"obtained incorrect inner product\")\n}\n\nfunc TestFullySec_DamgardDecMulti(t *testing.T) {\n\tparams := []damgardTestParam{{name: \"random\", modulusLength: 512, precomputed: false},\n\t\t{name: \"precomputed\", modulusLength: 2048, precomputed: true}}\n\n\tfor _, param := range params {\n\t\tt.Run(param.name, func(t *testing.T) {\n\t\t\ttestFullySecDamgardDecMultiFromParam(t, param)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "innerprod/fullysec/damgard_multi.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage fullysec\n\nimport (\n\t\"fmt\"\n\t\"math/big\"\n\n\t\"github.com/fentec-project/gofe/data\"\n\t\"github.com/fentec-project/gofe/internal\"\n\t\"github.com/fentec-project/gofe/internal/dlog\"\n\t\"github.com/fentec-project/gofe/sample\"\n)\n\n// DamgardMulti represents a multi input variant of the\n// underlying Damgard scheme based on\n// Abdalla, Catalano, Fiore, Gay, and Ursu:\n// \"Multi-Input Functional Encryption for Inner Products:\n// Function-Hiding Realizations and Constructions without Pairings\".\n// The participants in the scheme are clients and a central authority.\n// The central authority generates keys for each client so that client i\n// encrypts vector x_i. The scheme allows the central authority to\n// generate a key_Y, depending on a matrix Y with rows y_i, so that\n// given key_y and the ciphertext the decryptor can compute value\n// Σ_i <x_i, y_i> (sum of dot products).\n\n// DamgardMulti is a struct in DamgardMulti scheme, that holds\n// all the shared parameters, and can represent the central authority\n// or the decryptor.\ntype DamgardMulti struct {\n\t// number of clients\n\tNumClients int\n\tBound      *big.Int\n\t*Damgard\n}\n\n// DamgardMultiClient represents a single client for the DamgardMulti scheme.\ntype DamgardMultiClient struct {\n\tBound *big.Int\n\t*Damgard\n}\n\n// NewDamgardMulti configures a new instance of the scheme.\n// It accepts the number of clients, the length of\n// input vectors l, the bit length of the modulus (we are\n// operating in the Z_p group), and a bound by which coordinates\n// of input vectors are bounded. It generates all the remaining\n// parameters to be shared.\n//\n// It returns an error in case the underlying Damgard scheme\n// instances could not be properly instantiated.\nfunc NewDamgardMulti(numClients, l, modulusLength int, bound *big.Int) (*DamgardMulti, error) {\n\tbSquared := new(big.Int).Exp(bound, big.NewInt(2), nil)\n\tprod := new(big.Int).Mul(big.NewInt(int64(l*numClients*2)), bSquared)\n\n\tdamgard, err := NewDamgard(l, modulusLength, bound)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif prod.Cmp(damgard.Params.Q) > 0 {\n\t\treturn nil, fmt.Errorf(\"2 * l * numClients * bound^2 should be smaller than group order\")\n\t}\n\t// the bound of the underlying Damgard scheme is set to\n\t// the maximum value since the scheme will be used to encrypt\n\t// values summed with one time pad, thus arbitrary big\n\tdamgard.Params.Bound = damgard.Params.Q\n\n\treturn &DamgardMulti{\n\t\tNumClients: numClients,\n\t\tBound:      bound,\n\t\tDamgard:    damgard,\n\t}, nil\n}\n\n// NewDamgardMultiPrecomp configures a new instance of the scheme\n// based on precomputed prime numbers and generators.\n// It accepts the number of clients, the length of\n// input vectors l, the bit length of the modulus (we are\n// operating in the Z_p group), and a bound by which coordinates\n// of input vectors are bounded. It generates all the remaining\n// parameters to be shared. The modulus length should\n// be one of values 1024, 1536, 2048, 2560, 3072, or 4096. The precomputed\n// prime numbers and generators were simply obtained by running NewDamgard\n// function.\n//\n// It returns an error in case the underlying Damgard scheme\n// instances could not be properly instantiated.\nfunc NewDamgardMultiPrecomp(numClients, l, modulusLength int, bound *big.Int) (*DamgardMulti, error) {\n\tbSquared := new(big.Int).Exp(bound, big.NewInt(2), nil)\n\tprod := new(big.Int).Mul(big.NewInt(int64(l*numClients*2)), bSquared)\n\n\tdamgard, err := NewDamgardPrecomp(l, modulusLength, bound)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif prod.Cmp(damgard.Params.Q) > 0 {\n\t\treturn nil, fmt.Errorf(\"2 * l * numClients * bound^2 should be smaller than group order\")\n\t}\n\t// the bound of the underlying Damgard scheme is set to\n\t// the maximum value since the scheme will be used to encrypt\n\t// values summed with one time pad, thus arbitrary big\n\tdamgard.Params.Bound = damgard.Params.Q\n\n\treturn &DamgardMulti{\n\t\tNumClients: numClients,\n\t\tBound:      bound,\n\t\tDamgard:    damgard,\n\t}, nil\n}\n\n// NewDamgardMultiClientFromParams takes the bound and configuration parameters of an underlying\n// Damgard scheme instance, and instantiates a new DamgardMultiClient.\n//\n// It returns a new DamgardMultiClient instance.\nfunc NewDamgardMultiClientFromParams(bound *big.Int, params *DamgardParams) *DamgardMultiClient {\n\treturn &DamgardMultiClient{\n\t\tBound:   bound,\n\t\tDamgard: &Damgard{params},\n\t}\n}\n\n// NewDamgardMultiFromParams takes the number of clients, bound and configuration\n// parameters of an existing Damgard scheme instance, and reconstructs\n// the scheme with same configuration parameters.\n//\n// It returns a new DamgardMulti instance.\nfunc NewDamgardMultiFromParams(numClients int, bound *big.Int, params *DamgardParams) *DamgardMulti {\n\treturn &DamgardMulti{\n\t\tNumClients: numClients,\n\t\tBound:      bound,\n\t\tDamgard:    &Damgard{params},\n\t}\n}\n\n// DamgardMultiSecKeys is a struct containing keys and one time pads for all the clients in\n// the Damgard multi input scheme.\ntype DamgardMultiSecKeys struct {\n\tMsk []*DamgardSecKey\n\tMpk data.Matrix\n\tOtp data.Matrix\n}\n\n// GenerateMasterKeys generates keys and one time pads for all the clients.\n//\n// It returns an error in case values could not be generated.\nfunc (dm *DamgardMulti) GenerateMasterKeys() (*DamgardMultiSecKeys, error) {\n\tmultiMsk := make([]*DamgardSecKey, dm.NumClients)\n\tmultiMpk := make([]data.Vector, dm.NumClients)\n\tmultiOtp := make([]data.Vector, dm.NumClients)\n\n\tfor i := 0; i < dm.NumClients; i++ {\n\t\tmsk, mpk, err := dm.Damgard.GenerateMasterKeys()\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error in master key generation\")\n\t\t}\n\t\tmultiMsk[i] = msk\n\t\tmultiMpk[i] = mpk\n\n\t\totp, err := data.NewRandomVector(dm.Params.L, sample.NewUniform(dm.Params.Q))\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error in random vector generation\")\n\t\t}\n\t\tmultiOtp[i] = otp\n\t}\n\tsecKeys := &DamgardMultiSecKeys{\n\t\tMsk: multiMsk,\n\t\tMpk: data.Matrix(multiMpk),\n\t\tOtp: data.Matrix(multiOtp),\n\t}\n\n\treturn secKeys, nil\n}\n\n// Encrypt generates a ciphertext from the input vector x\n// with the provided public key of the underlying Damgard scheme and\n// one-time pad otp (which are a part of the secret key). It returns\n// the ciphertext vector. If the encryption failed, error is returned.\nfunc (e *DamgardMultiClient) Encrypt(x data.Vector, pubKey, otp data.Vector) (data.Vector, error) {\n\tif err := x.CheckBound(e.Params.Bound); err != nil {\n\t\treturn nil, err\n\t}\n\n\txAddOtp := x.Add(otp)\n\txAddOtp = xAddOtp.Mod(e.Params.Q)\n\n\treturn e.Damgard.Encrypt(xAddOtp, pubKey)\n}\n\n// DamgardMultiDerivedKey is a functional encryption key for DamgardMulti scheme.\ntype DamgardMultiDerivedKey struct {\n\tKeys []*DamgardDerivedKey\n\tZ    *big.Int // Σ <u_i, y_i> where u_i is OTP key for i-th client\n}\n\n// DeriveKey takes master secret key and a matrix y comprised\n// of input vectors, and returns the functional encryption key.\n// In case the key could not be derived, it returns an error.\nfunc (dm *DamgardMulti) DeriveKey(secKey *DamgardMultiSecKeys, y data.Matrix) (*DamgardMultiDerivedKey, error) {\n\tif err := y.CheckBound(dm.Bound); err != nil {\n\t\treturn nil, err\n\t}\n\n\tz, err := secKey.Otp.Dot(y)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tz.Mod(z, dm.Params.Q)\n\n\tderivedKeys := make([]*DamgardDerivedKey, dm.NumClients)\n\tfor i := 0; i < dm.NumClients; i++ {\n\t\tderivedKey, err := dm.Damgard.DeriveKey(secKey.Msk[i], y[i])\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tderivedKeys[i] = derivedKey\n\t}\n\n\treturn &DamgardMultiDerivedKey{derivedKeys, z}, nil\n}\n\n// Decrypt accepts an array of ciphers, i.e. an array of encrypted vectors,\n// functional encryption key, and a matrix y describing the inner-product.\n// It returns the sum of inner products Σ_i <x_i, y_i>.\n// If decryption failed, error is returned.\nfunc (dm *DamgardMulti) Decrypt(cipher []data.Vector, key *DamgardMultiDerivedKey, y data.Matrix) (*big.Int, error) {\n\tif err := y.CheckBound(dm.Bound); err != nil {\n\t\treturn nil, err\n\t}\n\n\tr := big.NewInt(1)\n\tfor k := 0; k < dm.NumClients; k++ {\n\t\tnum := big.NewInt(1)\n\t\tfor i, ct := range cipher[k][2:] {\n\t\t\tt1 := internal.ModExp(ct, y[k][i], dm.Params.P)\n\t\t\tnum = num.Mod(new(big.Int).Mul(num, t1), dm.Params.P)\n\t\t}\n\n\t\tt1 := new(big.Int).Exp(cipher[k][0], key.Keys[k].Key1, dm.Params.P)\n\t\tt2 := new(big.Int).Exp(cipher[k][1], key.Keys[k].Key2, dm.Params.P)\n\n\t\tdenom := new(big.Int).Mod(new(big.Int).Mul(t1, t2), dm.Params.P)\n\t\tdenomInv := new(big.Int).ModInverse(denom, dm.Params.P)\n\t\tr.Mul(r, denomInv)\n\t\tr.Mul(r, num)\n\t\tr.Mod(r, dm.Params.P)\n\t}\n\n\tzExp := new(big.Int).Exp(dm.Params.G, key.Z, dm.Params.P)\n\tzExpInv := new(big.Int).ModInverse(zExp, dm.Params.P)\n\n\tr.Mul(r, zExpInv)\n\tr.Mod(r, dm.Params.P)\n\n\tcalc, err := dlog.NewCalc().InZp(dm.Params.P, dm.Params.Q)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tcalc = calc.WithNeg()\n\n\tbound := new(big.Int).Mul(dm.Bound, dm.Bound)\n\tbound.Mul(bound, big.NewInt(int64(dm.Params.L*dm.NumClients)))\n\tres, err := calc.WithBound(bound).BabyStepGiantStep(r, dm.Params.G)\n\n\treturn res, err\n}\n"
  },
  {
    "path": "innerprod/fullysec/damgard_multi_test.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage fullysec_test\n\nimport (\n\t\"math/big\"\n\t\"testing\"\n\n\t\"github.com/fentec-project/gofe/data\"\n\t\"github.com/fentec-project/gofe/innerprod/fullysec\"\n\t\"github.com/fentec-project/gofe/sample\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc testFullySecDamgardMultiDDHFromParam(t *testing.T, param damgardTestParam) {\n\t// choose meta-parameters for the scheme\n\tnumClients := 6\n\tl := 5\n\tbound := big.NewInt(1024)\n\tsampler := sample.NewUniformRange(new(big.Int).Add(new(big.Int).Neg(bound), big.NewInt(1)), bound)\n\n\t// build the central authority for the scheme\n\tvar damgardMulti *fullysec.DamgardMulti\n\tvar err error\n\tif param.precomputed {\n\t\t// modulusLength defines the security of the scheme, the higher the better\n\t\tdamgardMulti, err = fullysec.NewDamgardMultiPrecomp(numClients, l, param.modulusLength, bound)\n\t} else {\n\t\tdamgardMulti, err = fullysec.NewDamgardMulti(numClients, l, param.modulusLength, bound)\n\t}\n\tif err != nil {\n\t\tt.Fatalf(\"Failed to initialize multi input inner product: %v\", err)\n\t}\n\n\t// we simulate different clients which might be on different machines (this means \"multi-input\"),\n\tclients := make([]*fullysec.DamgardMultiClient, numClients)\n\tfor i := 0; i < numClients; i++ {\n\t\tclients[i] = fullysec.NewDamgardMultiClientFromParams(bound, damgardMulti.Params)\n\t}\n\n\t// the central authority generates keys for all the clients\n\tsecKeys, err := damgardMulti.GenerateMasterKeys()\n\tif err != nil {\n\t\tt.Fatalf(\"Error during keys generation: %v\", err)\n\t}\n\n\t// pick a matrix that represent the collection of inner-product vectors y_i\n\ty, err := data.NewRandomMatrix(numClients, l, sampler)\n\tif err != nil {\n\t\tt.Fatalf(\"Error during matrix generation: %v\", err)\n\t}\n\n\t// each client encrypts its vector x_i\n\tcollectedX := make([]data.Vector, numClients) // solely for checking whether Encrypt/Decrypt works properly\n\tciphertexts := make([]data.Vector, numClients)\n\tfor i := 0; i < numClients; i++ {\n\t\tx, err := data.NewRandomVector(l, sampler) // x_i possessed and chosen by client[i]\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"Error during random vector generation: %v\", err)\n\t\t}\n\t\tcollectedX[i] = x\n\t\tc, err := clients[i].Encrypt(x, secKeys.Mpk[i], secKeys.Otp[i])\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"Error during encryption: %v\", err)\n\t\t}\n\t\tciphertexts[i] = c\n\t}\n\n\t// central authority derives the key for the decryptor\n\tderivedKey, err := damgardMulti.DeriveKey(secKeys, y)\n\tif err != nil {\n\t\tt.Fatalf(\"Error during key derivation: %v\", err)\n\t}\n\n\t// we simulate the decryptor\n\tdecryptor := fullysec.NewDamgardMultiFromParams(numClients, bound, damgardMulti.Params)\n\n\t// decryptor decrypts the value\n\txy, err := decryptor.Decrypt(ciphertexts, derivedKey, y)\n\tif err != nil {\n\t\tt.Fatalf(\"Error during decryption: %v\", err)\n\t}\n\n\t// we check if the decrypted value is correct\n\txMatrix, err := data.NewMatrix(collectedX)\n\tif err != nil {\n\t\tt.Fatalf(\"Error during collection of vectors to be encrypted: %v\", err)\n\t}\n\txyCheck, err := xMatrix.Dot(y)\n\tif err != nil {\n\t\tt.Fatalf(\"Error during inner product calculation: %v\", err)\n\t}\n\tassert.Equal(t, xy.Cmp(xyCheck), 0, \"obtained incorrect inner product\")\n}\n\nfunc TestFullySec_DamgardMultiDDH(t *testing.T) {\n\tparams := []damgardTestParam{{name: \"random\", modulusLength: 512, precomputed: false},\n\t\t{name: \"precomputed\", modulusLength: 2048, precomputed: true}}\n\n\tfor _, param := range params {\n\t\tt.Run(param.name, func(t *testing.T) {\n\t\t\ttestFullySecDamgardMultiDDHFromParam(t, param)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "innerprod/fullysec/damgard_test.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage fullysec_test\n\nimport (\n\t\"math/big\"\n\t\"testing\"\n\n\t\"github.com/fentec-project/gofe/data\"\n\t\"github.com/fentec-project/gofe/innerprod/fullysec\"\n\t\"github.com/fentec-project/gofe/sample\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\ntype damgardTestParam struct {\n\tname          string\n\tmodulusLength int\n\tprecomputed   bool\n}\n\nfunc testFullySecDamgardDDHFromParam(t *testing.T, param damgardTestParam) {\n\tl := 16\n\tbound := big.NewInt(1024)\n\tsampler := sample.NewUniformRange(new(big.Int).Add(new(big.Int).Neg(bound), big.NewInt(1)), bound)\n\n\tvar damgard *fullysec.Damgard\n\tvar err error\n\tif param.precomputed {\n\t\tdamgard, err = fullysec.NewDamgardPrecomp(l, param.modulusLength, bound)\n\t} else {\n\t\tdamgard, err = fullysec.NewDamgard(l, param.modulusLength, bound)\n\t}\n\tif err != nil {\n\t\tt.Fatalf(\"Error during simple inner product creation: %v\", err)\n\t}\n\n\tmasterSecKey, masterPubKey, err := damgard.GenerateMasterKeys()\n\n\tif err != nil {\n\t\tt.Fatalf(\"Error during master key generation: %v\", err)\n\t}\n\n\ty, err := data.NewRandomVector(l, sampler)\n\n\tif err != nil {\n\t\tt.Fatalf(\"Error during random generation: %v\", err)\n\t}\n\n\tkey, err := damgard.DeriveKey(masterSecKey, y)\n\n\tif err != nil {\n\t\tt.Fatalf(\"Error during key derivation: %v\", err)\n\t}\n\n\tx, err := data.NewRandomVector(l, sampler)\n\n\tif err != nil {\n\t\tt.Fatalf(\"Error during random generation: %v\", err)\n\t}\n\n\t// simulate the instantiation of encryptor (which should be given masterPubKey)\n\tencryptor := fullysec.NewDamgardFromParams(damgard.Params)\n\txyCheck, err := x.Dot(y)\n\n\tif err != nil {\n\t\tt.Fatalf(\"Error during inner product calculation\")\n\t}\n\tciphertext, err := encryptor.Encrypt(x, masterPubKey)\n\n\tif err != nil {\n\t\tt.Fatalf(\"Error during encryption: %v\", err)\n\t}\n\n\tdecryptor := fullysec.NewDamgardFromParams(damgard.Params)\n\txy, err := decryptor.Decrypt(ciphertext, key, y)\n\n\tif err != nil {\n\t\tt.Fatalf(\"Error during decryption: %v\", err)\n\t}\n\n\tassert.Equal(t, xy.Cmp(xyCheck), 0, \"obtained incorrect inner product\")\n}\n\nfunc TestFullySec_DamgardDDH(t *testing.T) {\n\tparams := []damgardTestParam{{name: \"random\", modulusLength: 512, precomputed: false},\n\t\t{name: \"precomputed\", modulusLength: 2048, precomputed: true}}\n\n\tfor _, param := range params {\n\t\tt.Run(param.name, func(t *testing.T) {\n\t\t\ttestFullySecDamgardDDHFromParam(t, param)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "innerprod/fullysec/dmcfe.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage fullysec\n\nimport (\n\t\"fmt\"\n\t\"math/big\"\n\n\t\"crypto/sha256\"\n\t\"strconv\"\n\n\t\"github.com/fentec-project/bn256\"\n\t\"github.com/fentec-project/gofe/data\"\n\t\"github.com/fentec-project/gofe/internal/dlog\"\n\t\"github.com/fentec-project/gofe/sample\"\n)\n\n// DMCFEClient is to be instantiated by the client. Idx presents index of the client.\ntype DMCFEClient struct {\n\tIdx          int\n\tClientSecKey *big.Int\n\tClientPubKey *bn256.G1\n\tShare        data.Matrix\n\tS            data.Vector\n}\n\n// NewDMCFEClient is to be called by the party that wants to encrypt number x_i.\n// The decryptor will be able to compute inner product of x and y where x = (x_1,...,x_l) and\n// y is publicly known vector y = (y_1,...,y_l). Value idx presents index of the party, where\n// it is assumed that if there are n clients, its indexes are in [0, n-1]\nfunc NewDMCFEClient(idx int) (*DMCFEClient, error) {\n\tsampler := sample.NewUniform(bn256.Order)\n\ts, err := data.NewRandomVector(2, sampler)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"could not generate random vector\")\n\t}\n\tsec, err := sampler.Sample()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"could not generate random value\")\n\t}\n\tpub := new(bn256.G1).ScalarBaseMult(sec)\n\n\treturn &DMCFEClient{\n\t\tIdx:          idx,\n\t\tClientSecKey: sec,\n\t\tClientPubKey: pub,\n\t\tS:            s,\n\t}, nil\n}\n\n// SetShare sets a shared key for client c, based on the public keys of all the\n// clients involved in the scheme. It assumes that Idx of a client indicates\n// which is the corresponding public key in pubKeys. Shared keys are such that\n// each client has a random key but all the shared keys sum to 0.\nfunc (c *DMCFEClient) SetShare(pubKeys []*bn256.G1) error {\n\tc.Share = data.NewConstantMatrix(2, 2, big.NewInt(0))\n\tvar add data.Matrix\n\tvar err error\n\tfor k := 0; k < len(pubKeys); k++ {\n\t\tif k == c.Idx {\n\t\t\tcontinue\n\t\t}\n\t\tsharedG1 := new(bn256.G1).ScalarMult(pubKeys[k], c.ClientSecKey)\n\t\tsharedKey := sha256.Sum256([]byte(sharedG1.String()))\n\n\t\tadd, err = data.NewRandomDetMatrix(2, 2, bn256.Order, &sharedKey)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif k < c.Idx {\n\t\t\tc.Share, err = c.Share.Add(add)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t} else {\n\t\t\tc.Share, err = c.Share.Sub(add)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\tc.Share = c.Share.Mod(bn256.Order)\n\t}\n\n\treturn nil\n}\n\n// Encrypt encrypts number x under some label.\nfunc (c *DMCFEClient) Encrypt(x *big.Int, label string) (*bn256.G1, error) {\n\tcipher := new(bn256.G1).ScalarBaseMult(big.NewInt(0))\n\tfor i := 0; i < 2; i++ {\n\t\ths, err := bn256.HashG1(strconv.Itoa(i) + \" \" + label)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\ths.ScalarMult(hs, c.S[i])\n\t\tcipher.Add(cipher, hs)\n\t}\n\n\tpow := new(big.Int).Set(x)\n\tgx := new(bn256.G1).ScalarBaseMult(big.NewInt(1))\n\tif pow.Sign() < 0 {\n\t\tpow.Neg(pow)\n\t\tgx.Neg(gx)\n\t}\n\tgx.ScalarMult(gx, pow)\n\tcipher.Add(cipher, gx)\n\n\treturn cipher, nil\n}\n\n// DeriveKeyShare generates client's key share. Decryptor needs shares from all clients.\nfunc (c *DMCFEClient) DeriveKeyShare(y data.Vector) (data.VectorG2, error) {\n\ths := make([]*bn256.G2, 2)\n\tvar err error\n\tfor i := 0; i < 2; i++ {\n\t\ths[i], err = bn256.HashG2(strconv.Itoa(i) + \" \" + y.String())\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tkeyShare := data.VectorG2{new(bn256.G2).ScalarBaseMult(big.NewInt(0)),\n\t\tnew(bn256.G2).ScalarBaseMult(big.NewInt(0))}\n\tfor k := 0; k < 2; k++ {\n\t\tfor i := 0; i < 2; i++ {\n\t\t\tadd := new(bn256.G2).ScalarMult(hs[i], c.Share[k][i])\n\t\t\tkeyShare[k].Add(keyShare[k], add)\n\t\t}\n\n\t\tpow := new(big.Int).Mul(y[c.Idx], c.S[k])\n\t\tpow.Mod(pow, bn256.Order)\n\t\tgS := new(bn256.G2).ScalarBaseMult(pow)\n\t\tkeyShare[k].Add(keyShare[k], gS)\n\t}\n\n\treturn keyShare, nil\n}\n\n// DMCFEDecrypt is to be called by a party that wants to decrypt a message - to compute inner product\n// of x and y. It needs ciphertexts from all clients and key shares from all clients. The label is\n// a string under which vector x has been encrypted (each client encrypted x_i under this label). The value bound\n// specifies the bound of the output (solution will be in the interval (-bound, bound)) and can be nil.\nfunc DMCFEDecrypt(ciphers []*bn256.G1, keyShares []data.VectorG2, y data.Vector, label string,\n\tbound *big.Int) (*big.Int, error) {\n\tkey1 := new(bn256.G2).ScalarBaseMult(big.NewInt(0))\n\tkey2 := new(bn256.G2).ScalarBaseMult(big.NewInt(0))\n\tfor i := 0; i < len(keyShares); i++ {\n\t\tkey1.Add(key1, keyShares[i][0])\n\t\tkey2.Add(key2, keyShares[i][1])\n\t}\n\n\tgen2 := new(bn256.G2).ScalarBaseMult(big.NewInt(1))\n\tcSum := new(bn256.G1).ScalarBaseMult(big.NewInt(0))\n\tcAdd := new(bn256.G1)\n\tpow := new(big.Int)\n\tfor i := 0; i < len(ciphers); i++ {\n\t\tcAdd.Set(ciphers[i])\n\t\tpow.Set(y[i])\n\t\tif pow.Sign() < 0 {\n\t\t\tcAdd.Neg(cAdd)\n\t\t\tpow.Neg(pow)\n\t\t}\n\n\t\tcAdd.ScalarMult(cAdd, pow)\n\t\tcSum.Add(cSum, cAdd)\n\t}\n\ts := bn256.Pair(cSum, gen2)\n\n\ths := make([]*bn256.G1, 2)\n\tvar err error\n\tfor i := 0; i < 2; i++ {\n\t\ths[i], err = bn256.HashG1(strconv.Itoa(i) + \" \" + label)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tt1 := bn256.Pair(hs[0], key1)\n\tt2 := bn256.Pair(hs[1], key2)\n\tt1.Add(t1, t2)\n\tt1.Neg(t1)\n\ts.Add(s, t1)\n\n\tg1gen := new(bn256.G1).ScalarBaseMult(big.NewInt(1))\n\tg2gen := new(bn256.G2).ScalarBaseMult(big.NewInt(1))\n\tg := bn256.Pair(g1gen, g2gen)\n\n\tdec, err := dlog.NewCalc().InBN256().WithNeg().WithBound(bound).BabyStepGiantStep(s, g)\n\n\treturn dec, err\n}\n"
  },
  {
    "path": "innerprod/fullysec/dmcfe_test.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage fullysec_test\n\nimport (\n\t\"math/big\"\n\t\"testing\"\n\n\t\"github.com/fentec-project/bn256\"\n\t\"github.com/fentec-project/gofe/data\"\n\t\"github.com/fentec-project/gofe/innerprod/fullysec\"\n\t\"github.com/fentec-project/gofe/sample\"\n\t\"github.com/pkg/errors\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc Test_DMCFE(t *testing.T) {\n\tnumClients := 10\n\tclients := make([]*fullysec.DMCFEClient, numClients)\n\n\tpubKeys := make([]*bn256.G1, numClients)\n\t// create clients and make a slice of their public values\n\tfor i := 0; i < numClients; i++ {\n\t\tc, err := fullysec.NewDMCFEClient(i)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"could not instantiate fullysec.Client: %v\", err)\n\t\t}\n\t\tclients[i] = c\n\t\tpubKeys[i] = c.ClientPubKey\n\t}\n\n\t// based on public values of each client create private matrices T_i summing to 0\n\tfor i := 0; i < numClients; i++ {\n\t\terr := clients[i].SetShare(pubKeys)\n\t\tif err != nil {\n\t\t\tpanic(errors.Wrap(err, \"could not create private values\"))\n\t\t}\n\t}\n\n\t// now that the clients have agreed on secret keys they can encrypt a vector in\n\t// a decentralized way and create partial keys such that only with all of them\n\t// the decryption of the inner product is possible\n\tlabel := \"some label\"\n\tbound := big.NewInt(1000)\n\tsampler := sample.NewUniformRange(new(big.Int).Add(new(big.Int).Neg(bound), big.NewInt(1)), bound)\n\ty, err := data.NewRandomVector(numClients, sampler)\n\tif err != nil {\n\t\tt.Fatalf(\"could not create random vector: %v\", err)\n\t}\n\tx, err := data.NewRandomVector(numClients, sampler)\n\tif err != nil {\n\t\tt.Fatalf(\"could not create random vector: %v\", err)\n\t}\n\n\txy, err := x.Dot(y)\n\tif err != nil {\n\t\tt.Fatalf(\"could not compute inner product: %v\", err)\n\t}\n\n\tciphers := make([]*bn256.G1, numClients)\n\tkeyShares := make([]data.VectorG2, numClients)\n\tfor i := 0; i < numClients; i++ {\n\t\tc, err := clients[i].Encrypt(x[i], label)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"could not encrypt: %v\", err)\n\t\t}\n\t\tciphers[i] = c\n\n\t\tkeyShare, err := clients[i].DeriveKeyShare(y)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"could not generate key share: %v\", err)\n\t\t}\n\t\tkeyShares[i] = keyShare\n\t}\n\n\tbound.Mul(bound, bound)\n\tbound.Mul(bound, big.NewInt(int64(numClients))) // numClients * (coordinate_bound)^2\n\td, err := fullysec.DMCFEDecrypt(ciphers, keyShares, y, label, bound)\n\tif err != nil {\n\t\tt.Fatalf(\"error when decrypting: %v\", err)\n\t}\n\n\tassert.Equal(t, d, xy, \"Decryption wrong\")\n}\n"
  },
  {
    "path": "innerprod/fullysec/doc.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// Package fullysec includes fully secure schemes for functional encryption\n// of inner products.\n//\n// All implementations in this package are based on the reference\n// paper by  Agrawal, Libert and Stehlé (see https://eprint.iacr.org/2015/608.pdf),\n// and offer adaptive security under chosen-plaintext\n// attacks (IND-CPA security).\n//\n// The reference scheme is public key, which means that no master secret\n// key is required for the encryption.\n//\n// For instantiation from the decisional Diffie-Hellman assumption\n// (DDH), see struct Damgard (and its multi-input variant DamgardMulti,\n// which is a secret key scheme, because a part of the secret key is\n// required for the encryption).\n//\n// For instantiation from learning with errors (LWE), see\n// struct LWE.\npackage fullysec\n"
  },
  {
    "path": "innerprod/fullysec/fh_multi_ipe.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage fullysec\n\nimport (\n\t\"math/big\"\n\n\t\"github.com/fentec-project/bn256\"\n\t\"github.com/fentec-project/gofe/data\"\n\t\"github.com/fentec-project/gofe/internal/dlog\"\n\t\"github.com/fentec-project/gofe/sample\"\n)\n\n// FHMultiIPEParams represents configuration parameters for the FHMultiIPE\n// scheme instance.\n// SecLevel (int): The parameter defines the security assumption of the scheme,\n// so called k-Lin assumption, where k is the specified SecLevel.\n// NumClients (int): The number of clients participating\n// VecLen (int): The length of vectors that clients encrypt.\n// BoundX (int): The value by which the coordinates of encrypted vectors are bounded.\n// BoundY (int): The value by which the coordinates of inner product vectors are bounded.\ntype FHMultiIPEParams struct {\n\tSecLevel   int\n\tNumClients int\n\tVecLen     int\n\tBoundX     *big.Int\n\tBoundY     *big.Int\n}\n\n// FHMultiIPE represents a Function Hiding Multi-input Inner Product\n// Encryption scheme based on the paper by P. Datta, T. Okamoto, and\n// J. Tomida:\n// \"Full-Hiding (Unbounded) Multi-Input Inner Product Functional Encryption\n// from the 𝒌-Linear Assumption\".\n// It allows clients to encrypt vectors {x_1,...,x_m} and derive a secret key\n// based on an inner product vectors {y_1,...,y_m} so that a decryptor can\n// decrypt the sum of inner products <x_1,y_1> + ... + <x_m, y_m> without\n// revealing vectors x_i or y_i. The scheme is slightly modified from the\n// original one to achieve a better performance. The difference is in\n// storing the secret master key as matrices B, BStar, instead of matrices\n// of elliptic curve elements g_1^B, g_2^BStar. This replaces elliptic curves\n// operations with matrix multiplication.\n//\n// This struct contains the shared choice for parameters on which the\n// functionality of the scheme depend.\ntype FHMultiIPE struct {\n\tParams *FHMultiIPEParams\n}\n\n// FHMultiIPESecKey represents a master secret key in FHMultiIPE scheme.\ntype FHMultiIPESecKey struct {\n\tBHat     []data.Matrix\n\tBStarHat []data.Matrix\n}\n\n// NewFHMultiIPE configures a new instance of the scheme. See struct\n// FHMultiIPEParams for the description of the parameters. It returns\n// a new FHMultiIPE instance.\nfunc NewFHMultiIPE(secLevel, numClients, vecLen int, boundX, boundY *big.Int) *FHMultiIPE {\n\tparams := &FHMultiIPEParams{SecLevel: secLevel, NumClients: numClients,\n\t\tVecLen: vecLen, BoundX: boundX, BoundY: boundY}\n\treturn &FHMultiIPE{Params: params}\n}\n\n// NewFHMultiIPEFromParams takes configuration parameters of an existing\n// FHMultiIPE scheme instance, and reconstructs the scheme with the same\n// configuration parameters. It returns a new FHMultiIPE instance.\nfunc NewFHMultiIPEFromParams(params *FHMultiIPEParams) *FHMultiIPE {\n\treturn &FHMultiIPE{\n\t\tParams: params,\n\t}\n}\n\n// GenerateKeys generates a pair of master secret key and public key\n// for the scheme. It returns an error in case keys could not be\n// generated.\nfunc (f FHMultiIPE) GenerateKeys() (*FHMultiIPESecKey, *bn256.GT, error) {\n\tsampler := sample.NewUniformRange(big.NewInt(1), bn256.Order)\n\tmu, err := sampler.Sample()\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\tgTMu := new(bn256.GT).ScalarBaseMult(mu)\n\n\tB := make([]data.Matrix, f.Params.NumClients)\n\tBStar := make([]data.Matrix, f.Params.NumClients)\n\tfor i := 0; i < f.Params.NumClients; i++ {\n\t\tB[i], BStar[i], err = randomOB(2*f.Params.VecLen+2*f.Params.SecLevel+1, mu)\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\t}\n\n\tBHat := make([]data.Matrix, f.Params.NumClients)\n\tBStarHat := make([]data.Matrix, f.Params.NumClients)\n\tfor i := 0; i < f.Params.NumClients; i++ {\n\t\tBHat[i] = make(data.Matrix, f.Params.VecLen+f.Params.SecLevel+1)\n\t\tBStarHat[i] = make(data.Matrix, f.Params.VecLen+f.Params.SecLevel)\n\t\tfor j := 0; j < f.Params.VecLen+f.Params.SecLevel+1; j++ {\n\t\t\tif j < f.Params.VecLen {\n\t\t\t\tBHat[i][j] = B[i][j]\n\t\t\t\tBStarHat[i][j] = BStar[i][j]\n\t\t\t} else if j == f.Params.VecLen {\n\t\t\t\tBHat[i][j] = B[i][j+f.Params.VecLen]\n\t\t\t\tBStarHat[i][j] = BStar[i][j+f.Params.VecLen]\n\t\t\t} else if j < f.Params.VecLen+f.Params.SecLevel {\n\t\t\t\tBHat[i][j] = B[i][j-1+f.Params.VecLen+f.Params.SecLevel]\n\t\t\t\tBStarHat[i][j] = BStar[i][j+f.Params.VecLen]\n\t\t\t} else {\n\t\t\t\tBHat[i][j] = B[i][j-1+f.Params.VecLen+f.Params.SecLevel]\n\t\t\t}\n\t\t}\n\t}\n\n\treturn &FHMultiIPESecKey{BHat: BHat, BStarHat: BStarHat}, gTMu, nil\n}\n\n// randomOB is a helping function that samples a random l x l matrix B\n// and calculates BStar = mu * (B^-1)^T\nfunc randomOB(l int, mu *big.Int) (data.Matrix, data.Matrix, error) {\n\tsampler := sample.NewUniform(bn256.Order)\n\tB, err := data.NewRandomMatrix(l, l, sampler)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tBStar, _, err := B.InverseModGauss(bn256.Order)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\tBStar = BStar.Transpose()\n\tBStar = BStar.MulScalar(mu)\n\tBStar = BStar.Mod(bn256.Order)\n\n\treturn B, BStar, nil\n}\n\n// DeriveKey takes a matrix y whose rows are input vector y_1,...,y_m and\n// master secret key, and returns the functional encryption key. That is\n// a key that for encrypted x_1,...,x_m allows to calculate the sum of\n// inner products <x_1,y_1> + ... + <x_m, y_m>. In case the key could not\n// be derived, it returns an error.\nfunc (f FHMultiIPE) DeriveKey(y data.Matrix, secKey *FHMultiIPESecKey) (data.MatrixG2, error) {\n\tsampler := sample.NewUniform(bn256.Order)\n\tgamma, err := data.NewRandomMatrix(f.Params.SecLevel, f.Params.NumClients, sampler)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tones := data.NewConstantVector(f.Params.NumClients-1, big.NewInt(1))\n\tr := data.NewVector(gamma[0][0:(f.Params.NumClients - 1)])\n\tsum, err := r.Dot(ones)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tsum.Neg(sum).Mod(sum, bn256.Order)\n\tgamma[0][f.Params.NumClients-1] = sum\n\n\tzeros := data.NewConstantVector(2*f.Params.VecLen+2*f.Params.SecLevel+1, big.NewInt(0))\n\tkeyMat := make(data.Matrix, f.Params.NumClients)\n\tvar s *big.Int\n\tfor i := 0; i < f.Params.NumClients; i++ {\n\t\tkeyMat[i] = zeros.Copy()\n\t\tfor j := 0; j < f.Params.VecLen+f.Params.SecLevel; j++ {\n\t\t\tif j < f.Params.VecLen {\n\t\t\t\ts = y[i][j]\n\t\t\t} else {\n\t\t\t\ts = gamma[j-f.Params.VecLen][i]\n\t\t\t}\n\n\t\t\tkeyMat[i] = keyMat[i].Add(secKey.BStarHat[i][j].MulScalar(s))\n\t\t\tkeyMat[i] = keyMat[i].Mod(bn256.Order)\n\t\t}\n\t}\n\n\treturn keyMat.MulG2(), nil\n}\n\n// Encrypt encrypts input vector x with the provided part of the master secret key.\n// It returns a ciphertext vector. If encryption failed, error is returned.\nfunc (f FHMultiIPE) Encrypt(x data.Vector, partSecKey data.Matrix) (data.VectorG1, error) {\n\tsampler := sample.NewUniform(bn256.Order)\n\tphi, err := data.NewRandomVector(f.Params.SecLevel, sampler)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tkeyVec := data.NewConstantVector(2*f.Params.VecLen+2*f.Params.SecLevel+1, big.NewInt(0))\n\tvar s *big.Int\n\tfor j := 0; j < f.Params.VecLen+f.Params.SecLevel+1; j++ {\n\t\tif j < f.Params.VecLen {\n\t\t\ts = x[j]\n\t\t} else if j == f.Params.VecLen {\n\t\t\ts = big.NewInt(1)\n\t\t} else {\n\t\t\ts = phi[j-f.Params.VecLen-1]\n\t\t}\n\n\t\tkeyVec = keyVec.Add(partSecKey[j].MulScalar(s))\n\t\tkeyVec = keyVec.Mod(bn256.Order)\n\t}\n\n\treturn keyVec.MulG1(), nil\n}\n\n// Decrypt accepts the ciphertext as a matrix whose rows are encryptions of vectors\n// x_1,...,x_m and a functional encryption key corresponding to vectors y_1,...,y_m.\n// It returns the sum of inner products <x_1,y_1> + ... + <x_m, y_m>. If decryption\n// failed, an error is returned.\nfunc (f *FHMultiIPE) Decrypt(cipher data.MatrixG1, key data.MatrixG2, pubKey *bn256.GT) (*big.Int, error) {\n\tsum := new(bn256.GT).ScalarBaseMult(big.NewInt(0))\n\tfor i := 0; i < f.Params.NumClients; i++ {\n\t\tfor j := 0; j < 2*f.Params.VecLen+2*f.Params.SecLevel+1; j++ {\n\t\t\tpaired := bn256.Pair(cipher[i][j], key[i][j])\n\t\t\tsum.Add(paired, sum)\n\t\t}\n\t}\n\n\tboundXY := new(big.Int).Mul(f.Params.BoundX, f.Params.BoundY)\n\tbound := new(big.Int).Mul(big.NewInt(int64(f.Params.NumClients*f.Params.VecLen)), boundXY)\n\n\tdec, err := dlog.NewCalc().InBN256().WithNeg().WithBound(bound).BabyStepGiantStep(sum, pubKey)\n\n\treturn dec, err\n}\n"
  },
  {
    "path": "innerprod/fullysec/fh_multi_ipe_test.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage fullysec_test\n\nimport (\n\t\"math/big\"\n\t\"testing\"\n\n\t\"github.com/fentec-project/gofe/data\"\n\t\"github.com/fentec-project/gofe/innerprod/fullysec\"\n\t\"github.com/fentec-project/gofe/sample\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestFH_Multi_IPE(t *testing.T) {\n\t// choose the parameters for the scheme\n\tsecLevel := 2\n\tvecLen := 10\n\tnumClient := 5\n\tbound := big.NewInt(128)\n\n\t// build the scheme\n\tfhmulti := fullysec.NewFHMultiIPE(secLevel, numClient, vecLen, bound, bound)\n\n\t// generate master secret key and public key\n\tmasterSecKey, pubKey, err := fhmulti.GenerateKeys()\n\tif err != nil {\n\t\tt.Fatalf(\"Error during keys generation: %v\", err)\n\t}\n\n\t// sample vectors that will be encrypted\n\tsampler := sample.NewUniformRange(new(big.Int).Add(new(big.Int).Neg(bound), big.NewInt(1)), bound)\n\tx := make(data.Matrix, numClient)\n\tfor i := 0; i < numClient; i++ {\n\t\tx[i], err = data.NewRandomVector(vecLen, sampler)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"Error during random vector generation: %v\", err)\n\t\t}\n\t}\n\n\t// simulate different clients (encryptors which should be given a part of the master key)\n\t// and encrypt their vectors\n\tcipher := make(data.MatrixG1, numClient)\n\tclients := make([]*fullysec.FHMultiIPE, numClient)\n\tfor i := 0; i < numClient; i++ {\n\t\tclients[i] = fullysec.NewFHMultiIPEFromParams(fhmulti.Params)\n\t\tcipher[i], err = clients[i].Encrypt(x[i], masterSecKey.BHat[i])\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"Error during encryption: %v\", err)\n\t\t}\n\t}\n\n\t// sample inner product vectors and put them in a matrix\n\ty := make(data.Matrix, numClient)\n\tfor i := 0; i < numClient; i++ {\n\t\ty[i], err = data.NewRandomVector(vecLen, sampler)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"Error during random vector generation: %v\", err)\n\t\t}\n\t}\n\n\t// derive a functional key for vector y\n\tkey, err := fhmulti.DeriveKey(y, masterSecKey)\n\tif err != nil {\n\t\tt.Fatalf(\"Error during key derivation: %v\", err)\n\t}\n\n\t// simulate a decryptor\n\tdecryptor := fullysec.NewFHMultiIPEFromParams(fhmulti.Params)\n\n\t// decryptor decrypts the inner-product without knowing\n\t// vectors x and y\n\txy, err := decryptor.Decrypt(cipher, key, pubKey)\n\tif err != nil {\n\t\tt.Fatalf(\"Error during decryption: %v\", err)\n\t}\n\n\t// check the correctness of the result\n\txyCheck, err := x.Dot(y)\n\tif err != nil {\n\t\tt.Fatalf(\"Error during inner product calculation\")\n\t}\n\tassert.Equal(t, xy.Cmp(xyCheck), 0, \"obtained incorrect inner product\")\n}\n"
  },
  {
    "path": "innerprod/fullysec/fhipe.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage fullysec\n\nimport (\n\t\"fmt\"\n\t\"math/big\"\n\n\t\"crypto/rand\"\n\n\t\"github.com/fentec-project/bn256\"\n\t\"github.com/fentec-project/gofe/data\"\n\t\"github.com/fentec-project/gofe/internal/dlog\"\n\t\"github.com/fentec-project/gofe/sample\"\n)\n\n// FHIPEParams holds common parameters used in the scheme. These are:\n// L (int): The length of vectors to be encrypted.\n// BoundX (int): The value by which coordinates of encrypted vectors x are bounded.\n// BoundY (int): The value by which coordinates of inner product vectors y are bounded.\ntype FHIPEParams struct {\n\tL      int\n\tBoundX *big.Int\n\tBoundY *big.Int\n}\n\n// FHIPE represents a Function Hiding Inner Product Encryption scheme\n// based on the paper by Kim, Lewi, Mandal, Montgomery, Roy, Wu:\n// \"Function-Hiding Inner Product Encryption is Practical\".\n// It allows to encrypt a vector x and derive a secret key based\n// on an inner product vector y so that a deryptor can decrypt the\n// inner product <x,y> without revealing x or y.\n// The struct contains the shared choice for parameters on which\n// the functionality of the scheme depend.\ntype FHIPE struct {\n\tParams *FHIPEParams\n}\n\n// NewFHIPE configures a new instance of the scheme.\n// It accepts the length of input vectors l, a bound by which\n// the coordinates of encryption vectors are bounded, and similarly a\n// bound by which the coordinates of inner product vectors are bounded.\n//\n// It returns an error in case the scheme could not be properly\n// configured, or if the possible decryption value is to big.\nfunc NewFHIPE(l int, boundX, boundY *big.Int) (*FHIPE, error) {\n\tboundXY := new(big.Int).Mul(boundX, boundY)\n\tprod := new(big.Int).Mul(big.NewInt(int64(2*l)), boundXY)\n\tif prod.Cmp(bn256.Order) > 0 {\n\t\treturn nil, fmt.Errorf(\"2 * l * boundX * boundY should be smaller than group order\")\n\t}\n\n\treturn &FHIPE{\n\t\tParams: &FHIPEParams{\n\t\t\tL:      l,\n\t\t\tBoundX: boundX,\n\t\t\tBoundY: boundY}}, nil\n}\n\n// NewFHIPEFromParams takes configuration parameters of an existing\n// FHIPE scheme instance, and reconstructs the scheme with same configuration\n// parameters. It returns a new FHIPE instance.\nfunc NewFHIPEFromParams(params *FHIPEParams) *FHIPE {\n\treturn &FHIPE{\n\t\tParams: params,\n\t}\n}\n\n// FHIPESecKey is a secret key for FHIPE scheme.\ntype FHIPESecKey struct {\n\tG1    *bn256.G1\n\tG2    *bn256.G2\n\tB     data.Matrix\n\tBStar data.Matrix\n}\n\n// GenerateMasterKey generates a master secret key for the scheme.\n// It returns an error in case master key could not be generated.\nfunc (d *FHIPE) GenerateMasterKey() (*FHIPESecKey, error) {\n\t_, g1, err := bn256.RandomG1(rand.Reader)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t_, g2, err := bn256.RandomG2(rand.Reader)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tsampler := sample.NewUniform(bn256.Order)\n\tb, err := data.NewRandomMatrix(d.Params.L, d.Params.L, sampler)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tbStar, det, err := b.InverseModGauss(bn256.Order)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tbStar = bStar.Transpose()\n\tbStar = bStar.MulScalar(det)\n\tbStar = bStar.Mod(bn256.Order)\n\n\treturn &FHIPESecKey{G1: g1, G2: g2, B: b, BStar: bStar}, nil\n}\n\n// FHIPEDerivedKey is a functional encryption key for FHIPE scheme.\ntype FHIPEDerivedKey struct {\n\tK1 *bn256.G1\n\tK2 data.VectorG1\n}\n\n// DeriveKey takes a master key and input vector y, and returns a\n// functional encryption key. In case the key could not be derived, it\n// returns an error.\nfunc (d *FHIPE) DeriveKey(y data.Vector, masterKey *FHIPESecKey) (*FHIPEDerivedKey, error) {\n\tif err := y.CheckBound(d.Params.BoundY); err != nil {\n\t\treturn nil, err\n\t}\n\tif len(y) != d.Params.L {\n\t\treturn nil, fmt.Errorf(\"vector dimension error\")\n\t}\n\tif masterKey.B.Rows() != d.Params.L {\n\t\treturn nil, fmt.Errorf(\"master key dimensions error\")\n\t}\n\n\tsampler := sample.NewUniform(bn256.Order)\n\talpha, err := sampler.Sample()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tdet, err := masterKey.B.DeterminantGauss(bn256.Order)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tk1 := new(bn256.G1).ScalarMult(masterKey.G1, det)\n\tk1.ScalarMult(k1, alpha)\n\n\talphaBY, err := masterKey.B.MulVec(y)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\talphaBY = alphaBY.MulScalar(alpha)\n\talphaBY = alphaBY.Mod(bn256.Order)\n\tg1Vec := make(data.VectorG1, d.Params.L)\n\tfor i := 0; i < d.Params.L; i++ {\n\t\tg1Vec[i] = new(bn256.G1).Set(masterKey.G1)\n\t}\n\tk2 := alphaBY.MulVecG1(g1Vec)\n\n\treturn &FHIPEDerivedKey{K1: k1, K2: k2}, nil\n}\n\n// FHIPECipher is a functional encryption ciphertext for FHIPE scheme.\ntype FHIPECipher struct {\n\tC1 *bn256.G2\n\tC2 data.VectorG2\n}\n\n// Encrypt encrypts input vector x with the provided master key and returns a ciphertext.\n// If encryption failed, error is returned.\nfunc (d *FHIPE) Encrypt(x data.Vector, masterKey *FHIPESecKey) (*FHIPECipher, error) {\n\tif err := x.CheckBound(d.Params.BoundX); err != nil {\n\t\treturn nil, err\n\t}\n\tif len(x) != d.Params.L {\n\t\treturn nil, fmt.Errorf(\"vector dimension error\")\n\t}\n\tif masterKey.B.Rows() != d.Params.L {\n\t\treturn nil, fmt.Errorf(\"master key dimensions error\")\n\t}\n\n\tsampler := sample.NewUniform(bn256.Order)\n\tbeta, err := sampler.Sample()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tc1 := new(bn256.G2).ScalarMult(masterKey.G2, beta)\n\n\tbetaBStarX, err := masterKey.BStar.MulVec(x)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tbetaBStarX = betaBStarX.MulScalar(beta)\n\tbetaBStarX = betaBStarX.Mod(bn256.Order)\n\tg2Vec := make(data.VectorG2, d.Params.L)\n\tfor i := 0; i < d.Params.L; i++ {\n\t\tg2Vec[i] = new(bn256.G2).Set(masterKey.G2)\n\t}\n\tc2 := betaBStarX.MulVecG2(g2Vec)\n\n\treturn &FHIPECipher{C1: c1, C2: c2}, nil\n}\n\n// Decrypt accepts the ciphertext and functional encryption key.\n// It returns the inner product of x and y. If decryption failed,\n// an error is returned.\nfunc (d *FHIPE) Decrypt(cipher *FHIPECipher, key *FHIPEDerivedKey) (*big.Int, error) {\n\tif len(cipher.C2) != d.Params.L || len(key.K2) != d.Params.L {\n\t\treturn nil, fmt.Errorf(\"key or cipher length error\")\n\t}\n\n\td1 := bn256.Pair(key.K1, cipher.C1)\n\n\td2 := new(bn256.GT).ScalarBaseMult(big.NewInt(0))\n\tfor i := 0; i < d.Params.L; i++ {\n\t\tpairedI := bn256.Pair(key.K2[i], cipher.C2[i])\n\t\td2 = new(bn256.GT).Add(pairedI, d2)\n\t}\n\n\t// calculate the upper bound of the result needed for the\n\t// discrete logarithm computation\n\tboundXY := new(big.Int).Mul(d.Params.BoundX, d.Params.BoundY)\n\tbound := new(big.Int).Mul(big.NewInt(int64(d.Params.L)), boundXY)\n\n\tdec, err := dlog.NewCalc().InBN256().WithNeg().WithBound(bound).BabyStepGiantStep(d2, d1)\n\treturn dec, err\n}\n"
  },
  {
    "path": "innerprod/fullysec/fhipe_test.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage fullysec_test\n\nimport (\n\t\"math/big\"\n\t\"testing\"\n\n\t\"github.com/fentec-project/gofe/data\"\n\t\"github.com/fentec-project/gofe/innerprod/fullysec\"\n\t\"github.com/fentec-project/gofe/sample\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestFHIPE(t *testing.T) {\n\t// choose the parameters for the encryption and build the scheme\n\tl := 30\n\tbound := big.NewInt(128)\n\n\tfhipe, err := fullysec.NewFHIPE(l, bound, bound)\n\tif err != nil {\n\t\tt.Fatalf(\"Error during scheme creation: %v\", err)\n\t}\n\n\t// generate master key\n\tmasterSecKey, err := fhipe.GenerateMasterKey()\n\tif err != nil {\n\t\tt.Fatalf(\"Error during master key generation: %v\", err)\n\t}\n\n\t// sample a vector that will be encrypted\n\tsampler := sample.NewUniformRange(new(big.Int).Add(new(big.Int).Neg(bound), big.NewInt(1)), bound)\n\tx, err := data.NewRandomVector(l, sampler)\n\tif err != nil {\n\t\tt.Fatalf(\"Error during random vector generation: %v\", err)\n\t}\n\n\t// simulate the instantiation of an encryptor (which should know the master key)\n\tencryptor := fullysec.NewFHIPEFromParams(fhipe.Params)\n\t// encrypt the vector\n\tciphertext, err := encryptor.Encrypt(x, masterSecKey)\n\tif err != nil {\n\t\tt.Fatalf(\"Error during encryption: %v\", err)\n\t}\n\n\t// sample a inner product vector\n\ty, err := data.NewRandomVector(l, sampler)\n\tif err != nil {\n\t\tt.Fatalf(\"Error during random vecotr generation: %v\", err)\n\t}\n\n\t// derive a functional key for vector y\n\tkey, err := fhipe.DeriveKey(y, masterSecKey)\n\tif err != nil {\n\t\tt.Fatalf(\"Error during key derivation: %v\", err)\n\t}\n\n\t// simulate a decryptor\n\tdecryptor := fullysec.NewFHIPEFromParams(fhipe.Params)\n\t// decryptor decrypts the inner-product without knowing\n\t// vectors x and y\n\txy, err := decryptor.Decrypt(ciphertext, key)\n\tif err != nil {\n\t\tt.Fatalf(\"Error during decryption: %v\", err)\n\t}\n\n\t// check the correctness of the result\n\txyCheck, err := x.Dot(y)\n\tif err != nil {\n\t\tt.Fatalf(\"Error during inner product calculation\")\n\t}\n\tassert.Equal(t, xy.Cmp(xyCheck), 0, \"obtained incorrect inner product\")\n}\n"
  },
  {
    "path": "innerprod/fullysec/lwe.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage fullysec\n\nimport (\n\t\"crypto/rand\"\n\t\"math\"\n\t\"math/big\"\n\n\t\"github.com/fentec-project/gofe/data\"\n\tgofe \"github.com/fentec-project/gofe/internal\"\n\t\"github.com/fentec-project/gofe/sample\"\n\t\"github.com/pkg/errors\"\n)\n\n// LWEParams represents parameters for the fully secure LWE scheme.\ntype LWEParams struct {\n\tL int // Length of data vectors for inner product\n\n\tN int // Main security parameters of the scheme\n\tM int // Number of samples\n\n\tBoundX *big.Int // Message space size\n\tBoundY *big.Int // Inner product vector space size\n\n\t// Modulus for the resulting inner product.\n\t// K depends on the parameters L, P and V and is computed by the scheme.\n\tK *big.Int\n\n\t// Modulus for ciphertext and keys.\n\t// Must be significantly larger than K.\n\tQ *big.Int\n\n\t// standard deviation for the noise terms in the encryption process\n\tSigmaQ *big.Float\n\t// precomputed LSigmaQ = SigmaQ / (1/2log(2)) needed for sampling\n\tLSigmaQ *big.Int\n\t// standard deviation for first half of the matrix for sampling private key\n\tSigma1 *big.Float\n\t// precomputed LSigma1 = Sigma1 / (1/2log(2)) needed for sampling\n\tLSigma1 *big.Int\n\t// standard deviation for second half of the matrix for sampling private key\n\tSigma2 *big.Float\n\t// precomputed LSigma2 = Sigma2 / (1/2log(2)) needed for sampling\n\tLSigma2 *big.Int\n\t// Matrix A of dimensions M*N is a public parameter of the scheme\n\tA data.Matrix\n}\n\n// LWE represents a scheme instantiated from the LWE problem.\n// Based on the LWE variant of:\n// Agrawal, Shweta, Libert, and Stehle:\n// \"Fully secure functional encryption for inner products,\n// from standard assumptions\".\ntype LWE struct {\n\tParams *LWEParams\n}\n\n// NewLWE configures a new instance of the scheme.\n// It accepts the length of input vectors l, the main security parameter\n// n, the message space size boundX, and the inner product vector space size\n// boundY. The function sets up the remaining public parameters as\n// it is suggested in the paper by Agrawal, Shweta, Libert, and Stehle:\n// \"Fully secure functional encryption for inner products,\n// from standard assumptions\".\n// Note that this is a prototype implementation and should not be\n// used in production before security testing against various\n// known attacks has been performed. Unfortunately, no such (theoretical)\n// evaluation exists yet in the literature.\n//\n// It returns an error in case public parameters of the scheme could\n// not be generated.\nfunc NewLWE(l, n int, boundX, boundY *big.Int) (*LWE, error) {\n\t// K = 2 * l * boundX * boundY\n\tK := new(big.Int).Mul(boundX, boundY)\n\tK.Mul(K, big.NewInt(int64(l*2)))\n\tkF := new(big.Float).SetInt(K)\n\tSquaredF := new(big.Float).Mul(kF, kF)\n\n\tnF := float64(n)\n\n\tnBitsQ := 1\n\tvar sigma, sigma1, sigma2 *big.Float\n\tvar lSigma1, lSigma2 *big.Int\n\t// parameters for the scheme are given as a set of requirements in the paper\n\t// hence we search for such parameters iteratively\n\tfor i := 1; true; i++ {\n\t\t//assuming that the final q will have at most i bits we calculate a bound\n\t\tboundMF := float64(n * i)\n\t\t// tmp values\n\t\tlog2M := math.Log2(boundMF)\n\t\tsqrtNLogM := math.Sqrt(nF * log2M)\n\n\t\tmax := new(big.Float)\n\t\tif SquaredF.Cmp(big.NewFloat(boundMF)) == 1 {\n\t\t\tmax.SetFloat64(boundMF)\n\t\t} else {\n\t\t\tmax.Set(SquaredF)\n\t\t}\n\n\t\tsqrtMax := new(big.Float).Sqrt(max)\n\n\t\tsigma1 = new(big.Float).Mul(big.NewFloat(sqrtNLogM), sqrtMax)\n\t\t// to sample with NormalDoubleConstant sigmaQ must be\n\t\t// a multiple of sample.SigmaCDT = sqrt(1/2ln(2)), hence we make\n\t\t// it such\n\t\tlSigma1F := new(big.Float).Quo(sigma1, sample.SigmaCDT)\n\t\tlSigma1, _ = lSigma1F.Int(nil)\n\t\tsigma1.Mul(sample.SigmaCDT, lSigma1F)\n\n\t\t// tmp values\n\t\tnPow3 := math.Pow(nF, 3)\n\t\tpowSqrtLogM5 := math.Pow(math.Sqrt(log2M), 5)\n\t\tmulVal := math.Sqrt(nF) * nPow3 * powSqrtLogM5 * math.Sqrt(boundMF)\n\t\tsigma2 = new(big.Float).Mul(big.NewFloat(mulVal), max)\n\t\t// to sample with NormalDoubleConstant sigmaQ must be\n\t\t// a multiple of sample.SigmaCDT = sqrt(1/2ln(2)), hence we make\n\t\t// it such\n\t\tlSigma2F := new(big.Float).Quo(sigma2, sample.SigmaCDT)\n\t\tlSigma2, _ = lSigma2F.Int(nil)\n\t\tsigma2.Mul(sample.SigmaCDT, lSigma2F)\n\n\t\t// tmp value\n\t\tsigma1Square := new(big.Float).Mul(sigma1, sigma1)\n\t\tsigma2Square := new(big.Float).Mul(sigma2, sigma2)\n\n\t\tbound2 := new(big.Float).Add(sigma1Square, sigma2Square)\n\t\tbound2.Sqrt(bound2)\n\t\tbound2.Mul(bound2, big.NewFloat(math.Sqrt(nF)))\n\n\t\tsigma = new(big.Float).Quo(big.NewFloat(1), SquaredF)\n\t\tsigma.Quo(sigma, bound2)\n\t\tsigma.Quo(sigma, big.NewFloat(math.Log2(nF)))\n\n\t\t// assuming number of bits of q will be at least nBitsQ from the previous\n\t\t// iteration (this is always true) we calculate sigma prime\n\t\tnfPow6 := math.Pow(nF, 6)\n\t\tnBitsQPow2 := math.Pow(float64(nBitsQ), 2)\n\t\tsqrtLog2nFPow5 := math.Pow(math.Sqrt(math.Log2(nF)), 5)\n\t\tsigmaPrime := new(big.Float).Quo(sigma, kF)\n\t\tsigmaPrime.Quo(sigmaPrime, big.NewFloat(nfPow6*nBitsQPow2*sqrtLog2nFPow5))\n\n\t\tboundForQ := new(big.Float)\n\t\tboundForQ.Quo(big.NewFloat(math.Sqrt(math.Log2(nF))), sigmaPrime)\n\t\tnBitsQ = boundForQ.MantExp(nil) + 1\n\t\t// check if the number of bits for q is greater than i as it was\n\t\t// assumed at the beginning of the iteration\n\t\tif nBitsQ < i {\n\t\t\tbreak\n\t\t}\n\t\t// in the next iteration the number of bits for q must be at least as\n\t\t// many as it was demanded in this iteration\n\t\ti = nBitsQ\n\t}\n\t// get q\n\tq, err := rand.Prime(rand.Reader, nBitsQ)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tm := int(1.01 * nF * float64(nBitsQ))\n\n\t// get sigmaQ\n\tqF := new(big.Float).SetInt(q)\n\tsigmaQ := new(big.Float).Mul(sigma, qF)\n\t// to sample with NormalDoubleConstant sigmaQ must be\n\t// a multiple of sample.SigmaCDT = sqrt(1/2ln(2)), hence we make\n\t// it such\n\tlSigmaQF := new(big.Float).Quo(sigmaQ, sample.SigmaCDT)\n\tlSigmaQ, _ := lSigmaQF.Int(nil)\n\tsigmaQ.Mul(sample.SigmaCDT, lSigmaQF)\n\n\trandMat, err := data.NewRandomMatrix(m, n, sample.NewUniform(q))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &LWE{\n\t\tParams: &LWEParams{\n\t\t\tL:       l,\n\t\t\tN:       n,\n\t\t\tM:       m,\n\t\t\tBoundX:  boundX,\n\t\t\tBoundY:  boundY,\n\t\t\tQ:       q,\n\t\t\tK:       K,\n\t\t\tSigmaQ:  sigmaQ,\n\t\t\tLSigmaQ: lSigmaQ,\n\t\t\tSigma1:  sigma1,\n\t\t\tLSigma1: lSigma1,\n\t\t\tSigma2:  sigma2,\n\t\t\tLSigma2: lSigma2,\n\t\t\tA:       randMat,\n\t\t},\n\t}, nil\n}\n\n// GenerateSecretKey generates a secret key for the scheme.\n// The secret key is a matrix with dimensions l*m.\n//\n// In case secret key could not be generated, it returns an error.\nfunc (s *LWE) GenerateSecretKey() (data.Matrix, error) {\n\tvar val *big.Int\n\n\tsampler1 := sample.NewNormalDoubleConstant(s.Params.LSigma1)\n\tsampler2 := sample.NewNormalDoubleConstant(s.Params.LSigma2)\n\n\tZ := make(data.Matrix, s.Params.L)\n\thalfRows := Z.Rows() / 2\n\tfor i := 0; i < Z.Rows(); i++ {\n\t\tZ[i] = make(data.Vector, s.Params.M)\n\t\tfor j := 0; j < Z.Cols(); j++ {\n\t\t\tif j < halfRows { // first half\n\t\t\t\tval, _ = sampler1.Sample()\n\t\t\t} else { // second half\n\t\t\t\tval, _ = sampler2.Sample()\n\t\t\t\tif j-halfRows == i {\n\t\t\t\t\tval.Add(val, big.NewInt(1))\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tZ[i][j] = val\n\t\t}\n\t}\n\n\treturn Z, nil\n}\n\n// GeneratePublicKey accepts a master secret key Z and generates a\n// corresponding master public key.\n// Public key is a matrix of l*m elements.\n// In case of a malformed secret key the function returns an error.\nfunc (s *LWE) GeneratePublicKey(Z data.Matrix) (data.Matrix, error) {\n\tif !Z.CheckDims(s.Params.L, s.Params.M) {\n\t\treturn nil, gofe.ErrMalformedSecKey\n\t}\n\t// public key is obtained by multiplying secret key Z by a random matrix A.\n\tU, _ := Z.Mul(s.Params.A)\n\tU = U.Mod(s.Params.Q)\n\n\treturn U, nil\n}\n\n// DeriveKey accepts input vector y and master secret key Z, and derives a\n// functional encryption key.\n// In case of malformed secret key or input vector that violates the\n// configured bound, it returns an error.\nfunc (s *LWE) DeriveKey(y data.Vector, Z data.Matrix) (data.Vector, error) {\n\tif err := y.CheckBound(s.Params.BoundY); err != nil {\n\t\treturn nil, err\n\t}\n\tif !Z.CheckDims(s.Params.L, s.Params.M) {\n\t\treturn nil, gofe.ErrMalformedSecKey\n\t}\n\t// Secret key is a linear combination of input vector x and master secret key Z.\n\tzY, err := Z.Transpose().MulVec(y)\n\tif err != nil {\n\t\treturn nil, gofe.ErrMalformedInput\n\t}\n\tzY = zY.Mod(s.Params.Q)\n\n\treturn zY, nil\n}\n\n// Encrypt encrypts vector y using public key U.\n// It returns the resulting ciphertext vector. In case of malformed\n// public key or input vector that violates the configured bound,\n// it returns an error.\nfunc (s *LWE) Encrypt(x data.Vector, U data.Matrix) (data.Vector, error) {\n\tif err := x.CheckBound(s.Params.BoundX); err != nil {\n\t\treturn nil, err\n\t}\n\tif !U.CheckDims(s.Params.L, s.Params.N) {\n\t\treturn nil, gofe.ErrMalformedPubKey\n\t}\n\tif len(x) != s.Params.L {\n\t\treturn nil, gofe.ErrMalformedInput\n\t}\n\n\t// Create a random vector\n\tr, err := data.NewRandomVector(s.Params.N, sample.NewUniform(s.Params.Q))\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"error in encrypt\")\n\t}\n\n\t// calculate the standard distribution and sample vectors e0, e1\n\tsampler := sample.NewNormalDoubleConstant(s.Params.LSigmaQ)\n\n\te0, err0 := data.NewRandomVector(s.Params.M, sampler)\n\te1, err1 := data.NewRandomVector(s.Params.L, sampler)\n\tif err0 != nil || err1 != nil {\n\t\treturn nil, errors.Wrap(err0, \"error in encrypt\")\n\t}\n\n\t// calculate first part of the cipher\n\tc0, _ := s.Params.A.MulVec(r)\n\tc0 = c0.Add(e0)\n\tc0 = c0.Mod(s.Params.Q)\n\n\t// calculate second part of the cipher\n\tqDivK := new(big.Int).Div(s.Params.Q, s.Params.K)\n\tt := x.MulScalar(qDivK) // center\n\n\tc1, _ := U.MulVec(r)\n\tc1 = c1.Add(e1)\n\tc1 = c1.Add(t)\n\tc1 = c1.Mod(s.Params.Q)\n\n\treturn append(c0, c1...), nil\n}\n\n// Decrypt accepts an encrypted vector cipher, functional encryption key zX,\n// and plaintext vector x, and calculates the inner product of x and y.\n// If decryption failed (for instance with input data that violates the\n// configured bound or malformed ciphertext or keys), error is returned.\nfunc (s *LWE) Decrypt(cipher, zY, y data.Vector) (*big.Int, error) {\n\tif err := y.CheckBound(s.Params.BoundY); err != nil {\n\t\treturn nil, err\n\t}\n\tif len(zY) != s.Params.M {\n\t\treturn nil, gofe.ErrMalformedDecKey\n\t}\n\tif len(y) != s.Params.L {\n\t\treturn nil, gofe.ErrMalformedInput\n\t}\n\n\tif len(cipher) != s.Params.M+s.Params.L {\n\t\treturn nil, gofe.ErrMalformedCipher\n\t}\n\tc0 := cipher[:s.Params.M]\n\tc1 := cipher[s.Params.M:]\n\tyDotC1, _ := y.Dot(c1)\n\tzYDotC0, _ := zY.Dot(c0)\n\n\tmu1 := new(big.Int).Sub(yDotC1, zYDotC0)\n\tmu1.Mod(mu1, s.Params.Q)\n\tif mu1.Cmp(new(big.Int).Quo(s.Params.Q, big.NewInt(2))) == 1 {\n\t\tmu1.Sub(mu1, s.Params.Q)\n\t}\n\n\tparamsKTimes2 := new(big.Int).Lsh(s.Params.K, 1)\n\tqDivK := new(big.Int).Div(s.Params.Q, s.Params.K)\n\tqDivKTimes2 := new(big.Int).Div(s.Params.Q, paramsKTimes2)\n\n\tmu := new(big.Int).Add(mu1, qDivKTimes2)\n\tmu.Div(mu, qDivK)\n\n\treturn mu, nil\n}\n"
  },
  {
    "path": "innerprod/fullysec/lwe_test.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage fullysec_test\n\nimport (\n\t\"math/big\"\n\t\"testing\"\n\n\t\"github.com/fentec-project/gofe/data\"\n\t\"github.com/fentec-project/gofe/innerprod/fullysec\"\n\t\"github.com/fentec-project/gofe/sample\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestFullySec_LWE(t *testing.T) {\n\tl := 4\n\tn := 64\n\tboundX := big.NewInt(1000) // maximal size of the entry of the message\n\tboundY := big.NewInt(1000) // maximal size of the entry of the other operand for inner product\n\n\tx, y, xy := testVectorData(l, boundX, boundY)\n\temptyVec := data.Vector{}\n\temptyMat := data.Matrix{}\n\n\tfsLWE, err := fullysec.NewLWE(l, n, boundX, boundY)\n\tassert.NoError(t, err)\n\n\tZ, err := fsLWE.GenerateSecretKey()\n\tassert.NoError(t, err)\n\n\t_, err = fsLWE.GeneratePublicKey(emptyMat)\n\tassert.Error(t, err)\n\tU, err := fsLWE.GeneratePublicKey(Z)\n\tassert.NoError(t, err)\n\n\t_, err = fsLWE.DeriveKey(emptyVec, Z)\n\tassert.Error(t, err)\n\t_, err = fsLWE.DeriveKey(y, emptyMat)\n\tassert.Error(t, err)\n\t_, err = fsLWE.DeriveKey(y.MulScalar(big.NewInt(10000)), emptyMat)\n\tassert.Error(t, err) // boundary violation\n\tzY, err := fsLWE.DeriveKey(y, Z)\n\tassert.NoError(t, err)\n\n\t_, err = fsLWE.Encrypt(emptyVec, U)\n\tassert.Error(t, err)\n\t_, err = fsLWE.Encrypt(x, emptyMat)\n\tassert.Error(t, err)\n\t_, err = fsLWE.Encrypt(x.MulScalar(big.NewInt(10000)), U)\n\tassert.Error(t, err) // boundary violation\n\tcipher, err := fsLWE.Encrypt(x, U)\n\tassert.NoError(t, err)\n\n\t_, err = fsLWE.Decrypt(emptyVec, zY, y)\n\tassert.Error(t, err)\n\t_, err = fsLWE.Decrypt(cipher, emptyVec, y)\n\tassert.Error(t, err)\n\t_, err = fsLWE.Decrypt(cipher, zY, emptyVec)\n\tassert.Error(t, err)\n\t_, err = fsLWE.Decrypt(cipher, zY, y.MulScalar(big.NewInt(10000)))\n\tassert.Error(t, err) // boundary violation\n\txyDecrypted, err := fsLWE.Decrypt(cipher, zY, y)\n\tassert.NoError(t, err)\n\tassert.Equal(t, xy.Cmp(xyDecrypted), 0, \"obtained incorrect inner product\")\n}\n\n// testVectorData returns random vectors x, y, each containing\n// elements up to the respective bound.\n// It also returns the dot product of the vectors.\nfunc testVectorData(len int, boundX, boundY *big.Int) (data.Vector, data.Vector, *big.Int) {\n\tsamplerX := sample.NewUniformRange(new(big.Int).Neg(boundX), boundX)\n\tsamplerY := sample.NewUniformRange(new(big.Int).Neg(boundY), boundY)\n\tx, _ := data.NewRandomVector(len, samplerX)\n\ty, _ := data.NewRandomVector(len, samplerY)\n\txy, _ := x.Dot(y)\n\n\treturn x, y, xy\n}\n"
  },
  {
    "path": "innerprod/fullysec/paillier.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage fullysec\n\nimport (\n\t\"crypto/rand\"\n\t\"fmt\"\n\t\"math/big\"\n\n\t\"github.com/fentec-project/gofe/data\"\n\t\"github.com/fentec-project/gofe/internal\"\n\t\"github.com/fentec-project/gofe/internal/keygen\"\n\t\"github.com/fentec-project/gofe/sample\"\n)\n\n// PaillierParams represents parameters for the fully secure Paillier scheme.\ntype PaillierParams struct {\n\tL       int        // Length of data vectors for inner product\n\tN       *big.Int   // a big integer, a product of two safe primes\n\tNSquare *big.Int   // N^2 a modulus for computations\n\tBoundX  *big.Int   // a bound on the entries of the input vector\n\tBoundY  *big.Int   // a bound on the entries of the inner product vector\n\tSigma   *big.Float // the standard deviation for the sampling a secret key\n\tLSigma  *big.Int   // precomputed Sigma/(1/2log(2)) needed for sampling\n\tLambda  int        // security parameter\n\tG       *big.Int   // generator of the 2n-th residues subgroup of Z_N^2*\n}\n\n// Paillier represents a scheme based on the Paillier variant by\n// Agrawal, Shweta, Libert, and Stehle\":\n// \"Fully secure functional encryption for inner products,\n// from standard assumptions\".\ntype Paillier struct {\n\tParams *PaillierParams\n}\n\n// NewPaillier configures a new instance of the scheme.\n// It accepts the length of input vectors l, security parameter lambda,\n// the bit length of prime numbers (giving security to the scheme, it\n// should be such that factoring two primes with such a bit length takes\n// at least 2^lambda operations), and boundX and boundY by which\n// coordinates of input vectors and inner product vectors are bounded.\n// If you are not sure how to choose lambda and bitLen, setting\n// lambda = 128, bitLen = 1024 will result in a scheme that is believed\n// to have 128 bit security.\n//\n// It returns an error in the case the scheme could not be properly\n// configured, or if the precondition boundX, boundY < (n / l)^(1/2)\n// is not satisfied.\nfunc NewPaillier(l, lambda, bitLen int, boundX, boundY *big.Int) (*Paillier, error) {\n\t// generate two safe primes\n\tp, err := keygen.GetSafePrime(bitLen)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tq, err := keygen.GetSafePrime(bitLen)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// calculate n = p * q\n\tn := new(big.Int).Mul(p, q)\n\n\t// calculate n^2\n\tnSquare := new(big.Int).Mul(n, n)\n\n\t// check if the parameters of the scheme are compatible,\n\t// i.e. security parameter should be big enough that\n\t// the generated n is much greater than l and the bounds\n\tif boundX != nil && boundY != nil {\n\t\txSquareL := new(big.Int).Mul(boundX, boundX)\n\t\txSquareL.Mul(xSquareL, big.NewInt(int64(2*l)))\n\t\tySquareL := new(big.Int).Mul(boundY, boundY)\n\t\tySquareL.Mul(ySquareL, big.NewInt(int64(2*l)))\n\t\tif n.Cmp(xSquareL) < 1 {\n\t\t\treturn nil, fmt.Errorf(\"parameters generation failed,\" +\n\t\t\t\t\"boundX and l too big for bitLen\")\n\t\t}\n\t\tif n.Cmp(ySquareL) < 1 {\n\t\t\treturn nil, fmt.Errorf(\"parameters generation failed,\" +\n\t\t\t\t\"boundY and l too big for bitLen\")\n\t\t}\n\t}\n\n\t// generate a generator for the 2n-th residues subgroup of Z_n^2*\n\tgPrime, err := rand.Int(rand.Reader, nSquare)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tg := new(big.Int).Exp(gPrime, n, nSquare)\n\tg.Exp(g, big.NewInt(2), nSquare)\n\n\t// check if generated g is invertible, which should be the case except with\n\t// negligible probability\n\tif check := new(big.Int).ModInverse(g, nSquare); check == nil {\n\t\treturn nil, fmt.Errorf(\"parameters generation failed,\" +\n\t\t\t\"unexpected event of generator g is not invertible\")\n\t}\n\n\t// calculate sigma\n\tnTo5 := new(big.Int).Exp(n, big.NewInt(5), nil)\n\tsigma := new(big.Float).SetInt(nTo5)\n\tsigma.Mul(sigma, big.NewFloat(float64(lambda)))\n\tsigma.Sqrt(sigma)\n\tsigma.Add(sigma, big.NewFloat(2))\n\t// to sample with NormalDoubleConstant sigma must be\n\t// a multiple of sample.SigmaCDT = sqrt(1/2ln(2)), hence we make\n\t// it such\n\tlSigmaF := new(big.Float).Quo(sigma, sample.SigmaCDT)\n\tlSigma, _ := lSigmaF.Int(nil)\n\tlSigma.Add(lSigma, big.NewInt(1))\n\tsigma.Mul(sample.SigmaCDT, lSigmaF)\n\n\treturn &Paillier{\n\t\tParams: &PaillierParams{\n\t\t\tL:       l,\n\t\t\tN:       n,\n\t\t\tNSquare: nSquare,\n\t\t\tBoundX:  boundX,\n\t\t\tBoundY:  boundY,\n\t\t\tSigma:   sigma,\n\t\t\tLSigma:  lSigma,\n\t\t\tLambda:  lambda,\n\t\t\tG:       g,\n\t\t},\n\t}, nil\n}\n\n// NewPaillierFromParams takes configuration parameters of an existing\n// Paillier scheme instance, and reconstructs the scheme with same configuration\n// parameters. It returns a new Paillier instance.\nfunc NewPaillierFromParams(params *PaillierParams) *Paillier {\n\treturn &Paillier{\n\t\tParams: params,\n\t}\n}\n\n// GenerateMasterKeys generates a master secret key and a master\n// public key for the scheme. It returns an error in case master keys\n// could not be generated.\nfunc (s *Paillier) GenerateMasterKeys() (data.Vector, data.Vector, error) {\n\t// sampler for sampling a secret key\n\tsampler := sample.NewNormalDoubleConstant(s.Params.LSigma)\n\n\t// generate a secret key\n\tsecKey, err := data.NewRandomVector(s.Params.L, sampler)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\t// derive the public key from the generated secret key\n\tpubKey := secKey.Apply(func(x *big.Int) *big.Int {\n\t\treturn internal.ModExp(s.Params.G, x, s.Params.NSquare)\n\t})\n\treturn secKey, pubKey, nil\n}\n\n// DeriveKey accepts master secret key masterSecKey and input vector y, and derives a\n// functional encryption key for the inner product with y.\n// In case of malformed secret key or input vector that violates the configured\n// bound, it returns an error.\nfunc (s *Paillier) DeriveKey(masterSecKey data.Vector, y data.Vector) (*big.Int, error) {\n\tif s.Params.BoundY != nil {\n\t\tif err := y.CheckBound(s.Params.BoundY); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\treturn masterSecKey.Dot(y)\n}\n\n// Encrypt encrypts input vector x with the provided master public key.\n// It returns a ciphertext vector. If encryption failed, error is returned.\nfunc (s *Paillier) Encrypt(x, masterPubKey data.Vector) (data.Vector, error) {\n\tif s.Params.BoundX != nil {\n\t\tif err := x.CheckBound(s.Params.BoundX); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\t// generate a randomness for the encryption\n\tnOver4 := new(big.Int).Quo(s.Params.N, big.NewInt(4))\n\tr, err := rand.Int(rand.Reader, nOver4)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// encrypt x under randomness r\n\tcipher := make(data.Vector, s.Params.L+1)\n\t// c_0 = g^r in Z_n^2\n\tc0 := new(big.Int).Exp(s.Params.G, r, s.Params.NSquare)\n\tcipher[0] = c0\n\tfor i := 0; i < s.Params.L; i++ {\n\t\t// c_i = (1 + x_i * n) * pubKey_i^r in Z_n^2\n\t\tt1 := new(big.Int).Mul(x[i], s.Params.N)\n\t\tt1.Add(t1, big.NewInt(1))\n\t\tt2 := new(big.Int).Exp(masterPubKey[i], r, s.Params.NSquare)\n\t\tct := new(big.Int).Mul(t1, t2)\n\t\tct.Mod(ct, s.Params.NSquare)\n\t\tcipher[i+1] = ct\n\t}\n\n\treturn cipher, nil\n}\n\n// Decrypt accepts the encrypted vector, functional encryption key, and\n// a vector y. It returns the inner product of x and y.\nfunc (s *Paillier) Decrypt(cipher data.Vector, key *big.Int, y data.Vector) (*big.Int, error) {\n\tif s.Params.BoundX != nil {\n\t\tif err := y.CheckBound(s.Params.BoundY); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\t// tmp value cX is calculated as (prod_{i=1 to l} c_i^y_i) * c_0^(-key) in Z_n^2\n\tkeyNeg := new(big.Int).Neg(key)\n\tcX := internal.ModExp(cipher[0], keyNeg, s.Params.NSquare)\n\n\tfor i, ct := range cipher[1:] {\n\t\tt1 := internal.ModExp(ct, y[i], s.Params.NSquare)\n\t\tcX.Mul(cX, t1)\n\t\tcX.Mod(cX, s.Params.NSquare)\n\t}\n\n\t// decryption is calculated as (cX-1 mod n^2)/n\n\tcX.Sub(cX, big.NewInt(1))\n\tcX.Mod(cX, s.Params.NSquare)\n\tret := new(big.Int).Quo(cX, s.Params.N)\n\t// if the return value is negative this is seen as the above ret being\n\t// greater than n/2; in this case ret = ret - n\n\tnHalf := new(big.Int).Quo(s.Params.N, big.NewInt(2))\n\tif ret.Cmp(nHalf) == 1 {\n\t\tret.Sub(ret, s.Params.N)\n\t}\n\n\treturn ret, nil\n}\n"
  },
  {
    "path": "innerprod/fullysec/paillier_multi.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage fullysec\n\nimport (\n\t\"fmt\"\n\t\"math/big\"\n\n\t\"github.com/fentec-project/gofe/data\"\n\t\"github.com/fentec-project/gofe/internal\"\n\t\"github.com/fentec-project/gofe/sample\"\n)\n\n// PaillierMulti represents a multi input variant of the\n// underlying Paillier scheme based on\n// Abdalla, Catalano, Fiore, Gay, and Ursu:\n// \"Multi-Input Functional Encryption for Inner Products:\n// Function-Hiding Realizations and Constructions without Pairings\".\n// The participants in the scheme are clients and a central authority.\n// The central authority generates keys for each client so that client i\n// encrypts vector x_i. The scheme allows the central authority to\n// generate a key_Y, depending on a matrix Y with rows y_i, so that\n// given key_y and the ciphertext the decryptor can compute value\n// Σ_i <x_i, y_i> (sum of dot products).\n\n// PaillierMulti is a struct in PaillierMulti scheme, that holds\n// all the shared parameters, and can represent the central authority\n// or the decryptor.\ntype PaillierMulti struct {\n\tNumClients int\n\tBoundX     *big.Int\n\tBoundY     *big.Int\n\t*Paillier\n}\n\n// PaillerMultiClient represents a single client for the PaillierMulti scheme.\ntype PaillierMultiClient struct {\n\tBoundX *big.Int\n\tBoundY *big.Int\n\t*Paillier\n}\n\n// NewPaillierMulti configures a new instance of the scheme.\n// It accepts the number of clients, the length of\n// input vectors l, security parameter lambda (for number of\n// bits of security the bit length of primes p and q to be generated\n// (the scheme is operating in the Z_{(pq)^2} group), and a bound by\n// which coordinates of input vectors are bounded. It generates all\n// the remaining parameters to be shared.\n// If you are not sure how to choose lambda and bitLen, setting\n// lambda = 128, bitLen = 1024 will result in a scheme that is believed\n// to have 128 bit security.\n//\n// It returns an error in case the underlying Paillier scheme\n// instances could not be properly instantiated.\nfunc NewPaillierMulti(numClients, l, lambda, bitLength int, boundX, boundY *big.Int) (*PaillierMulti, error) {\n\tvar newBoundX *big.Int\n\tnewBoundX = nil\n\tif boundX != nil && boundY != nil {\n\t\tnewBoundX = new(big.Int).Mul(boundX, big.NewInt(3))\n\t}\n\tpaillier, err := NewPaillier(l, lambda, bitLength, newBoundX, boundY)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// the bound of the underlying Paillier scheme is set to\n\t// nil value since the scheme will be used to encrypt\n\t// values summed with one time pad, thus arbitrary big\n\tpaillier.Params.BoundX = nil\n\tpaillier.Params.BoundY = nil\n\n\treturn &PaillierMulti{\n\t\tNumClients: numClients,\n\t\tBoundY:     boundY,\n\t\tBoundX:     boundX,\n\t\tPaillier:   paillier,\n\t}, nil\n}\n\n// NewPaillierMultiClientFromParams takes the bounds and configuration parameters of an underlying\n// Paillier scheme instance, and instantiates a new PaillierMultiClient.\n//\n// It returns a new PaillierMultiClient instance.\nfunc NewPaillierMultiClientFromParams(params *PaillierParams, boundX, boundY *big.Int) *PaillierMultiClient {\n\treturn &PaillierMultiClient{\n\t\tBoundY:   boundY,\n\t\tBoundX:   boundX,\n\t\tPaillier: &Paillier{params},\n\t}\n}\n\n// NewPaillierMultiFromParams takes the number of clients, bound and configuration\n// parameters of an existing Paillier scheme instance, and reconstructs\n// the scheme with the same configuration parameters.\n//\n// It returns a new PaillierMulti instance.\nfunc NewPaillierMultiFromParams(numClients int, boundX, boundY *big.Int, params *PaillierParams) *PaillierMulti {\n\treturn &PaillierMulti{\n\t\tNumClients: numClients,\n\t\tBoundX:     boundX,\n\t\tBoundY:     boundY,\n\t\tPaillier:   &Paillier{params},\n\t}\n}\n\n// PaillierMultiSecKeys is a struct containing keys and one time pads for all the clients in\n// the Paillier multi input scheme.\ntype PaillierMultiSecKeys struct {\n\tMsk data.Matrix\n\tMpk data.Matrix\n\tOtp data.Matrix\n}\n\n// GenerateMasterKeys generates keys and one time pads for all the clients.\n// It returns an error in case values could not be generated.\nfunc (dm *PaillierMulti) GenerateMasterKeys() (*PaillierMultiSecKeys, error) {\n\tmultiMsk := make([]data.Vector, dm.NumClients)\n\tmultiMpk := make([]data.Vector, dm.NumClients)\n\tmultiOtp := make([]data.Vector, dm.NumClients)\n\n\tfor i := 0; i < dm.NumClients; i++ {\n\t\tmsk, mpk, err := dm.Paillier.GenerateMasterKeys()\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error in master key generation\")\n\t\t}\n\t\tmultiMsk[i] = msk\n\t\tmultiMpk[i] = mpk\n\n\t\totp, err := data.NewRandomVector(dm.Params.L, sample.NewUniform(dm.Params.NSquare))\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error in random vector generation\")\n\t\t}\n\t\tmultiOtp[i] = otp\n\t}\n\tsecKeys := &PaillierMultiSecKeys{\n\t\tMsk: data.Matrix(multiMsk),\n\t\tMpk: data.Matrix(multiMpk),\n\t\tOtp: data.Matrix(multiOtp),\n\t}\n\n\treturn secKeys, nil\n}\n\n// Encrypt generates a ciphertext from the input vector x\n// with the provided public key of the underlying Paillier scheme and\n// one-time pad otp (which are a part of the secret key). It returns\n// the ciphertext vector. If the encryption failed, error is returned.\nfunc (e *PaillierMultiClient) Encrypt(x data.Vector, pubKey, otp data.Vector) (data.Vector, error) {\n\tif e.BoundX != nil {\n\t\tif err := x.CheckBound(e.BoundX); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\txAddOtp := x.Add(otp)\n\txAddOtp = xAddOtp.Mod(e.Params.NSquare)\n\n\treturn e.Paillier.Encrypt(xAddOtp, pubKey)\n}\n\n// PaillierMultiDerivedKey is a functional encryption key for PaillierMulti scheme.\ntype PaillierMultiDerivedKey struct {\n\tKeys []*big.Int\n\tZ    *big.Int // Σ <u_i, y_i> where u_i is OTP key for i-th client\n}\n\n// DeriveKey takes master secret key and a matrix y comprised\n// of input vectors, and returns the functional encryption key.\n// In case the key could not be derived, it returns an error.\nfunc (dm *PaillierMulti) DeriveKey(secKey *PaillierMultiSecKeys, y data.Matrix) (*PaillierMultiDerivedKey, error) {\n\tif dm.BoundY != nil {\n\t\tif err := y.CheckBound(dm.BoundY); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\tz, err := secKey.Otp.Dot(y)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tz.Mod(z, dm.Params.NSquare)\n\n\tderivedKeys := make([]*big.Int, dm.NumClients)\n\tfor i := 0; i < dm.NumClients; i++ {\n\t\tderivedKey, err := dm.Paillier.DeriveKey(secKey.Msk[i], y[i])\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tderivedKeys[i] = derivedKey\n\t}\n\n\treturn &PaillierMultiDerivedKey{derivedKeys, z}, nil\n}\n\n// Decrypt accepts an array of ciphers, i.e. an array of encrypted vectors,\n// functional encryption key, and a matrix y describing the inner-product.\n// It returns the sum of inner products Σ_i <x_i, y_i>.\n// If decryption failed, error is returned.\nfunc (dm *PaillierMulti) Decrypt(cipher []data.Vector, key *PaillierMultiDerivedKey, y data.Matrix) (*big.Int, error) {\n\tif dm.BoundY != nil {\n\t\tif err := y.CheckBound(dm.BoundY); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tr := big.NewInt(0)\n\tfor k := 0; k < dm.NumClients; k++ {\n\t\tkeyNeg := new(big.Int).Neg(key.Keys[k])\n\t\tcX := internal.ModExp(cipher[k][0], keyNeg, dm.Params.NSquare)\n\n\t\tfor i, ct := range cipher[k][1:] {\n\t\t\tt1 := internal.ModExp(ct, y[k][i], dm.Params.NSquare)\n\t\t\tcX.Mul(cX, t1)\n\t\t\tcX.Mod(cX, dm.Params.NSquare)\n\t\t}\n\t\tr.Add(r, cX)\n\t\tr.Mod(r, dm.Params.NSquare)\n\t}\n\n\tz := new(big.Int).Mul(dm.Params.N, key.Z)\n\tz.Sub(big.NewInt(1), z)\n\tz.Mod(z, dm.Params.NSquare)\n\tr.Add(r, z)\n\tr.Mod(r, dm.Params.NSquare)\n\n\t// decryption is calculated as (cX-1 mod n^2)/n\n\tr.Sub(r, big.NewInt(1))\n\tr.Mod(r, dm.Params.NSquare)\n\tret := new(big.Int).Quo(r, dm.Params.N)\n\t// if the return value is negative this is seen as the above ret being\n\t// greater than n/2; in this case ret = ret - n\n\tnHalf := new(big.Int).Quo(dm.Params.N, big.NewInt(2))\n\tif ret.Cmp(nHalf) == 1 {\n\t\tret.Sub(ret, dm.Params.N)\n\t}\n\n\treturn ret, nil\n}\n"
  },
  {
    "path": "innerprod/fullysec/paillier_multi_test.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage fullysec_test\n\nimport (\n\t\"math/big\"\n\t\"testing\"\n\n\t\"github.com/fentec-project/gofe/data\"\n\t\"github.com/fentec-project/gofe/innerprod/fullysec\"\n\t\"github.com/fentec-project/gofe/sample\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestFullySec_PaillierMulti(t *testing.T) {\n\t// choose meta-parameters for the scheme\n\tnumClients := 6\n\tl := 5\n\tbound := big.NewInt(1024)\n\tsampler := sample.NewUniformRange(new(big.Int).Add(new(big.Int).Neg(bound), big.NewInt(1)), bound)\n\n\t// build the central authority for the scheme with parameters that should provide 128-bit security\n\tvar paillierMulti *fullysec.PaillierMulti\n\tvar err error\n\tpaillierMulti, err = fullysec.NewPaillierMulti(numClients, l, 128, 1024, bound, bound)\n\n\tif err != nil {\n\t\tt.Fatalf(\"Failed to initialize multi input inner product: %v\", err)\n\t}\n\n\t// we simulate different clients which might be on different machines (this means \"multi-input\"),\n\tclients := make([]*fullysec.PaillierMultiClient, numClients)\n\tfor i := 0; i < numClients; i++ {\n\t\tclients[i] = fullysec.NewPaillierMultiClientFromParams(paillierMulti.Params, bound, bound)\n\t}\n\n\t// the central authority generates keys for all the clients\n\tsecKeys, err := paillierMulti.GenerateMasterKeys()\n\tif err != nil {\n\t\tt.Fatalf(\"Error during keys generation: %v\", err)\n\t}\n\n\t// pick a matrix that represent the collection of inner-product vectors y_i\n\ty, err := data.NewRandomMatrix(numClients, l, sampler)\n\tif err != nil {\n\t\tt.Fatalf(\"Error during matrix generation: %v\", err)\n\t}\n\n\t// each client encrypts its vector x_i\n\tcollectedX := make([]data.Vector, numClients) // solely for checking whether Encrypt/Decrypt works properly\n\tciphertexts := make([]data.Vector, numClients)\n\tfor i := 0; i < numClients; i++ {\n\t\tx, err := data.NewRandomVector(l, sampler) // x_i possessed and chosen by client[i]\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"Error during random vector generation: %v\", err)\n\t\t}\n\t\tcollectedX[i] = x\n\t\tc, err := clients[i].Encrypt(x, secKeys.Mpk[i], secKeys.Otp[i])\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"Error during encryption: %v\", err)\n\t\t}\n\t\tciphertexts[i] = c\n\t}\n\n\t// central authority derives the key for the decryptor\n\tderivedKey, err := paillierMulti.DeriveKey(secKeys, y)\n\tif err != nil {\n\t\tt.Fatalf(\"Error during key derivation: %v\", err)\n\t}\n\n\t// we simulate the decryptor\n\tdecryptor := fullysec.NewPaillierMultiFromParams(numClients, bound, bound, paillierMulti.Params)\n\n\t// decryptor decrypts the value\n\txy, err := decryptor.Decrypt(ciphertexts, derivedKey, y)\n\tif err != nil {\n\t\tt.Fatalf(\"Error during decryption: %v\", err)\n\t}\n\n\t// we check if the decrypted value is correct\n\txMatrix, err := data.NewMatrix(collectedX)\n\tif err != nil {\n\t\tt.Fatalf(\"Error during collection of vectors to be encrypted: %v\", err)\n\t}\n\txyCheck, err := xMatrix.Dot(y)\n\tif err != nil {\n\t\tt.Fatalf(\"Error during inner product calculation: %v\", err)\n\t}\n\tassert.Equal(t, xy.Cmp(xyCheck), 0, \"obtained incorrect inner product\")\n}\n"
  },
  {
    "path": "innerprod/fullysec/paillier_test.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage fullysec_test\n\nimport (\n\t\"math/big\"\n\t\"testing\"\n\n\t\"github.com/fentec-project/gofe/data\"\n\t\"github.com/fentec-project/gofe/innerprod/fullysec\"\n\t\"github.com/fentec-project/gofe/sample\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestFullySec_Paillier(t *testing.T) {\n\tl := 50\n\tboundX := new(big.Int).Exp(big.NewInt(2), big.NewInt(64), nil)\n\tboundY := new(big.Int).Exp(big.NewInt(2), big.NewInt(64), nil)\n\n\tsamplerX := sample.NewUniformRange(new(big.Int).Neg(boundX), boundX)\n\tsamplerY := sample.NewUniformRange(new(big.Int).Neg(boundY), boundY)\n\tbitLength := 512\n\tlambda := 128\n\n\tpaillier, err := fullysec.NewPaillier(l, lambda, bitLength, boundX, boundY)\n\tif err != nil {\n\t\tt.Fatalf(\"Error during simple inner product creation: %v\", err)\n\t}\n\n\tmasterSecKey, masterPubKey, err := paillier.GenerateMasterKeys()\n\tif err != nil {\n\t\tt.Fatalf(\"Error during master key generation: %v\", err)\n\t}\n\n\ty, err := data.NewRandomVector(l, samplerY)\n\tif err != nil {\n\t\tt.Fatalf(\"Error during random generation: %v\", err)\n\t}\n\n\tkey, err := paillier.DeriveKey(masterSecKey, y)\n\tif err != nil {\n\t\tt.Fatalf(\"Error during key derivation: %v\", err)\n\t}\n\n\tx, err := data.NewRandomVector(l, samplerX)\n\tif err != nil {\n\t\tt.Fatalf(\"Error during random generation: %v\", err)\n\t}\n\n\t// simulate the instantiation of encryptor (which should be given masterPubKey)\n\tencryptor := fullysec.NewPaillierFromParams(paillier.Params)\n\n\tciphertext, err := encryptor.Encrypt(x, masterPubKey)\n\tif err != nil {\n\t\tt.Fatalf(\"Error during encryption: %v\", err)\n\t}\n\n\txy, err := paillier.Decrypt(ciphertext, key, y)\n\tif err != nil {\n\t\tt.Fatalf(\"Error during decryption\")\n\t}\n\n\txyCheck, err := x.Dot(y)\n\tif err != nil {\n\t\tt.Fatalf(\"Error during inner product calculation\")\n\t}\n\tassert.Equal(t, xy.Cmp(xyCheck), 0, \"Original and decrypted values should match\")\n}\n"
  },
  {
    "path": "innerprod/fullysec/part_fh_ipe.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage fullysec\n\nimport (\n\t\"fmt\"\n\t\"math/big\"\n\n\t\"github.com/fentec-project/bn256\"\n\t\"github.com/fentec-project/gofe/data\"\n\t\"github.com/fentec-project/gofe/internal/dlog\"\n\t\"github.com/fentec-project/gofe/sample\"\n)\n\n// PartFHIPEParams includes public parameters for the partially\n// function hiding inner product scheme.\n// L (int): The length of vectors to be encrypted.\n// Bound (*big.Int): The value by which coordinates of vectors x and y are bounded.\ntype PartFHIPEParams struct {\n\tL     int\n\tBound *big.Int\n}\n\n// PartFHIPE represents a partially function hiding inner product\n// FE scheme. A partially function hiding scheme is a public\n// key FE scheme that allows to encrypt vectors and produce FE\n// keys to be able to decrypt only the inner product of the encryption\n// and chosen vector without revealing the encrypted or FE key vector.\n// Public key encryption allows to encrypt only vectors from a chosen\n// subspace. This way a functional encryption key does not reveal\n// its corresponding inner product vector. Decryption of a\n// ciphertext using FE key can be done without knowing the function.\n// Additionally, owner of the secret key can encrypt any vector.\n//\n// The scheme is based on the paper by Romain Gay:\n// \"A New Paradigm for Public-Key Functional Encryption for\n// Degree-2 Polynomials\".\ntype PartFHIPE struct {\n\tParams *PartFHIPEParams\n}\n\n// NewPartFHIPE configures a new instance of the scheme.\n// It accepts the length of input vectors l, and a bound by which\n// the absolute values of the coordinates of input vectors are bounded.\n//\n// It returns an error in case the scheme could not be properly\n// configured, or if precondition 2* l * bound² is >= order of the cyclic\n// group.\nfunc NewPartFHIPE(l int, bound *big.Int) (*PartFHIPE, error) {\n\tvar b *big.Int\n\tif bound != nil {\n\t\tb = new(big.Int).Set(bound)\n\t\tbSquared := new(big.Int).Mul(bound, bound)\n\t\tupper := new(big.Int).Mul(big.NewInt(int64(2*l)), bSquared)\n\t\tif upper.Cmp(bn256.Order) > 0 {\n\t\t\treturn nil, fmt.Errorf(\"bound and l too big for the group\")\n\t\t}\n\t}\n\n\treturn &PartFHIPE{\n\t\tParams: &PartFHIPEParams{\n\t\t\tL:     l,\n\t\t\tBound: b,\n\t\t},\n\t}, nil\n}\n\n// NewPartFHIPEFromParams takes configuration parameters of an existing\n// PartFHIPE instance, and reconstructs the scheme with the same configuration\n// parameters. It returns a new PartFHIPE instance.\nfunc NewPartFHIPEFromParams(params *PartFHIPEParams) *PartFHIPE {\n\treturn &PartFHIPE{\n\t\tParams: params,\n\t}\n}\n\n// PartFHIPESecKey is a secret key for the partially function hiding\n// inner product scheme.\ntype PartFHIPESecKey struct {\n\tB data.Vector\n\tV data.Matrix\n\tU data.Matrix\n}\n\n// PartFHIPEPubKey is a public key for the partially function hiding\n// inner product scheme.\ntype PartFHIPEPubKey struct {\n\tA   data.VectorG1\n\tUa  data.VectorG1\n\tVtM data.MatrixG1\n\tM   data.Matrix\n\tMG1 data.MatrixG1\n}\n\n// GenerateKeys generates a master secret key and public key for the scheme.\n// A matrix M needs to be specified so that the generated public key will\n// allow to encrypt arbitrary vector in the span on the columns of M.\n// It returns an error in case the keys could not be generated.\nfunc (d *PartFHIPE) GenerateKeys(M data.Matrix) (*PartFHIPEPubKey, *PartFHIPESecKey, error) {\n\tif d.Params.L != M.Rows() {\n\t\treturn nil, nil, fmt.Errorf(\"dimensions of the given matrix do not match dimensions of the scheme\")\n\t}\n\tsampler := sample.NewUniform(bn256.Order)\n\n\taVec := make(data.Vector, 2)\n\taVec[0] = big.NewInt(1)\n\tx, err := sampler.Sample()\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\taVec[1] = x\n\n\tb := make(data.Vector, 2)\n\tb[0] = big.NewInt(1)\n\tx, err = sampler.Sample()\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\tb[1] = x\n\n\ta := aVec.MulG1()\n\n\tU, err := data.NewRandomMatrix(d.Params.L+2, 2, sampler)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tV, err := data.NewRandomMatrix(d.Params.L, 2, sampler)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tUaVec, err := U.MulVec(aVec)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\tUaVec = UaVec.Mod(bn256.Order)\n\n\tUa := UaVec.MulG1()\n\n\tVtMMat, err := V.Transpose().Mul(M)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\tVtMMat = VtMMat.Mod(bn256.Order)\n\tVtM := VtMMat.MulG1()\n\n\tMG1 := M.MulG1()\n\n\treturn &PartFHIPEPubKey{A: a, Ua: Ua, VtM: VtM, M: M.Copy(), MG1: MG1},\n\t\t&PartFHIPESecKey{B: b, V: V, U: U},\n\t\tnil\n}\n\n// DeriveKey takes input vector y and master secret key, and returns the\n// functional encryption key. In case the key could not be derived, it\n// returns an error.\nfunc (d *PartFHIPE) DeriveKey(y data.Vector, secKey *PartFHIPESecKey) (data.VectorG2, error) {\n\tif len(y) != d.Params.L {\n\t\treturn nil, fmt.Errorf(\"the dimension of the given vector does not match the dimension of the scheme\")\n\t}\n\tif d.Params.Bound != nil {\n\t\tif err := y.CheckBound(d.Params.Bound); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tsampler := sample.NewUniform(bn256.Order)\n\n\ts, err := sampler.Sample()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tbs := secKey.B.MulScalar(s)\n\tbs = bs.Mod(bn256.Order)\n\n\tVbs, err := secKey.V.MulVec(bs)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tYVbs := y.Add(Vbs)\n\tYVbs = YVbs.Mod(bn256.Order)\n\tkey2 := append(bs, YVbs...)\n\n\tkey1, err := secKey.U.Transpose().MulVec(key2)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tkey1 = key1.Neg()\n\tkey1 = key1.Mod(bn256.Order)\n\n\tkey := append(key1, key2...)\n\n\treturn key.MulG2(), nil\n}\n\n// Encrypt on input vector t encrypts vector x = Mt with the provided public key\n// (matrix M is specified in the public key). It returns a ciphertext vector.\n// Entries of Mt should not be greater then bound.\n// If encryption fails, an error is returned.\nfunc (d *PartFHIPE) Encrypt(t data.Vector, pubKey *PartFHIPEPubKey) (data.VectorG1, error) {\n\tx, err := pubKey.M.MulVec(t)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif d.Params.Bound != nil {\n\t\tif err := x.CheckBound(d.Params.Bound); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tsampler := sample.NewUniform(bn256.Order)\n\n\tr, err := sampler.Sample()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tc := pubKey.A.MulScalar(r)\n\tUc := pubKey.Ua.MulScalar(r)\n\n\tMt := pubKey.MG1.MulVector(t)\n\tVtMt := pubKey.VtM.MulVector(t)\n\tVtMxNeg := VtMt.Neg()\n\tcipher2 := append(VtMxNeg, Mt...)\n\tcipher2add := cipher2.Add(Uc)\n\n\tcipher := append(c, cipher2add...)\n\n\treturn cipher, nil\n}\n\n// SecEncrypt encrypts an arbitrary vector x using master secret key and\n// public key. It returns a ciphertext vector. If encryption failed,\n// an error is returned.\nfunc (d *PartFHIPE) SecEncrypt(x data.Vector, pubKey *PartFHIPEPubKey, secKey *PartFHIPESecKey) (data.VectorG1, error) {\n\tif len(x) != d.Params.L {\n\t\treturn nil, fmt.Errorf(\"the dimension of the given vector does not match the dimension of the scheme\")\n\t}\n\tif d.Params.Bound != nil {\n\t\tif err := x.CheckBound(d.Params.Bound); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tsampler := sample.NewUniform(bn256.Order)\n\n\tr, err := sampler.Sample()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tc := pubKey.A.MulScalar(r)\n\tUc := pubKey.Ua.MulScalar(r)\n\n\tVtx, err := secKey.V.Transpose().MulVec(x)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tVtx = Vtx.Neg().Mod(bn256.Order)\n\n\tVtxG1 := Vtx.MulG1()\n\txG1 := x.MulG1()\n\tcipher2 := append(VtxG1, xG1...)\n\tcipher2add := cipher2.Add(Uc)\n\n\tcipher := append(c, cipher2add...)\n\n\treturn cipher, nil\n}\n\n// PartDecrypt accepts the encrypted vector and functional encryption key. It\n// returns the value d*[bn256.GT] where d is the inner product of x and y.\n// To obtain a final result, calculating the discrete logarithm is needed.\nfunc (d *PartFHIPE) PartDecrypt(cipher data.VectorG1, feKey data.VectorG2) (*bn256.GT, error) {\n\tif len(cipher) != d.Params.L+4 || len(feKey) != d.Params.L+4 {\n\t\treturn nil, fmt.Errorf(\"the length of FE key or ciphertext does not match the dimension of the scheme\")\n\t}\n\tdec := new(bn256.GT).ScalarBaseMult(big.NewInt(0))\n\tfor i := 0; i < d.Params.L+4; i++ {\n\t\tpairedI := bn256.Pair(cipher[i], feKey[i])\n\t\tdec = new(bn256.GT).Add(pairedI, dec)\n\t}\n\n\treturn dec, nil\n}\n\n// Decrypt accepts the encrypted vector and functional encryption key.\n// It returns the inner product of x and y. If decryption failed, error is returned.\nfunc (d *PartFHIPE) Decrypt(cipher data.VectorG1, feKey data.VectorG2) (*big.Int, error) {\n\tdec, err := d.PartDecrypt(cipher, feKey)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tcalc := dlog.NewCalc().InBN256().WithNeg()\n\n\tif d.Params.Bound != nil {\n\t\tbSquared := new(big.Int).Mul(d.Params.Bound, d.Params.Bound)\n\t\tbound := new(big.Int).Mul(big.NewInt(int64(d.Params.L)), bSquared)\n\t\tcalc = calc.WithBound(bound)\n\t}\n\n\tres, err := calc.BabyStepGiantStep(dec, new(bn256.GT).ScalarBaseMult(big.NewInt(1)))\n\n\treturn res, err\n}\n"
  },
  {
    "path": "innerprod/fullysec/part_fh_ipe_test.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage fullysec_test\n\nimport (\n\t\"math/big\"\n\t\"testing\"\n\n\t\"github.com/fentec-project/gofe/data\"\n\t\"github.com/fentec-project/gofe/innerprod/fullysec\"\n\t\"github.com/fentec-project/gofe/sample\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestPartFHIPE(te *testing.T) {\n\t// choose parameters for the encryption and build the scheme\n\tl := 50\n\tbound := big.NewInt(100)\n\tboundNeg := new(big.Int).Add(new(big.Int).Neg(bound), big.NewInt(1))\n\tsampler := sample.NewUniformRange(boundNeg, bound)\n\tpartfhipe, err := fullysec.NewPartFHIPE(l, bound)\n\tif err != nil {\n\t\tte.Fatalf(\"Error during scheme creation: %v\", err)\n\t}\n\n\t// choose a subspace in which encryption will be allowed\n\tk := 5 // dimension of the subspace\n\t// the subspace is given by the columns of the matrix m\n\t// we sample m with not too big inputs\n\tsamplerM := sample.NewUniform(new(big.Int).Div(bound, big.NewInt(int64(k))))\n\tm, err := data.NewRandomMatrix(l, k, samplerM)\n\tif err != nil {\n\t\tte.Fatalf(\"Error during random matrix generation: %v\", err)\n\t}\n\t// generate public and secret key based on matrix m\n\tpubKey, secKey, err := partfhipe.GenerateKeys(m)\n\tif err != nil {\n\t\tte.Fatalf(\"Error during master key generation: %v\", err)\n\t}\n\n\t// simulate the instantiation of an encryptor\n\tencryptor := fullysec.NewPartFHIPEFromParams(partfhipe.Params)\n\t// sample a vector x that the encryptor will encrypt with public key;\n\t// the vector is described with k dimensional vector t such that\n\t// x = Mt\n\tsampler2 := sample.NewUniformRange(big.NewInt(-1), big.NewInt(2))\n\tt, err := data.NewRandomVector(k, sampler2)\n\tif err != nil {\n\t\tte.Fatalf(\"Error during random vector generation: %v\", err)\n\t}\n\n\t// encrypt the vector\n\tciphertextMt, err := encryptor.Encrypt(t, pubKey)\n\tif err != nil {\n\t\tte.Fatalf(\"Error during encryption: %v\", err)\n\t}\n\n\t// the owner of the secret key encrypts an arbitrary vector\n\tx, err := data.NewRandomVector(l, sampler)\n\tif err != nil {\n\t\tte.Fatalf(\"Error during random vector generation: %v\", err)\n\t}\n\tciphertextX, err := partfhipe.SecEncrypt(x, pubKey, secKey)\n\tif err != nil {\n\t\tte.Fatalf(\"Error during encryption with secret key: %v\", err)\n\t}\n\n\t// sample an inner product vector\n\ty, err := data.NewRandomVector(l, sampler)\n\tif err != nil {\n\t\tte.Fatalf(\"Error during random vecotr generation: %v\", err)\n\t}\n\n\t// derive a functional key for vector y\n\tfeKey, err := partfhipe.DeriveKey(y, secKey)\n\tif err != nil {\n\t\tte.Fatalf(\"Error during key derivation: %v\", err)\n\t}\n\n\t// simulate a decryptor\n\tdecryptor := fullysec.NewPartFHIPEFromParams(partfhipe.Params)\n\t// decryptor decrypts the inner-product y^TMt without knowing\n\t// vectors Mt and y\n\tyMt, err := decryptor.Decrypt(ciphertextMt, feKey)\n\tif err != nil {\n\t\tte.Fatalf(\"Error during decryption: %v\", err)\n\t}\n\t// and decrypts the inner-product x^Ty without knowing\n\t// vectors x and y\n\tyx, err := decryptor.Decrypt(ciphertextX, feKey)\n\tif err != nil {\n\t\tte.Fatalf(\"Error during decryption: %v\", err)\n\t}\n\n\t// check the correctness of the results\n\tMt, err := m.MulVec(t)\n\tif err != nil {\n\t\tte.Fatalf(\"Error calculating the inner product: %v\", err)\n\t}\n\tyMtCheck, err := y.Dot(Mt)\n\tif err != nil {\n\t\tte.Fatalf(\"Error calculating the inner product: %v\", err)\n\t}\n\tyxCheck, err := y.Dot(x)\n\tif err != nil {\n\t\tte.Fatalf(\"Error calculating the inner product: %v\", err)\n\t}\n\tassert.Equal(te, yMt.Cmp(yMtCheck), 0, \"obtained incorrect inner product\")\n\tassert.Equal(te, yx.Cmp(yxCheck), 0, \"obtained incorrect inner product\")\n}\n"
  },
  {
    "path": "innerprod/simple/ddh.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage simple\n\nimport (\n\t\"fmt\"\n\t\"math/big\"\n\n\t\"github.com/fentec-project/gofe/data\"\n\t\"github.com/fentec-project/gofe/internal\"\n\t\"github.com/fentec-project/gofe/internal/dlog\"\n\t\"github.com/fentec-project/gofe/internal/keygen\"\n\t\"github.com/fentec-project/gofe/sample\"\n)\n\n// DDHParams represents configuration parameters for the DDH scheme instance.\ntype DDHParams struct {\n\t// length of input vectors x and y\n\tL int\n\t// The value by which coordinates of input vectors x and y are bounded.\n\tBound *big.Int\n\t// Generator of a cyclic group Z_P: G^(Q) = 1 (mod P).\n\tG *big.Int\n\t// Modulus - we are operating in a cyclic group Z_P.\n\tP *big.Int\n\t// Order of the generator G.\n\tQ *big.Int\n}\n\n// DDH represents a scheme instantiated from the DDH assumption,\n// based on the DDH variant by\n// Abdalla, Bourse, De Caro, and Pointchev:\n// \"Simple Functional Encryption Schemes for Inner Products\".\ntype DDH struct {\n\tParams *DDHParams\n}\n\n// NewDDH configures a new instance of the scheme.\n// It accepts the length of input vectors l, the bit length of the\n// modulus (we are operating in the Z_p group), and a bound by which\n// coordinates of input vectors are bounded.\n//\n// It returns an error in case the scheme could not be properly\n// configured, or if precondition l * bound² is >= order of the cyclic\n// group.\nfunc NewDDH(l, modulusLength int, bound *big.Int) (*DDH, error) {\n\tkey, err := keygen.NewElGamal(modulusLength)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif new(big.Int).Mul(big.NewInt(int64(2*l)), new(big.Int).Exp(bound, big.NewInt(2), big.NewInt(0))).Cmp(key.Q) > 0 {\n\t\treturn nil, fmt.Errorf(\"2 * l * bound^2 should be smaller than group order\")\n\t}\n\n\tsip := DDH{\n\t\tParams: &DDHParams{\n\t\t\tL:     l,\n\t\t\tBound: bound,\n\t\t\tG:     key.G,\n\t\t\tP:     key.P,\n\t\t\tQ:     key.Q,\n\t\t},\n\t}\n\n\treturn &sip, nil\n}\n\n// NewDDHPrecomp configures a new instance of the scheme based on\n// precomputed prime numbers and generators.\n// It accepts the length of input vectors l, the bit length of the\n// modulus (we are operating in the Z_p group), and a bound by which\n// coordinates of input vectors are bounded. The modulus length should\n// be one of values 1024, 1536, 2048, 2560, 3072, or 4096.\n//\n// It returns an error in case the scheme could not be properly\n// configured, or if precondition l * bound² is >= order of the cyclic\n// group.\nfunc NewDDHPrecomp(l, modulusLength int, bound *big.Int) (*DDH, error) {\n\tzero := big.NewInt(0)\n\tone := big.NewInt(1)\n\ttwo := big.NewInt(2)\n\n\tg := new(big.Int)\n\tp := new(big.Int)\n\n\tif modulusLength == 1024 {\n\t\tg.SetString(\"34902160241479276675539633849372382885917193816560610471607073855548755350834003692485735908635894317735639518678334280193650806072183057417077181724192674928134805218882803812978345229222559213790765817899845072682155064387311523738581388872686127675360979304234957611566801734164757915959042140104663977828\", 10)\n\t\tp.SetString(\"166211269243229118758738154756726384542659478479960313411107431885216572625212662756677338184675400324411541201832214281445670912135683272416408753424543622705770319923251281963485084208425069817917631106045349238686234860629044433560424091289406000897029571960128048529362925472176997104870527051276406995203\", 10)\n\t} else if modulusLength == 1536 {\n\t\tg.SetString(\"676416913692519694440150163403654362412279108516867264953779609011365998625435399420336578530015558254310139891236630566729665914687641028600402606957815727025192669238117788115237116562468680376464346714542467465836552396661693422160454402926392749202926871877212792118140354124110927269910674002861908621272286950597240072605316784317536178700101838123530590145680002962405974024190384775185108002307650499125333676880320808656556635493186351335151559453463208\", 10)\n\t\tp.SetString(\"1851297899986638926486011430658634631676522135433726749065856232802142091866650774719879427474637700607873256035038534449089405369134066444876856913629831069906506096279113968447116822488133963417347136141052507685108634240736100862550194947326287783557220764070479431781692630708747550712729778398000353165406458520850089303530985563143326919073190605085889925484113854496074216626577246143598303709289292397203458923541841135799203967503522114881404128535647507\", 10)\n\t} else if modulusLength == 2048 {\n\t\tg.SetString(\"4006960929413042209594165215465319088439374252008797022450541422457034721098828647078778605657155669917104962611933792130890703423519992986737966991597160684973795472419962788730248050852176194215699504914899438223683843401963466624139534923052671383315398134823370041633710463630745156269175253639670460050105594663691338308037509280576148624454011047879615100156717631945194107791315234171086603775159708325087759679758438868772220133433497821899045165244202228696902434100209752952701657306825368599999359102329396520012735146260911352901326915877502873633420811221206110021993351144711002138373506576799781061829\", 10)\n\t\tp.SetString(\"28884237504713658990682089080899862128005980675308910325841161962760155725037929764087367167449843609136681034352509183117742758446654629096509285354423361556493020266963222508540306384896802796001914743293196010488452478370041404523014215612960481024232879327123268440037633547483165934132901270561772860319969916305482525766132307669097012989986613879246932730824899649301621408341438037745468033187743673001187803377254713546325789438300798311106106322698517805307792059495696632070953526611920926003483451787562399452650878943515646786958216714025307572678422373120397225912926110031401983688860264234966561627699\", 10)\n\t} else if modulusLength == 2560 {\n\t\tg.SetString(\"283408881721750179985507845260248881237898607313021593637913985490973593382472548378053368228310040484438920416918021737085067966444840449068073874437662089659563355479608930182263107110969154912883370207053052795964658868443319273167870311282045348396320159912742394374241864712808383029954025256232806465551969466207671603658677963161975454703127476120201164519187150268352527923664649275471494757270139533433456630363925187498055211365480086561354743681517539297815712218419607006668655891574362066382949706266666189227897710299445185100212256741698216505337617571970963008519334554537811591236478130526432239803909461119767954934793813410765013072006162612226471775059215628326278458577643374735250370115470812597459244082296191871275203831471332697557979904062571849\", 10)\n\t\tp.SetString(\"403126381462544353337185732949672984701995200694926494258456907009253008321275627278199160008680481542251933923210212978304159426174307419863781623411302777276318286800690060166638633211627521530173324015527027650548199185539205697958056639406116068885574865579676651743820636201007864067569576455725489531113260031526605827601510665037511961715114944815619491261828558745083975042855063688267346905844510423020844412350570902289599734320004108557140241966071165594059732527795488131297017205383953304055105007982366596746708951250486384299368612656872813778220074826250625689603663742175288397398948456522281031888042417278385238985218731264092285591879578299600853004336936458454638992426900228708418575870946630137618851131144232868141478901063119847104013555395370887\", 10)\n\t} else if modulusLength == 3072 {\n\t\tg.SetString(\"3696261717511684685041982088526264061294500298114921057816954458306445697150348237912729036967670872345042594238223317055749478029025374644864924550052402546275985983344583674703146236623453822520422465163020824494790581472736649085281450730460445260696087738043872307629635997875332076478424042345012004769107421873566499123042621978973433575500345010912635742477932006291250637245855027695943163956584173316781442078828050076620331751405548730676363847526959436516279320074682721438642683731766682502490935962962293815202487144775533102010333956118641968798500514719248831145108532912211817219793191951880318961073149276914867129023978524587935704313755469570162971499124682746476415187933097132047611840762510892175328320025164466873845777990557296853549970943298347924080102740724512079409979152285019931666423541870247789529268168448010024121369388707140296446100906359619586133848407970098685310317291828335700424602208\", 10)\n\t\tp.SetString(\"4387756306134544957818467663802660683665166110605728231080818705443663402154316615145921798856363268744945754470238000282108344905251127487705736550297997444150840902348669718478564904142834154197029830975532074167513046443903186309497214496864577129616824062991068960005865144004932069025136224356325248036029606434443391988386519658751798077031844645051726026696307027395796695909035405241040411794836124123435225690961994089776517262574417789067836840997650095451062948856617211542724543995145259735683916440579956961657374517806591607068842498749297993409884001044324428640569001916341503645559748760311343179943896427393009949062735145363544745972252566600994034655540841225414736222780096833045470605544717177880459300618917961703559234544541206877026518430276932498602360341258899345739335298856394124351357206871568254540730107127298623178526868418799471896060015463201459762913197633841160710893895836663035998106119\", 10)\n\t} else if modulusLength == 4096 {\n\t\tg.SetString(\"51665588681810560577916524923861643358980285220048008212528567741884121491554604183472728540139463099618903178110360757930742372390027135064809646425064896539133721148335557788263239281487173350543811713890328584918216783142094297306639941000480756707312457878765754357205186485080839623690156744636468433787780205323460166423447602447200754978133176713947189000663528355089645281397174452923418212485422962705227706103188302892660448134233848971142570881089940852441776074246332915421265800026335300100610273942459340241610730244726628211914068945587128124478812632725838440727321816905181830592204023095726270782834020990986443265625389712733369116937470448592846480352222814297792606318850361699893703272484112273500581408730519942517586496563772194165844831300501908379990979449691597045730512107756238377635183257797115883839801779086058652272455400286891699445584526719648220045380141260347316315487340493029966105973850214850475440630205768783542021741101804842248602349004364816943429122368563644935802417389995380389429997320053299323220481603252879925927515844929958940305561718295197935926645561977544440676439150126025681320050786964708227836328341875446457912905977470123640014345655062829575775837287500880054558386787\", 10)\n\t\tp.SetString(\"1022249395832567838406986294560330159176972202126664245047364146720891252715766488477689126342364655087193411078517616569887825896401401223927363505007778278205623713273194552498760148834874746839752870298152746450585455651115247220867383465863156721401567161663838310658875672995951663020449772454232797368263754624173026584111779206080723120076751471597509403139249260220696195263597156452889920392585797464801375940661326779247976331028637271512085826066667631423502199894046717721786935806581428328491087482664043743281068318459302242239861275878019857365021173868449409246193470959347916848019032536247915451026158871684654213802886886213841729258073333569276986893577214659899227179735448593265633219968622571880602115519942763955551007919826002851866939641065270816032435114864853636918330698605282572789904941484540512478406984407320963402583009124880812235841866246441862987563989772424040933513333746472128494254253767426962063553015635240386636751473945937412527996558505231385625318878887383161350102080329744822052478052004574860361461762694379860797225344866320388590336321515376486033237159694567932935601775209663052272120524337888258857351777348841323194553467226791591208931619058871750498804369190487499494069660723\", 10)\n\t} else {\n\t\treturn nil, fmt.Errorf(\"modulus length should be one of values 1024, 1536, 2048, 2560, 3072, or 4096\")\n\t}\n\n\tq := new(big.Int).Sub(p, one)\n\tq.Div(q, two)\n\n\tif new(big.Int).Mul(big.NewInt(int64(2*l)), new(big.Int).Exp(bound, two, zero)).Cmp(q) > 0 {\n\t\treturn nil, fmt.Errorf(\"2 * l * bound^2 should be smaller than group order\")\n\t}\n\n\tsip := DDH{\n\t\tParams: &DDHParams{\n\t\t\tL:     l,\n\t\t\tBound: bound,\n\t\t\tG:     g,\n\t\t\tP:     p,\n\t\t\tQ:     q,\n\t\t},\n\t}\n\n\treturn &sip, nil\n}\n\n// NewDDHFromParams takes configuration parameters of an existing\n// DDH scheme instance, and reconstructs the scheme with same configuration\n// parameters. It returns a new DDH instance.\nfunc NewDDHFromParams(params *DDHParams) *DDH {\n\treturn &DDH{\n\t\tParams: params,\n\t}\n}\n\n// GenerateMasterKeys generates a pair of master secret key and master\n// public key for the scheme. It returns an error in case master keys\n// could not be generated.\nfunc (d *DDH) GenerateMasterKeys() (data.Vector, data.Vector, error) {\n\tmasterSecKey := make(data.Vector, d.Params.L)\n\tmasterPubKey := make(data.Vector, d.Params.L)\n\tsampler := sample.NewUniformRange(big.NewInt(2), d.Params.Q)\n\n\tfor i := 0; i < d.Params.L; i++ {\n\t\tx, err := sampler.Sample()\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\t\ty := internal.ModExp(d.Params.G, x, d.Params.P)\n\t\tmasterSecKey[i] = x\n\t\tmasterPubKey[i] = y\n\t}\n\n\treturn masterSecKey, masterPubKey, nil\n}\n\n// DeriveKey takes master secret key and input vector y, and returns the\n// functional encryption key. In case the key could not be derived, it\n// returns an error.\nfunc (d *DDH) DeriveKey(masterSecKey, y data.Vector) (*big.Int, error) {\n\tif err := y.CheckBound(d.Params.Bound); err != nil {\n\t\treturn nil, err\n\t}\n\n\tkey, err := masterSecKey.Dot(y)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn new(big.Int).Mod(key, d.Params.Q), nil\n}\n\n// Encrypt encrypts input vector x with the provided master public key.\n// It returns a ciphertext vector. If encryption failed, error is returned.\nfunc (d *DDH) Encrypt(x, masterPubKey data.Vector) (data.Vector, error) {\n\tif err := x.CheckBound(d.Params.Bound); err != nil {\n\t\treturn nil, err\n\t}\n\n\tsampler := sample.NewUniformRange(big.NewInt(2), d.Params.Q)\n\tr, err := sampler.Sample()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tciphertext := make([]*big.Int, len(x)+1)\n\t// ct0 = g^r\n\tct0 := new(big.Int).Exp(d.Params.G, r, d.Params.P)\n\tciphertext[0] = ct0\n\n\tfor i := 0; i < len(x); i++ {\n\t\t// ct_i = h_i^r * g^x_i\n\t\t// ct_i = mpk[i]^r * g^x_i\n\t\tt1 := new(big.Int).Exp(masterPubKey[i], r, d.Params.P)\n\t\tt2 := internal.ModExp(d.Params.G, x[i], d.Params.P)\n\t\tct := new(big.Int).Mod(new(big.Int).Mul(t1, t2), d.Params.P)\n\t\tciphertext[i+1] = ct\n\t}\n\n\treturn ciphertext, nil\n}\n\n// Decrypt accepts the encrypted vector, functional encryption key, and\n// a plaintext vector y. It returns the inner product of x and y.\n// If decryption failed, error is returned.\nfunc (d *DDH) Decrypt(cipher data.Vector, key *big.Int, y data.Vector) (*big.Int, error) {\n\tif err := y.CheckBound(d.Params.Bound); err != nil {\n\t\treturn nil, err\n\t}\n\n\tnum := big.NewInt(1)\n\tfor i, ct := range cipher[1:] {\n\t\tt1 := internal.ModExp(ct, y[i], d.Params.P)\n\t\tnum = num.Mod(new(big.Int).Mul(num, t1), d.Params.P)\n\t}\n\n\tdenom := internal.ModExp(cipher[0], key, d.Params.P)\n\tdenomInv := new(big.Int).ModInverse(denom, d.Params.P)\n\tr := new(big.Int).Mod(new(big.Int).Mul(num, denomInv), d.Params.P)\n\n\tbound := new(big.Int).Mul(big.NewInt(int64(d.Params.L)), new(big.Int).Exp(d.Params.Bound, big.NewInt(2), big.NewInt(0)))\n\n\tcalc, err := dlog.NewCalc().InZp(d.Params.P, d.Params.Q)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tcalc = calc.WithNeg()\n\n\tres, err := calc.WithBound(bound).BabyStepGiantStep(r, d.Params.G)\n\n\treturn res, err\n}\n"
  },
  {
    "path": "innerprod/simple/ddh_multi.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage simple\n\nimport (\n\t\"fmt\"\n\t\"math/big\"\n\n\t\"github.com/fentec-project/gofe/data\"\n\t\"github.com/fentec-project/gofe/sample\"\n)\n\n// DDHMulti represents a multi input variant of the\n// underlying DDH scheme based on\n// Abdalla, Catalano, Fiore, Gay, and Ursu:\n// \"Multi-Input Functional Encryption for Inner Products:\n// Function-Hiding Realizations and Constructions without Pairings\".\ntype DDHMulti struct {\n\t// number of encryptors\n\tSlots int\n\t*DDH\n}\n\n// DDHMultiClient represents a multi input variant of the\n// underlying DDH scheme based on\n// Abdalla, Catalano, Fiore, Gay, and Ursu:\n// \"Multi-Input Functional Encryption for Inner Products:\n// Function-Hiding Realizations and Constructions without Pairings\".\ntype DDHMultiClient struct {\n\t*DDH\n}\n\n// NewDDHMulti configures a new instance of the scheme.\n// It accepts the number of slots (encryptors), the length of\n// input vectors l, the bit length of the modulus (we are\n// operating in the Z_p group), and a bound by which coordinates\n// of input vectors are bounded.\n//\n// It returns an error in case the underlying DDH scheme instances could\n// not be properly instantiated.\nfunc NewDDHMulti(slots, l, modulusLength int, bound *big.Int) (*DDHMulti, error) {\n\tddh, err := NewDDH(l, modulusLength, bound)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &DDHMulti{\n\t\tSlots: slots,\n\t\tDDH:   ddh,\n\t}, nil\n}\n\n// NewDDHMultiPrecomp configures a new instance of the scheme based on\n// precomputed prime numbers and generators..\n// It accepts the number of slots (encryptors), the length of\n// input vectors l, the bit length of the modulus (we are\n// operating in the Z_p group), and a bound by which coordinates\n// of input vectors are bounded. The modulus length should\n// be one of values 1024, 1536, 2048, 2560, 3072, or 4096.\n//\n// It returns an error in case the underlying DDH scheme instances could\n// not be properly instantiated.\nfunc NewDDHMultiPrecomp(slots, l, modulusLength int, bound *big.Int) (*DDHMulti, error) {\n\tddh, err := NewDDHPrecomp(l, modulusLength, bound)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &DDHMulti{\n\t\tSlots: slots,\n\t\tDDH:   ddh,\n\t}, nil\n}\n\n// NewDDHMultiFromParams takes the number of slots and configuration\n// parameters of an existing DDH scheme instance, and reconstructs\n// the scheme with same configuration parameters.\n//\n// It returns a new DDHMulti instance.\nfunc NewDDHMultiFromParams(slots int, params *DDHParams) *DDHMulti {\n\treturn &DDHMulti{\n\t\tSlots: slots,\n\t\tDDH:   &DDH{params},\n\t}\n}\n\n// NewDDHMultiClient configures a new instance of the scheme.\n// It accepts the number of slots (encryptors), the length of\n// input vectors l, the bit length of the modulus (we are\n// operating in the Z_p group), and a bound by which coordinates\n// of input vectors are bounded.\n//\n// It returns an error in case the underlying DDH scheme instances could\n// not be properly instantiated.\nfunc NewDDHMultiClient(params *DDHParams) *DDHMultiClient {\n\treturn &DDHMultiClient{\n\t\tDDH: &DDH{params},\n\t}\n}\n\n// DDHMultiSecKey is a secret key for DDH multi input scheme.\ntype DDHMultiSecKey struct {\n\tMsk    data.Matrix\n\tOtpKey data.Matrix\n}\n\n// GenerateMasterKeys generates matrices comprised of master secret\n// keys and master public keys for the scheme.\n//\n// It returns an error in case master keys could not be generated.\nfunc (dm *DDHMulti) GenerateMasterKeys() (data.Matrix, *DDHMultiSecKey, error) {\n\tmskVecs := make([]data.Vector, dm.Slots)\n\tmpkVecs := make([]data.Vector, dm.Slots)\n\totpVecs := make([]data.Vector, dm.Slots)\n\n\tfor i := 0; i < dm.Slots; i++ {\n\t\tmasterSecretKey, masterPublicKey, err := dm.DDH.GenerateMasterKeys()\n\n\t\tif err != nil {\n\t\t\treturn nil, nil, fmt.Errorf(\"error in master key generation\")\n\t\t}\n\t\tmskVecs[i] = masterSecretKey\n\t\tmpkVecs[i] = masterPublicKey\n\n\t\totpVector, err := data.NewRandomVector(dm.Params.L, sample.NewUniform(dm.Params.Bound))\n\t\tif err != nil {\n\t\t\treturn nil, nil, fmt.Errorf(\"error in random vector generation\")\n\t\t}\n\t\totpVecs[i] = otpVector\n\t}\n\n\tpubKey, err := data.NewMatrix(mpkVecs)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tsecKey, err := data.NewMatrix(mskVecs)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\totp, err := data.NewMatrix(otpVecs)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\treturn pubKey, &DDHMultiSecKey{secKey, otp}, nil\n}\n\n// Encrypt generates a ciphertext from the input vector x\n// with the provided public key and one-time pad otp (which\n// is a part of the secret key). It returns the ciphertext vector.\n// If encryption failed, error is returned.\nfunc (e *DDHMultiClient) Encrypt(x data.Vector, pubKey, otp data.Vector) (data.Vector, error) {\n\tif err := x.CheckBound(e.Params.Bound); err != nil {\n\t\treturn nil, err\n\t}\n\n\totp = x.Add(otp)\n\totpModulo := otp.Mod(e.Params.Bound)\n\n\treturn e.DDH.Encrypt(otpModulo, pubKey)\n}\n\n// DDHMultiDerivedKey is functional encryption key for DDH Scheme.\ntype DDHMultiDerivedKey struct {\n\tKeys   data.Vector\n\tOTPKey *big.Int\n}\n\n// DeriveKey takes master secret key and a matrix y comprised\n// of input vectors, and returns the functional encryption key.\n// In case the key could not be derived, it returns an error.\nfunc (dm *DDHMulti) DeriveKey(secKey *DDHMultiSecKey, y data.Matrix) (*DDHMultiDerivedKey, error) {\n\tif err := y.CheckBound(dm.Params.Bound); err != nil {\n\t\treturn nil, err\n\t}\n\n\tz, err := secKey.OtpKey.Dot(y)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tz.Mod(z, dm.Params.Bound)\n\n\tderivedKeys := make([]*big.Int, dm.Slots)\n\n\tfor i := 0; i < dm.Slots; i++ {\n\t\tderivedKey, err := dm.DDH.DeriveKey(secKey.Msk[i], y[i])\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tderivedKeys[i] = derivedKey\n\t}\n\n\treturn &DDHMultiDerivedKey{data.NewVector(derivedKeys), z}, nil\n}\n\n// Decrypt accepts the matrix cipher comprised of encrypted vectors,\n// functional encryption key, and a matrix y comprised of plaintext vectors.\n// It returns the sum of inner products.\n// If decryption failed, error is returned.\nfunc (dm *DDHMulti) Decrypt(cipher []data.Vector, key *DDHMultiDerivedKey, y data.Matrix) (*big.Int, error) {\n\tif err := y.CheckBound(dm.Params.Bound); err != nil {\n\t\treturn nil, err\n\t}\n\n\tsum := big.NewInt(0)\n\tfor i := 0; i < dm.Slots; i++ {\n\t\tc, err := dm.DDH.Decrypt(cipher[i], key.Keys[i], y[i])\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tsum.Add(sum, c)\n\t}\n\n\tres := new(big.Int).Sub(sum, key.OTPKey)\n\tres.Mod(res, dm.Params.Bound)\n\treturn res, nil\n}\n"
  },
  {
    "path": "innerprod/simple/ddh_multi_test.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage simple_test\n\nimport (\n\t\"math/big\"\n\t\"testing\"\n\n\t\"github.com/fentec-project/gofe/data\"\n\t\"github.com/fentec-project/gofe/innerprod/simple\"\n\t\"github.com/fentec-project/gofe/sample\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc testSimpleMultiDDHFromParam(t *testing.T, param ddhTestParam) {\n\t// choose meta-parameters for the scheme\n\tnumOfSlots := 2\n\tl := 3\n\tbound := big.NewInt(1000)\n\tsampler := sample.NewUniform(bound)\n\n\t// build the central authority for the scheme\n\tvar multiDDH *simple.DDHMulti\n\tvar err error\n\tif param.precomputed {\n\t\t// modulusLength defines the security of the scheme, the higher the better\n\t\tmultiDDH, err = simple.NewDDHMultiPrecomp(numOfSlots, l, param.modulusLength, bound)\n\t} else {\n\t\tmultiDDH, err = simple.NewDDHMulti(numOfSlots, l, param.modulusLength, bound)\n\t}\n\tif err != nil {\n\t\tt.Fatalf(\"Failed to initialize multi input inner product: %v\", err)\n\t}\n\n\t// the central authority generates keys for all the clients\n\tpubKey, secKey, err := multiDDH.GenerateMasterKeys()\n\tif err != nil {\n\t\tt.Fatalf(\"Error during keys generation: %v\", err)\n\t}\n\n\t// pick a matrix that represent the collection of inner-product vectors y_i\n\ty, err := data.NewRandomMatrix(numOfSlots, l, sampler)\n\tif err != nil {\n\t\tt.Fatalf(\"Error during matrix generation: %v\", err)\n\t}\n\n\t// we simulate different clients encrypting which might be on different machines (this means \"multi-input\"),\n\t// ciphertexts are then collected by decryptor and inner-product over vectors from all encryptors is computed\n\tclients := make([]*simple.DDHMultiClient, numOfSlots)\n\tfor i := 0; i < numOfSlots; i++ {\n\t\tclients[i] = simple.NewDDHMultiClient(multiDDH.Params)\n\t}\n\n\t// central authority derives the key for the decryptor\n\tderivedKey, err := multiDDH.DeriveKey(secKey, y)\n\tif err != nil {\n\t\tt.Fatalf(\"Error during key derivation: %v\", err)\n\t}\n\n\t// each client encrypts its vector x_i\n\tcollectedX := make([]data.Vector, numOfSlots) // for checking whether encrypt/decrypt works properly\n\tciphertexts := make([]data.Vector, numOfSlots)\n\tfor i := 0; i < numOfSlots; i++ {\n\t\tx, err := data.NewRandomVector(l, sampler) // x possessed and chosen by clients[i]\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"Error during random vector generation: %v\", err)\n\t\t}\n\t\tcollectedX[i] = x\n\n\t\tc, err := clients[i].Encrypt(x, pubKey[i], secKey.OtpKey[i])\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"Error during encryption: %v\", err)\n\t\t}\n\t\tciphertexts[i] = c\n\t}\n\n\txMatrix, err := data.NewMatrix(collectedX)\n\tif err != nil {\n\t\tt.Fatalf(\"Error during collection of vectors to be encrypted: %v\", err)\n\t}\n\n\txyCheck, err := xMatrix.Dot(y)\n\txyCheck.Mod(xyCheck, bound)\n\tif err != nil {\n\t\tt.Fatalf(\"Error during inner product calculation: %v\", err)\n\t}\n\n\t// we simulate the decryptor\n\tdecryptor := simple.NewDDHMultiFromParams(numOfSlots, multiDDH.Params)\n\n\tciphertextMatrix, err := data.NewMatrix(ciphertexts)\n\tif err != nil {\n\t\tt.Fatalf(\"Error during collection of ciphertexts: %v\", err)\n\t}\n\n\t// decryptor decrypts the value\n\txy, err := decryptor.Decrypt(ciphertextMatrix, derivedKey, y)\n\tif err != nil {\n\t\tt.Fatalf(\"Error during decryption: %v\", err)\n\t}\n\n\t// we check if the decrypted value is correct\n\tassert.Equal(t, xy.Cmp(xyCheck), 0, \"obtained incorrect inner product\")\n}\n\nfunc TestSimple_MultiDDH(t *testing.T) {\n\tparams := []ddhTestParam{{name: \"random\", modulusLength: 512, precomputed: false},\n\t\t{name: \"precomputed\", modulusLength: 2048, precomputed: true}}\n\n\tfor _, param := range params {\n\t\tt.Run(param.name, func(t *testing.T) {\n\t\t\ttestSimpleMultiDDHFromParam(t, param)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "innerprod/simple/ddh_test.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage simple_test\n\nimport (\n\t\"math/big\"\n\t\"testing\"\n\n\t\"github.com/fentec-project/gofe/data\"\n\t\"github.com/fentec-project/gofe/innerprod/simple\"\n\t\"github.com/fentec-project/gofe/sample\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\ntype ddhTestParam struct {\n\tname          string\n\tmodulusLength int\n\tprecomputed   bool\n}\n\nfunc testSimpleDDHFromParam(t *testing.T, param ddhTestParam) {\n\tl := 3\n\tbound := new(big.Int).Exp(big.NewInt(2), big.NewInt(10), nil)\n\tsampler := sample.NewUniformRange(new(big.Int).Add(new(big.Int).Neg(bound), big.NewInt(1)), bound)\n\n\tvar simpleDDH *simple.DDH\n\tvar err error\n\tif param.precomputed {\n\t\tsimpleDDH, err = simple.NewDDHPrecomp(l, param.modulusLength, bound)\n\t} else {\n\t\tsimpleDDH, err = simple.NewDDH(l, param.modulusLength, bound)\n\t}\n\tif err != nil {\n\t\tt.Fatalf(\"Error during simple inner product creation: %v\", err)\n\t}\n\n\tmasterSecKey, masterPubKey, err := simpleDDH.GenerateMasterKeys()\n\n\tif err != nil {\n\t\tt.Fatalf(\"Error during master key generation: %v\", err)\n\t}\n\n\ty, err := data.NewRandomVector(l, sampler)\n\n\tif err != nil {\n\t\tt.Fatalf(\"Error during random generation: %v\", err)\n\t}\n\n\tfuncKey, err := simpleDDH.DeriveKey(masterSecKey, y)\n\n\tif err != nil {\n\t\tt.Fatalf(\"Error during key derivation: %v\", err)\n\t}\n\n\tx, err := data.NewRandomVector(l, sampler)\n\n\tif err != nil {\n\t\tt.Fatalf(\"Error during random generation: %v\", err)\n\t}\n\n\t// simulate the instantiation of encryptor (which should be given masterPubKey)\n\tencryptor := simple.NewDDHFromParams(simpleDDH.Params)\n\txyCheck, err := x.Dot(y)\n\n\tif err != nil {\n\t\tt.Fatalf(\"Error during inner product calculation\")\n\t}\n\tciphertext, err := encryptor.Encrypt(x, masterPubKey)\n\n\tif err != nil {\n\t\tt.Fatalf(\"Error during encryption: %v\", err)\n\t}\n\n\tdecryptor := simple.NewDDHFromParams(simpleDDH.Params)\n\txy, err := decryptor.Decrypt(ciphertext, funcKey, y)\n\n\tif err != nil {\n\t\tt.Fatalf(\"Error during decryption: %v\", err)\n\t}\n\n\tassert.Equal(t, xy, xyCheck, \"Original and decrypted values should match\")\n}\n\nfunc TestSimple_DDH(t *testing.T) {\n\tparams := []ddhTestParam{{name: \"random\", modulusLength: 512, precomputed: false},\n\t\t{name: \"precomputed\", modulusLength: 2048, precomputed: true}}\n\n\tfor _, param := range params {\n\t\tt.Run(param.name, func(t *testing.T) {\n\t\t\ttestSimpleDDHFromParam(t, param)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "innerprod/simple/doc.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// Package simple includes simple schemes for functional encryption of\n// inner products.\n//\n// All implementations in this package are based on the reference\n// paper by  Abdalla et. al (see https://eprint.iacr.org/2015/017.pdf).\n// The reference scheme offers selective security under chosen-plaintext\n// attacks (s-IND-CPA security).\n//\n// The reference scheme is public key, which means that no master secret\n// key is required for the encryption.\n//\n// For instantiation from the decisional Diffie-Hellman assumption\n// (DDH), see struct DDH (and its multi-input variant DDHMulti, which\n// is a secret key scheme, because a part of the secret key is required\n// for the encryption).\n//\n// For instantiation from learning with errors (LWE), see\n// structs LWE and RingLWE.\npackage simple\n"
  },
  {
    "path": "innerprod/simple/lwe.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage simple\n\nimport (\n\t\"math/big\"\n\n\t\"crypto/rand\"\n\t\"math\"\n\t\"math/bits\"\n\n\t\"fmt\"\n\n\t\"github.com/fentec-project/gofe/data\"\n\tgofe \"github.com/fentec-project/gofe/internal\"\n\t\"github.com/fentec-project/gofe/sample\"\n\t\"github.com/pkg/errors\"\n)\n\n// LWEParams represents parameters for the simple LWE scheme.\ntype LWEParams struct {\n\tL int // Length of data vectors for inner product\n\n\tN int // Main security parameters of the scheme\n\tM int // Number of rows (samples) for the LWE problem\n\n\tBoundX *big.Int // Bound for input vector coordinates (for x)\n\tBoundY *big.Int // Bound for inner product vector coordinates (for y)\n\n\tP *big.Int // Modulus for message space\n\tQ *big.Int // Modulus for ciphertext and keys\n\n\tSigmaQ *big.Float // standard deviation for the noise terms LWE\n\tLSigma *big.Int   // precomputed LSigma = SigmaQ / (1/2log(2)) needed for sampling\n\n\t// Matrix A of dimensions M*N is a public parameter of the scheme\n\tA data.Matrix\n}\n\n// LWE represents a scheme instantiated from the LWE assumption,\n// based on the LWE variant by\n// Abdalla, Bourse, De Caro, and Pointchev:\n// \"Simple Functional Encryption Schemes for Inner Products\".\ntype LWE struct {\n\tParams *LWEParams\n}\n\n// NewLWE configures a new instance of the scheme.\n// It accepts the length of input vectors l, bound for coordinates of\n// input vectors x and y, the main security parameters n and m,\n// modulus for input data p, and modulus for ciphertext and keys q.\n// Security parameters are generated so that they satisfy theoretical\n// bounds provided in the phd thesis Functional Encryption for\n// Inner-Product Evaluations, see Section 8.3.1 in\n// https://www.di.ens.fr/~fbourse/publications/Thesis.pdf\n// Note that this is a prototype implementation and should not be\n// used in production before security testing against various\n// known attacks has been performed. Unfortunately, no such (theoretical)\n// evaluation exists yet in the literature.\n//\n// It returns an error in case public parameters of the scheme could\n// not be generated.\nfunc NewLWE(l int, boundX, boundY *big.Int, n int) (*LWE, error) {\n\t// generate parameters\n\t// p > boundX * boundY * l * 2\n\tnBitsP := boundX.BitLen() + boundY.BitLen() + bits.Len(uint(l)) + 2\n\tp, err := rand.Prime(rand.Reader, nBitsP)\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"cannot generate public parameters\")\n\t}\n\n\tpF := new(big.Float).SetInt(p)\n\tboundXF := new(big.Float).SetInt(boundX)\n\tboundYF := new(big.Float).SetInt(boundY)\n\n\tval := new(big.Float).Mul(boundXF, big.NewFloat(math.Sqrt(float64(l))))\n\tval.Add(val, big.NewFloat(1))\n\tx := new(big.Float).Mul(val, pF)\n\tx.Mul(x, boundYF)\n\tx.Mul(x, big.NewFloat(float64(8*n)*math.Sqrt(float64(n+l+1))))\n\txSqrt := new(big.Float).Sqrt(x)\n\tx.Mul(x, xSqrt)\n\txI, _ := x.Int(nil)\n\tnBitsQ := xI.BitLen() + 1\n\tq, err := rand.Prime(rand.Reader, nBitsQ)\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"cannot generate public parameters\")\n\t}\n\n\tm := (n+l+1)*nBitsQ + 2*n + 1\n\n\tsigma := new(big.Float)\n\tsigma.SetPrec(uint(n))\n\tsigma.Quo(big.NewFloat(1/(2*math.Sqrt(float64(2*l*m*n)))), pF)\n\tsigma.Quo(sigma, boundYF)\n\tqF := new(big.Float).SetInt(q)\n\tsigmaQ := new(big.Float).Mul(sigma, qF)\n\n\t// to sample with NormalDoubleConstant sigmaQ must be\n\t// a multiple of sample.SigmaCDT = sqrt(1/2ln(2)), hence we make\n\t// it such\n\tlSigmaF := new(big.Float).Quo(sigmaQ, sample.SigmaCDT)\n\tlSigma, _ := lSigmaF.Int(nil)\n\tlSigma.Add(lSigma, big.NewInt(1))\n\tlSigmaF.SetInt(lSigma)\n\tsigmaQ.Mul(sample.SigmaCDT, lSigmaF)\n\n\t// sanity check if the parameters satisfy theoretical bounds\n\tval.Quo(sigmaQ, val)\n\tif val.Cmp(big.NewFloat(2*math.Sqrt(float64(n)))) < 1 {\n\t\treturn nil, fmt.Errorf(\"parameters generation faliled, sigmaQ too small\")\n\t}\n\n\t// generate a random matrix\n\tA, err := data.NewRandomMatrix(m, n, sample.NewUniform(q))\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"cannot generate public parameters\")\n\t}\n\treturn &LWE{\n\t\tParams: &LWEParams{\n\t\t\tL:      l,\n\t\t\tBoundX: boundX,\n\t\t\tBoundY: boundY,\n\t\t\tN:      n,\n\t\t\tM:      m,\n\t\t\tP:      p,\n\t\t\tQ:      q,\n\t\t\tA:      A,\n\t\t\tSigmaQ: sigmaQ,\n\t\t\tLSigma: lSigma,\n\t\t},\n\t}, nil\n}\n\n// GenerateSecretKey generates a secret key for the scheme.\n// The key is represented by a matrix with dimensions n*l whose\n// elements are random values from the interval [0, q).\n//\n// In case secret key could not be generated, it returns an error.\nfunc (s *LWE) GenerateSecretKey() (data.Matrix, error) {\n\treturn data.NewRandomMatrix(s.Params.N, s.Params.L, sample.NewUniform(s.Params.Q))\n}\n\n// GeneratePublicKey accepts a secret key SK, standard deviation sigma.\n// It generates a public key PK for the scheme. Public key is a matrix\n// of m*l elements.\n//\n// In case of a malformed secret key the function returns an error.\nfunc (s *LWE) GeneratePublicKey(SK data.Matrix) (data.Matrix, error) {\n\tif !SK.CheckDims(s.Params.N, s.Params.L) {\n\t\treturn nil, gofe.ErrMalformedSecKey\n\t}\n\n\t// Initialize and fill noise matrix E with m*l samples\n\tsampler := sample.NewNormalDoubleConstant(s.Params.LSigma)\n\n\tE, err := data.NewRandomMatrix(s.Params.M, s.Params.L, sampler)\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"error generating public key\")\n\t}\n\n\t// Calculate public key as PK = (A * SK + E) % q\n\t// we ignore error checks because they errors could only arise if SK\n\t// was not of the proper form, but we validated it at the beginning\n\tPK, _ := s.Params.A.Mul(SK)\n\tPK = PK.Mod(s.Params.Q)\n\tPK, _ = PK.Add(E)\n\tPK = PK.Mod(s.Params.Q)\n\n\treturn PK, nil\n}\n\n// DeriveKey accepts input vector y and master secret key SK, and derives a\n// functional encryption key.\n//\n// In case of malformed secret key or input vector that violates the configured\n// bound, it returns an error.\nfunc (s *LWE) DeriveKey(y data.Vector, SK data.Matrix) (data.Vector, error) {\n\tif err := y.CheckBound(s.Params.BoundY); err != nil {\n\t\treturn nil, err\n\t}\n\tif !SK.CheckDims(s.Params.N, s.Params.L) {\n\t\treturn nil, gofe.ErrMalformedSecKey\n\t}\n\t// Secret key is a linear combination of input vector y\n\t// and master secret key SK.\n\tskY, err := SK.MulVec(y)\n\tif err != nil {\n\t\treturn nil, gofe.ErrMalformedInput\n\t}\n\tskY = skY.Mod(s.Params.Q)\n\n\treturn skY, nil\n}\n\n// Encrypt encrypts vector x using public key PK.\n// It returns the resulting ciphertext vector. In case of malformed\n// public key or input vector that violates the configured bound,\n// it returns an error.\nfunc (s *LWE) Encrypt(x data.Vector, PK data.Matrix) (data.Vector, error) {\n\tif err := x.CheckBound(s.Params.BoundX); err != nil {\n\t\treturn nil, err\n\t}\n\tif !PK.CheckDims(s.Params.M, s.Params.L) {\n\t\treturn nil, gofe.ErrMalformedPubKey\n\t}\n\tif len(x) != s.Params.L {\n\t\treturn nil, gofe.ErrMalformedInput\n\t}\n\n\t// Create a random vector comprised of m 0s and 1s\n\tr, err := data.NewRandomVector(s.Params.M, sample.NewBit())\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"error in encrypt\")\n\t}\n\n\t// Ciphertext vectors will be composed of two vectors: ct0 and ctLast.\n\t// ct0 ... a vector comprising the first n elements of the cipher\n\t// ctLast ... a vector comprising the last l elements of the cipher\n\n\t// ct0 = A(transposed) * r\n\tATrans := s.Params.A.Transpose()\n\tct0, _ := ATrans.MulVec(r)\n\n\t// Calculate coordinates ct_last_i = <pkI, r> + t(xi) mod q\n\t// We can obtain the vector of dot products <pk_i, r> as PK(transposed) * r\n\t// Function t(x) is denoted as the center function\n\tPKTrans := PK.Transpose()\n\tctLast, _ := PKTrans.MulVec(r)\n\n\tt := s.center(x)\n\tctLast = ctLast.Add(t)\n\tctLast = ctLast.Mod(s.Params.Q)\n\n\t// Construct the final ciphertext vector by joining both parts\n\treturn append(ct0, ctLast...), nil\n}\n\n// Calculates the center function t(x) = floor(x*q/p) % q for a vector x.\nfunc (s *LWE) center(v data.Vector) data.Vector {\n\treturn v.Apply(func(x *big.Int) *big.Int {\n\t\tt := new(big.Int)\n\t\tt.Mul(x, s.Params.Q)\n\t\tt.Div(t, s.Params.P)\n\t\tt.Mod(t, s.Params.Q)\n\n\t\treturn t\n\t})\n}\n\n// Decrypt accepts an encrypted vector ct, functional encryption key skY,\n// and plaintext vector y. It returns the inner product of x and y.\n// If decryption failed (for instance with input data that violates the\n// configured bound or malformed ciphertext or keys), error is returned.\nfunc (s *LWE) Decrypt(ct, skY, y data.Vector) (*big.Int, error) {\n\tif err := y.CheckBound(s.Params.BoundY); err != nil {\n\t\treturn nil, err\n\t}\n\tif len(skY) != s.Params.N {\n\t\treturn nil, gofe.ErrMalformedDecKey\n\t}\n\tif len(y) != s.Params.L {\n\t\treturn nil, gofe.ErrMalformedInput\n\t}\n\n\t// Break down the ciphertext vector into\n\t// ct0     which holds first n elements of the cipher, and\n\t// ctLast  which holds last n elements of the cipher\n\tif len(ct) != s.Params.N+s.Params.L {\n\t\treturn nil, gofe.ErrMalformedCipher\n\t}\n\tct0 := ct[:s.Params.N]\n\tctLast := ct[s.Params.N:]\n\n\t// Calculate d = <y, ctLast> - <ct0, skY>\n\tyDotCtLast, _ := y.Dot(ctLast)\n\tyDotCtLast.Mod(yDotCtLast, s.Params.Q)\n\tct0DotSkY, _ := ct0.Dot(skY)\n\tct0DotSkY.Mod(ct0DotSkY, s.Params.Q)\n\n\thalfQ := new(big.Int).Div(s.Params.Q, big.NewInt(2))\n\n\t// d will hold the decrypted message\n\td := new(big.Int).Sub(yDotCtLast, ct0DotSkY)\n\td.Mod(d, s.Params.Q)\n\t// in case d > q/2 the result will be negative\n\tif d.Cmp(halfQ) == 1 {\n\t\td.Sub(d, s.Params.Q)\n\t}\n\n\td.Mul(d, s.Params.P)\n\td.Add(d, halfQ)\n\td.Div(d, s.Params.Q)\n\treturn d, nil\n}\n"
  },
  {
    "path": "innerprod/simple/lwe_test.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage simple_test\n\nimport (\n\t\"math/big\"\n\t\"testing\"\n\n\t\"github.com/fentec-project/gofe/data\"\n\t\"github.com/fentec-project/gofe/innerprod/simple\"\n\t\"github.com/fentec-project/gofe/sample\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestSimple_LWE(t *testing.T) {\n\tl := 4\n\tn := 128\n\tb := big.NewInt(10000)\n\n\tx, y, xy := testVectorData(l, b, b)\n\temptyVec := data.Vector{}\n\temptyMat := data.Matrix{}\n\n\tsimpleLWE, err := simple.NewLWE(l, b, b, n)\n\tassert.NoError(t, err)\n\n\tSK, err := simpleLWE.GenerateSecretKey()\n\tassert.NoError(t, err)\n\n\t_, err = simpleLWE.GeneratePublicKey(emptyMat)\n\tassert.Error(t, err)\n\tPK, err := simpleLWE.GeneratePublicKey(SK)\n\tassert.NoError(t, err)\n\n\t_, err = simpleLWE.DeriveKey(emptyVec, SK)\n\tassert.Error(t, err)\n\t_, err = simpleLWE.DeriveKey(y, emptyMat)\n\tassert.Error(t, err)\n\tskY, err := simpleLWE.DeriveKey(y, SK)\n\tassert.NoError(t, err)\n\n\t_, err = simpleLWE.Encrypt(emptyVec, PK)\n\tassert.Error(t, err)\n\t_, err = simpleLWE.Encrypt(x, emptyMat)\n\tassert.Error(t, err)\n\tcipher, err := simpleLWE.Encrypt(x, PK)\n\tassert.NoError(t, err)\n\n\t_, err = simpleLWE.Decrypt(emptyVec, skY, y)\n\tassert.Error(t, err)\n\t_, err = simpleLWE.Decrypt(cipher, emptyVec, y)\n\tassert.Error(t, err)\n\t_, err = simpleLWE.Decrypt(cipher, skY, emptyVec)\n\tassert.Error(t, err)\n\txyDecrypted, err := simpleLWE.Decrypt(cipher, skY, y)\n\tassert.NoError(t, err)\n\tassert.Equal(t, xy.Cmp(xyDecrypted), 0, \"obtained incorrect inner product\")\n}\n\n// testVectorData returns random vectors x, y, each containing\n// elements up to the respective bound.\n// It also returns the dot product of the vectors.\nfunc testVectorData(len int, boundX, boundY *big.Int) (data.Vector, data.Vector, *big.Int) {\n\tsamplerX := sample.NewUniformRange(new(big.Int).Neg(boundX), boundX)\n\tsamplerY := sample.NewUniformRange(new(big.Int).Neg(boundY), boundY)\n\tx, _ := data.NewRandomVector(len, samplerX)\n\ty, _ := data.NewRandomVector(len, samplerY)\n\txy, _ := x.Dot(y)\n\n\treturn x, y, xy\n}\n"
  },
  {
    "path": "innerprod/simple/ringlwe.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage simple\n\nimport (\n\tgofe \"github.com/fentec-project/gofe/internal\"\n\t\"math\"\n\t\"math/big\"\n\n\t\"github.com/fentec-project/gofe/data\"\n\t\"github.com/fentec-project/gofe/sample\"\n\t\"github.com/pkg/errors\"\n)\n\n// RingLWEParams represents parameters for the ring LWE scheme.\ntype RingLWEParams struct {\n\tL int // Length of data vectors for inner product\n\n\t// Main security parameters of the scheme\n\tN int\n\n\t// Settings for discrete gaussian sampler\n\tSigma1 *big.Float // standard deviation\n\tSigma2 *big.Float // standard deviation\n\tSigma3 *big.Float // standard deviation\n\n\tBoundX *big.Int // upper bound for coordinates of input vectors\n\tBoundY *big.Int // upper bound for coordinates of inner-product vectors\n\n\tP *big.Int // bound for the resulting inner product\n\tQ *big.Int // modulus for ciphertext and keys\n\n\t// A is a vector with N coordinates.\n\t// It represents a random polynomial for the scheme.\n\tA data.Vector\n}\n\n// RingLWE represents a FE scheme instantiated from the ringLWE assumption. It\n// allows to encrypt a matrix X and derive a FE based on a vector y, so that\n// one can decrypt y^T * X and nothing else. This can be seen as a SIMD version\n// of a simple inner product scheme, since multiple vectors (columns of X) can be\n// multiplied with y at the same time.\n// It is based on\n// Bermudo Mera, Karmakar, Marc, and Soleimanian:\n// \"Efficient Lattice-Based Inner-Product Functional Encryption\",\n// see https://eprint.iacr.org/2021/046.\ntype RingLWE struct {\n\tParams  *RingLWEParams\n}\n\n// NewRingLWE configures a new instance of the scheme.\n// It accepts a security parameter sec, the length of input vectors l,\n// bound for coordinates of input vectors x and y. It generates all the\n// parameters needed to have a scheme with at least sec bits of security\n// by using all the bounds derived in the paper https://eprint.iacr.org/2021/046,\n// as well as having the parameters secure against so called primal attack\n// on LWE.\nfunc NewRingLWE(sec, l int, boundX, boundY *big.Int) (*RingLWE, error) {\n\tK := new(big.Int).Mul(boundX, boundY)\n\tK.Mul(K, big.NewInt(int64(2*l)))\n\n\tkappa := big.NewFloat(float64(sec))\n\tkappaSqrt := new(big.Float).Sqrt(kappa)\n\n\tsigma := big.NewFloat(1)\n\tsigma1 := new(big.Float).Mul(big.NewFloat(math.Sqrt(float64(4*l))), sigma)\n\tsigma1.Mul(sigma1, new(big.Float).SetInt(boundX))\n\tvar q *big.Int\n\tvar sigma2, sigma3 *big.Float\n\tvar safe bool\n\tvar n int\n\tboundOfB := float64(sec) / 0.265\n\tfor pow := 6; pow < 20; pow++ {\n\t\tn = 1 << uint(pow)\n\n\t\tsigma2 = new(big.Float).Mul(big.NewFloat(math.Sqrt(float64(2*(l+2)*n*n))), sigma)\n\t\tsigma2.Mul(sigma2, sigma1)\n\t\tsigma2.Mul(sigma2, kappaSqrt)\n\n\t\tsigma3 = new(big.Float).Mul(sigma2, big.NewFloat(math.Sqrt(float64(2))))\n\n\t\tqFloat1 := new(big.Float).Mul(sigma1, sigma2)\n\t\tqFloat1.Mul(qFloat1, kappa)\n\t\tqFloat1.Mul(qFloat1, big.NewFloat(float64(2*n)))\n\t\tqFloat2 := new(big.Float).Mul(kappaSqrt, sigma3)\n\t\tqFloat := new(big.Float).Add(qFloat1, qFloat2)\n\t\tqFloat.Mul(qFloat, new(big.Float).SetInt(boundY))\n\t\tqFloat.Mul(qFloat, big.NewFloat(float64(2*l)))\n\n\t\tq, _ = qFloat.Int(nil)\n\t\tq.Mul(q, K)\n\n\t\tqF := new(big.Float).SetInt(q)\n\t\tqFF, _ := qF.Float64()\n\t\tsigmaPrimeQF, _ := sigma.Float64()\n\n\t\tsafe = true\n\t\tfor b := float64(50); b <= boundOfB; b = b + 1 {\n\t\t\tfor m := int(math.Max(1, b-float64(n))); m < 3*n; m++ {\n\t\t\t\tdelta := math.Pow(math.Pow(math.Pi*b, 1/b)*b/(2*math.Pi*math.E), 1./(2.*b-2.))\n\t\t\t\tleft := sigmaPrimeQF * math.Sqrt(b)\n\t\t\t\td := n + m\n\t\t\t\tright := math.Pow(delta, 2*b-float64(d)-1) * math.Pow(qFF, float64(m)/float64(d))\n\t\t\t\tif left < right {\n\t\t\t\t\tsafe = false\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif !safe {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif safe {\n\t\t\tbreak\n\t\t}\n\t}\n\n\trandVec, err := data.NewRandomVector(n, sample.NewUniform(q))\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"cannot generate random polynomial\")\n\t}\n\n\treturn &RingLWE{\n\t\tParams: &RingLWEParams{\n\t\t\tL:     l,\n\t\t\tN:     n,\n\t\t\tBoundX: boundX,\n\t\t\tBoundY: boundY,\n\t\t\tP:     K,\n\t\t\tQ:     q,\n\t\t\tSigma1: sigma1,\n\t\t\tSigma2: sigma2,\n\t\t\tSigma3: sigma3,\n\t\t\tA:     randVec,\n\t\t},\n\t}, nil\n}\n\n// GenerateSecretKey generates a secret key for the scheme.\n// The key is a matrix of l*n small elements sampled from\n// Discrete Gaussian distribution.\n//\n// In case secret key could not be generated, it returns an error.\nfunc (s *RingLWE) GenerateSecretKey() (data.Matrix, error) {\n\tlSigmaF := new(big.Float).Quo(s.Params.Sigma1, sample.SigmaCDT)\n\tlSigma, _ := lSigmaF.Int(nil)\n\tsampler := sample.NewNormalDoubleConstant(lSigma)\n\treturn data.NewRandomMatrix(s.Params.L, s.Params.N, sampler)\n}\n\n// GeneratePublicKey accepts a master secret key SK and generates a\n// corresponding master public key.\n// Public key is a matrix of l*n elements.\n// In case of a malformed secret key the function returns an error.\nfunc (s *RingLWE) GeneratePublicKey(SK data.Matrix) (data.Matrix, error) {\n\tif !SK.CheckDims(s.Params.L, s.Params.N) {\n\t\treturn nil, gofe.ErrMalformedPubKey\n\t}\n\t// Generate noise matrix\n\t// Elements are sampled from the same distribution as the secret key S.\n\tlSigmaF := new(big.Float).Quo(s.Params.Sigma1, sample.SigmaCDT)\n\tlSigma, _ := lSigmaF.Int(nil)\n\tsampler := sample.NewNormalDoubleConstant(lSigma)\n\tE, err := data.NewRandomMatrix(s.Params.L, s.Params.N, sampler)\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"public key generation failed\")\n\t}\n\n\t// Calculate public key PK row by row as PKi = (a * SKi + Ei) % q.\n\t// Multiplication and addition are in the ring of polynomials\n\tPK := make(data.Matrix, s.Params.L)\n\tfor i := 0; i < PK.Rows(); i++ {\n\t\tpkI, _ := SK[i].MulAsPolyInRing(s.Params.A)\n\t\tpkI = pkI.Add(E[i])\n\t\tPK[i] = pkI\n\t}\n\tPK = PK.Mod(s.Params.Q)\n\n\treturn PK, nil\n}\n\n// DeriveKey accepts input vector y and master secret key SK, and derives a\n// functional encryption key.\n// In case of malformed secret key or input vector that violates the\n// configured bound, it returns an error.\nfunc (s *RingLWE) DeriveKey(y data.Vector, SK data.Matrix) (data.Vector, error) {\n\tif err := y.CheckBound(s.Params.BoundY); err != nil {\n\t\treturn nil, err\n\t}\n\tif !SK.CheckDims(s.Params.L, s.Params.N) {\n\t\treturn nil, gofe.ErrMalformedSecKey\n\t}\n\t// Secret key is a linear combination of input vector y and master secret keys.\n\tSKTrans := SK.Transpose()\n\tskY, err := SKTrans.MulVec(y)\n\tif err != nil {\n\t\treturn nil, gofe.ErrMalformedInput\n\t}\n\tskY = skY.Mod(s.Params.Q)\n\n\treturn skY, nil\n}\n\n// Calculates the center function t(x) = floor(x*q/p) % q for a matrix X and\n// place it in a bigger matrix.\nfunc (s *RingLWE) center(X data.Matrix) data.Matrix {\n\tret := data.NewConstantMatrix(s.Params.L, s.Params.N, big.NewInt(0))\n\n\tfor i := 0; i < X.Rows(); i++ {\n\t\tfor j := 0; j < X.Cols(); j++ {\n\t\t\tret[i][j].Mul(X[i][j], s.Params.Q)\n\t\t\tret[i][j].Div(ret[i][j], s.Params.P)\n\t\t\tret[i][j].Mod(ret[i][j], s.Params.Q)\n\t\t}\n\t}\n\n\treturn ret\n}\n\n// RingLWECipher is functional encryption key for DDH Scheme.\ntype RingLWECipher struct {\n\tCt0   data.Matrix\n\tCt1   data.Vector\n\tK    int\n}\n\n// Encrypt encrypts matrix X using public key PK.\n// It returns the resulting ciphertext matrix. In case of malformed\n// public key or input matrix that violates the configured bound,\n// it returns an error.\n//\n//The resulting ciphertext has dimensions (l + 1) * n.\nfunc (s *RingLWE) Encrypt(X data.Matrix, PK data.Matrix) (*RingLWECipher, error) {\n\tif err := X.CheckBound(s.Params.BoundX); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif !PK.CheckDims(s.Params.L, s.Params.N) {\n\t\treturn nil, gofe.ErrMalformedPubKey\n\t}\n\tif !(X.Rows() == s.Params.L && X.Cols() <= s.Params.N) {\n\t\treturn nil, gofe.ErrMalformedInput\n\t}\n\n\t// Create a small random vector r\n\tlSigma2F := new(big.Float).Quo(s.Params.Sigma2, sample.SigmaCDT)\n\tlSigma2, _ := lSigma2F.Int(nil)\n\tsampler2 := sample.NewNormalDoubleConstant(lSigma2)\n\tr, err := data.NewRandomVector(s.Params.N, sampler2)\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"error in encrypt\")\n\t}\n\t// Create noise matrix E to secure the encryption\n\tlSigma3F := new(big.Float).Quo(s.Params.Sigma3, sample.SigmaCDT)\n\tlSigma3, _ := lSigma3F.Int(nil)\n\tsampler3 := sample.NewNormalDoubleConstant(lSigma3)\n\tE, err := data.NewRandomMatrix(s.Params.L, s.Params.N, sampler3)\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"error in encrypt\")\n\t}\n\t// Calculate cipher CT row by row as CTi = (PKi * r + Ei) % q.\n\t// Multiplication and addition are in the ring of polynomials.\n\tCT0 := make(data.Matrix, s.Params.L)\n\tfor i := 0; i < CT0.Rows(); i++ {\n\t\tCT0i, _ := PK[i].MulAsPolyInRing(r)\n\t\tCT0i = CT0i.Add(E[i])\n\t\tCT0[i] = CT0i\n\t}\n\tCT0 = CT0.Mod(s.Params.Q)\n\n\t// Include the message X in the encryption\n\tT := s.center(X)\n\tCT0, _ = CT0.Add(T)\n\tCT0 = CT0.Mod(s.Params.Q)\n\n\t// Construct the last row of the cipher\n\tct1, _ := s.Params.A.MulAsPolyInRing(r)\n\te, err := data.NewRandomVector(s.Params.N, sampler2)\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"error in encrypt\")\n\t}\n\tct1 = ct1.Add(e)\n\tct1 = ct1.Mod(s.Params.Q)\n\n\tres := &RingLWECipher{Ct0: CT0, Ct1: ct1, K: X.Cols()}\n\n\treturn res, nil\n}\n\n// Decrypt accepts a ciphertext CT, secret key skY, and plaintext\n// vector y, and returns a vector of inner products of X's rows and y.\n// If decryption failed (for instance with input data that violates the\n// configured bound or malformed ciphertext or keys), error is returned.\nfunc (s *RingLWE) Decrypt(CT *RingLWECipher, skY, y data.Vector) (data.Vector, error) {\n\tif err := y.CheckBound(s.Params.BoundY); err != nil {\n\t\treturn nil, err\n\t}\n\tif len(skY) != s.Params.N {\n\t\treturn nil, gofe.ErrMalformedDecKey\n\t}\n\tif len(y) != s.Params.L {\n\t\treturn nil, gofe.ErrMalformedInput\n\t}\n\n\tif !CT.Ct0.CheckDims(s.Params.L, s.Params.N) || len(CT.Ct1) != s.Params.N {\n\t\treturn nil, gofe.ErrMalformedCipher\n\t}\n\tCT0 := CT.Ct0\n\tct1 := CT.Ct1\n\n\tCT0Trans := CT0.Transpose()\n\tCT0TransMulY, _ := CT0Trans.MulVec(y)\n\tCT0TransMulY = CT0TransMulY.Mod(s.Params.Q)\n\n\tct1MulSkY, _ := ct1.MulAsPolyInRing(skY)\n\tct1MulSkY = ct1MulSkY.Apply(func(x *big.Int) *big.Int {\n\t\treturn new(big.Int).Neg(x)\n\t})\n\n\td := CT0TransMulY.Add(ct1MulSkY)\n\td = d.Mod(s.Params.Q)\n\thalfQ := new(big.Int).Div(s.Params.Q, big.NewInt(2))\n\n\td = d.Apply(func(x *big.Int) *big.Int {\n\t\tif x.Cmp(halfQ) == 1 {\n\t\t\tx.Sub(x, s.Params.Q)\n\t\t}\n\t\tx.Mul(x, s.Params.P)\n\t\tx.Add(x, halfQ)\n\t\tx.Div(x, s.Params.Q)\n\n\t\treturn x\n\t})\n\n\treturn d[:CT.K], nil\n}\n"
  },
  {
    "path": "innerprod/simple/ringlwe_test.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage simple_test\n\nimport (\n\t\"github.com/fentec-project/gofe/data\"\n\t\"github.com/fentec-project/gofe/sample\"\n\t\"math/big\"\n\t\"testing\"\n\n\t\"github.com/fentec-project/gofe/innerprod/simple\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestSimple_RingLWE(t *testing.T) {\n\t// choose meta-parameters\n\tl := 30 // l-dimensional vectors\n\tsec := 75 // min bits of security\n\tbx := big.NewInt(2) // bound for the input coordinates\n\tby := big.NewInt(2) // bound for the inner-product coordinates\n\n\t// setup a ringLWE scheme\n\tringLWE, err := simple.NewRingLWE(sec, l, bx, by)\n\tassert.NoError(t, err)\n\n\t// sample an input and an inner-product vector\n\tsampler := sample.NewUniformRange(new(big.Int).Neg(bx), bx)\n\ty, _ := data.NewRandomVector(l, sampler)\n\tdimX := ringLWE.Params.N / 2\n\tX, _ := data.NewRandomMatrix(l, dimX, sampler)\n\txy, _ := X.Transpose().MulVec(y)\n\n\t// generate a master secret key\n\tSK, err := ringLWE.GenerateSecretKey()\n\tassert.NoError(t, err)\n\n    // generate a public key\n\tPK, err := ringLWE.GeneratePublicKey(SK)\n\tassert.NoError(t, err)\n\n\t// check if errors are raised if the input is of the wrong form\n\temptyVec := data.Vector{}\n\temptyMat := data.Matrix{}\n\t_, err = ringLWE.GeneratePublicKey(emptyMat)\n\tassert.Error(t, err)\n\t_, err = ringLWE.DeriveKey(emptyVec, SK)\n\tassert.Error(t, err)\n\t_, err = ringLWE.DeriveKey(y, emptyMat)\n\tassert.Error(t, err)\n\n\t// derive FE key with respect to y\n\tskY, err := ringLWE.DeriveKey(y, SK)\n\tassert.NoError(t, err)\n\n\t// encrypt a matrix X\n\tcipher, err := ringLWE.Encrypt(X, PK)\n\tassert.NoError(t, err)\n\n\t// check if errors are raised if the input is of the wrong form\n\t_, err = ringLWE.Encrypt(emptyMat, PK)\n\tassert.Error(t, err)\n\t_, err = ringLWE.Encrypt(X, emptyMat)\n\tassert.Error(t, err)\n\n\t// decrypt the product y^T * X using the derived key\n\txyDecrypted, err := ringLWE.Decrypt(cipher, skY, y)\n\tassert.NoError(t, err)\n\t// check the result\n\tfor i:=0; i < dimX; i++ {\n\t\tassert.Equal(t, xy[i].Cmp(xyDecrypted[i]), 0, \"obtained incorrect inner product\")\n\t}\n}\n"
  },
  {
    "path": "internal/dlog/brute_force.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage dlog\n\nimport (\n\t\"fmt\"\n\t\"math/big\"\n\n\t\"github.com/fentec-project/bn256\"\n)\n\n// Simply brute-forces all possible options.\nfunc bruteForce(h, g, p, bound *big.Int) (*big.Int, error) {\n\tif bound == nil {\n\t\tbound = new(big.Int).Sub(p, big.NewInt(1))\n\t}\n\n\tfor i := big.NewInt(0); i.Cmp(bound) < 0; i.Add(i, big.NewInt(1)) {\n\t\tif new(big.Int).Exp(g, i, p).Cmp(h) == 0 {\n\t\t\treturn i, nil\n\t\t}\n\t}\n\n\treturn nil, fmt.Errorf(\"failed to find discrete logarithm within bound\")\n}\n\n// Simply brute-forces all possible options to compute dlog in BN256 GT group.\nfunc bruteForceBN256(h, g *bn256.GT, bound *big.Int) (*big.Int, error) {\n\tif bound == nil {\n\t\tbound = bn256.Order\n\t}\n\n\tfor i := big.NewInt(0); i.Cmp(bound) <= 0; i.Add(i, big.NewInt(1)) {\n\t\tt := new(bn256.GT).ScalarMult(g, i)\n\t\tif t.String() == h.String() {\n\t\t\treturn i, nil\n\t\t}\n\t}\n\n\treturn nil, fmt.Errorf(\"failed to find discrete logarithm within bound\")\n}\n"
  },
  {
    "path": "internal/dlog/brute_force_test.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage dlog\n\nimport (\n\t\"math/big\"\n\t\"testing\"\n\n\t\"github.com/fentec-project/bn256\"\n\t\"github.com/fentec-project/gofe/internal/keygen\"\n\t\"github.com/fentec-project/gofe/sample\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestBruteForceBN256(t *testing.T) {\n\tbound := big.NewInt(1000)\n\tsampler := sample.NewUniform(bound)\n\txCheck, err := sampler.Sample()\n\tif err != nil {\n\t\tt.Fatalf(\"error in random value generation: %v\", err)\n\t}\n\n\tg1gen := new(bn256.G1).ScalarBaseMult(big.NewInt(1))\n\tg2gen := new(bn256.G2).ScalarBaseMult(big.NewInt(1))\n\tg := bn256.Pair(g1gen, g2gen)\n\th := new(bn256.GT).ScalarMult(g, xCheck)\n\n\tx, err := bruteForceBN256(h, g, bound)\n\tif err != nil {\n\t\tt.Fatalf(\"error in brute force algorithm: %v\", err)\n\t}\n\tassert.Equal(t, xCheck.Cmp(x), 0, \"obtained incorrect result\")\n}\n\nfunc TestBruteForce(t *testing.T) {\n\tbound := big.NewInt(1000)\n\tsampler := sample.NewUniform(bound)\n\txCheck, err := sampler.Sample()\n\tif err != nil {\n\t\tt.Fatalf(\"error in random value generation: %v\", err)\n\t}\n\n\tkey, err := keygen.NewElGamal(20)\n\tif err != nil {\n\t\tt.Fatalf(\"error in parameters generation: %v\", err)\n\t}\n\n\th := new(big.Int).Exp(key.G, xCheck, key.P)\n\n\tx, err := bruteForce(h, key.G, key.P, bound)\n\tif err != nil {\n\t\tt.Fatalf(\"error in brute force algorithm: %v\", err)\n\t}\n\tassert.Equal(t, xCheck.Cmp(x), 0, \"obtained incorrect result\")\n}\n"
  },
  {
    "path": "internal/dlog/calc.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage dlog\n\nimport (\n\t\"crypto/sha1\"\n\t\"fmt\"\n\t\"math/big\"\n\n\t\"github.com/fentec-project/bn256\"\n)\n\n// MaxBound limits the interval of values that are checked when\n// computing discrete logarithms. It prevents time and memory\n// exhaustive computation for practical purposes.\n// If Calc is configured to use a boundary value > MaxBound,\n// it will be automatically adjusted to MaxBound.\nvar MaxBound = new(big.Int).Exp(big.NewInt(2), big.NewInt(48), nil)\n\n// Calc represents a discrete logarithm calculator.\ntype Calc struct{}\n\n// NewCalc generates a new discrete logarithm calculator.\nfunc NewCalc() *Calc {\n\treturn &Calc{}\n}\n\n// CalcZp represents a calculator for discrete logarithms\n// that operates in the Zp group of integers modulo prime p.\ntype CalcZp struct {\n\tp     *big.Int\n\tbound *big.Int\n\tm     *big.Int\n\tneg   bool\n}\n\n// InZp builds parameters needed to calculate a discrete\n// logarithm in Z_p group.\nfunc (*Calc) InZp(p, order *big.Int) (*CalcZp, error) {\n\tone := big.NewInt(1)\n\tvar bound *big.Int\n\tif p == nil {\n\t\treturn nil, fmt.Errorf(\"group modulus p cannot be nil\")\n\t}\n\n\tif order == nil {\n\t\tif !p.ProbablyPrime(20) {\n\t\t\treturn nil, fmt.Errorf(\"group modulus p must be prime\")\n\t\t}\n\t\tbound = new(big.Int).Sub(p, one)\n\t} else {\n\t\tbound = order\n\t}\n\n\tm := new(big.Int).Sqrt(bound)\n\tm.Add(m, one)\n\n\treturn &CalcZp{\n\t\tp:     p,\n\t\tbound: bound,\n\t\tm:     m,\n\t\tneg:   false,\n\t}, nil\n}\n\n// WithBound sets a bound for the calculator of the discrete logarithm.\nfunc (c *CalcZp) WithBound(bound *big.Int) *CalcZp {\n\tif bound != nil && bound.Cmp(MaxBound) < 0 && bound.Sign() > 0 {\n\t\tm := new(big.Int).Sqrt(bound)\n\t\tm.Add(m, big.NewInt(1))\n\n\t\treturn &CalcZp{\n\t\t\tbound: bound,\n\t\t\tm:     m,\n\t\t\tp:     c.p,\n\t\t\tneg:   c.neg,\n\t\t}\n\t}\n\treturn c\n}\n\n// WithNeg sets that the result should be searched also among\n// negative integers.\nfunc (c *CalcZp) WithNeg() *CalcZp {\n\treturn &CalcZp{\n\t\tbound: c.bound,\n\t\tm:     c.m,\n\t\tp:     c.p,\n\t\tneg:   true,\n\t}\n}\n\n// BabyStepGiantStep uses the baby-step giant-step method to\n// compute the discrete logarithm in the Zp group. If c.neg is\n// set to true it searches for the answer within [-bound, bound].\n// It does so by running two goroutines, one for negative\n// answers and one for positive. If c.neg is set to false\n// only one goroutine is started, searching for the answer\n// within [0, bound].\nfunc (c *CalcZp) BabyStepGiantStep(h, g *big.Int) (*big.Int, error) {\n\t// create goroutines calculating positive and possibly negative\n\t// result if c.neg is set to true\n\tretChan := make(chan *big.Int)\n\terrChan := make(chan error)\n\tgo c.runBabyStepGiantStepIterative(h, g, retChan, errChan)\n\tif c.neg {\n\t\tgInv := new(big.Int).ModInverse(g, c.p)\n\t\tgo c.runBabyStepGiantStepIterative(h, gInv, retChan, errChan)\n\t}\n\n\t// catch a value when the first routine finishes\n\tret := <-retChan\n\terr := <-errChan\n\t// prevent the situation when one routine exhausted all possibilities\n\t// before the second found the solution\n\tif c.neg && err != nil {\n\t\tret = <-retChan\n\t\terr = <-errChan\n\t}\n\t// if both routines give an error, return an error\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// based on ret decide which routine gave the answer, thus if\n\t// answer is negative\n\tif c.neg && h.Cmp(new(big.Int).Exp(g, ret, c.p)) != 0 {\n\t\tret.Neg(ret)\n\t}\n\n\treturn ret, nil\n}\n\n// runBabyStepGiantStep implements the baby-step giant-step method to\n// compute the discrete logarithm in the Zp group. It is meant to be run\n// as a goroutine.\n//\n// The function searches for x, where h = g^x mod p. If the solution was not found\n// within the provided bound, it returns an error.\nfunc (c *CalcZp) runBabyStepGiantStep(h, g *big.Int, retChan chan *big.Int, errChan chan error) {\n\tone := big.NewInt(1)\n\n\t// big.Int cannot be a key, thus we use a stringified bytes representation of the integer\n\tT := make(map[string]*big.Int)\n\tx := big.NewInt(1)\n\n\t// remainders (r)\n\tfor i := big.NewInt(0); i.Cmp(c.m) < 0; i.Add(i, one) {\n\t\t// important: insert a copy of i into the map as i is mutated each loop\n\t\tT[string(x.Bytes())] = new(big.Int).Set(i)\n\t\tx = new(big.Int).Mod(new(big.Int).Mul(x, g), c.p)\n\t}\n\n\t// g^-m\n\tz := new(big.Int).ModInverse(g, c.p)\n\tz.Exp(z, c.m, c.p)\n\tx = new(big.Int).Set(h)\n\tfor i := big.NewInt(0); i.Cmp(c.m) < 0; i.Add(i, one) {\n\t\tif e, ok := T[string(x.Bytes())]; ok {\n\t\t\tretChan <- new(big.Int).Add(new(big.Int).Mul(i, c.m), e)\n\t\t\terrChan <- nil\n\t\t\treturn\n\t\t}\n\t\tx = new(big.Int).Mod(new(big.Int).Mul(x, z), c.p)\n\t}\n\tretChan <- nil\n\terrChan <- fmt.Errorf(\"failed to find the discrete logarithm within bound \" + c.bound.String())\n}\n\n// runBabyStepGiantStepIterative implements the baby-step giant-step method to\n// compute the discrete logarithm in the Zp group. It is meant to be run\n// as a goroutine.\n//\n// The function searches for x, where h = g^x mod p. If the solution was not found\n// within the provided bound, it returns an error. In contrast to the usual\n// implementation of the method, this one proceeds iteratively, meaning that\n// smaller the solution is, faster the algorithm finishes.\nfunc (c *CalcZp) runBabyStepGiantStepIterative(h, g *big.Int, retChan chan *big.Int, errChan chan error) {\n\tone := big.NewInt(1)\n\ttwo := big.NewInt(2)\n\n\t// big.Int cannot be a key, thus we use a stringified bytes representation of the integer\n\tT := make(map[string]*big.Int)\n\t// prepare values for the loop\n\tx := big.NewInt(1)\n\ty := new(big.Int).Set(h)\n\tz := new(big.Int).ModInverse(g, c.p)\n\tz.Exp(z, two, c.p)\n\n\tbits := int64(c.m.BitLen())\n\n\tT[string(x.Bytes())] = big.NewInt(0)\n\tx.Mod(x.Mul(x, g), c.p)\n\tj := big.NewInt(0)\n\tgiantStep := new(big.Int)\n\tbound := new(big.Int)\n\tfor i := int64(0); i < bits; i++ {\n\t\t// iteratively increasing giant step up to maximal value c.m\n\t\tgiantStep.Exp(two, big.NewInt(i+1), nil)\n\t\tif giantStep.Cmp(c.m) > 0 {\n\t\t\tgiantStep.Set(c.m)\n\t\t\tz.ModInverse(g, c.p)\n\t\t\tz.Exp(z, c.m, c.p)\n\t\t}\n\t\t// for the selected giant step, add all the needed small steps\n\t\tfor k := new(big.Int).Exp(two, big.NewInt(i), nil); k.Cmp(giantStep) < 0; k.Add(k, one) {\n\t\t\tT[string(x.Bytes())] = new(big.Int).Set(k)\n\t\t\tx = x.Mod(x.Mul(x, g), c.p)\n\t\t}\n\t\t// make giant steps and search for the solution\n\t\tbound.Exp(two, big.NewInt(2*(i+1)), nil)\n\t\tfor ; j.Cmp(bound) < 0; j.Add(j, giantStep) {\n\t\t\tif e, ok := T[string(y.Bytes())]; ok {\n\t\t\t\tretChan <- new(big.Int).Add(j, e)\n\t\t\t\terrChan <- nil\n\t\t\t\treturn\n\t\t\t}\n\t\t\ty.Mod(y.Mul(y, z), c.p)\n\t\t}\n\t\tz.Mul(z, z)\n\t\tz.Mod(z, c.p)\n\t}\n\n\tretChan <- nil\n\terrChan <- fmt.Errorf(\"failed to find the discrete logarithm within bound\")\n}\n\n// CalcBN256 represents a calculator for discrete logarithms\n// that operates in the BN256 group.\ntype CalcBN256 struct {\n\tbound   *big.Int\n\tm       *big.Int\n\tPrecomp map[string]*big.Int\n\tprecompMaxBits int\n\tneg     bool\n}\n\n// InBN256 builds parameters needed to calculate a discrete\n// logarithm in a pairing BN256 group.\nfunc (*Calc) InBN256() *CalcBN256 {\n\tm := new(big.Int).Sqrt(MaxBound)\n\tm.Add(m, big.NewInt(1))\n\treturn &CalcBN256{\n\t\tbound: MaxBound,\n\t\tm:     m,\n\t\tneg:   false,\n\t}\n}\n\n// WithBound sets a bound for the calculator of the discrete logarithm.\nfunc (c *CalcBN256) WithBound(bound *big.Int) *CalcBN256 {\n\tif bound != nil && bound.Cmp(MaxBound) < 0 {\n\t\tm := new(big.Int).Sqrt(bound)\n\t\tm.Add(m, big.NewInt(1))\n\n\t\treturn &CalcBN256{\n\t\t\tbound:   bound,\n\t\t\tm:       m,\n\t\t\tPrecomp: c.Precomp,\n\t\t\tprecompMaxBits: c.precompMaxBits,\n\t\t\tneg:     c.neg,\n\t\t}\n\t}\n\treturn c\n}\n\n// WithNeg sets that the result should be searched also among\n// negative integers.\nfunc (c *CalcBN256) WithNeg() *CalcBN256 {\n\treturn &CalcBN256{\n\t\tbound:   c.bound,\n\t\tm:       c.m,\n\t\tPrecomp: c.Precomp,\n\t\tprecompMaxBits: c.precompMaxBits,\n\t\tneg:     true,\n\t}\n}\n\n// Precompute precomputes small steps for the discrete logarithm\n// search. The resulting precomputation table is of size 2^maxBits.\nfunc (c *CalcBN256) Precompute(maxBits int) error {\n\tif maxBits < 2 {\n\t\treturn fmt.Errorf(\"maxBits should be at least 1\")\n\t}\n\tg := new(bn256.GT).ScalarBaseMult(big.NewInt(1))\n\n\tone := big.NewInt(1)\n\tsh := sha1.New()\n\t// big.Int cannot be a key, thus we use a stringified bytes representation of the integer\n\tT := make(map[string]*big.Int)\n\tx := bn256.GetGTOne()\n\n\tfor i := big.NewInt(0); i.BitLen() <= maxBits; i.Add(i, one) {\n\t\tsh.Write([]byte(x.String()))\n\t\tT[string(sh.Sum(nil)[:10])] = new(big.Int).Set(i)\n\t\tsh.Reset()\n\t\tx = new(bn256.GT).Add(x, g)\n\t}\n\n\tc.Precomp = T\n\tc.precompMaxBits = maxBits\n\treturn nil\n}\n\n// BabyStepGiantStepStd implements the baby-step giant-step method to\n// compute the discrete logarithm in the BN256.GT group.\n//\n// It searches for a solution <= bound. If bound argument is nil,\n// the bound is automatically set to the hard coded MaxBound.\n//\n// The function returns x, where h = g^x in BN256.GT group where operations\n// are written as multiplications. If the solution was not found\n// within the provided bound, it returns an error.\nfunc (c *CalcBN256) BabyStepGiantStepStd(h, g *bn256.GT) (*big.Int, error) {\n\tone := big.NewInt(1)\n\n\t// first part of the method can be reused so we\n\t// Precompute it and save it for later\n\n\tif c.Precomp == nil {\n\t\tmaxbits := c.m.BitLen() + 1\n\t\t_ = c.Precompute(maxbits)\n\t}\n\n\t// z = g^-m\n\tgm := new(bn256.GT).ScalarMult(g, c.m)\n\tz := new(bn256.GT).Neg(gm)\n\tx := new(bn256.GT).Set(h)\n\tfor i := big.NewInt(0); i.Cmp(c.m) < 0; i.Add(i, one) {\n\t\tif e, ok := c.Precomp[x.String()]; ok {\n\t\t\treturn new(big.Int).Add(new(big.Int).Mul(i, c.m), e), nil\n\t\t}\n\t\tx.Add(x, z)\n\t}\n\n\treturn nil, fmt.Errorf(\"failed to find discrete logarithm within bound\")\n}\n\n// BabyStepGiantStep uses the baby-step giant-step method to\n// compute the discrete logarithm in the BN256.GT group. If c.neg is\n// set to true it searches for the answer within [-bound, bound].\n// It does so by running two goroutines, one for negative\n// answers and one for positive. If c.neg is set to false\n// only one goroutine is started, searching for the answer\n// within [0, bound].\nfunc (c *CalcBN256) BabyStepGiantStep(h, g *bn256.GT) (*big.Int, error) {\n\t// create goroutines calculating positive and possibly negative\n\t// result if c.neg is set to true\n\tretChan := make(chan *big.Int, 2)\n\terrChan := make(chan error, 2)\n\tquit := make(chan bool, 2)\n\tgo c.runBabyStepGiantStepIterative(h, g, retChan, errChan, quit)\n\tif c.neg {\n\t\thInv := new(bn256.GT).Neg(h)\n\t\tgo c.runBabyStepGiantStepIterative(hInv, g, retChan, errChan, quit)\n\t}\n\n\t// catch a value when the first routine finishes\n\tret := <-retChan\n\terr := <-errChan\n\n\t// prevent the situation when one routine exhausted all possibilities\n\t// before the second found the solution\n\tif c.neg && err != nil {\n\t\tret = <-retChan\n\t\terr = <-errChan\n\t}\n\tif c.neg {\n\t\tquit <- true\n\t}\n\t// if both routines give an error, return an error\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// based on ret decide which routine gave the answer, thus if\n\t// answer is negative\n\tif c.neg && h.String() != new(bn256.GT).ScalarMult(g, ret).String() {\n\t\tret.Neg(ret)\n\t}\n\n\treturn ret, nil\n}\n\n// runBabyStepGiantStepIterative implements the baby-step giant-step method to\n// compute the discrete logarithm in the BN256.GT group. It is meant to be run\n// as a goroutine.\n//\n// The function searches for x, where h = g^x in BN256.GT group where operations\n// are written as multiplications. If the solution was not found\n// within the provided bound, it returns an error. In contrast to the usual\n// implementation of the method, this one proceeds iteratively, meaning that\n// smaller the solution is, faster the algorithm finishes.\nfunc (c *CalcBN256) runBabyStepGiantStepIterative(h, g *bn256.GT, retChan chan *big.Int, errChan chan error,  quit chan bool) {\n\tone := big.NewInt(1)\n\ttwo := big.NewInt(2)\n\n\n\tvar startBits int\n\tif c.Precomp == nil {\n\t\t_ = c.Precompute(2)\n\t}\n\n\tstartBits = c.precompMaxBits\n\n\t// prepare values for the loop\n\ty := new(bn256.GT).Set(h)\n\tj := big.NewInt(0)\n\n\t// define first giant step\n\tgiantStep := new(big.Int)\n\tgiantStep.Exp(big.NewInt(2), big.NewInt(int64(startBits)), nil)\n\tz := new(bn256.GT).Neg(g)\n\tz.ScalarMult(z, giantStep)\n\n\tbound := new(big.Int).Exp(two, big.NewInt(2*int64(startBits)), nil)\n\tsh := sha1.New()\n\tfor ; j.Cmp(bound) < 0; j.Add(j, giantStep) {\n\t\tselect {\n\t\tcase <-quit:\n\t\t\treturn\n\t\tdefault:\n\t\t\tsh.Write([]byte(y.String()))\n\t\t\te, ok := c.Precomp[string(sh.Sum(nil)[:10])]\n\t\t\tsh.Reset()\n\t\t\tif ok {\n\t\t\t\tretChan <- new(big.Int).Add(j, e)\n\t\t\t\terrChan <- nil\n\t\t\t\treturn\n\t\t\t}\n\t\t\ty.Add(y, z)\n\t\t}\n\t}\n\tz.Add(z, z)\n\tx := new(bn256.GT).ScalarMult(g, new(big.Int).Exp(big.NewInt(2), big.NewInt(int64(startBits)), nil))\n\n\tT := make(map[string]*big.Int)\n\tfor k,v := range c.Precomp {\n\t\tT[k] = v\n\t}\n\n\tbits := int64(c.m.BitLen())\n\tfor i := int64(startBits); i < bits; i++ {\n\t\tselect {\n\t\tcase <-quit:\n\t\t\treturn\n\t\tdefault:\n\t\t\t// iteratively increasing giant step up to maximal value c.m\n\t\t\tgiantStep.Exp(two, big.NewInt(i+1), nil)\n\t\t\tif giantStep.Cmp(c.m) > 0 {\n\t\t\t\tgiantStep.Set(c.m)\n\t\t\t\tz.Neg(g)\n\t\t\t\tz.ScalarMult(z, c.m)\n\t\t\t}\n\t\t\t// for the selected giant step, add all the needed small steps\n\t\t\tfor k := new(big.Int).Exp(two, big.NewInt(i), nil); k.Cmp(giantStep) < 0; k.Add(k, one) {\n\t\t\t\tselect {\n\t\t\t\tcase <-quit:\n\t\t\t\t\treturn\n\t\t\t\tdefault:\n\t\t\t\t\tsh.Write([]byte(x.String()))\n\t\t\t\t\tT[string(sh.Sum(nil)[:10])] = new(big.Int).Set(k)\n\t\t\t\t\tsh.Reset()\n\t\t\t\t\tx = new(bn256.GT).Add(x, g)\n\t\t\t\t}\n\t\t\t}\n\t\t\t// make giant steps and search for the solution\n\t\t\tbound.Exp(giantStep, two, nil)\n\t\t\tfor ; j.Cmp(bound) < 0; j.Add(j, giantStep) {\n\t\t\t\tselect {\n\t\t\t\tcase <-quit:\n\t\t\t\t\treturn\n\t\t\t\tdefault:\n\t\t\t\t\tsh.Write([]byte(y.String()))\n\t\t\t\t\te, ok := T[string(sh.Sum(nil)[:10])]\n\t\t\t\t\tsh.Reset()\n\t\t\t\t\tif ok {\n\t\t\t\t\t\tretChan <- new(big.Int).Add(j, e)\n\t\t\t\t\t\terrChan <- nil\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\ty.Add(y, z)\n\t\t\t\t}\n\t\t\t}\n\t\t\tz.Add(z, z)\n\t\t}\n\t}\n\tretChan <- nil\n\terrChan <- fmt.Errorf(\"failed to find the discrete logarithm within bound\")\n}\n"
  },
  {
    "path": "internal/dlog/calc_test.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage dlog\n\nimport (\n\t\"math/big\"\n\t\"testing\"\n\n\t\"github.com/fentec-project/bn256\"\n\t\"github.com/fentec-project/gofe/internal\"\n\t\"github.com/fentec-project/gofe/internal/keygen\"\n\t\"github.com/fentec-project/gofe/sample\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestCalcZp_BabyStepGiantStep_ElGamal(t *testing.T) {\n\tmodulusLength := 128\n\n\tkey, err := keygen.NewElGamal(modulusLength)\n\tif err != nil {\n\t\tt.Fatalf(\"Error in ElGamal key generation: %v\", err)\n\t}\n\n\tbound := big.NewInt(100000000)\n\n\t// first test when x is positive\n\tsampler := sample.NewUniformRange(big.NewInt(2), bound)\n\txCheck, err := sampler.Sample()\n\tif err != nil {\n\t\tt.Fatalf(\"Error during random int generation: %v\", err)\n\t}\n\n\th := new(big.Int).Exp(key.G, xCheck, key.P)\n\n\tcalc, err := NewCalc().InZp(key.P, nil)\n\tif err != nil {\n\t\tt.Fatal(\"Error in creation of new CalcZp:\", err)\n\t}\n\tcalc = calc.WithBound(bound)\n\tx, err := calc.BabyStepGiantStep(h, key.G)\n\tif err != nil {\n\t\tt.Fatalf(\"Error in baby step - giant step algorithm: %v\", err)\n\t}\n\n\tassert.Equal(t, xCheck, x, \"BabyStepGiantStep result is wrong\")\n\n\t// second test when the answer can also be negative\n\tsampler = sample.NewUniformRange(new(big.Int).Neg(bound), bound)\n\txCheck, err = sampler.Sample()\n\tif err != nil {\n\t\tt.Fatalf(\"Error during random int generation: %v\", err)\n\t}\n\n\th = internal.ModExp(key.G, xCheck, key.P)\n\n\tcalc = calc.WithNeg()\n\n\tx, err = calc.BabyStepGiantStep(h, key.G)\n\tif err != nil {\n\t\tt.Fatalf(\"Error in baby step - giant step algorithm: %v\", err)\n\t}\n\tassert.Equal(t, xCheck.Cmp(x), 0, \"BabyStepGiantStep result is wrong\")\n}\n\nfunc TestCalcBN256_BabyStepGiantStep(t *testing.T) {\n\tbound := big.NewInt(1000000)\n\tsampler := sample.NewUniformRange(new(big.Int).Neg(bound), bound)\n\n\txCheck, err := sampler.Sample()\n\tif err != nil {\n\t\tt.Fatalf(\"error when generating random number: %v\", err)\n\t}\n\n\t//xCheck = big.NewInt(16)\n\tg := new(bn256.GT).ScalarBaseMult(big.NewInt(1))\n\th := new(bn256.GT)\n\tif xCheck.Sign() == 1 {\n\t\th.ScalarMult(g, xCheck)\n\t} else {\n\t\txCheckNeg := new(big.Int).Neg(xCheck)\n\t\th.ScalarMult(g, xCheckNeg)\n\t\th.Neg(h)\n\t}\n\n\tcalc := NewCalc().InBN256().WithBound(bound).WithNeg()\n\terr = calc.Precompute(5)\n\tif err != nil {\n\t\tt.Fatalf(\"error when prcomputing: %v\", err)\n\t}\n\tx, err := calc.BabyStepGiantStep(h, g)\n\tif err != nil {\n\t\tt.Fatalf(\"Error in baby step - giant step algorithm: %v\", err)\n\t}\n\tassert.Equal(t, xCheck.Cmp(x), 0, \"BabyStepGiantStep in BN256 returns wrong dlog\")\n}\n"
  },
  {
    "path": "internal/dlog/dlog_test.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage dlog\n\nimport (\n\t\"math/big\"\n\t\"testing\"\n\n\t\"github.com/fentec-project/gofe/internal/keygen\"\n\t\"github.com/fentec-project/gofe/sample\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\ntype params struct {\n\tp, order, g *big.Int\n}\n\nfunc getParams() (*params, error) {\n\tkey, err := keygen.NewElGamal(20)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &params{\n\t\tp:     key.P,\n\t\torder: key.Q,\n\t\tg:     key.G,\n\t}, nil\n}\n\nfunc TestDLog(t *testing.T) {\n\tparams, err := getParams()\n\tif err != nil {\n\t\tt.Fatalf(\"Error during parameters generation: %v\", err)\n\t}\n\n\tsampler := sample.NewUniformRange(big.NewInt(2), params.order)\n\txCheck, err := sampler.Sample()\n\n\tif err != nil {\n\t\tt.Fatalf(\"Error during random int generation: %v\", err)\n\t}\n\n\th := new(big.Int).Exp(params.g, xCheck, params.p)\n\n\tcalc, _ := NewCalc().InZp(params.p, params.order)\n\tx1, err := calc.WithBound(nil).BabyStepGiantStep(h, params.g)\n\tif err != nil {\n\t\tt.Fatalf(\"Error in BabyStepGiantStep algorithm: %v\", err)\n\t}\n\n\tx2, err := pollardRhoParallel(h, params.g, params.p, params.order)\n\n\tif err != nil {\n\t\tt.Fatalf(\"Error in Pollard rho algorithm: %v\", err)\n\t}\n\n\tassert.Equal(t, xCheck.Cmp(x1), 0, \"BabyStepGiantStep result is wrong\")\n\tassert.Equal(t, xCheck.Cmp(x2), 0, \"pollardRho result is wrong\")\n}\n"
  },
  {
    "path": "internal/dlog/doc.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// Package dlog includes algorithms for computing discrete logarithms.\n//\n// FE schemes instantiated from the Discrete Diffie-Hellman assumption\n// (DDH) all rely on efficient algorithms for calculating discrete\n// logarithms.\npackage dlog\n"
  },
  {
    "path": "internal/dlog/pollard_rho.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage dlog\n\nimport (\n\t\"fmt\"\n\t\"math\"\n\t\"math/big\"\n\n\t\"github.com/fentec-project/gofe/sample\"\n)\n\n// Pollard's rho algorithm - simple, non-parallel version.\nfunc pollardRho(h, g, p, order *big.Int) (*big.Int, error) {\n\tn := new(big.Int).Set(order)\n\n\t// a, b random from [1, n]\n\tsampler := sample.NewUniformRange(big.NewInt(1), new(big.Int).Add(n, big.NewInt(1)))\n\ta1, err := sampler.Sample()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tb1, err := sampler.Sample()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// x = ((g ^ a mod p) * (h ^ b mod p ) mod p\n\tx1 := new(big.Int).Mod(new(big.Int).Mul(new(big.Int).Exp(g, a1, p), new(big.Int).Exp(h, b1, p)), p)\n\n\tx2, a2, b2 := new(big.Int).Set(x1), new(big.Int).Set(a1), new(big.Int).Set(b1)\n\n\tr, q, t := new(big.Int), new(big.Int), new(big.Int)\n\n\titerate := func(x, a, b *big.Int) {\n\t\ts := r.Mod(x, big.NewInt(3)).Int64()\n\t\tswitch s {\n\t\tcase 0:\n\t\t\tx.Exp(x, big.NewInt(2), p)\n\t\t\ta.Mod(r.Mul(a, big.NewInt(2)), n)\n\t\t\tb.Mod(r.Mul(b, big.NewInt(2)), n)\n\t\tcase 1:\n\t\t\tx.Mod(r.Mul(x, g), p)\n\t\t\ta.Mod(r.Add(a, big.NewInt(1)), n)\n\t\tcase 2:\n\t\t\tx.Mod(r.Mul(x, h), p)\n\t\t\tb.Mod(r.Add(b, big.NewInt(1)), n)\n\t\t}\n\t}\n\n\titerations := math.MaxInt32\n\tone := big.NewInt(1)\n\n\tfor i := 0; i < iterations; i++ {\n\t\titerate(x1, a1, b1)\n\t\titerate(x2, a2, b2)\n\t\titerate(x2, a2, b2)\n\t\tif x1.Cmp(x2) == 0 {\n\t\t\tr.Mod(q.Sub(b2, b1), n)\n\t\t\tt.Mod(q.Sub(a1, a2), n)\n\t\t\tif r.Cmp(big.NewInt(0)) == 0 {\n\t\t\t\treturn nil, fmt.Errorf(\"error in Pollard rho: no modular inverse for factor\")\n\t\t\t}\n\t\t\td := new(big.Int).GCD(nil, nil, r, n)\n\n\t\t\t// if r and n are coprime the algorithm is simple\n\t\t\tif d.Cmp(big.NewInt(1)) == 0 {\n\t\t\t\tq.ModInverse(r, n)\n\t\t\t\treturn q.Mod(q.Mul(q, t), n), nil\n\t\t\t}\n\n\t\t\t// in case r and n are not coprime additional computations are needed\n\t\t\tr.Div(r, d)\n\t\t\tt.Div(t, d)\n\t\t\tnDivD := new(big.Int).Div(n, d)\n\t\t\tq.ModInverse(r, nDivD)\n\t\t\tq.Mod(q.Mul(q, t), nDivD)\n\n\t\t\tfor j := big.NewInt(0); j.Cmp(d) == -1; j.Add(j, one) {\n\t\t\t\tif h.Cmp(new(big.Int).Exp(g, q, p)) == 0 {\n\t\t\t\t\treturn q, nil\n\t\t\t\t}\n\t\t\t\tq.Add(q, nDivD)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil, fmt.Errorf(\"failed to find discrete logarithm in %d iterations\", iterations)\n}\n\ntype triple struct {\n\tx *big.Int\n\ta *big.Int\n\tb *big.Int\n}\n\nfunc process(x, a, b *big.Int, iterate func(x, a, b *big.Int), c chan<- triple, quit <-chan struct{}) {\n\tfor {\n\t\tselect {\n\t\tcase <-quit:\n\t\t\treturn\n\t\tdefault:\n\t\t\t// nonblocking\n\t\t}\n\n\t\titerate(x, a, b)\n\t\txab := triple{\n\t\t\tx: new(big.Int).Set(x),\n\t\t\ta: new(big.Int).Set(a),\n\t\t\tb: new(big.Int).Set(b),\n\t\t}\n\t\tc <- xab\n\t}\n}\n\n// Parallelized Pollard's rho algorithm.\nfunc pollardRhoParallel(h, g, p, order *big.Int) (*big.Int, error) {\n\tn := new(big.Int).Set(order)\n\n\titerate := func(x, a, b *big.Int) {\n\t\tr := new(big.Int)\n\t\ts := r.Mod(x, big.NewInt(3)).Int64()\n\t\tswitch s {\n\t\tcase 0:\n\t\t\tx.Exp(x, big.NewInt(2), p)\n\t\t\ta.Mod(r.Mul(a, big.NewInt(2)), n)\n\t\t\tb.Mod(r.Mul(b, big.NewInt(2)), n)\n\t\tcase 1:\n\t\t\tx.Mod(r.Mul(x, g), p)\n\t\t\ta.Mod(r.Add(a, big.NewInt(1)), n)\n\t\tcase 2:\n\t\t\tx.Mod(r.Mul(x, h), p)\n\t\t\tb.Mod(r.Add(b, big.NewInt(1)), n)\n\t\t}\n\t}\n\n\tc := make(chan triple, 8)\n\tquit := make(chan struct{})\n\ttriples := make(map[string]triple)\n\n\tr, q, t := new(big.Int), new(big.Int), new(big.Int)\n\n\tsampler := sample.NewUniformRange(big.NewInt(1), new(big.Int).Add(n, big.NewInt(1)))\n\tfor i := 0; i < 8; i++ {\n\t\ta0, err := sampler.Sample()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tb0, err := sampler.Sample()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tx0 := new(big.Int).Mod(new(big.Int).Mul(new(big.Int).Exp(g, a0, p), new(big.Int).Exp(h, b0, p)), p)\n\n\t\tgo process(x0, a0, b0, iterate, c, quit)\n\t}\n\n\tfor {\n\t\ttriple := <-c\n\t\tstr := string(triple.x.Bytes())\n\n\t\tif el, ok := triples[str]; ok {\n\t\t\ta1 := triple.a\n\t\t\ta2 := el.a\n\t\t\tb1 := triple.b\n\t\t\tb2 := el.b\n\n\t\t\tr.Mod(q.Sub(b2, b1), n)\n\t\t\tt.Mod(q.Sub(a1, a2), n)\n\t\t\t// presume that at least one goroutine will compute the right value, do not terminate with error here\n\t\t\tif r.Cmp(big.NewInt(0)) == 0 {\n\t\t\t\ttriples[str] = triple\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tclose(quit)\n\n\t\t\td := new(big.Int).GCD(nil, nil, r, n)\n\t\t\t// if r and n are coprime the algorithm is simple\n\t\t\tif d.Cmp(big.NewInt(1)) == 0 {\n\t\t\t\tq.ModInverse(r, n)\n\t\t\t\treturn q.Mod(q.Mul(q, t), n), nil\n\t\t\t}\n\n\t\t\t// in case r and n are not coprime additional computations are needed\n\t\t\tr.Div(r, d)\n\t\t\tt.Div(t, d)\n\t\t\tnDivD := new(big.Int).Div(n, d)\n\t\t\tq.ModInverse(r, nDivD)\n\t\t\tq.Mod(q.Mul(q, t), nDivD)\n\t\t\tone := big.NewInt(1)\n\t\t\tfor j := big.NewInt(0); j.Cmp(d) == -1; j.Add(j, one) {\n\t\t\t\tif h.Cmp(new(big.Int).Exp(g, q, p)) == 0 {\n\t\t\t\t\treturn q, nil\n\t\t\t\t}\n\t\t\t\tq.Add(q, nDivD)\n\t\t\t}\n\n\t\t} else {\n\t\t\ttriples[str] = triple\n\t\t}\n\t}\n\n}\n\nconst cycleSizeBound = 1024 * 1024\n\n// first 1000 primes\nvar smallPrimes = []int{2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291, 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511, 1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, 1597, 1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, 1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, 1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889, 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987, 1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053, 2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111, 2113, 2129, 2131, 2137, 2141, 2143, 2153, 2161, 2179, 2203, 2207, 2213, 2221, 2237, 2239, 2243, 2251, 2267, 2269, 2273, 2281, 2287, 2293, 2297, 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357, 2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411, 2417, 2423, 2437, 2441, 2447, 2459, 2467, 2473, 2477, 2503, 2521, 2531, 2539, 2543, 2549, 2551, 2557, 2579, 2591, 2593, 2609, 2617, 2621, 2633, 2647, 2657, 2659, 2663, 2671, 2677, 2683, 2687, 2689, 2693, 2699, 2707, 2711, 2713, 2719, 2729, 2731, 2741, 2749, 2753, 2767, 2777, 2789, 2791, 2797, 2801, 2803, 2819, 2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887, 2897, 2903, 2909, 2917, 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999, 3001, 3011, 3019, 3023, 3037, 3041, 3049, 3061, 3067, 3079, 3083, 3089, 3109, 3119, 3121, 3137, 3163, 3167, 3169, 3181, 3187, 3191, 3203, 3209, 3217, 3221, 3229, 3251, 3253, 3257, 3259, 3271, 3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331, 3343, 3347, 3359, 3361, 3371, 3373, 3389, 3391, 3407, 3413, 3433, 3449, 3457, 3461, 3463, 3467, 3469, 3491, 3499, 3511, 3517, 3527, 3529, 3533, 3539, 3541, 3547, 3557, 3559, 3571, 3581, 3583, 3593, 3607, 3613, 3617, 3623, 3631, 3637, 3643, 3659, 3671, 3673, 3677, 3691, 3697, 3701, 3709, 3719, 3727, 3733, 3739, 3761, 3767, 3769, 3779, 3793, 3797, 3803, 3821, 3823, 3833, 3847, 3851, 3853, 3863, 3877, 3881, 3889, 3907, 3911, 3917, 3919, 3923, 3929, 3931, 3943, 3947, 3967, 3989, 4001, 4003, 4007, 4013, 4019, 4021, 4027, 4049, 4051, 4057, 4073, 4079, 4091, 4093, 4099, 4111, 4127, 4129, 4133, 4139, 4153, 4157, 4159, 4177, 4201, 4211, 4217, 4219, 4229, 4231, 4241, 4243, 4253, 4259, 4261, 4271, 4273, 4283, 4289, 4297, 4327, 4337, 4339, 4349, 4357, 4363, 4373, 4391, 4397, 4409, 4421, 4423, 4441, 4447, 4451, 4457, 4463, 4481, 4483, 4493, 4507, 4513, 4517, 4519, 4523, 4547, 4549, 4561, 4567, 4583, 4591, 4597, 4603, 4621, 4637, 4639, 4643, 4649, 4651, 4657, 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729, 4733, 4751, 4759, 4783, 4787, 4789, 4793, 4799, 4801, 4813, 4817, 4831, 4861, 4871, 4877, 4889, 4903, 4909, 4919, 4931, 4933, 4937, 4943, 4951, 4957, 4967, 4969, 4973, 4987, 4993, 4999, 5003, 5009, 5011, 5021, 5023, 5039, 5051, 5059, 5077, 5081, 5087, 5099, 5101, 5107, 5113, 5119, 5147, 5153, 5167, 5171, 5179, 5189, 5197, 5209, 5227, 5231, 5233, 5237, 5261, 5273, 5279, 5281, 5297, 5303, 5309, 5323, 5333, 5347, 5351, 5381, 5387, 5393, 5399, 5407, 5413, 5417, 5419, 5431, 5437, 5441, 5443, 5449, 5471, 5477, 5479, 5483, 5501, 5503, 5507, 5519, 5521, 5527, 5531, 5557, 5563, 5569, 5573, 5581, 5591, 5623, 5639, 5641, 5647, 5651, 5653, 5657, 5659, 5669, 5683, 5689, 5693, 5701, 5711, 5717, 5737, 5741, 5743, 5749, 5779, 5783, 5791, 5801, 5807, 5813, 5821, 5827, 5839, 5843, 5849, 5851, 5857, 5861, 5867, 5869, 5879, 5881, 5897, 5903, 5923, 5927, 5939, 5953, 5981, 5987, 6007, 6011, 6029, 6037, 6043, 6047, 6053, 6067, 6073, 6079, 6089, 6091, 6101, 6113, 6121, 6131, 6133, 6143, 6151, 6163, 6173, 6197, 6199, 6203, 6211, 6217, 6221, 6229, 6247, 6257, 6263, 6269, 6271, 6277, 6287, 6299, 6301, 6311, 6317, 6323, 6329, 6337, 6343, 6353, 6359, 6361, 6367, 6373, 6379, 6389, 6397, 6421, 6427, 6449, 6451, 6469, 6473, 6481, 6491, 6521, 6529, 6547, 6551, 6553, 6563, 6569, 6571, 6577, 6581, 6599, 6607, 6619, 6637, 6653, 6659, 6661, 6673, 6679, 6689, 6691, 6701, 6703, 6709, 6719, 6733, 6737, 6761, 6763, 6779, 6781, 6791, 6793, 6803, 6823, 6827, 6829, 6833, 6841, 6857, 6863, 6869, 6871, 6883, 6899, 6907, 6911, 6917, 6947, 6949, 6959, 6961, 6967, 6971, 6977, 6983, 6991, 6997, 7001, 7013, 7019, 7027, 7039, 7043, 7057, 7069, 7079, 7103, 7109, 7121, 7127, 7129, 7151, 7159, 7177, 7187, 7193, 7207, 7211, 7213, 7219, 7229, 7237, 7243, 7247, 7253, 7283, 7297, 7307, 7309, 7321, 7331, 7333, 7349, 7351, 7369, 7393, 7411, 7417, 7433, 7451, 7457, 7459, 7477, 7481, 7487, 7489, 7499, 7507, 7517, 7523, 7529, 7537, 7541, 7547, 7549, 7559, 7561, 7573, 7577, 7583, 7589, 7591, 7603, 7607, 7621, 7639, 7643, 7649, 7669, 7673, 7681, 7687, 7691, 7699, 7703, 7717, 7723, 7727, 7741, 7753, 7757, 7759, 7789, 7793, 7817, 7823, 7829, 7841, 7853, 7867, 7873, 7877, 7879, 7883, 7901, 7907, 7919}\n\n// Returns the prime factorization of n.\n// The factorization is bounded by smoothness bound b (i.e. no factors can be bigger than b)\nfunc pollardRhoFactorization(n, b *big.Int) (map[string]int, error) {\n\tfactors := make(map[string]int)\n\n\t// use the queue to process numbers until they are factorized to primes\n\tqueue := make([]*big.Int, 0)\n\tqueue = append(queue, n)\n\tvar i *big.Int\n\n\tfor len(queue) > 0 {\n\t\ti, queue = queue[0], queue[1:]\n\n\t\t// discard trivial factors\n\t\tif i.Cmp(big.NewInt(1)) == 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\t// if the number is a prime, we save it\n\t\tif i.ProbablyPrime(20) {\n\t\t\t// we got a factor bigger than the smoothness bound - fail\n\t\t\tif b != nil && i.Cmp(b) > 0 {\n\t\t\t\treturn nil, fmt.Errorf(\"bounded factorization failed: factor %d is bigger than bound %d\", i, b)\n\t\t\t}\n\n\t\t\tstringified := string(i.Bytes())\n\t\t\tif _, ok := factors[stringified]; ok {\n\t\t\t\tfactors[stringified]++\n\t\t\t} else {\n\t\t\t\tfactors[stringified] = 1\n\t\t\t}\n\n\t\t\tcontinue\n\t\t}\n\n\t\t// calculate a new divisor\n\t\tfactor, err := pollardRhoCycle(i)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\t// continue factoring the divisor and number/divisor\n\t\tqueue = append(queue, factor)\n\t\tqueue = append(queue, new(big.Int).Div(i, factor))\n\n\t}\n\n\tif len(factors) == 0 {\n\t\treturn nil, fmt.Errorf(\"failed to find the prime factors\")\n\t}\n\n\treturn factors, nil\n\n}\n\n// Returns a divisor of n. It runs the cycle of Pollard Rho until it encounters a non-trivial divisor.\nfunc pollardRhoCycle(n *big.Int) (*big.Int, error) {\n\tfactor := big.NewInt(1)\n\n\tsampler := sample.NewUniform(n)\n\t// run until the returned value is > 1\n\tfor factor.Cmp(big.NewInt(1)) < 1 {\n\t\t// random starting values\n\t\tr, err := sampler.Sample()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tfactor = runCycle(n, r)\n\t}\n\n\treturn factor, nil\n}\n\n// Runs one cycle of the Pollard Rho algorithm. It may fail to find a divisor and may need to be restarted with\n// different starting values.\nfunc runCycle(n, x *big.Int) *big.Int {\n\txFixed := new(big.Int).Set(x)\n\tcycleSize := 2\n\tone := big.NewInt(1)\n\tfactor := big.NewInt(1)\n\n\tfor cycleSize < cycleSizeBound && factor.Cmp(one) == 0 {\n\t\tcount := 0\n\n\t\tfor count < cycleSize && factor.Cmp(one) < 1 {\n\t\t\t// g(x) = (x^2 + 1) mod n\n\t\t\tx.Mod(new(big.Int).Add(new(big.Int).Mul(x, x), one), n)\n\t\t\tabsDiff := new(big.Int).Abs(new(big.Int).Sub(x, xFixed))\n\t\t\tfactor.GCD(nil, nil, absDiff, n)\n\t\t\tcount++\n\t\t}\n\n\t\tcycleSize *= 2\n\t\txFixed.Set(x)\n\t}\n\n\treturn factor\n}\n"
  },
  {
    "path": "internal/dlog/pollard_rho_test.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage dlog\n\nimport (\n\t\"math/big\"\n\t\"math/rand\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/fentec-project/gofe/internal/keygen\"\n\t\"github.com/fentec-project/gofe/sample\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestPollardRho(t *testing.T) {\n\tparams, err := getParams()\n\tif err != nil {\n\t\tt.Fatalf(\"Error during parameters generation: %v\", err)\n\t}\n\n\tsampler := sample.NewUniformRange(big.NewInt(2), params.order)\n\txCheck, err := sampler.Sample()\n\n\tif err != nil {\n\t\tt.Fatalf(\"Error during random int generation: %v\", err)\n\t}\n\n\th := new(big.Int).Exp(params.g, xCheck, params.p)\n\n\tx, err := pollardRho(h, params.g, params.p, params.order)\n\n\tif err != nil {\n\t\tt.Fatalf(\"Error in Pollard rho algorithm: %v\", err)\n\t}\n\n\tassert.Equal(t, xCheck.Cmp(x), 0, \"pollardRho result is wrong\")\n}\n\nfunc TestPollardRhoParallel(t *testing.T) {\n\tparams, err := getParams()\n\tif err != nil {\n\t\tt.Fatalf(\"Error during parameters generation: %v\", err)\n\t}\n\n\tsampler := sample.NewUniformRange(big.NewInt(2), params.order)\n\txCheck, err := sampler.Sample()\n\n\tif err != nil {\n\t\tt.Fatalf(\"Error during random int generation: %v\", err)\n\t}\n\n\th := new(big.Int).Exp(params.g, xCheck, params.p)\n\tx, err := pollardRhoParallel(h, params.g, params.p, params.order)\n\n\tif err != nil {\n\t\tt.Fatalf(\"Error in Pollard rho algorithm: %v\", err)\n\t}\n\n\tassert.Equal(t, xCheck.Cmp(x), 0, \"pollardRho result is wrong\")\n}\n\nfunc TestPollardRhoFactorization(t *testing.T) {\n\tsampler := sample.NewUniform(new(big.Int).Exp(big.NewInt(2), big.NewInt(32), nil))\n\tn, err := sampler.Sample()\n\tif err != nil {\n\t\tt.Fatalf(\"Error during random int generation: %v\", err)\n\t}\n\n\tfactorization, err := pollardRhoFactorization(n, nil)\n\n\tif err != nil {\n\t\tt.Fatalf(\"error in pollard rho factorization: %v\", err)\n\t}\n\n\tcheckFactorization(factorization, n, t)\n}\n\n// Pollard rho with ElGamal group\nfunc TestPollardRhoElGamal(t *testing.T) {\n\tmodulusLength := 32\n\n\tkey, err := keygen.NewElGamal(modulusLength)\n\tif err != nil {\n\t\tt.Fatalf(\"Error in group generation: %v\", err)\n\t}\n\n\torder := key.Q\n\tsampler := sample.NewUniform(new(big.Int).Exp(big.NewInt(2), big.NewInt(30), nil))\n\txCheck, err := sampler.Sample()\n\n\tif err != nil {\n\t\tt.Fatalf(\"Error during random int generation: %v\", err)\n\t}\n\n\th := new(big.Int).Exp(key.G, xCheck, key.P)\n\tx, err := pollardRho(h, key.G, key.P, order)\n\n\tif err != nil {\n\t\tt.Fatalf(\"Error in Pollard rho algorithm: %v\", err)\n\t}\n\n\tassert.Equal(t, xCheck.Cmp(x), 0, \"pollardRho result is wrong\")\n}\n\nfunc checkFactorization(factorization map[string]int, n *big.Int, t *testing.T) {\n\tnCheck := big.NewInt(1)\n\n\tfor prime, power := range factorization {\n\t\tprime := new(big.Int).SetBytes([]byte(prime))\n\n\t\tif !prime.ProbablyPrime(10) {\n\t\t\tt.Errorf(\"%d is not prime, but should be\", prime)\n\t\t}\n\n\t\tnCheck.Mul(nCheck, new(big.Int).Exp(prime, big.NewInt(int64(power)), big.NewInt(0)))\n\t}\n\n\tassert.Equal(t, nCheck.Cmp(n), 0, \"Product of factor powers should match original number\")\n}\n\n// Hard factorization problem - the number is a product of two large primes\nfunc TestPollardRhoFactorizationHard(t *testing.T) {\n\tp := keygen.GetGermainPrime(35)\n\tq := keygen.GetGermainPrime(35)\n\n\tn := new(big.Int).Mul(p, q)\n\n\tfactorization, err := pollardRhoFactorization(n, nil)\n\n\tif err != nil {\n\t\tt.Fatalf(\"error in pollard rho factorization: %v\", err)\n\t}\n\n\tcheckFactorization(factorization, n, t)\n}\n\n// Run Pollard rho factorization on a smooth number.\nfunc TestPollardRhoFactorizationBounded(t *testing.T) {\n\tB := smallPrimes[len(smallPrimes)-1]\n\tn := getSmoothNumber(B, 30, 10)\n\tfactorization, err := pollardRhoFactorization(n, big.NewInt(int64(B)))\n\n\tif err != nil {\n\t\tt.Fatalf(\"error in bounded pollard rho factorization: %v\", err)\n\t}\n\n\tcheckFactorization(factorization, n, t)\n}\n\nfunc getSmoothNumber(B, numPrimes, maxPower int) *big.Int {\n\t// find the index of the maximal allowed factor\n\tindexBound := len(smallPrimes)\n\tfor i, p := range smallPrimes {\n\t\tif p > B {\n\t\t\tindexBound = i\n\t\t\tbreak\n\t\t}\n\t}\n\n\trand.Seed(time.Now().UTC().UnixNano())\n\tprod := big.NewInt(1)\n\n\t// pick a random prime < B and a random power < 10, numPrimes times\n\t// multiply the cumulative product by prime ^ power\n\tfor i := 0; i < numPrimes; i++ {\n\t\tprime := smallPrimes[rand.Intn(indexBound)]\n\t\tpower := rand.Intn(maxPower + 1)\n\t\tprod.Mul(prod, new(big.Int).Exp(big.NewInt(int64(prime)), big.NewInt(int64(power)), big.NewInt(0)))\n\t}\n\n\treturn prod\n}\n"
  },
  {
    "path": "internal/errors.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage internal\n\nimport (\n\t\"fmt\"\n)\n\nvar malformedStr = \"is not of the proper form\"\n\n// ErrMalformedPubKey is an error for public key.\nvar ErrMalformedPubKey = fmt.Errorf(\"public key %s\", malformedStr)\n\n// ErrMalformedSecKey is an error for secret key.\nvar ErrMalformedSecKey = fmt.Errorf(\"secret key %s\", malformedStr)\n\n// ErrMalformedDecKey is an error for derived key.\nvar ErrMalformedDecKey = fmt.Errorf(\"decryption key %s\", malformedStr)\n\n// ErrMalformedCipher is an error for ciphertext.\nvar ErrMalformedCipher = fmt.Errorf(\"ciphertext %s\", malformedStr)\n\n// ErrMalformedInput is an error for input data.\nvar ErrMalformedInput = fmt.Errorf(\"input data %s\", malformedStr)\n"
  },
  {
    "path": "internal/keygen/elgamal.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage keygen\n\nimport (\n\t\"fmt\"\n\t\"math/big\"\n\n\t\"github.com/fentec-project/gofe/sample\"\n)\n\n// ElGamal holds paramenters for ElGamal scheme.\ntype ElGamal struct {\n\tY *big.Int // public key\n\tG *big.Int // generator\n\tP *big.Int // modulus\n\tQ *big.Int // (P - 1) / 2, i.e. order of G\n}\n\n// NewElGamal creates parameters for ElGamal scheme. Implementation is\n// adapted from https://github.com/dlitz/pycrypto/blob/master/lib/Crypto/PublicKey/ElGamal.py.\nfunc NewElGamal(modulusLength int) (*ElGamal, error) {\n\tp, err := GetSafePrime(modulusLength)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to generate safe prime\")\n\t}\n\n\tzero := big.NewInt(0)\n\tone := big.NewInt(1)\n\ttwo := big.NewInt(2)\n\tthree := big.NewInt(3)\n\n\t// q = (p - 1) / 2\n\tq := new(big.Int).Sub(p, one)\n\tq.Div(q, two)\n\tvar g *big.Int\n\tsampler := sample.NewUniformRange(three, p)\n\n\tfor {\n\t\tg, err = sampler.Sample()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\t// make g an element of the subgroup of quadratic residues\n\t\tg.Exp(g, two, p)\n\n\t\t// additional checks to avoid some known attacks\n\t\tif new(big.Int).Mod(new(big.Int).Sub(p, one), g).Cmp(zero) == 0 {\n\t\t\tcontinue\n\t\t}\n\t\tgInv := new(big.Int).ModInverse(g, p)\n\t\tif new(big.Int).Mod(new(big.Int).Sub(p, one), gInv).Cmp(zero) == 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\tbreak\n\t}\n\n\tx, err := sampler.Sample()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\ty := new(big.Int).Exp(g, x, p)\n\n\treturn &ElGamal{\n\t\tY: y,\n\t\tG: g,\n\t\tP: p,\n\t\tQ: q,\n\t}, nil\n}\n"
  },
  {
    "path": "internal/keygen/prime.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage keygen\n\nimport (\n\t\"crypto/rand\"\n\t\"fmt\"\n\t\"io\"\n\t\"math/big\"\n)\n\n// GetSafePrime returns a safe prime p (p = 2*p1 + 2 where p1 is prime too).\nfunc GetSafePrime(bits int) (p *big.Int, err error) {\n\tp1 := GetGermainPrime(bits - 1)\n\tp = big.NewInt(0)\n\tp.Mul(p1, big.NewInt(2))\n\tp.Add(p, big.NewInt(1))\n\n\tif p.BitLen() != bits {\n\t\terr := fmt.Errorf(\"bit length not correct\")\n\t\treturn nil, err\n\t}\n\n\treturn p, nil\n}\n\n// GetGermainPrime returns a prime number p for which 2*p + 1 is also prime. Note that\n// conversely 2*p + 1 is called a safe prime.\nfunc GetGermainPrime(bits int) (p *big.Int) {\n\t// multiple germainPrime goroutines are called and we assume at least one will compute a\n\t// safe prime and send it to the channel, thus we do not handle errors in germainPrime\n\tc := make(chan *big.Int)\n\tquit := make(chan int)\n\tfor j := int(0); j < 8; j++ {\n\t\tgo germainPrime(bits, c, quit)\n\t}\n\tmsg := <-c\n\t// for small values for parameter bits (which should be small only for testing) it sometimes\n\t// happen \"send on closed channel\" - so we leave the channel c to a garbage collector\n\t// close(c)\n\tclose(quit)\n\treturn msg\n}\n\nvar smallPrimes = []uint8{\n\t3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53,\n}\n\n// smallPrimesProduct is the product of the values in smallPrimes and allows us\n// to reduce a candidate prime by this number and then determine whether it's\n// coprime to all the elements of smallPrimes without further big.Int\n// operations.\nvar smallPrimesProduct = new(big.Int).SetUint64(16294579238595022365)\n\n// germainPrime is slightly modified Prime function from:\n// https://github.com/golang/go/blob/master/src/crypto/rand/util.go\n// germainPrime returns a number, p, of the given size, such that p and 2*p+1 are primes\n// with high probability.\n// germainPrime will return error for any error returned by rand.Read or if bits < 2.\nfunc germainPrime(bits int, c chan *big.Int, quit chan int) (p *big.Int, err error) {\n\trandom := rand.Reader\n\n\tif bits < 2 {\n\t\terr = fmt.Errorf(\"crypto/rand: prime size must be at least 2-bit\")\n\t\treturn\n\t}\n\n\tb := uint(bits % 8)\n\tif b == 0 {\n\t\tb = 8\n\t}\n\n\tbytes := make([]byte, (bits+7)/8)\n\tp = new(big.Int)\n\tp1 := new(big.Int)\n\n\tbigMod := new(big.Int)\n\n\tfor {\n\t\tselect {\n\t\tcase <-quit:\n\t\t\treturn\n\t\tdefault:\n\t\t\t// this is to make it non-blocking\n\t\t}\n\n\t\t_, err = io.ReadFull(random, bytes)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\t// Clear bits in the first byte to make sure the candidate has a size <= bits.\n\t\tbytes[0] &= uint8(int(1<<b) - 1)\n\t\t// Don't let the value be too small, i.e, set the most significant two bits.\n\t\t// Setting the top two bits, rather than just the top bit,\n\t\t// means that when two of these values are multiplied together,\n\t\t// the result isn't ever one bit short.\n\t\tif b >= 2 {\n\t\t\tbytes[0] |= 3 << (b - 2)\n\t\t} else {\n\t\t\t// Here b==1, because b cannot be zero.\n\t\t\tbytes[0] |= 1\n\t\t\tif len(bytes) > 1 {\n\t\t\t\tbytes[1] |= 0x80\n\t\t\t}\n\t\t}\n\t\t// Make the value odd since an even number this large certainly isn't prime.\n\t\tbytes[len(bytes)-1] |= 1\n\n\t\tp.SetBytes(bytes)\n\n\t\t// Calculate the value mod the product of smallPrimes. If it's\n\t\t// a multiple of any of these primes we add two until it isn't.\n\t\t// The probability of overflowing is minimal and can be ignored\n\t\t// because we still perform Miller-Rabin tests on the result.\n\t\tbigMod.Mod(p, smallPrimesProduct)\n\t\tmod := bigMod.Uint64()\n\n\tNextDelta:\n\t\tfor delta := uint64(0); delta < 1<<20; delta += 2 {\n\t\t\tm := mod + delta\n\t\t\tfor _, prime := range smallPrimes {\n\t\t\t\tif m%uint64(prime) == 0 && (bits > 6 || m != uint64(prime)) {\n\t\t\t\t\tcontinue NextDelta\n\t\t\t\t}\n\n\t\t\t\t// 2*mod + 2*delta + 1\tshould not be divisible by smallPrimes as well\n\t\t\t\tm1 := (2*m + 1) % smallPrimesProduct.Uint64()\n\n\t\t\t\tif m1%uint64(prime) == 0 && (bits > 6 || m1 != uint64(prime)) {\n\t\t\t\t\tcontinue NextDelta\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif delta > 0 {\n\t\t\t\tbigMod.SetUint64(delta)\n\t\t\t\tp.Add(p, bigMod)\n\t\t\t}\n\n\t\t\tp1.Add(p, p)\n\t\t\tp1.Add(p1, big.NewInt(1))\n\t\t\tbreak\n\t\t}\n\n\t\t// There is a tiny possibility that, by adding delta, we caused\n\t\t// the number to be one bit too long. Thus we check BitLen\n\t\t// here.\n\t\tif p.ProbablyPrime(20) && p.BitLen() == bits {\n\t\t\tif p1.ProbablyPrime(20) {\n\t\t\t\t// waiting for a message about channel being closed is repeated here,\n\t\t\t\t// because it might happen that channel is closed after waiting at the\n\t\t\t\t// beginning of for loop above (but we want to have it there also,\n\t\t\t\t// otherwise it this goroutine might be searching for a germain\n\t\t\t\t// prime for some time after one was found by another goroutine\n\t\t\t\tselect {\n\t\t\t\tcase <-quit:\n\t\t\t\t\treturn\n\t\t\t\tdefault:\n\t\t\t\t\t// this is to make it non-blocking\n\t\t\t\t}\n\n\t\t\t\tc <- p\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "internal/mod_exp.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage internal\n\nimport \"math/big\"\n\n// ModExp calculates g^x in Z_m*, even if x < 0.\nfunc ModExp(g, x, m *big.Int) *big.Int {\n\tret := new(big.Int)\n\tif x.Sign() == -1 {\n\t\txNeg := new(big.Int).Neg(x)\n\t\tret.Exp(g, xNeg, m)\n\t\tret.ModInverse(ret, m)\n\t} else {\n\t\tret.Exp(g, x, m)\n\t}\n\n\treturn ret\n}\n"
  },
  {
    "path": "quadratic/doc.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// Package quadratic includes functional encryption schemes for quadratic\n// multi-variate polynomials.\npackage quadratic\n"
  },
  {
    "path": "quadratic/quad.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage quadratic\n\nimport (\n\t\"fmt\"\n\t\"math/big\"\n\n\t\"github.com/fentec-project/bn256\"\n\t\"github.com/fentec-project/gofe/data\"\n\t\"github.com/fentec-project/gofe/innerprod/fullysec\"\n\t\"github.com/fentec-project/gofe/internal/dlog\"\n\t\"github.com/fentec-project/gofe/sample\"\n)\n\n// QuadParams includes public parameters for the partially\n// function hiding inner product scheme.\n// PartFHIPE: underlying partially function hiding scheme.\n// N (int): The length of x vectors to be encrypted.\n// M (int): The length of y vectors to be encrypted.\n// Bound (*big.Int): The value by which coordinates of vectors x, y and F are bounded.\ntype QuadParams struct {\n\tPartFHIPE *fullysec.PartFHIPE\n\t// N should be greater or equal to M\n\tN int // length of vectors x\n\tM int // length of vectors y\n\t// The value by which elements of vectors x, y, and the\n\t// matrix F are bounded.\n\tBound *big.Int\n}\n\n// Quad represents a public key FE scheme for quadratic multi-variate polynomials.\n// More precisely, it allows to encrypt vectors x and y using public key,\n// derive a functional encryption key corresponding to a matrix F, and\n// decrypt value x^T * F * y from encryption of x, y and functional key, without\n// reveling any other information about x or y. The scheme is based on\n// a paper by Romain Gay: \"A New Paradigm for Public-Key Functional\n// Encryption for Degree-2 Polynomials\".\n// The scheme uses an underling partially function hiding inner product\n// FE scheme.\ntype Quad struct {\n\tParams *QuadParams\n}\n\n// NewQuad configures a new instance of the quadratic public key scheme.\n// It accepts the length of input vectors n and m and the upper bound b\n// for coordinates of input vectors x, y, and the function\n// matrix F. Parameter n should be greater or equal to m.\nfunc NewQuad(n, m int, b *big.Int) (*Quad, error) {\n\tif n < m {\n\t\treturn nil, fmt.Errorf(\"n should be greater or equal to m\")\n\t}\n\tbound := new(big.Int).Set(b)\n\tbound.Exp(bound, big.NewInt(3), nil)\n\tbound.Mul(big.NewInt(int64(2*n*m)), bound)\n\tif bound.Cmp(bn256.Order) > 0 {\n\t\treturn nil, fmt.Errorf(\"bound and n, m too big for the group\")\n\t}\n\n\tpartFHIPE, err := fullysec.NewPartFHIPE(2*m+n*3, nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &Quad{\n\t\tParams: &QuadParams{\n\t\t\tPartFHIPE: partFHIPE,\n\t\t\tN:         n,\n\t\t\tM:         m,\n\t\t\tBound:     new(big.Int).Set(b),\n\t\t},\n\t}, nil\n}\n\n// NewQuadFromParams takes configuration parameters of an existing\n// Quad instance, and reconstructs the scheme with the same configuration\n// parameters. It returns a new Quad instance.\nfunc NewQuadFromParams(params *QuadParams) *Quad {\n\treturn &Quad{\n\t\tParams: params,\n\t}\n}\n\n// QuadPubKey represents a public key for the scheme.\n// An instance of this type is returned by the\n// GenerateKeys method.\ntype QuadPubKey struct {\n\tUa     data.VectorG1\n\tVB     data.MatrixG2\n\tPubIPE *fullysec.PartFHIPEPubKey\n}\n\n// QuadSecKey represents a master secret key for the scheme.\n// An instance of this type is returned by the\n// GenerateKeys method.\ntype QuadSecKey struct {\n\tU      data.Matrix\n\tV      data.Matrix\n\tSecIPE *fullysec.PartFHIPESecKey\n}\n\n// GenerateKeys generates a public key and master secret\n// key for the scheme. It returns an error if the keys could\n// not be generated.\nfunc (q *Quad) GenerateKeys() (*QuadPubKey, *QuadSecKey, error) {\n\tsampler := sample.NewUniform(bn256.Order)\n\tvar err error\n\n\t// create a vector a over DDH distribution\n\ta := make(data.Vector, 2)\n\ta[0] = big.NewInt(1)\n\ta[1], err = sampler.Sample()\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\t// create a vector a over DLIN distribution\n\tB := make(data.Matrix, 3)\n\tB[0] = make(data.Vector, 2)\n\tB[0][1] = big.NewInt(0)\n\tB[0][0], err = sampler.Sample()\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\tB[1] = make(data.Vector, 2)\n\tB[1][0] = big.NewInt(0)\n\tB[1][1], err = sampler.Sample()\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\tB[2] = data.NewConstantVector(2, big.NewInt(1))\n\n\t// sample matrices U, V and calculate Ua, VB\n\tU, err := data.NewRandomMatrix(q.Params.N, 2, sampler)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\tV, err := data.NewRandomMatrix(q.Params.M, 3, sampler)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tUaVec, err := U.MulVec(a)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\tUaVec = UaVec.Mod(bn256.Order)\n\tUa := UaVec.MulG1()\n\n\tVBMat, err := V.Mul(B)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\tVBMat = VBMat.Mod(bn256.Order)\n\tVB := VBMat.MulG2()\n\n\t// assemble matrix M\n\t// upper part\n\tIdnVB, err := data.Identity(q.Params.M, q.Params.M).JoinCols(VBMat)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\taMat := data.Matrix{a}.Transpose()\n\taTensorIdnVB := aMat.Tensor(IdnVB)\n\taTensorIdnVB = aTensorIdnVB.Mod(bn256.Order)\n\tM0, err := aTensorIdnVB.JoinCols(data.NewConstantMatrix(2*q.Params.M, q.Params.N*2, big.NewInt(0)))\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\t// lower part\n\tIdnB := data.Identity(q.Params.N, q.Params.N).Tensor(B)\n\tM1, err := data.NewConstantMatrix(q.Params.N*3, IdnVB.Cols(), big.NewInt(0)).JoinCols(IdnB)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\t// together\n\tM, err := M0.JoinRows(M1)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tpkIPE, skIPE, err := q.Params.PartFHIPE.GenerateKeys(M)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tpk := &QuadPubKey{Ua: Ua, VB: VB, PubIPE: pkIPE}\n\tsk := &QuadSecKey{U: U, V: V, SecIPE: skIPE}\n\n\treturn pk, sk, nil\n}\n\n// QuadCipher represents ciphertext in the scheme.\ntype QuadCipher struct {\n\tCx   data.VectorG1\n\tCy   data.VectorG2\n\tCIPE data.VectorG1\n}\n\n// Encrypt encrypts input vectors x and y with the given\n// public key. It returns the appropriate ciphertext.\n// If the ciphertext could not be generated, it returns an error.\nfunc (q *Quad) Encrypt(x, y data.Vector, pubKey *QuadPubKey) (*QuadCipher, error) {\n\tif len(x) != q.Params.N || len(y) != q.Params.M {\n\t\treturn nil, fmt.Errorf(\"dimensions of vectors are incorrect\")\n\t}\n\tif err := x.CheckBound(q.Params.Bound); err != nil {\n\t\treturn nil, err\n\t}\n\tif err := y.CheckBound(q.Params.Bound); err != nil {\n\t\treturn nil, err\n\t}\n\n\tsampler := sample.NewUniform(bn256.Order)\n\tr, err := sampler.Sample()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\ts, err := data.NewRandomVector(2, sampler)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tUar := pubKey.Ua.MulScalar(r)\n\txG1 := x.MulG1()\n\tCx := xG1.Add(Uar)\n\n\tVBs := pubKey.VB.MulVector(s)\n\tyG2 := y.MulG2()\n\tCy := yG2.Add(VBs)\n\n\tys := append(y, s...)\n\trys := ys.MulScalar(r)\n\txs := x.Tensor(s)\n\txIPE := append(rys, xs...)\n\txIPE = xIPE.Mod(bn256.Order)\n\tcIPE, err := q.Params.PartFHIPE.Encrypt(xIPE, pubKey.PubIPE)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &QuadCipher{Cx: Cx, Cy: Cy, CIPE: cIPE}, nil\n}\n\n// DeriveKey derives the functional encryption key for the scheme.\n// It returns an error if the key could not be derived.\nfunc (q *Quad) DeriveKey(secKey *QuadSecKey, F data.Matrix) (data.VectorG2, error) {\n\tif F.Rows() != q.Params.N || F.Cols() != q.Params.M {\n\t\treturn nil, fmt.Errorf(\"dimensions of the given matrix are incorrect\")\n\t}\n\n\tUtF, err := secKey.U.Transpose().Mul(F)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tUtF = UtF.Mod(bn256.Order)\n\tUTFvec := UtF.ToVec()\n\n\tFV, err := F.Mul(secKey.V)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tFV = FV.Mod(bn256.Order)\n\tFVvec := FV.ToVec()\n\n\tyIPE := append(UTFvec, FVvec...)\n\tfeKey, err := q.Params.PartFHIPE.DeriveKey(yIPE, secKey.SecIPE)\n\n\treturn feKey, err\n}\n\n// Decrypt decrypts the ciphertext c with the derived functional\n// encryption key key in order to obtain function x^T * F * y.\nfunc (q *Quad) Decrypt(c *QuadCipher, feKey data.VectorG2, F data.Matrix) (*big.Int, error) {\n\tif len(feKey) != q.Params.PartFHIPE.Params.L+4 {\n\t\treturn nil, fmt.Errorf(\"dimensions of the given FE key are incorrect\")\n\t}\n\tif F.Rows() != q.Params.N || F.Cols() != q.Params.M {\n\t\treturn nil, fmt.Errorf(\"dimensions of the given matrix are incorrect\")\n\t}\n\n\td, err := q.Params.PartFHIPE.PartDecrypt(c.CIPE, feKey)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tFCy, err := F.MatMulVecG2(c.Cy)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tdec := new(bn256.GT).ScalarBaseMult(big.NewInt(0))\n\tfor i := 0; i < q.Params.N; i++ {\n\t\tpairedI := bn256.Pair(c.Cx[i], FCy[i])\n\t\tdec = new(bn256.GT).Add(pairedI, dec)\n\t}\n\td = new(bn256.GT).Neg(d)\n\tdec = new(bn256.GT).Add(dec, d)\n\n\t// get upper bounds\n\tb3 := new(big.Int).Exp(q.Params.Bound, big.NewInt(3), nil)\n\tb := new(big.Int).Mul(b3, big.NewInt(int64(q.Params.N*q.Params.M)))\n\tcalc := dlog.NewCalc().InBN256().WithBound(b).WithNeg()\n\n\tres, err := calc.BabyStepGiantStep(dec, new(bn256.GT).ScalarBaseMult(big.NewInt(1)))\n\n\treturn res, err\n}\n"
  },
  {
    "path": "quadratic/quad_test.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage quadratic_test\n\nimport (\n\t\"math/big\"\n\t\"testing\"\n\n\t\"github.com/fentec-project/gofe/data\"\n\t\"github.com/fentec-project/gofe/quadratic\"\n\t\"github.com/fentec-project/gofe/sample\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestQuad(t *testing.T) {\n\t// choose parameters for the encryption and build the scheme\n\tn := 10\n\tm := 8\n\tbound := big.NewInt(100)\n\tq, err := quadratic.NewQuad(n, m, bound)\n\tif err != nil {\n\t\tt.Fatalf(\"error when creating scheme: %v\", err)\n\t}\n\n\t// generate public and secret key\n\tpubKey, secKey, err := q.GenerateKeys()\n\tif err != nil {\n\t\tt.Fatalf(\"error when generating keys: %v\", err)\n\t}\n\n\t// sample vectors x and y that the encryptor will encrypt with public key;\n\tboundNeg := new(big.Int).Add(new(big.Int).Neg(bound), big.NewInt(1))\n\tsampler := sample.NewUniformRange(boundNeg, bound)\n\tx, err := data.NewRandomVector(n, sampler)\n\tif err != nil {\n\t\tt.Fatalf(\"error when generating random vector: %v\", err)\n\t}\n\ty, err := data.NewRandomVector(m, sampler)\n\tif err != nil {\n\t\tt.Fatalf(\"error when generating random vector: %v\", err)\n\t}\n\n\t// simulate an encryptor that encrypts the two random vectors\n\tencryptor := quadratic.NewQuadFromParams(q.Params)\n\tc, err := encryptor.Encrypt(x, y, pubKey)\n\tif err != nil {\n\t\tt.Fatalf(\"error when encrypting: %v\", err)\n\t}\n\n\t// derive a functional encryption key for a random matrix f\n\tf, err := data.NewRandomMatrix(n, m, sampler)\n\tif err != nil {\n\t\tt.Fatalf(\"error when generating random matrix: %v\", err)\n\t}\n\tfeKey, err := q.DeriveKey(secKey, f)\n\tif err != nil {\n\t\tt.Fatalf(\"error when deriving key: %v\", err)\n\t}\n\n\t// simulate a decryptor that using FE key decrypt the x^T * f * y\n\t// without knowing x and y\n\tdec, err := q.Decrypt(c, feKey, f)\n\tif err != nil {\n\t\tt.Fatalf(\"error when decrypting: %v\", err)\n\t}\n\n\t// check the correctness of the result\n\tcheck, err := f.MulXMatY(x, y)\n\tif err != nil {\n\t\tt.Fatalf(\"error when computing x*F*y: %v\", err)\n\t}\n\tassert.Equal(t, check, dec, \"Decryption wrong\")\n}\n"
  },
  {
    "path": "quadratic/sgp.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage quadratic\n\nimport (\n\t\"math/big\"\n\n\t\"github.com/fentec-project/bn256\"\n\t\"github.com/fentec-project/gofe/data\"\n\t\"github.com/fentec-project/gofe/internal/dlog\"\n\t\"github.com/fentec-project/gofe/sample\"\n)\n\n// SGP implements efficient FE scheme for quadratic multi-variate polynomials\n// based on Dufour Sans, Gay and Pointcheval:\n// \"Reading in the Dark: Classifying Encrypted Digits with\n// Functional Encryption\".\n// See paper: https://eprint.iacr.org/2018/206.pdf which is based on bilinear pairings.\n// It offers adaptive security under chosen-plaintext attacks (IND-CPA security).\n// This is a secret key scheme, meaning that we need a master secret key to\n// encrypt the messages.\n// Assuming input vectors x and y, the SGP scheme allows the decryptor to\n// calculate x^T * F * y, where F is matrix that represents the function,\n// and vectors x, y are only known to the encryptor, but not to decryptor.\ntype SGP struct {\n\t// length of vectors x and y (matrix F is N x N)\n\tN int\n\t// Modulus for ciphertext and keys\n\tMod *big.Int\n\n\t// The value by which elements of vectors x, y, and the\n\t// matrix F are bounded.\n\tBound *big.Int\n\n\tGCalc    *dlog.CalcBN256\n\tGInvCalc *dlog.CalcBN256\n}\n\n// NewSGP configures a new instance of the SGP scheme.\n// It accepts the length of input vectors n and the upper bound b\n// for coordinates of input vectors x, y, and the function\n// matrix F.\nfunc NewSGP(n int, b *big.Int) *SGP {\n\treturn &SGP{\n\t\tN:        n,\n\t\tMod:      bn256.Order,\n\t\tBound:    b,\n\t\tGCalc:    dlog.NewCalc().InBN256(), //.WithBound(b),\n\t\tGInvCalc: dlog.NewCalc().InBN256(), //.WithBound(b),\n\t}\n}\n\n// SGPSecKey represents a master secret key for the SGP scheme.\n// An instance of this type is returned by the\n// GenerateMasterKey method.\ntype SGPSecKey struct {\n\tS data.Vector\n\tT data.Vector\n}\n\n// NewSGPSecKey constructs an instance of SGPSecKey.\nfunc NewSGPSecKey(s, t data.Vector) *SGPSecKey {\n\treturn &SGPSecKey{\n\t\tS: s,\n\t\tT: t,\n\t}\n}\n\n// GenerateMasterKey generates a master secret key for the\n// SGP scheme. It returns an error if the secret key could\n// not be generated.\nfunc (q *SGP) GenerateMasterKey() (*SGPSecKey, error) {\n\t// msk is random s, t from Z_p^n\n\tsampler := sample.NewUniform(q.Mod)\n\ts, err := data.NewRandomVector(q.N, sampler)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tt, err := data.NewRandomVector(q.N, sampler)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn NewSGPSecKey(s, t), nil\n}\n\n// SGPCipher represents a ciphertext. An instance of this type\n// is returned as a result of the Encrypt method.\ntype SGPCipher struct {\n\tG1MulGamma *bn256.G1\n\tAMulG1     []data.VectorG1\n\tBMulG2     []data.VectorG2\n}\n\n// NewSGPCipher constructs an instance of SGPCipher.\nfunc NewSGPCipher(g1MulGamma *bn256.G1, aMulG1 []data.VectorG1,\n\tbMulG2 []data.VectorG2) *SGPCipher {\n\treturn &SGPCipher{\n\t\tG1MulGamma: g1MulGamma,\n\t\tAMulG1:     aMulG1,\n\t\tBMulG2:     bMulG2,\n\t}\n}\n\n// Encrypt encrypts input vectors x and y with the\n// master secret key msk. It returns the appropriate ciphertext.\n// If ciphertext could not be generated, it returns an error.\nfunc (q *SGP) Encrypt(x, y data.Vector, msk *SGPSecKey) (*SGPCipher, error) {\n\tsampler := sample.NewUniform(q.Mod)\n\tgamma, err := sampler.Sample()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tW, err := data.NewRandomMatrix(2, 2, sampler)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tWInv, err := W.InverseMod(q.Mod)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tWInvT := WInv.Transpose()\n\n\ta := make([]data.Vector, q.N)\n\tb := make([]data.Vector, q.N)\n\tfor i := 0; i < q.N; i++ {\n\t\t// v = (x_i, gamma * s_i)\n\t\ttmp := new(big.Int).Mul(gamma, msk.S[i])\n\t\ttmp.Mod(tmp, q.Mod)\n\t\tv := data.NewVector([]*big.Int{x[i], tmp})\n\t\tai, err := WInvT.MulVec(v)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\ta[i] = ai.Mod(q.Mod)\n\n\t\t// v = (y_i, -t_i)\n\t\ttiNeg := new(big.Int).Sub(q.Mod, msk.T[i])\n\t\tbi, err := W.MulVec(data.NewVector([]*big.Int{y[i], tiNeg}))\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tb[i] = bi.Mod(q.Mod)\n\t}\n\taMulG1 := make([]data.VectorG1, q.N)\n\tbMulG2 := make([]data.VectorG2, q.N)\n\tfor i := range a {\n\t\taMulG1[i] = a[i].MulG1()\n\t\tbMulG2[i] = b[i].MulG2()\n\t}\n\n\tc := NewSGPCipher(new(bn256.G1).ScalarBaseMult(gamma), aMulG1, bMulG2)\n\n\treturn c, nil\n}\n\n// DeriveKey derives the functional encryption key for the scheme.\n// It returns an error if the key could not be derived.\nfunc (q *SGP) DeriveKey(msk *SGPSecKey, F data.Matrix) (*bn256.G2, error) {\n\t// F is matrix and represents function (x, y) -> Σ f_i,j * x_i * y_i.\n\t// Functional encryption key is g2 * f(s, t).\n\tv, err := F.MulXMatY(msk.S, msk.T)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\ttmp := new(big.Int).Set(v)\n\te := new(bn256.G2).ScalarBaseMult(big.NewInt(1))\n\tif tmp.Cmp(big.NewInt(0)) < 0 {\n\t\ttmp.Neg(tmp)\n\t\te.Neg(e)\n\t}\n\n\treturn new(bn256.G2).ScalarMult(e, tmp), nil\n}\n\n// Decrypt decrypts the ciphertext c with the derived functional\n// encryption key key in order to obtain function x^T * F * y.\nfunc (q *SGP) Decrypt(c *SGPCipher, key *bn256.G2, F data.Matrix) (*big.Int, error) {\n\tprod := bn256.Pair(c.G1MulGamma, key)\n\n\tfor i, row := range F {\n\t\tfor j, rowEl := range row {\n\t\t\tif rowEl.Sign() != 0 {\n\t\t\t\te1 := bn256.Pair(c.AMulG1[i][0], c.BMulG2[j][0])\n\t\t\t\te2 := bn256.Pair(c.AMulG1[i][1], c.BMulG2[j][1])\n\t\t\t\te := new(bn256.GT).Add(e1, e2)\n\n\t\t\t\ttmp := new(big.Int).Set(rowEl)\n\t\t\t\tif tmp.Sign() == -1 {\n\t\t\t\t\ttmp.Neg(tmp)\n\t\t\t\t\te.Neg(e)\n\t\t\t\t}\n\n\t\t\t\tt := new(bn256.GT).ScalarMult(e, tmp)\n\t\t\t\tprod.Add(prod, t)\n\t\t\t}\n\t\t}\n\t}\n\n\tg1gen := new(bn256.G1).ScalarBaseMult(big.NewInt(1))\n\tg2gen := new(bn256.G2).ScalarBaseMult(big.NewInt(1))\n\tg := bn256.Pair(g1gen, g2gen)\n\n\t// b: b = n^2 * b^3\n\tb3 := new(big.Int).Exp(q.Bound, big.NewInt(3), nil)\n\tn2 := new(big.Int).Exp(big.NewInt(int64(q.N)), big.NewInt(2), nil)\n\tb := new(big.Int).Mul(n2, b3)\n\n\treturn q.GCalc.WithBound(b).WithNeg().BabyStepGiantStep(prod, g)\n}\n"
  },
  {
    "path": "quadratic/sgp_test.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage quadratic_test\n\nimport (\n\t\"math/big\"\n\t\"testing\"\n\n\t\"github.com/fentec-project/gofe/data\"\n\t\"github.com/fentec-project/gofe/quadratic\"\n\t\"github.com/fentec-project/gofe/sample\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestSGP(t *testing.T) {\n\tbound := big.NewInt(100)\n\tsampler := sample.NewUniformRange(new(big.Int).Neg(bound), bound)\n\tn := 10\n\tf, err := data.NewRandomMatrix(n, n, sampler)\n\tif err != nil {\n\t\tt.Fatalf(\"error when generating random matrix: %v\", err)\n\t}\n\n\tq := quadratic.NewSGP(n, bound)\n\tmsk, err := q.GenerateMasterKey()\n\tif err != nil {\n\t\tt.Fatalf(\"error when generating master keys: %v\", err)\n\t}\n\n\tx, err := data.NewRandomVector(n, sampler)\n\tif err != nil {\n\t\tt.Fatalf(\"error when generating random vector: %v\", err)\n\t}\n\ty, err := data.NewRandomVector(n, sampler)\n\tif err != nil {\n\t\tt.Fatalf(\"error when generating random vector: %v\", err)\n\t}\n\t//x[0].Set(big.NewInt(-10))\n\n\tc, err := q.Encrypt(x, y, msk)\n\tif err != nil {\n\t\tt.Fatalf(\"error when encrypting: %v\", err)\n\t}\n\n\tkey, err := q.DeriveKey(msk, f)\n\tif err != nil {\n\t\tt.Fatalf(\"error when deriving key: %v\", err)\n\t}\n\n\tcheck, err := f.MulXMatY(x, y)\n\tif err != nil {\n\t\tt.Fatalf(\"error when computing x*F*y: %v\", err)\n\t}\n\n\tdec, err := q.Decrypt(c, key, f)\n\tif err != nil {\n\t\tt.Fatalf(\"error when decrypting: %v\", err)\n\t}\n\n\tassert.Equal(t, check, dec, \"Decryption wrong\")\n}\n"
  },
  {
    "path": "sample/doc.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// Package sample includes samplers for sampling random values\n// from different probability distributions.\n//\n// Package sample provides the Sampler interface\n// along with different implementations of this interface.\n// Its primary purpose is support choosing random *big.Int values\n// from selected probability distributions.\n//\n// Implementations of the Sampler interface can be used,\n// for instance, to fill vector or matrix structures with\n// the desired random data.\npackage sample\n"
  },
  {
    "path": "sample/normal.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage sample\n\nimport (\n\t\"crypto/rand\"\n\t\"encoding/binary\"\n\t\"math\"\n\t\"math/big\"\n)\n\n// Normal samples random values from the Normal (Gaussian)\n// probability distribution, centered on 0.\ntype normal struct {\n\t// Standard deviation\n\tsigma *big.Float\n\t// Precision parameter\n\tn uint\n\t// Precomputed values of exponential function with precision n\n\tpreExp []*big.Float\n\t// Precomputed values for quicker sampling\n\tpowN  *big.Int\n\tpowNF *big.Float\n}\n\n// NewNormal returns an instance of Normal sampler.\n// It assumes mean = 0.\nfunc newNormal(sigma *big.Float, n uint) *normal {\n\tpowN := new(big.Int).Exp(big.NewInt(2), big.NewInt(int64(n)), nil)\n\tpowNF := new(big.Float)\n\tpowNF.SetPrec(n)\n\tpowNF.SetInt(powN)\n\n\treturn &normal{\n\t\tsigma:  sigma,\n\t\tn:      n,\n\t\tpreExp: nil,\n\t\tpowN:   powN,\n\t\tpowNF:  powNF,\n\t}\n}\n\n// expCoef are coefficients of a polynomial approximating an exponential\n// function.\nvar expCoef = []float64{1.43291003789439094275872613876154915146798884961754e-7,\n\t1.2303944375555413249736938854916878938183799618855e-6,\n\t1.5359914219462011698283041005730353845137869939208e-5,\n\t1.5396043210538638053991311593904356413986533880234e-4,\n\t1.3333877552501097445841748978523355617653578519821e-3,\n\t9.6181209331756452318717975913386908359825611114502e-3,\n\t5.5504109841318247098307381293125217780470848083496e-2,\n\t0.24022650687652774559310842050763312727212905883789,\n\t0.69314718056193380668617010087473317980766296386719,\n\t1}\n\nvar mantissaPrecision = uint64(52)\nvar mantissaMask = (uint64(1) << mantissaPrecision) - 1\nvar bitLenForSample = uint64(19)\nvar maxExp = uint64(1023)\nvar cmpMask = uint64(1) << 61\n\n// Bernoulli returns true with probability proportional to\n// 2^{-t/l^2}. A polynomial approximation is used to evaluate\n// the exponential function. The implementation is based on paper:\n// \"FACCT: FAst, Compact, and Constant-Time Discrete Gaussian\n// Sampler over Integers\" by R. K. Zhao, R. Steinfeld, and A. Sakzad\n// (https://eprint.iacr.org/2018/1234.pdf). See the above paper where\n// it is argued that such a sampling achieves a relative error at most\n// 2^{-45} with the chosen parameters.\nfunc Bernoulli(t *big.Int, lSquareInv *big.Float) (bool, error) {\n\taBig := new(big.Float).SetInt(t)\n\taBig.Mul(aBig, lSquareInv)\n\ta, _ := aBig.Float64()\n\ta = -a\n\n\tnegFloorA := -math.Floor(a)\n\tz := a + negFloorA\n\n\tpowOfZ := expCoef[0]\n\tfor i := 1; i < 10; i++ {\n\t\tpowOfZ = powOfZ*z + expCoef[i]\n\t}\n\n\tpowOfAMantissa := math.Float64bits(powOfZ) & mantissaMask\n\tpowOfAExponent := (math.Float64bits(powOfZ) >> mantissaPrecision) - uint64(negFloorA)\n\n\trandBytes := make([]byte, 16)\n\t_, err := rand.Read(randBytes)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\tr1 := binary.LittleEndian.Uint64(randBytes[0:8])\n\tr1 = r1 >> (64 - (mantissaPrecision + 1))\n\tr2 := binary.LittleEndian.Uint64(randBytes[8:16])\n\tr2 = r2 >> (64 - bitLenForSample)\n\n\tcheck1 := powOfAMantissa | (uint64(1) << mantissaPrecision)\n\tcheck2 := uint64(1) << (bitLenForSample + powOfAExponent + 1 - maxExp)\n\n\t// constant time check if r1 < check1 && r2 < check2\n\treturn (cmpMask&(r1-check1)&(r2-check2)) > 0 || powOfZ == 1, nil\n}\n\n// precompExp precomputes the values of exp(-2^i / 2 * sigma^2) needed\n// for sampling discrete Gauss distribution wit standard deviation sigma\n// to arbitrary precision. This is needed since such computations present\n// one of the bottlenecks of the computation. Values are precomputed in the\n// interval 0 <= i < sigma^2 * sqrt(n) since for greater i the results are\n// negligible.\nfunc (c normal) precompExp() []*big.Float {\n\tmaxFloat := new(big.Float).Mul(c.sigma, big.NewFloat(math.Sqrt(float64(c.n))))\n\tmaxBits := maxFloat.MantExp(nil) * 2\n\tvec := make([]*big.Float, maxBits+1)\n\n\ttwoSigmaSquare := new(big.Float)\n\ttwoSigmaSquare.SetPrec(c.n)\n\ttwoSigmaSquare.Mul(c.sigma, c.sigma)\n\ttwoSigmaSquare.Mul(twoSigmaSquare, big.NewFloat(2))\n\n\tx := big.NewInt(1)\n\tfor i := 0; i < maxBits+1; i++ {\n\t\tvec[i] = taylorExp(x, twoSigmaSquare, 8*c.n, c.n)\n\t\tx.Mul(x, big.NewInt(2))\n\t}\n\treturn vec\n}\n\n// isExpGreater outputs if y > exp(-x/(2*sigma^2)) with minimal\n// calculation of exp(-x/(2*sigma^2)) based on the precomputed\n// values. Sigma is implicit in the precomputed values saved in c.\nfunc (c normal) isExpGreater(y *big.Float, x *big.Int) bool {\n\t// set up an upper and lower bound for possible value of\n\t// exp(-x/(2*sigma^2))\n\tupper := big.NewFloat(1)\n\tupper.SetPrec(c.n)\n\tlower := new(big.Float)\n\tlower.SetPrec(c.n)\n\tmaxBits := x.BitLen()\n\n\tlower.Set(c.preExp[maxBits])\n\tlower.Quo(lower, c.preExp[0])\n\tif lower.Cmp(y) == 1 {\n\t\treturn false\n\t}\n\n\t// based on bits of x and the precomputed values\n\t// change the upper and lower bound\n\tfor i := 0; i < maxBits; i++ {\n\t\tbit := x.Bit(maxBits - 1 - i)\n\t\tif bit == 1 {\n\t\t\tupper.Mul(upper, c.preExp[maxBits-1-i])\n\t\t\tif y.Cmp(upper) == 1 {\n\t\t\t\treturn true\n\t\t\t}\n\t\t} else {\n\t\t\tlower.Quo(lower, c.preExp[maxBits-1-i])\n\t\t\tif y.Cmp(lower) == -1 {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t}\n\treturn false\n}\n\n// taylorExp approximates exp(-x/alpha) with taylor polynomial\n// of degree k, precise at least up to 2^-n.\nfunc taylorExp(x *big.Int, alpha *big.Float, k uint, n uint) *big.Float {\n\t// prepare the values for calculating the taylor polynomial of exp(x/sigma)\n\tres := big.NewFloat(1)\n\tres.SetPrec(n)\n\n\tval := new(big.Float)\n\tval.SetPrec(n)\n\tval.SetInt(x)\n\tval.Quo(val, alpha)\n\n\tpowVal := new(big.Float)\n\tpowVal.SetPrec(n)\n\tpowVal.Set(val)\n\n\tfactorial := new(big.Float)\n\tfactorial.SetPrec(n)\n\tfactorial.SetInt64(1)\n\n\ttmp := new(big.Float)\n\ttmp.SetPrec(n)\n\n\t// set up a minimal value up to which it calculates the precision\n\toneOverEps := new(big.Int).Exp(big.NewInt(2), big.NewInt(int64(n)), nil)\n\teps := new(big.Float)\n\teps.SetPrec(n)\n\teps.SetInt(oneOverEps)\n\teps.Quo(big.NewFloat(1), eps)\n\n\t// computation of the polynomial\n\tfor i := uint(1); i <= k; i++ {\n\t\ttmp.Quo(powVal, factorial)\n\n\t\tres.Add(res, tmp)\n\n\t\tpowVal.Mul(powVal, val)\n\t\tfactorial.Mul(factorial, big.NewFloat(float64(i+1)))\n\t\tif tmp.Cmp(eps) == -1 {\n\t\t\tbreak\n\t\t}\n\t}\n\tres.Quo(big.NewFloat(1), res)\n\n\treturn res\n}\n"
  },
  {
    "path": "sample/normal_cdt.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage sample\n\nimport (\n\t\"crypto/rand\"\n\t\"encoding/binary\"\n\t\"math/big\"\n)\n\n// cdtTable consists of a precomputed table of values\n// using which one can create a constant time half-Gaussian\n// sampler with sigma = sqrt(1/2ln(2))\nvar cdtTable = [][2]uint64{{2200310400551559144, 3327841033070651387},\n\t{7912151619254726620, 380075531178589176},\n\t{5167367257772081627, 11604843442081400},\n\t{5081592746475748971, 90134450315532},\n\t{6522074513864805092, 175786317361},\n\t{2579734681240182346, 85801740},\n\t{8175784047440310133, 10472},\n\t{2947787991558061753, 0},\n\t{22489665999543, 0}}\n\nvar cdtLen = 9 // upper bound on sample values\n\nvar cdtLowMask uint64 = 0x7fffffffffffffff\n\n// SigmaCDT is a constant sqrt(1/(2ln(2)))\nvar SigmaCDT, _ = new(big.Float).SetString(\"0.84932180028801904272150283410\")\n\n// NormalCDT samples random values from the discrete Normal (Gaussian)\n// probability distribution, limited to non-negative values (half-Gaussian).\n// In particular each value x from Z^+ is sampled with probability proportional to\n// exp(-x^2/sigma^2) where sigma = sqrt(1/2ln(2)).\n// The implementation is based on paper:\n// \"FACCT: FAst, Compact, and Constant-Time Discrete Gaussian\n// Sampler over Integers\" by R. K. Zhao, R. Steinfeld, and A. Sakzad\n// (https://eprint.iacr.org/2018/1234.pdf). See the above paper where\n// it is argued that such a sampling achieves a relative error at most\n// 2^{-46} with the chosen parameters.\ntype NormalCDT struct {\n\t*normal\n}\n\n// NewNormalCDT returns an instance of NormalCDT sampler.\nfunc NewNormalCDT() *NormalCDT {\n\ts := &NormalCDT{}\n\treturn s\n}\n\n// Sample samples discrete non-negative values with Gaussian\n// distribution.\nfunc (c *NormalCDT) Sample() (*big.Int, error) {\n\trandBytes := make([]byte, 16)\n\t_, err := rand.Read(randBytes)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tr1 := binary.LittleEndian.Uint64(randBytes[0:8])\n\tr1 = r1 & cdtLowMask\n\tr2 := binary.LittleEndian.Uint64(randBytes[8:16])\n\tr2 = r2 & cdtLowMask\n\n\tx := uint64(0)\n\tfor i := 0; i < cdtLen; i++ {\n\t\tx += (((r1 - cdtTable[i][0]) & ((uint64(1) << 63) ^ ((r2 - cdtTable[i][1]) | (cdtTable[i][1] - r2)))) | (r2 - cdtTable[i][1])) >> 63\n\t}\n\n\treturn big.NewInt(int64(x)), nil\n}\n"
  },
  {
    "path": "sample/normal_cdt_test.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage sample_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/fentec-project/gofe/sample\"\n)\n\nfunc TestNormalCDT(t *testing.T) {\n\tvar tests = []struct {\n\t\tname   string\n\t\texpect paramBounds\n\t}{\n\t\t{\n\t\t\tname: \"CDT\",\n\t\t\texpect: paramBounds{\n\t\t\t\tmeanLow:  0.39,\n\t\t\t\tmeanHigh: 0.41,\n\t\t\t\tvarLow:   0.48,\n\t\t\t\tvarHigh:  0.5,\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, test := range tests {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\ttestNormalSampler(\n\t\t\t\tt,\n\t\t\t\tsample.NewNormalCDT(),\n\t\t\t\ttest.expect,\n\t\t\t)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "sample/normal_cumulative.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage sample\n\nimport (\n\t\"crypto/rand\"\n\t\"math\"\n\t\"math/big\"\n\t\"sort\"\n)\n\n// NormalCumulative samples random values from the\n// cumulative Normal (Gaussian) probability distribution, centered on 0.\n// This sampler is the fastest, but is limited only to cases when sigma\n// is not too big, due to the sizes of the precomputed tables. Note that\n// the sampler offers arbitrary precision but the implementation is not\n// constant time.\ntype NormalCumulative struct {\n\t*normal\n\t// table of precomputed values relative to the cumulative distribution\n\tprecomputed []*big.Int\n\t// twoSided defines if we limit sampling only to non-negative integers\n\t// or to all\n\ttwoSided bool\n\t// integer defining from how big of an interval do we need to sample\n\t// uniformly to sample according to discrete Gauss\n\tsampleSize *big.Int\n}\n\n// NewNormalCumulative returns an instance of NormalCumulative sampler.\n// It assumes mean = 0. Values are precomputed when this function is\n// called, so that Sample merely returns a precomputed value.\nfunc NewNormalCumulative(sigma *big.Float, n uint, twoSided bool) *NormalCumulative {\n\ts := &NormalCumulative{\n\t\tnormal:   newNormal(sigma, n),\n\t\ttwoSided: twoSided,\n\t}\n\ts.precompute()\n\ts.sampleSize = new(big.Int).Set(s.precomputed[len(s.precomputed)-1])\n\tif s.twoSided {\n\t\ts.sampleSize.Mul(s.sampleSize, big.NewInt(2))\n\t}\n\treturn s\n}\n\n// Sample samples discrete cumulative distribution with\n// precomputed values.\nfunc (c *NormalCumulative) Sample() (*big.Int, error) {\n\tu, err := rand.Int(rand.Reader, c.sampleSize)\n\tsample := new(big.Int).Set(u)\n\tsign := 1\n\n\t// if we sample two sided, one bit is reserved for the sign of the output\n\tif c.twoSided && u.Cmp(c.precomputed[len(c.precomputed)-1]) != -1 {\n\t\tsample.Sub(sample, c.precomputed[len(c.precomputed)-1])\n\t\tsign = -1\n\t}\n\t// Find the precomputed sample\n\ti := sort.Search(len(c.precomputed),\n\t\tfunc(i int) bool { return sample.Cmp(c.precomputed[i]) != 1 })\n\tres := big.NewInt(int64(sign) * int64(i-1))\n\treturn res, err\n}\n\n// precompCumu precomputes the values for sampling.\n// This can be used only if sigma is not too big.\nfunc (c *NormalCumulative) precompute() {\n\tcutF := new(big.Float).Mul(c.sigma, big.NewFloat(math.Sqrt(float64(c.n))))\n\tcut, _ := cutF.Int64()\n\tcut = cut + 1\n\tvec := make([]*big.Int, cut+1) // vec is a table of precomputed values\n\tvec[0] = big.NewInt(0)\n\tiSquare := new(big.Int)\n\ttwoSigmaSquare := new(big.Float).Mul(c.sigma, c.sigma)\n\ttwoSigmaSquare.Mul(twoSigmaSquare, big.NewFloat(2))\n\taddF := new(big.Float)\n\taddF.SetPrec(c.n)\n\tadd := new(big.Int)\n\tfor i := int64(0); i < cut; i++ {\n\t\tiSquare.SetInt64(i * i)\n\t\t// compute the value of exp(-i^2/2sigma^2) with precision n.\n\t\t// Computing the taylor polynomial with 8 * n elements suffices\n\t\tvalue := taylorExp(iSquare, twoSigmaSquare, 8*c.n, c.n)\n\t\t// in the case of sampling all integers, sampling 0 is counted twice\n\t\t// as positive and as negative, hence its probability must be halved\n\t\tif i == 0 && c.twoSided {\n\t\t\tvalue.Quo(value, big.NewFloat(2))\n\t\t}\n\t\t// calculate the relative probability\n\t\taddF.Mul(value, c.powNF)\n\t\taddF.Int(add)\n\t\t// save the relative probability\n\t\tvec[i+1] = new(big.Int).Add(vec[i], add)\n\t}\n\tc.precomputed = vec\n}\n"
  },
  {
    "path": "sample/normal_cumulative_test.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage sample_test\n\nimport (\n\t\"math/big\"\n\t\"testing\"\n\n\t\"github.com/fentec-project/gofe/sample\"\n)\n\nfunc TestNormalCumulative(t *testing.T) {\n\tvar tests = []struct {\n\t\tname     string\n\t\tsigma    *big.Float\n\t\tn        uint\n\t\ttwoSided bool\n\t\texpect   paramBounds\n\t}{\n\t\t{\n\t\t\tname:     \"TwoSided, sigma 10\",\n\t\t\tsigma:    big.NewFloat(10),\n\t\t\tn:        256,\n\t\t\ttwoSided: true,\n\t\t\texpect: paramBounds{\n\t\t\t\tmeanLow:  -2,\n\t\t\t\tmeanHigh: 2,\n\t\t\t\tvarLow:   90,\n\t\t\t\tvarHigh:  110,\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, test := range tests {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\ttestNormalSampler(\n\t\t\t\tt,\n\t\t\t\tsample.NewNormalCumulative(test.sigma, test.n, test.twoSided),\n\t\t\t\ttest.expect,\n\t\t\t)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "sample/normal_double.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage sample\n\nimport (\n\t\"crypto/rand\"\n\t\"fmt\"\n\t\"math/big\"\n)\n\n// NormalDouble samples random values from the\n// normal (Gaussian) probability distribution, centered on 0.\n// This sampler works in a way that it first samples from a\n// NormalCumulative with some small sigma and then using\n// another sampling from uniform distribution creates a candidate\n// for the output, which is accepted or rejected with certain\n// probability. Note that the sampler offers arbitrary precision\n// but the implementation is not constant time.\ntype NormalDouble struct {\n\t*normal\n\t// NormalCumulative sampler used in the first part\n\tsamplerCumu *NormalCumulative\n\t// precomputed parameters used for sampling\n\tk      *big.Int\n\ttwiceK *big.Int\n}\n\n// NewNormalDouble returns an instance of NormalDouble sampler.\n// It assumes mean = 0. Values are precomputed when this function is\n// called, so that Sample merely samples a value.\n// sigma should be a multiple of firstSigma. Increasing firstSigma a bit speeds\n// up the algorithm but increases the number of precomputed values\nfunc NewNormalDouble(sigma *big.Float, n uint, firstSigma *big.Float) (*NormalDouble, error) {\n\tkF := new(big.Float)\n\tkF.Quo(sigma, firstSigma)\n\tif !kF.IsInt() {\n\t\treturn nil, fmt.Errorf(\"Sigma should be a multiple of firstSigma\")\n\t}\n\tk, _ := kF.Int(nil)\n\ttwiceK := new(big.Int).Mul(k, big.NewInt(2))\n\ts := &NormalDouble{\n\t\tnormal:      newNormal(sigma, n),\n\t\tsamplerCumu: NewNormalCumulative(firstSigma, n, false),\n\t\tk:           k,\n\t\ttwiceK:      twiceK,\n\t}\n\ts.preExp = s.precompExp()\n\treturn s, nil\n}\n\n// Sample samples according to discrete Gauss distribution using\n// NormalCumulative and second sampling.\nfunc (s *NormalDouble) Sample() (*big.Int, error) {\n\t// prepare values\n\tvar sign int64\n\tcheckVal := new(big.Int)\n\tuF := new(big.Float)\n\tuF.SetPrec(s.n)\n\tfor {\n\t\tsign = 1\n\t\t// first sample according to discrete gauss with smaller\n\t\t// sigma\n\t\tx, err := s.samplerCumu.Sample()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\t// sample uniformly from an interval\n\t\ty, err := rand.Int(rand.Reader, s.twiceK)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\t// use the last sampling to decide the sign of the output\n\t\tif y.Cmp(s.k) != -1 {\n\t\t\tsign = -1\n\t\t\ty.Sub(y, s.k)\n\t\t}\n\n\t\t// calculate the probability of the accepting the result\n\t\tcheckVal.Mul(s.k, x)\n\t\tcheckVal.Mul(checkVal, big.NewInt(2))\n\t\tcheckVal.Add(checkVal, y)\n\t\tcheckVal.Mul(checkVal, y)\n\n\t\t// sample if accept the output\n\t\tu, err := rand.Int(rand.Reader, s.powN)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\t// decide if accept\n\t\tuF.SetInt(u)\n\t\tuF.Quo(uF, s.powNF)\n\t\tif !s.isExpGreater(uF, checkVal) {\n\t\t\t// calculate the value that we accepted\n\t\t\tres := new(big.Int).Mul(s.k, x)\n\t\t\tres.Add(res, y)\n\t\t\tres.Mul(res, big.NewInt(sign))\n\n\t\t\t// in case the value is 0 we need to sample again to\n\t\t\t// decide if we accept the value, otherwise we return\n\t\t\t// the value\n\t\t\tif res.Cmp(big.NewInt(0)) == 0 {\n\t\t\t\tbit, err := rand.Int(rand.Reader, big.NewInt(2))\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t\tif bit.Cmp(big.NewInt(0)) == 0 {\n\t\t\t\t\treturn res, err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\treturn res, err\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "sample/normal_double_constant.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage sample\n\nimport (\n\t\"crypto/rand\"\n\t\"math/big\"\n)\n\n// NormalDoubleConstant samples random values from the\n// normal (Gaussian) probability distribution, centered on 0.\n// This sampler works by double sampling: it first samples from a\n// fixed Gaussian distribution with NormalCDT and then using\n// another sampling from uniform distribution creates a candidate\n// for the output, which is accepted or rejected with certain\n// probability. The sampler algorithm is constant time in the\n// sense that the sampled value is independent of the time needed.\n// The implementation is based on paper:\n// \"FACCT: FAst, Compact, and Constant-Time Discrete Gaussian Sampler\n// over Integers\" by R. K. Zhao, R. Steinfeld, and A. Sakzad,\n// see https://eprint.iacr.org/2018/1234.pdf.\n// See the above paper for the argumentation of the choice of\n// parameters and proof of precision and security.\ntype NormalDoubleConstant struct {\n\t*normal\n\t// NormalCDT sampler used in the first part\n\tsamplerCDT *NormalCDT\n\t// sigma = l * sqrt(1/2ln(2))\n\tl *big.Int\n\t// precomputed values for faster sampling\n\tlSquareInv *big.Float\n\ttwiceL     *big.Int\n}\n\n// NewNormalDoubleConstant returns an instance of NormalDoubleConstant\n// sampler. It assumes mean = 0. Parameter l needs to be given, such\n// that sigma = l * sqrt(1/2ln(2)).\nfunc NewNormalDoubleConstant(l *big.Int) *NormalDoubleConstant {\n\tlSquare := new(big.Float).SetInt(l)\n\tlSquare.Mul(lSquare, lSquare)\n\tlSquareInv := new(big.Float).Quo(big.NewFloat(1), lSquare)\n\n\ttwiceL := new(big.Int).Mul(l, big.NewInt(2))\n\n\ts := &NormalDoubleConstant{\n\t\tnormal:     &normal{},\n\t\tsamplerCDT: NewNormalCDT(),\n\t\tl:          new(big.Int).Set(l),\n\t\tlSquareInv: lSquareInv,\n\t\ttwiceL:     twiceL,\n\t}\n\n\treturn s\n}\n\n// Sample samples according to discrete Gauss distribution using\n// NormalDoubleConstant and second sampling.\nfunc (s *NormalDoubleConstant) Sample() (*big.Int, error) {\n\t// prepare values\n\tvar sign int64\n\tvar check bool\n\tcheckVal := new(big.Int)\n\tres := new(big.Int)\n\tfor {\n\t\tsign = 1\n\t\t// first sample according to discrete gauss with smaller\n\t\t// sigma\n\t\tx, err := s.samplerCDT.Sample()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\t// sample uniformly from an interval\n\t\ty, err := rand.Int(rand.Reader, s.twiceL)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\t// use one bit of sampling to decide the sign of the output\n\t\tif y.Cmp(s.l) != -1 {\n\t\t\tsign = -1\n\t\t\ty.Sub(y, s.l)\n\t\t}\n\n\t\t// partially calculate the result and the probability of accepting the result\n\t\tres.Mul(s.l, x)\n\t\tcheckVal.Mul(res, big.NewInt(2))\n\t\tcheckVal.Add(checkVal, y)\n\t\tcheckVal.Mul(checkVal, y)\n\t\tres.Add(res, y)\n\n\t\t// zeroCheck == 1 if and only if sign == 1 and res.Sign() == 0\n\t\tzeroCheck := int64(res.Sign()) + sign\n\t\t// sample from Bernoulli to decide if accept\n\t\tcheck, err = Bernoulli(checkVal, s.lSquareInv)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tif check && zeroCheck != 1 {\n\t\t\t// calculate the final value that we accepted\n\t\t\tres.Mul(res, big.NewInt(sign))\n\n\t\t\treturn res, nil\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "sample/normal_double_constant_test.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage sample_test\n\nimport (\n\t\"math/big\"\n\t\"testing\"\n\n\t\"github.com/fentec-project/gofe/sample\"\n)\n\nfunc TestNormalDoubleConstant(t *testing.T) {\n\tsigmaCDTSquare := 0.84932180028801904272150283410\n\tsigmaCDTSquare *= sigmaCDTSquare\n\tvar tests = []struct {\n\t\tk      *big.Int\n\t\tname   string\n\t\texpect paramBounds\n\t}{\n\t\t{\n\t\t\tname: \"sigma= 1 * sqrt(1/(2*ln(2)))\",\n\t\t\tk:    big.NewInt(1),\n\t\t\texpect: paramBounds{\n\t\t\t\tmeanLow:  -0.2,\n\t\t\t\tmeanHigh: 0.2,\n\t\t\t\tvarLow:   sigmaCDTSquare - 0.02,\n\t\t\t\tvarHigh:  sigmaCDTSquare + 0.02,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"sigma= 10 * sqrt(1/(2*ln(2)))\",\n\t\t\tk:    big.NewInt(10),\n\t\t\texpect: paramBounds{\n\t\t\t\tmeanLow:  -2,\n\t\t\t\tmeanHigh: 2,\n\t\t\t\tvarLow:   100 * (sigmaCDTSquare - 0.02),\n\t\t\t\tvarHigh:  100 * (sigmaCDTSquare + 0.02),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"sigma= 1000 * sqrt(1/(2*ln(2)))\",\n\t\t\tk:    big.NewInt(1000),\n\t\t\texpect: paramBounds{\n\t\t\t\tmeanLow:  -20,\n\t\t\t\tmeanHigh: 20,\n\t\t\t\tvarLow:   1000000 * (sigmaCDTSquare - 0.02),\n\t\t\t\tvarHigh:  1000000 * (sigmaCDTSquare + 0.02),\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, test := range tests {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tsampler := sample.NewNormalDoubleConstant(test.k)\n\t\t\ttestNormalSampler(\n\t\t\t\tt,\n\t\t\t\tsampler,\n\t\t\t\ttest.expect,\n\t\t\t)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "sample/normal_double_test.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage sample_test\n\nimport (\n\t\"math/big\"\n\t\"testing\"\n\n\t\"github.com/fentec-project/gofe/sample\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestNewNormalDouble(t *testing.T) {\n\tvar tests = []struct {\n\t\tname       string\n\t\tsigma      *big.Float\n\t\tsigmaFirst *big.Float\n\t\tn          uint\n\t\texpect     paramBounds\n\t}{\n\t\t{\n\t\t\tname:       \"SigmaFirst=1, sigma=1.5\",\n\t\t\tsigmaFirst: big.NewFloat(1),\n\t\t\tsigma:      big.NewFloat(1.5),\n\t\t\tn:          256,\n\t\t\texpect: paramBounds{\n\t\t\t\tmeanLow:  -0.5,\n\t\t\t\tmeanHigh: 0.5,\n\t\t\t\tvarLow:   90,\n\t\t\t\tvarHigh:  110,\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, test := range tests {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\t_, err := sample.NewNormalDouble(test.sigma, test.n, test.sigmaFirst)\n\t\t\tassert.Error(t, err)\n\t\t})\n\t}\n}\n\nfunc TestNormalDouble(t *testing.T) {\n\tvar tests = []struct {\n\t\tname       string\n\t\tsigma      *big.Float\n\t\tsigmaFirst *big.Float\n\t\tn          uint\n\t\texpect     paramBounds\n\t}{\n\t\t{\n\t\t\tname:       \"SigmaFirst=1, sigma10\",\n\t\t\tsigmaFirst: big.NewFloat(1),\n\t\t\tsigma:      big.NewFloat(10),\n\t\t\tn:          256,\n\t\t\texpect: paramBounds{\n\t\t\t\tmeanLow:  -2,\n\t\t\t\tmeanHigh: 2,\n\t\t\t\tvarLow:   90,\n\t\t\t\tvarHigh:  110,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:       \"SigmaFirst=1.5, sigma9\",\n\t\t\tsigmaFirst: big.NewFloat(1.5),\n\t\t\tsigma:      big.NewFloat(9),\n\t\t\tn:          256,\n\t\t\texpect: paramBounds{\n\t\t\t\tmeanLow:  -2,\n\t\t\t\tmeanHigh: 2,\n\t\t\t\tvarLow:   70,\n\t\t\t\tvarHigh:  100,\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, test := range tests {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tsampler, err := sample.NewNormalDouble(test.sigma, test.n, test.sigmaFirst)\n\t\t\tassert.NoError(t, err)\n\t\t\ttestNormalSampler(\n\t\t\t\tt,\n\t\t\t\tsampler,\n\t\t\t\ttest.expect,\n\t\t\t)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "sample/normal_negative.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage sample\n\nimport (\n\t\"crypto/rand\"\n\t\"math\"\n\t\"math/big\"\n\n\t\"github.com/pkg/errors\"\n)\n\n// NormalNegative samples random values from the possible\n// outputs of Normal (Gaussian) probability distribution centered on 0 and\n// accepts or denies each sample with probability defined by the distribution\ntype NormalNegative struct {\n\t*normal\n\t// cut defines from which interval we sample\n\tcut *big.Int\n\t// precomputed value so we do not need to calculate it each time\n\ttwiceCutPlusOne *big.Int\n}\n\n// NewNormalNegative returns an instance of NormalNegative sampler.\n// It assumes mean = 0. Values are precomputed when this function is\n// called, so that Sample merely returns a precomputed value.\nfunc NewNormalNegative(sigma *big.Float, n uint) *NormalNegative {\n\tcutF := new(big.Float).Mul(sigma, big.NewFloat(math.Sqrt(float64(n))))\n\tcut := new(big.Int)\n\tcut, _ = cutF.Int(cut)\n\ttwiceCutPlusOne := new(big.Int).Mul(cut, big.NewInt(2))\n\ttwiceCutPlusOne = twiceCutPlusOne.Add(twiceCutPlusOne, big.NewInt(1))\n\ts := &NormalNegative{\n\t\tnormal:          newNormal(sigma, n),\n\t\tcut:             cut,\n\t\ttwiceCutPlusOne: twiceCutPlusOne,\n\t}\n\ts.preExp = s.precompExp()\n\treturn s\n}\n\n// Sample samples a value from discrete Gaussian distribution based on\n// negative (rejection) sampling.\nfunc (c *NormalNegative) Sample() (*big.Int, error) {\n\tuF := new(big.Float)\n\tuF.SetPrec(c.n)\n\tnSquare := new(big.Int)\n\n\tfor {\n\t\t// random sample from the interval\n\t\tn, err := rand.Int(rand.Reader, c.twiceCutPlusOne)\n\t\tif err != nil {\n\t\t\treturn nil, errors.Wrap(err, \"error while sampling\")\n\t\t}\n\t\tn = n.Sub(n, c.cut)\n\t\tnSquare.Mul(n, n)\n\n\t\t// sample again to decide if we except the sampled value\n\t\tu, err := rand.Int(rand.Reader, c.powN)\n\t\tif err != nil {\n\t\t\treturn nil, errors.Wrap(err, \"error while sampling\")\n\t\t}\n\t\tuF.SetInt(u)\n\t\tuF.Quo(uF, c.powNF)\n\t\tif !c.isExpGreater(uF, nSquare) {\n\t\t\treturn n, nil\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "sample/normal_negative_test.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage sample_test\n\nimport (\n\t\"fmt\"\n\t\"math/big\"\n\t\"testing\"\n\n\t\"github.com/fentec-project/gofe/sample\"\n)\n\nfunc TestNormalNegative(t *testing.T) {\n\tvar tests = []struct {\n\t\tsigma  *big.Float\n\t\tn      uint\n\t\texpect paramBounds\n\t}{\n\t\t{\n\t\t\tsigma: big.NewFloat(10),\n\t\t\tn:     256,\n\t\t\texpect: paramBounds{\n\t\t\t\tmeanLow:  -2,\n\t\t\t\tmeanHigh: 2,\n\t\t\t\tvarLow:   90,\n\t\t\t\tvarHigh:  110,\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, test := range tests {\n\t\tt.Run(fmt.Sprintf(\"Sigma=%v\", test.sigma), func(t *testing.T) {\n\t\t\ttestNormalSampler(t, sample.NewNormalNegative(test.sigma, test.n), test.expect)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "sample/normal_test.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage sample_test\n\nimport (\n\t\"testing\"\n\n\t\"math/big\"\n\n\t\"github.com/fentec-project/gofe/sample\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc mean(vec []*big.Int) *big.Float {\n\tmeanI := big.NewInt(0)\n\tfor i := 0; i < len(vec); i++ {\n\t\tmeanI.Add(meanI, vec[i])\n\t}\n\tret := new(big.Float).SetInt(meanI)\n\tret.Quo(ret, big.NewFloat(float64(len(vec))))\n\treturn ret\n}\n\nfunc variance(vec []*big.Int) *big.Float {\n\tmeanI := big.NewInt(0)\n\tsquare := new(big.Int)\n\tfor i := 0; i < len(vec); i++ {\n\t\tsquare.Mul(vec[i], vec[i])\n\t\tmeanI.Add(meanI, square)\n\t}\n\tret := new(big.Float).SetInt(meanI)\n\tret.Quo(ret, big.NewFloat(float64(len(vec))))\n\treturn ret\n}\n\n// paramBounds holds the boundaries for acceptable mean\n// and variance values.\ntype paramBounds struct {\n\tmeanLow, meanHigh, varLow, varHigh float64\n}\n\n// testNormalSampler takes a normal sampler and checks whether\n// it is producing expected results - such that mean and variance\n// of a series of samples are within acceptable bounds.\nfunc testNormalSampler(t *testing.T, s sample.Sampler, bounds paramBounds) {\n\tvec := make([]*big.Int, 100000)\n\tfor i := 0; i < len(vec); i++ {\n\t\tvec[i], _ = s.Sample()\n\t}\n\n\tme, _ := mean(vec).Float64()\n\tv, _ := variance(vec).Float64()\n\n\t// me should be around 0 and v should be around 100\n\tassert.True(t, me > bounds.meanLow, \"mean value of the normal distribution is too small\")\n\tassert.True(t, me < bounds.meanHigh, \"mean value of the normal distribution is too big\")\n\tassert.True(t, v > bounds.varLow, \"variance of the normal distribution is too small\")\n\tassert.True(t, v < bounds.varHigh, \"variance of the normal distribution is too big\")\n}\n"
  },
  {
    "path": "sample/sampler.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage sample\n\nimport (\n\t\"math/big\"\n)\n\n// Sampler samples random big integer values.\n// Implementations of this interface provide a method for\n// sampling random values from the desired distribution.\ntype Sampler interface {\n\t// Sample samples random big integer values,\n\t// possibly returning an error.\n\tSample() (*big.Int, error)\n}\n"
  },
  {
    "path": "sample/uniform.go",
    "content": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage sample\n\nimport (\n\t\"crypto/rand\"\n\t\"math/big\"\n)\n\n// UniformRange samples random values from the interval [min, max).\ntype UniformRange struct {\n\tmin *big.Int\n\tmax *big.Int\n}\n\n// NewUniformRange returns an instance of the UniformRange sampler.\n// It accepts lower and upper bounds on the sampled values.\nfunc NewUniformRange(min, max *big.Int) *UniformRange {\n\treturn &UniformRange{\n\t\tmin: min,\n\t\tmax: max,\n\t}\n}\n\n// Sample samples random values from the interval [min, max).\nfunc (u *UniformRange) Sample() (*big.Int, error) {\n\tmaxMinusMin := new(big.Int).Sub(u.max, u.min)\n\tres, err := rand.Int(rand.Reader, maxMinusMin)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tres.Add(res, u.min)\n\n\treturn res, err\n}\n\n// Uniform samples random values from the interval [0, max).\ntype Uniform struct {\n\tUniformRange\n}\n\n// NewUniform returns an instance of the Uniform sampler.\n// It accepts an upper bound on the sampled values.\nfunc NewUniform(max *big.Int) *UniformRange {\n\treturn NewUniformRange(big.NewInt(0), max)\n}\n\n// Sample samples random values from the interval [0, max).\nfunc (u *Uniform) Sample() (*big.Int, error) {\n\treturn rand.Int(rand.Reader, u.max)\n}\n\n// Bit samples a single random bit (value 0 or 1).\ntype Bit struct {\n\tUniform\n}\n\n// NewBit returns an instance of Bit sampler.\nfunc NewBit() *UniformRange {\n\treturn NewUniform(big.NewInt(2))\n}\n"
  }
]