Full Code of fentec-project/gofe for AI

master ccc7482d20ef cached
89 files
452.9 KB
139.9k tokens
434 symbols
1 requests
Download .txt
Showing preview only (479K chars total). Download the full file or copy to clipboard to get everything.
Repository: fentec-project/gofe
Branch: master
Commit: ccc7482d20ef
Files: 89
Total size: 452.9 KB

Directory structure:
gitextract_ii1m5ucw/

├── .circleci/
│   └── config.yml
├── .gitignore
├── AUTHORS.md
├── LICENSE
├── README.md
├── abe/
│   ├── dippe.go
│   ├── dippe_test.go
│   ├── doc.go
│   ├── fame.go
│   ├── fame_test.go
│   ├── gpsw.go
│   ├── gpsw_test.go
│   ├── ma-abe.go
│   ├── ma-abe_test.go
│   ├── policy.go
│   └── policy_test.go
├── data/
│   ├── doc.go
│   ├── matrix.go
│   ├── matrix_bn256.go
│   ├── matrix_test.go
│   ├── vector.go
│   ├── vector_bn256.go
│   └── vector_test.go
├── doc.go
├── go.mod
├── go.sum
├── innerprod/
│   ├── doc.go
│   ├── fullysec/
│   │   ├── damgard.go
│   │   ├── damgard_dec_multi.go
│   │   ├── damgard_dec_multi_test.go
│   │   ├── damgard_multi.go
│   │   ├── damgard_multi_test.go
│   │   ├── damgard_test.go
│   │   ├── dmcfe.go
│   │   ├── dmcfe_test.go
│   │   ├── doc.go
│   │   ├── fh_multi_ipe.go
│   │   ├── fh_multi_ipe_test.go
│   │   ├── fhipe.go
│   │   ├── fhipe_test.go
│   │   ├── lwe.go
│   │   ├── lwe_test.go
│   │   ├── paillier.go
│   │   ├── paillier_multi.go
│   │   ├── paillier_multi_test.go
│   │   ├── paillier_test.go
│   │   ├── part_fh_ipe.go
│   │   └── part_fh_ipe_test.go
│   └── simple/
│       ├── ddh.go
│       ├── ddh_multi.go
│       ├── ddh_multi_test.go
│       ├── ddh_test.go
│       ├── doc.go
│       ├── lwe.go
│       ├── lwe_test.go
│       ├── ringlwe.go
│       └── ringlwe_test.go
├── internal/
│   ├── dlog/
│   │   ├── brute_force.go
│   │   ├── brute_force_test.go
│   │   ├── calc.go
│   │   ├── calc_test.go
│   │   ├── dlog_test.go
│   │   ├── doc.go
│   │   ├── pollard_rho.go
│   │   └── pollard_rho_test.go
│   ├── errors.go
│   ├── keygen/
│   │   ├── elgamal.go
│   │   └── prime.go
│   └── mod_exp.go
├── quadratic/
│   ├── doc.go
│   ├── quad.go
│   ├── quad_test.go
│   ├── sgp.go
│   └── sgp_test.go
└── sample/
    ├── doc.go
    ├── normal.go
    ├── normal_cdt.go
    ├── normal_cdt_test.go
    ├── normal_cumulative.go
    ├── normal_cumulative_test.go
    ├── normal_double.go
    ├── normal_double_constant.go
    ├── normal_double_constant_test.go
    ├── normal_double_test.go
    ├── normal_negative.go
    ├── normal_negative_test.go
    ├── normal_test.go
    ├── sampler.go
    └── uniform.go

================================================
FILE CONTENTS
================================================

================================================
FILE: .circleci/config.yml
================================================
version: 2
jobs:
  build:
    docker:
      - image: circleci/golang:1.14

    working_directory: /go/src/github.com/fentec-project/gofe

    steps:
      - checkout

      - run:
          name: Get dependencies
          command: go get -t -v ./...

      - run:
          name: Run tests
          command: go test -v ./...

================================================
FILE: .gitignore
================================================
# IDE files
.idea
.vscode

# Vendor directory
vendor/*/

# Other
*.swp
*.swo
.DS_Store

# Binary
fentec

================================================
FILE: AUTHORS.md
================================================
# Authors
A list of code contributors to GoFE library for
functional encryption.

## Maintainer
The team from [XLAB d.o.o](https://www.xlab.si/)

## Original authors
*   Manca Bizjak <manca.bizjak@xlab.si>
*   Jan Hartman <jan.hartman@xlab.si>
*   Tilen Marc <tilen.marc@xlab.si>
*   Miha Stopar <miha.stopar@xlab.si>


================================================
FILE: LICENSE
================================================
                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "{}"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright {yyyy} {name of copyright owner}

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

================================================
FILE: README.md
================================================
# GoFE - Functional Encryption library
[![Build Status](https://circleci.com/gh/fentec-project/gofe.svg?style=svg)](https://circleci.com/gh/fentec-project/gofe)
[![GoDoc](https://godoc.org/github.com/fentec-project/gofe?status.svg)](https://godoc.org/github.com/fentec-project/gofe)
[![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)

<p align="center">
        <img src="GoFE_logo.png" width="160" />
</p>

GoFE is a cryptographic library offering different state-of-the-art
implementations of functional encryption schemes, specifically FE
schemes for _linear_ (e.g. _inner products_) and _quadratic polynomials_.

To quickly get familiar with FE, read a short and very high-level 
introduction on our [Introductory Wiki page](../../wiki/Introduction-to-FE).
A more detailed introduction with lots of interactive diagrams can be found on [this blog](https://alicebobstory.com/fe).

<!-- toc -->
- [Installing GoFE](#installing-gofe)
- [Using GoFE in your project](#using-gofe-in-your-project)
    * [Select the FE scheme](#select-the-fe-scheme)
    * [Configure selected scheme](#configure-selected-scheme)
    * [Prepare input data](#prepare-input-data)
    * [Use the scheme (examples)](#use-the-scheme-(examples))
- [Related work](#related-work)
    * [Other implementations](#other-implementations)
    * [Example projects](#example-projects)
<!-- tocstop -->

### Before using the library
Please note that the library is a work in progress and has not yet
reached a stable release. Code organization and APIs are **not stable**.
You can expect them to change at any point.

The purpose of GoFE is to support research and proof-of-concept
implementations. It **should not be used in production**.

## Installing GoFE
First, download and build the library by running either
`go install github.com/fentec-project/gofe/...` or
 `go get -u -t github.com/fentec-project/gofe/...` from the terminal (note that this also
 downloads and builds all the dependencies of the library).
 Please note that from Go version 1.18 on, `go get` will [no longer build packages](https://golang.org/doc/go-get-install-deprecation),
 and `go install` should be used instead.
 
To make sure the library works as expected, navigate to your `$GOPATH/pkg/mod/github.com/fentec-project/gofe` 
directory and run `go test -v ./...` . 
If you are still using Go version below 1.16 or have `GO111MODULE=off` set, navigate to `$GOPATH/src/github.com/fentec-project/gofe` instead.

## Using GoFE in your project
After you have successfully built the library, you can use it in your project.
Instructions below provide a brief introduction to the most important parts
of the library, and guide you through a sequence of steps that will quickly
get your FE example up and running.  

### Select the FE scheme
You can choose from the following  set of schemes:

#### Inner product schemes
You will need to import packages from `ìnnerprod` directory.

We organized implementations in two categories based on their security assumptions:

* Schemes with **selective security under chosen-plaintext 
attacks** (s-IND-CPA security):
    * 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.
    * Ring-LWE scheme based on _Bermudo Mera, Karmakar, Marc, and Soleimanian_ ([paper](https://eprint.iacr.org/2021/046)), see `simple.RingLWE`.
    * 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`).

* Schemes with stronger **adaptive security under chosen-plaintext attacks** (IND-CPA
security) or **simulation based security** (SIM-Security for IPE):
    * 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.
    * 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`).
    * 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`).
    * 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 
procedure for decentralization of an inner product scheme, in particular the decentralization of a Damgard DDH scheme (`fullysec.DamgardDecMultiClient`).
    * 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 
functional key that allows a decrytor to decrypt an inner product without revealing the ciphertext or the function (`fullysec.FHMultiIPE`).
    * 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
decrypt the inner product of x and y without reveling (ciphertext) x or (function) y (`fullysec.fhipe`).
    * Partially function hiding inner product scheme by _Romain Gay_ ([paper](https://eprint.iacr.org/2020/093.pdf)). This scheme
 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
 achieved by limiting the space of vectors that can be encrypted with a public key (`fullysec.partFHIPE`).

#### Quadratic polynomial schemes
There are two implemented FE schemes for **quadratic multi-variate polynomials**:
* First is an efficient symmetric FE scheme by _Dufour Sans, Gay_ and _Pointcheval_ 
([paper](https://eprint.iacr.org/2018/206.pdf)) which is based on
bilinear pairings, and offers adaptive security under chosen-plaintext
attacks (IND-CPA security). You will need `SGP` scheme from package `quadratic`.
* Second is an efficient pubic key FE by _Romain Gay_ ([paper](https://eprint.iacr.org/2020/093.pdf))
that is based on the underlying partially function hiding inner product scheme and offers semi-adaptive
simulation based security. You will need `quad` scheme from package `quadratic`.

#### Schemes with the attribute based encryption (ABE)
Schemes are organized under package `abe`.

It contains four ABE schemes:
* A ciphertext policy (CP) ABE scheme named FAME by _Agrawal, Chase_ ([paper](https://eprint.iacr.org/2017/807.pdf)) allowing encrypting a
message based on a boolean expression defining a policy which attributes are needed for the decryption. It is implemented in `abe.fame`.
* A key policy (KP) ABE scheme by _Goyal, Pandey, Sahai, Waters_ ([paper](https://eprint.iacr.org/2006/309.pdf)) allowing a distribution of
keys following a boolean expression defining a policy which attributes are needed for the decryption. It is implemented in `abe.gpsw`.
* A decentralized inner product predicate scheme by _Michalevsky, Joye_ ([paper](https://eprint.iacr.org/2018/753.pdf)) allowing encryption
with policy described as a vector, and a decentralized distribution of keys based on users' vectors so that
only users with  vectors orthogonal to the encryption vector posses a key that can decrypt the ciphertext. It is implemented in `abe.dippe`.
* 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`.

### Configure selected scheme
All GoFE schemes are implemented as Go structs with (at least logically)
similar APIs. So the first thing we need to do is to create a scheme instance
by instantiating the appropriate struct. For this step, we need to pass in 
some configuration, e.g. values of parameters for the selected scheme.

Let's say we selected a `simple.DDH` scheme. We create a new scheme instance with:
````go
scheme, _ := simple.NewDDH(5, 1024, big.NewInt(1000))
````

In the line above, the first argument is length of input vectors **x**
and **y**, the second argument is bit length of prime modulus _p_
(because this particular scheme operates in the &#8484;<sub>p</sub> group), and
the last argument represents the upper bound for elements of input vectors.

However, configuration parameters for different FE schemes vary quite a bit.
Please refer to [library documentation](https://godoc.org/github.com/fentec-project/gofe) regarding the meaning of parameters for
 specific schemes. For now, examples and reasonable defaults can be found in 
 the test code. 
 
After you successfully created a FE scheme instance, you can call its
 methods for:
* generation of (secret and public) master keys,
* derivation of functional encryption key,
* encryption, and
* decryption. 

### Prepare input data
#### Vectors and matrices
All GoFE chemes rely on vectors (or matrices) of big integer (`*big.Int`) 
components. 

GoFE schemes use the library's own `Vector` and `Matrix` types. They are implemented
 in the `data` package. A `Vector` is basically a wrapper around `[]*big.Int`
slice, while a `Matrix` wraps a slice of `Vector`s.

In general, you only have to worry about providing input data (usually
vectors **x** and **y**). If you already have your slice of `*big.Int`s 
defined, you can create a `Vector` by calling
`data.NewVector` function with your slice as argument, for example:
````go
// Let's say you already have your data defined in a slice of *big.Ints
x := []*big.Int{big.NewInt(0), big.NewInt(1), big.NewInt(2)}
xVec := data.NewVector(x)
````

Similarly, for matrices, you will first have to construct your slice of 
`Vector`s, and pass it to `data.NewMatrix` function: 
````go
vecs := make([]data.Vector, 3) // a slice of 3 vectors
// fill vecs
vecs[0] := []*big.Int{big.NewInt(0), big.NewInt(1), big.NewInt(2)}
vecs[1] := []*big.Int{big.NewInt(2), big.NewInt(1), big.NewInt(0)}
vecs[2] := []*big.Int{big.NewInt(1), big.NewInt(1), big.NewInt(1)}
xMat := data.NewMatrix(vecs)
````

#### Random data
To generate random `*big.Int` values from different probability distributions,
you can use one of our several implementations of random samplers. The samplers
are provided in the `sample` package and all implement `sample.Sampler`
 interface.
 
You can quickly construct random vectors and matrices by:
1. Configuring the sampler of your choice, for example:
    ````go
    s := sample.NewUniform(big.NewInt(100)) // will sample uniformly from [0,100)
    ````
2. Providing it as an argument to`data.NewRandomVector` or `data.NewRandomMatrix` functions. 
    ````go
    x, _ := data.NewRandomVector(5, s) // creates a random vector with 5 elements
    X, _ := data.NewRandomMatrix(2, 3, s) // creates a random 2x3 matrix
    ````
    
## Use the scheme
To see how the schemes can be used consult one of the following.

#### Tests
Every implemented scheme has an implemented test to verify the correctness
of the implementation (for example Paillier inner-product scheme implemented in
`innerprod/fullysec/paillier.go` has a corresponding test in 
`innerprod/fullysec/paillier_test.go`). One can check the appropriate test
file to see an example of how the chosen scheme can be used.

#### Examples
We give some concrete examples how to use the schemes. 
Please note that all the examples below omit error management.

##### Using a single input scheme
The example below demonstrates how to use single input scheme instances.
Although the example shows how to use the`DDH` from package 
`simple`, the usage is similar for all single input schemes, regardless
of their security properties (s-IND-CPA or IND-CPA) and instantiation
 (DDH or LWE).
 
You will see that three `DDH` structs are instantiated to simulate the
 real-world scenarios where each of the three entities involved in FE
 are on separate machines.
 
```go
// Instantiation of a trusted entity that
// will generate master keys and FE key
l := 2 // length of input vectors
bound := big.NewInt(10) // upper bound for input vector coordinates
modulusLength := 2048 // bit length of prime modulus p 
trustedEnt, _ := simple.NewDDHPrecomp(l, modulusLength, bound)
msk, mpk, _ := trustedEnt.GenerateMasterKeys()

y := data.NewVector([]*big.Int{big.NewInt(1), big.NewInt(2)})
feKey, _ := trustedEnt.DeriveKey(msk, y)

// Simulate instantiation of encryptor 
// Encryptor wants to hide x and should be given
// master public key by the trusted entity
enc := simple.NewDDHFromParams(trustedEnt.Params)
x := data.NewVector([]*big.Int{big.NewInt(3), big.NewInt(4)})
cipher, _ := enc.Encrypt(x, mpk)

// Simulate instantiation of decryptor that decrypts the cipher 
// generated by encryptor.
dec := simple.NewDDHFromParams(trustedEnt.Params)
// decrypt to obtain the result: inner prod of x and y
// we expect xy to be 11 (e.g. <[1,2],[3,4]>)
xy, _ := dec.Decrypt(cipher, feKey, y)
```

##### Using a multi input scheme
This example demonstrates how multi input FE schemes can be used.
 
 Here we assume
 that there are `numClients` encryptors (e<sub>i</sub>), each with their corresponding
 input vector x<sub>i</sub>. A trusted entity generates all the master keys needed
 for encryption and distributes appropriate keys to appropriate encryptor. Then, 
 encryptor e<sub>i</sub> uses their keys to encrypt their data x<sub>i</sub>.
 The decryptor collects ciphers from all the encryptors. It then relies on the trusted
  entity to derive a decryption key based on its own set of vectors y<sub>i</sub>. With the
  derived key, the decryptor is able to compute the result - inner product
over all vectors, as _Σ <x<sub>i</sub>,y<sub>i</sub>>._

```go
numClients := 2           // number of encryptors
l := 3                    // length of input vectors
bound := big.NewInt(1000) // upper bound for input vectors

// Simulate collection of input data.
// X and Y represent matrices of input vectors, where X are collected
// from numClients encryptors (omitted), and Y is only known by a single decryptor.
// Encryptor i only knows its own input vector X[i].
sampler := sample.NewUniform(bound)
X, _ := data.NewRandomMatrix(numClients, l, sampler)
Y, _ := data.NewRandomMatrix(numClients, l, sampler)

// Trusted entity instantiates scheme instance and generates
// master keys for all the encryptors. It also derives the FE
// key derivedKey for the decryptor.
modulusLength := 2048
multiDDH, _ := simple.NewDDHMultiPrecomp(numClients, l, modulusLength, bound)
pubKey, secKey, _ := multiDDH.GenerateMasterKeys()
derivedKey, _ := multiDDH.DeriveKey(secKey, Y)

// Different encryptors may reside on different machines.
// We simulate this with the for loop below, where numClients
// encryptors are generated.
encryptors := make([]*simple.DDHMultiClient, numClients)
for i := 0; i < numClients; i++ {
    encryptors[i] = simple.NewDDHMultiClient(multiDDH.Params)
}
// Each encryptor encrypts its own input vector X[i] with the
// keys given to it by the trusted entity.
ciphers := make([]data.Vector, numClients)
for i := 0; i < numClients; i++ {
    cipher, _ := encryptors[i].Encrypt(X[i], pubKey[i], secKey.OtpKey[i])
    ciphers[i] = cipher
}

// Ciphers are collected by decryptor, who then computes
// inner product over vectors from all encryptors.
decryptor := simple.NewDDHMultiFromParams(numClients, multiDDH.Params)
prod, _ = decryptor.Decrypt(ciphers, derivedKey, Y)
```
Note that above we instantiate multiple encryptors - in reality,
 different encryptors will be instantiated on different machines. 
 

##### Using quadratic polynomial scheme
In the example below, we omit instantiation of different entities
(encryptor and decryptor).
```go
l := 2 // length of input vectors
bound := big.NewInt(10) // Upper bound for coordinates of vectors x, y, and matrix F

// Here we fill our vectors and the matrix F (that represents the
// quadratic function) with random data from [0, bound).
sampler := sample.NewUniform(bound)
F, _ := data.NewRandomMatrix(l, l, sampler)
x, _ := data.NewRandomVector(l, sampler)
y, _ := data.NewRandomVector(l, sampler)

sgp := quadratic.NewSGP(l, bound)     // Create scheme instance
msk, _ := sgp.GenerateMasterKey()     // Create master secret key
cipher, _ := sgp.Encrypt(x, y, msk)   // Encrypt input vectors x, y with secret key
key, _ := sgp.DeriveKey(msk, F)       // Derive FE key for decryption
dec, _ := sgp.Decrypt(cipher, key, F) // Decrypt the result to obtain x^T * F * y
```

##### Using ABE schemes
Let's say we selected `abe.FAME` scheme. In the example below, we omit instantiation of different entities
(encryptor and decryptor). Say we want to encrypt the following message `msg` so that only those
who own the attributes satisfying a boolean expression 'policy' can decrypt.
```go
msg := "Attack at dawn!"
policy := "((0 AND 1) OR (2 AND 3)) AND 5"

gamma := []string{"0", "2", "3", "5"} // owned attributes

a := abe.NewFAME() // Create the scheme instance
pubKey, secKey, _ := a.GenerateMasterKeys() // Create a public key and a master secret key
msp, _ := abe.BooleanToMSP(policy, false) // The MSP structure defining the policy
cipher, _ := a.Encrypt(msg, msp, pubKey) // Encrypt msg with policy msp under public key pubKey
keys, _ := a.GenerateAttribKeys(gamma, secKey) // Generate keys for the entity with attributes gamma
dec, _ := a.Decrypt(cipher, keys, pubKey) // Decrypt the message
```

## Related work

### Other implementations

Apart from the GoFE library, there is also a C library called CiFEr that
implements many of the same schemes as GoFE, and can be found
[here](https://github.com/fentec-project/CiFEr).

### Example projects

A few reference uses of the GoFE library are provided:
* [creating a privacy preserving heatmap](https://github.com/fentec-project/FE-anonymous-heatmap),
* [evaluating a machine learning function on encrypted data](https://github.com/fentec-project/neural-network-on-encrypted-data),
* [privacy friendly data analysis on encrypted data](https://github.com/fentec-project/privacy-friendly-analyses).


================================================
FILE: abe/dippe.go
================================================
/*
 * Copyright (c) 2018 XLAB d.o.o
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package abe

import (
	"crypto/aes"
	cbc "crypto/cipher"
	"crypto/rand"
	"crypto/sha256"
	"fmt"
	"math/big"
	"strconv"

	"io"

	"github.com/fentec-project/bn256"
	"github.com/fentec-project/gofe/data"
	"github.com/fentec-project/gofe/sample"
)

// DIPPE represents a Decentralized Inner-Product Predicate Encryption
// (DIPPE) scheme introduced by Y. Michalevsky and M. Joye in:
// "Decentralized Policy-Hiding Attribute-Based Encryption with Receiver Privacy"
// https://eprint.iacr.org/2018/753.pdf
type DIPPE struct {
	secLevel int
	G1ToA    data.MatrixG1
	G1ToUA   data.MatrixG1
	P        *big.Int // order of the elliptic curve
}

// DIPPEPubKey represents a public key of an authority in DIPPE scheme.
type DIPPEPubKey struct {
	G1ToWtA   data.MatrixG1
	GToAlphaA data.VectorGT
	G2ToSigma *bn256.G2
}

// DIPPESecKey represents a secret key of an authority in DIPPE scheme.
type DIPPESecKey struct {
	Sigma *big.Int
	W     data.Matrix
	Alpha data.Vector
}

// DIPPEAuth represents an authority in DIPPE scheme
type DIPPEAuth struct {
	ID int
	Sk DIPPESecKey
	Pk DIPPEPubKey
}

// DIPPECipher represents a ciphertext in DIPPE scheme
type DIPPECipher struct {
	C0     data.VectorG1
	C      data.MatrixG1
	CPrime *bn256.GT
	X      data.Vector // policy vector
	SymEnc []byte      // symmetric encryption of the message
	Iv     []byte      // initialization vector for symmetric encryption
}

// NewDIPPE configures a new instance of the scheme. The input parameter
// defines the security assumption of the scheme, so called k-Lin assumption,
// where k is the input.
func NewDIPPE(secLevel int) (*DIPPE, error) {
	sampler := sample.NewUniform(bn256.Order)

	A, err := data.NewRandomMatrix(secLevel+1, secLevel, sampler)
	if err != nil {
		return nil, err
	}
	g1ToA := A.MulG1()

	U, err := data.NewRandomMatrix(secLevel+1, secLevel+1, sampler)
	if err != nil {
		return nil, err
	}
	UA, err := U.Mul(A)
	if err != nil {
		return nil, err
	}
	UA.Mod(bn256.Order)
	g1ToUA := UA.MulG1()

	return &DIPPE{secLevel: secLevel,
		G1ToA:  g1ToA,
		G1ToUA: g1ToUA,
		P:      bn256.Order}, nil
}

// NewDIPPEAuth configures a new authority that will be able to
// produce decryption keys. If the scheme will have n authorities
// it is assumed that each will have a different id from [0, n).
func (d *DIPPE) NewDIPPEAuth(id int) (*DIPPEAuth, error) {
	sampler := sample.NewUniform(bn256.Order)

	W, err := data.NewRandomMatrix(d.secLevel+1, d.secLevel+1, sampler)
	if err != nil {
		return nil, err
	}

	alpha, err := data.NewRandomVector(d.secLevel+1, sampler)
	if err != nil {
		return nil, err
	}

	sigma, err := sampler.Sample()
	if err != nil {
		return nil, err
	}

	sk := DIPPESecKey{W: W, Alpha: alpha, Sigma: sigma}

	g1ToWtA, err := W.Transpose().MatMulMatG1(d.G1ToA)
	if err != nil {
		return nil, err
	}

	alphaAsMatrix := data.Matrix([]data.Vector{alpha})
	g1ToAlphaA, err := alphaAsMatrix.MatMulMatG1(d.G1ToA)
	if err != nil {
		return nil, err
	}

	g2 := new(bn256.G2).ScalarBaseMult(big.NewInt(1))
	gtToAlphaA := make(data.VectorGT, d.secLevel)
	for i := 0; i < d.secLevel; i++ {
		gtToAlphaA[i] = bn256.Pair(g1ToAlphaA[0][i], g2)
	}

	g2ToSigma := new(bn256.G2).ScalarMult(g2, sigma)

	pk := DIPPEPubKey{G1ToWtA: g1ToWtA, GToAlphaA: gtToAlphaA, G2ToSigma: g2ToSigma}

	return &DIPPEAuth{ID: id, Sk: sk, Pk: pk}, nil
}

// Encrypt takes as an input a string message msg, a vector x representing a
// decryption policy and a slice of public keys of the participating authorities.
// The i-th coordinate of x corresponds to i-th public key of the authority with
// id i. It returns an encryption of msg. In case of a failed procedure an
// error is returned.
func (d *DIPPE) Encrypt(msg string, x data.Vector, pubKeys []*DIPPEPubKey) (*DIPPECipher, error) {
	// msg is encrypted using CBC, with a random key that is encapsulated
	// with DIPPE
	_, keyGt, err := bn256.RandomGT(rand.Reader)
	if err != nil {
		return nil, err
	}
	keyCBC := sha256.Sum256([]byte(keyGt.String()))

	a, err := aes.NewCipher(keyCBC[:])
	if err != nil {
		return nil, err
	}

	iv := make([]byte, a.BlockSize())
	_, err = io.ReadFull(rand.Reader, iv)
	if err != nil {
		return nil, err
	}
	encrypterCBC := cbc.NewCBCEncrypter(a, iv)

	msgByte := []byte(msg)
	// message is padded according to pkcs7 standard
	padLen := a.BlockSize() - (len(msgByte) % a.BlockSize())
	msgPad := make([]byte, len(msgByte)+padLen)
	copy(msgPad, msgByte)
	for i := len(msgByte); i < len(msgPad); i++ {
		msgPad[i] = byte(padLen)
	}

	symEnc := make([]byte, len(msgPad))
	encrypterCBC.CryptBlocks(symEnc, msgPad)

	// encapsulate the key with DIPPE
	sampler := sample.NewUniform(bn256.Order)
	s, err := data.NewRandomVector(d.secLevel, sampler)
	if err != nil {
		return nil, err
	}

	c0 := d.G1ToA.MulVector(s)
	if err != nil {
		return nil, err
	}

	c := make(data.MatrixG1, len(x))
	for i := range x {
		g1ToXiUA := d.G1ToUA.MulScalar(x[i])
		g1ToXiUplusWtiA := g1ToXiUA.Add(pubKeys[i].G1ToWtA)
		c[i] = g1ToXiUplusWtiA.MulVector(s)
	}

	cPrime := new(bn256.GT).ScalarBaseMult(big.NewInt(0))
	for _, e := range pubKeys {
		tmp := e.GToAlphaA.Dot(s)
		cPrime.Add(tmp, cPrime)
	}
	cPrime.Add(keyGt, cPrime)

	return &DIPPECipher{C0: c0, C: c, CPrime: cPrime, X: x.Copy(), SymEnc: symEnc, Iv: iv}, nil
}

// DeriveKeyShare allows an authority to give a partial decryption key. Collecting all
// such partial keys allows a user to decrypt the message. The input vector v contains
// an information about the user that will allow him to decrypt iff the inner product
// v times x = 0 for the policy x. GID is a global identifier of the user and a slice of
// public keys of the authorities should be given.
func (a *DIPPEAuth) DeriveKeyShare(v data.Vector, pubKeys []*DIPPEPubKey, gid string) (data.VectorG2, error) {
	g2ToMu := make(data.VectorG2, a.Sk.W.Rows())
	for i := 0; i < a.Sk.W.Rows(); i++ {
		g2ToMu[i] = new(bn256.G2).ScalarBaseMult(big.NewInt(0))
	}

	g2ToAlpha := a.Sk.Alpha.MulG2()

	var err error
	for j := 0; j < len(pubKeys); j++ {
		if j == a.ID {
			continue
		}

		yToSigma := new(bn256.G2).ScalarMult(pubKeys[j].G2ToSigma, a.Sk.Sigma)
		for i := 0; i < a.Sk.W.Rows(); i++ {
			hashed, err := bn256.HashG2(strconv.Itoa(i) + yToSigma.String() + gid + v.String())
			if err != nil {
				return nil, err
			}

			if j > a.ID {
				hashed.Neg(hashed)
			}
			g2ToMu[i] = g2ToMu[i].Add(hashed, g2ToMu[i])
		}
	}

	g2ToH := make(data.VectorG2, a.Sk.W.Rows())
	for j := range g2ToH {
		g2ToH[j], err = bn256.HashG2(strconv.Itoa(j) + gid + v.String())

		if err != nil {
			return nil, err
		}
	}
	g2ToWH, err := a.Sk.W.MatMulVecG2(g2ToH)
	if err != nil {
		return nil, err
	}
	g2ToViWH := g2ToWH.MulScalar(v[a.ID]).Neg()

	return g2ToAlpha.Add(g2ToViWH).Add(g2ToMu), nil
}

// Decrypt accepts the ciphertext, a slice of keys obtained from the authorities,
// a vector v representing the users decryption allowance, and a global identifier.
// If the provided keys are correct and the inner product v times x = 0 for the policy
// x, the message is decrypted, otherwise an error is returned.
func (d *DIPPE) Decrypt(cipher *DIPPECipher, keys []data.VectorG2, v data.Vector, gid string) (string, error) {
	// check if the decryption is possible
	prod, err := v.Dot(cipher.X)
	if err != nil {
		return "", err
	}

	if prod.Sign() != 0 {
		return "", fmt.Errorf("insufficient keys")
	}

	// use DIPPE decryption procedure to get a CBC key
	// needed for the decryption of the message
	gTToAlphaAS := new(bn256.GT).ScalarBaseMult(big.NewInt(0))

	ones := data.NewConstantMatrix(1, len(keys), big.NewInt(1))
	sum, err := ones.MatMulMatG2(data.MatrixG2(keys))
	if err != nil {
		return "", err
	}

	for i, e := range cipher.C0 {
		tmpGT := bn256.Pair(e, sum[0][i])
		gTToAlphaAS.Add(gTToAlphaAS, tmpGT)
	}

	vMat := make(data.Matrix, 1)
	vMat[0] = v
	cSum, err := vMat.MatMulMatG1(cipher.C)
	if err != nil {
		return "", err
	}

	for j := range cSum[0] {
		hashed, err := bn256.HashG2(strconv.Itoa(j) + gid + v.String())
		if err != nil {
			return "", err
		}

		tmpGT := bn256.Pair(cSum[0][j], hashed)
		gTToAlphaAS.Add(gTToAlphaAS, tmpGT)
	}
	gTToAlphaAS.Neg(gTToAlphaAS)

	keyGt := new(bn256.GT).Add(cipher.CPrime, gTToAlphaAS)

	keyCBC := sha256.Sum256([]byte(keyGt.String()))

	a, err := aes.NewCipher(keyCBC[:])
	if err != nil {
		return "", err
	}

	msgPad := make([]byte, len(cipher.SymEnc))
	decrypter := cbc.NewCBCDecrypter(a, cipher.Iv)
	decrypter.CryptBlocks(msgPad, cipher.SymEnc)

	// unpad the message
	padLen := int(msgPad[len(msgPad)-1])
	if (len(msgPad) - padLen) < 0 {
		return "", fmt.Errorf("failed to decrypt")
	}
	msgByte := msgPad[0:(len(msgPad) - padLen)]

	return string(msgByte), nil
}

// ExactThresholdPolicyVecInit is used for the transformation of the DIPPE
// scheme into an ABE scheme with an exact threshold. In particular given a
// slice of attributes, a threshold value and the number of all possible
// attributes it creates a policy vector that can be used for the DIPPE encryption.
// The user will be able to decrypt only if he posses exactly the threshold
// value of the attributes.
func (d DIPPE) ExactThresholdPolicyVecInit(attrib []int, threshold int, numAttrib int) (data.Vector, error) {
	policyVec := data.NewConstantVector(numAttrib+1, big.NewInt(0))
	one := big.NewInt(1)
	for _, e := range attrib {
		if e > numAttrib {
			return nil, fmt.Errorf("attributes out of range")
		}
		policyVec[e].Set(one)
	}
	policyVec[numAttrib].Set(big.NewInt(int64(-threshold)))

	return policyVec, nil
}

// ConjunctionPolicyVecInit is used for the transformation of the DIPPE
// scheme into an ABE scheme with conjugation policy. In particular given a
// slice of attributes and the number of all possible attributes it creates
// a policy vector that can be used for the DIPPE encryption. The user will
// be able to decrypt only if he posses all the demanded attributes.
func (d DIPPE) ConjunctionPolicyVecInit(attrib []int, numAttrib int) (data.Vector, error) {
	policyVec := data.NewConstantVector(numAttrib+1, big.NewInt(0))
	sampler := sample.NewUniform(bn256.Order)
	last := big.NewInt(0)
	for _, e := range attrib {
		if e > numAttrib {
			return nil, fmt.Errorf("attributes out of range")
		}
		tmp, err := sampler.Sample()
		if err != nil {
			return nil, err
		}
		policyVec[e].Set(tmp)
		last.Sub(last, tmp)
	}
	policyVec[numAttrib].Set(last)

	return policyVec, nil
}

// AttributeVecInit given the attributes and the number of all possible
// attributes creates a vector describing the users allowance. The function is
// needed in the the transformation of the DIPPE scheme into an ABE scheme
// with threshold or conjugation.
func (d DIPPE) AttributeVecInit(attrib []int, numAttrib int) (data.Vector, error) {
	attribVec := data.NewConstantVector(numAttrib+1, big.NewInt(0))
	one := big.NewInt(1)
	for _, e := range attrib {
		if e > numAttrib {
			return nil, fmt.Errorf("attributes out of range")
		}
		attribVec[e].Set(one)
	}
	attribVec[numAttrib].Set(one)

	return attribVec, nil
}


================================================
FILE: abe/dippe_test.go
================================================
/*
 * Copyright (c) 2018 XLAB d.o.o
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package abe_test

import (
	"testing"

	"math/big"

	"github.com/fentec-project/gofe/abe"
	"github.com/fentec-project/gofe/data"
	"github.com/stretchr/testify/assert"
)

func TestDIPPE(t *testing.T) {
	// create a new DIPPE struct, choosing the security parameter
	d, err := abe.NewDIPPE(3)
	if err != nil {
		t.Fatalf("Failed to generate a new scheme: %v", err)
	}
	vecLen := 5

	// create authorities and their public keys
	auth := make([]*abe.DIPPEAuth, vecLen)
	pubKeys := make([]*abe.DIPPEPubKey, vecLen)
	for i := range auth {
		auth[i], err = d.NewDIPPEAuth(i)
		if err != nil {
			t.Fatalf("Failed to generate a new authority: %v", err)
		}
		pubKeys[i] = &auth[i].Pk
	}

	msg := "some message"

	// choose a policy vector
	policyVec := data.Vector([]*big.Int{big.NewInt(1), big.NewInt(-1),
		big.NewInt(1), big.NewInt(0), big.NewInt(0)})

	// encrypt the message with the chosen policy give by a policy vector,
	cipher, err := d.Encrypt(msg, policyVec, pubKeys)
	if err != nil {
		t.Fatalf("Failed to encrypt: %v", err)
	}

	// choose a unique user's GID
	userGID := "someGID"
	// choose user's vector, decryption is possible if and only if
	// the users's and policy vector are orthogonal
	userVec := data.Vector([]*big.Int{big.NewInt(0), big.NewInt(1),
		big.NewInt(1), big.NewInt(-3), big.NewInt(4)})

	// authorities generate decryption keys for the user
	userKeys := make([]data.VectorG2, vecLen)
	for i := range auth {
		userKeys[i], err = auth[i].DeriveKeyShare(userVec, pubKeys, userGID)
		if err != nil {
			t.Fatalf("Failed to generate a user key: %v", err)
		}
	}

	// user decrypts using collected keys
	dec, err := d.Decrypt(cipher, userKeys, userVec, userGID)
	if err != nil {
		t.Fatalf("Failed to decrypt: %v", err)
	}
	assert.Equal(t, msg, dec)
}

func TestDIPPE_ABE_threshold(t *testing.T) {
	// this test transforms DIPPE scheme into an ABE scheme
	// with the exact threshold policy; in threshold policy each user has
	// attributes but only the users that have exactly the
	// threshold value of specified attributes can decrypt

	// create a new DIPPE struct, choosing the security parameter
	d, err := abe.NewDIPPE(3)
	if err != nil {
		t.Fatalf("Failed to generate a new scheme: %v", err)
	}
	// specify the number of all attributes
	numAttrib := 10

	// create authorities and their public keys
	auth := make([]*abe.DIPPEAuth, numAttrib+1)
	pubKeys := make([]*abe.DIPPEPubKey, numAttrib+1)
	for i := range auth {
		auth[i], err = d.NewDIPPEAuth(i)
		if err != nil {
			t.Fatalf("Failed to generate a new authority: %v", err)
		}
		pubKeys[i] = &auth[i].Pk
	}

	msg := "some important message"

	// choose attributes needed for the exact threshold policy and the
	// threshold value
	thresholdAttrib := []int{0, 2, 5, 8, 9}
	exactThreshold := 3
	// generate the exact threshold vector (this conversion allows the
	// DIPPE scheme to be used as an ABE threshold scheme)
	thresholdPolicyVec, err := d.ExactThresholdPolicyVecInit(thresholdAttrib, exactThreshold, numAttrib)
	if err != nil {
		t.Fatalf("Failed to generate threshold vector: %v", err)
	}

	// encrypt the message with the chosen threshold policy
	thresholdCipher, err := d.Encrypt(msg, thresholdPolicyVec, pubKeys)
	if err != nil {
		t.Fatalf("Failed to encrypt: %v", err)
	}

	// choose a unique user's GID
	thresholdUserGID := "thresholdGID"

	// choose the attributes possessed by the users
	thresholdUserAttrib := []int{0, 1, 5, 7, 9}

	// generate user's vector
	thresholdUserVec, err := d.AttributeVecInit(thresholdUserAttrib, numAttrib)
	if err != nil {
		t.Fatalf("Failed to generate attributes vector: %v", err)
	}

	// authorities generate decryption keys for the user
	thresholdUserKeys := make([]data.VectorG2, len(auth))
	for i := range auth {
		thresholdUserKeys[i], err = auth[i].DeriveKeyShare(thresholdUserVec, pubKeys, thresholdUserGID)
		if err != nil {
			t.Fatalf("Failed to generate a user key: %v", err)
		}
	}

	// user decrypts using collected keys
	dec, err := d.Decrypt(thresholdCipher, thresholdUserKeys, thresholdUserVec, thresholdUserGID)
	if err != nil {
		t.Fatalf("Failed to decrypt: %v", err)
	}
	assert.Equal(t, msg, dec)
}

func TestDIPPE_ABE_conjugation(t *testing.T) {
	// this test transforms DIPPE scheme into an ABE scheme
	// with the conjugation policy; in the conjugation policy
	// the user must have all the specified attributes to be
	// able to decrypt

	// create a new DIPPE struct, choosing the security parameter
	d, err := abe.NewDIPPE(3)
	if err != nil {
		t.Fatalf("Failed to generate a new scheme: %v", err)
	}
	// specify the number of all attributes
	numAttrib := 10

	// create authorities and their public keys
	auth := make([]*abe.DIPPEAuth, numAttrib+1)
	pubKeys := make([]*abe.DIPPEPubKey, numAttrib+1)
	for i := range auth {
		auth[i], err = d.NewDIPPEAuth(i)
		if err != nil {
			t.Fatalf("Failed to generate a new authority: %v", err)
		}
		pubKeys[i] = &auth[i].Pk
	}

	msg := "some important message"

	// choose attributes needed for the conjunction policy
	conjunctAttrib := []int{1, 2, 3, 7}
	// generate the conjunction vector (this conversion allows the
	// DIPPE scheme to be used as an ABE conjunction scheme)
	conjunctPolicyVec, err := d.ConjunctionPolicyVecInit(conjunctAttrib, numAttrib)
	if err != nil {
		t.Fatalf("Failed to generate conjucnction vector: %v", err)
	}

	// encrypt the message with the chosen conjunction policy
	conjunctCipher, err := d.Encrypt(msg, conjunctPolicyVec, pubKeys)
	if err != nil {
		t.Fatalf("Failed to encrypt: %v", err)
	}

	// choose a unique user's GID
	conjunctUserGID := "conjunctionGID"

	// choose the attributes possessed by the user
	conjunctUserAttrib := []int{0, 1, 2, 3, 7, 9}

	// generate user's vector
	conjunctUserVec, err := d.AttributeVecInit(conjunctUserAttrib, numAttrib)
	if err != nil {
		t.Fatalf("Failed to generate attributes vector: %v", err)
	}

	// authorities generate decryption keys for the user
	conjunctUserKeys := make([]data.VectorG2, len(auth))
	for i := range auth {
		conjunctUserKeys[i], err = auth[i].DeriveKeyShare(conjunctUserVec, pubKeys, conjunctUserGID)
		if err != nil {
			t.Fatalf("Failed to generate a user key: %v", err)
		}
	}

	// user decrypts using collected keys
	dec, err := d.Decrypt(conjunctCipher, conjunctUserKeys, conjunctUserVec, conjunctUserGID)
	if err != nil {
		t.Fatalf("Failed to decrypt: %v", err)
	}
	assert.Equal(t, msg, dec)
}


================================================
FILE: abe/doc.go
================================================
/*
 * Copyright (c) 2018 XLAB d.o.o
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// Package abe includes schemes allowing attribute based encryption.
package abe


================================================
FILE: abe/fame.go
================================================
/*
 * Copyright (c) 2018 XLAB d.o.o
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package abe

import (
	"math/big"

	"fmt"
	"strconv"

	"crypto/aes"
	cbc "crypto/cipher"
	"crypto/rand"
	"crypto/sha256"

	"io"

	"github.com/fentec-project/bn256"
	"github.com/fentec-project/gofe/data"
	"github.com/fentec-project/gofe/sample"
)

// This is a ciphertext policy (CP) attribute based (ABE) scheme based
// on Shashank Agrawal, Melissa Chase:
// "FAME: Fast Attribute-based Message Encryption"
//
// This scheme enables encryption based on a boolean expression
// determining which attributes are needed for an entity to be able
// to decrypt. Moreover, secret keys are generated, where each key
// is connected to some attribute, such that only a set of keys whose
// attributes are sufficient can decrypt the massage.
// This scheme is a PUBLIC-KEY scheme - no master secret key is needed
// to encrypt the messages.
//

// FAME represents a FAME scheme.
type FAME struct {
	P *big.Int // order of the elliptic curve
}

// NewFAME configures a new instance of the scheme.
func NewFAME() *FAME {
	return &FAME{P: bn256.Order}
}

// FAMESecKey represents a master secret key of a FAME scheme.
type FAMESecKey struct {
	PartInt [4]*big.Int
	PartG1  [3]*bn256.G1
}

// FAMEPubKey represents a public key of a FAME scheme.
type FAMEPubKey struct {
	PartG2 [2]*bn256.G2
	PartGT [2]*bn256.GT
}

// GenerateMasterKeys generates a new set of public keys, needed
// for encrypting data, and master secret keys needed for generating
// keys for decrypting.
func (a *FAME) GenerateMasterKeys() (*FAMEPubKey, *FAMESecKey, error) {
	sampler := sample.NewUniformRange(big.NewInt(1), a.P)
	val, err := data.NewRandomVector(7, sampler)
	if err != nil {
		return nil, nil, err
	}

	partInt := [4]*big.Int{val[0], val[1], val[2], val[3]}
	partG1 := [3]*bn256.G1{new(bn256.G1).ScalarBaseMult(val[4]),
		new(bn256.G1).ScalarBaseMult(val[5]),
		new(bn256.G1).ScalarBaseMult(val[6])}
	partG2 := [2]*bn256.G2{new(bn256.G2).ScalarBaseMult(val[0]),
		new(bn256.G2).ScalarBaseMult(val[1])}
	tmp1 := new(big.Int).Mod(new(big.Int).Add(new(big.Int).Mul(val[0], val[4]), val[6]), a.P)
	tmp2 := new(big.Int).Mod(new(big.Int).Add(new(big.Int).Mul(val[1], val[5]), val[6]), a.P)
	partGT := [2]*bn256.GT{new(bn256.GT).ScalarBaseMult(tmp1),
		new(bn256.GT).ScalarBaseMult(tmp2)}

	return &FAMEPubKey{PartG2: partG2, PartGT: partGT},
		&FAMESecKey{PartInt: partInt, PartG1: partG1}, nil
}

// FAMECipher represents a ciphertext of a FAME scheme.
type FAMECipher struct {
	Ct0     [3]*bn256.G2
	Ct      [][3]*bn256.G1
	CtPrime *bn256.GT
	Msp     *MSP
	SymEnc  []byte // symmetric encryption of the message
	Iv      []byte // initialization vector for symmetric encryption
}

// Encrypt takes as an input a message msg represented as an element of an elliptic
// curve, a MSP struct representing the decryption policy, and a public key pk. It
// returns an encryption of the message. In case of a failed procedure an error
// is returned. Note that safety of the encryption is only proved if the mapping
// msp.RowToAttrib from the rows of msp.Mat to attributes is injective.
func (a *FAME) Encrypt(msg string, msp *MSP, pk *FAMEPubKey) (*FAMECipher, error) {
	if len(msp.Mat) == 0 || len(msp.Mat[0]) == 0 {
		return nil, fmt.Errorf("empty msp matrix")
	}

	attrib := make(map[string]bool)
	for _, i := range msp.RowToAttrib {
		if attrib[i] {
			return nil, fmt.Errorf("some attributes correspond to" +
				"multiple rows of the MSP struct, the scheme is not secure")
		}
		attrib[i] = true
	}

	// msg is encrypted using CBC, with a random key that is encapsulated
	// with FAME
	_, keyGt, err := bn256.RandomGT(rand.Reader)
	if err != nil {
		return nil, err
	}
	keyCBC := sha256.Sum256([]byte(keyGt.String()))

	c, err := aes.NewCipher(keyCBC[:])
	if err != nil {
		return nil, err
	}

	iv := make([]byte, c.BlockSize())
	_, err = io.ReadFull(rand.Reader, iv)
	if err != nil {
		return nil, err
	}
	encrypterCBC := cbc.NewCBCEncrypter(c, iv)

	msgByte := []byte(msg)

	// message is padded according to pkcs7 standard
	padLen := c.BlockSize() - (len(msgByte) % c.BlockSize())
	msgPad := make([]byte, len(msgByte)+padLen)
	copy(msgPad, msgByte)
	for i := len(msgByte); i < len(msgPad); i++ {
		msgPad[i] = byte(padLen)
	}

	symEnc := make([]byte, len(msgPad))
	encrypterCBC.CryptBlocks(symEnc, msgPad)

	// encapsulate the key with FAME
	sampler := sample.NewUniform(a.P)
	s, err := data.NewRandomVector(2, sampler)
	if err != nil {
		return nil, err
	}
	ct0 := [3]*bn256.G2{new(bn256.G2).ScalarMult(pk.PartG2[0], s[0]),
		new(bn256.G2).ScalarMult(pk.PartG2[1], s[1]),
		new(bn256.G2).ScalarBaseMult(new(big.Int).Add(s[0], s[1]))}

	ct := make([][3]*bn256.G1, len(msp.Mat))
	for i := 0; i < len(msp.Mat); i++ {
		for l := 0; l < 3; l++ {
			hs1, err := bn256.HashG1(msp.RowToAttrib[i] + " " + strconv.Itoa(l) + " 0")
			if err != nil {
				return nil, err
			}
			hs1.ScalarMult(hs1, s[0])

			hs2, err := bn256.HashG1(msp.RowToAttrib[i] + " " + strconv.Itoa(l) + " 1")
			if err != nil {
				return nil, err
			}
			hs2.ScalarMult(hs2, s[1])

			ct[i][l] = new(bn256.G1).Add(hs1, hs2)
			for j := 0; j < len(msp.Mat[0]); j++ {
				hs1, err = bn256.HashG1("0 " + strconv.Itoa(j) + " " + strconv.Itoa(l) + " 0")
				if err != nil {
					return nil, err
				}
				hs1.ScalarMult(hs1, s[0])

				hs2, err = bn256.HashG1("0 " + strconv.Itoa(j) + " " + strconv.Itoa(l) + " 1")
				if err != nil {
					return nil, err
				}
				hs2.ScalarMult(hs2, s[1])

				hsToM := new(bn256.G1).Add(hs1, hs2)
				pow := new(big.Int).Set(msp.Mat[i][j])
				if pow.Sign() == -1 {
					pow.Neg(pow)
					hsToM.ScalarMult(hsToM, pow)
					hsToM.Neg(hsToM)
				} else {
					hsToM.ScalarMult(hsToM, pow)
				}
				ct[i][l].Add(ct[i][l], hsToM)
			}
		}
	}

	ctPrime := new(bn256.GT).ScalarMult(pk.PartGT[0], s[0])
	ctPrime.Add(ctPrime, new(bn256.GT).ScalarMult(pk.PartGT[1], s[1]))
	ctPrime.Add(ctPrime, keyGt)

	return &FAMECipher{Ct0: ct0, Ct: ct, CtPrime: ctPrime, Msp: msp, SymEnc: symEnc, Iv: iv}, nil
}

// FAMEAttribKeys represents keys corresponding to attributes possessed by
// an entity and used for decrypting in a FAME scheme.
type FAMEAttribKeys struct {
	K0        [3]*bn256.G2
	K         [][3]*bn256.G1
	KPrime    [3]*bn256.G1
	AttribToI map[string]int
}

// GenerateAttribKeys given a set of attributes gamma and the master secret key
// generates keys that can be used for the decryption of any ciphertext encoded
// with a policy for which attributes gamma are sufficient.
func (a *FAME) GenerateAttribKeys(gamma []string, sk *FAMESecKey) (*FAMEAttribKeys, error) {
	sampler := sample.NewUniform(a.P)
	r, err := data.NewRandomVector(2, sampler)
	if err != nil {
		return nil, err
	}
	sigma, err := data.NewRandomVector(len(gamma), sampler)
	if err != nil {
		return nil, err
	}

	pow0 := new(big.Int).Mul(sk.PartInt[2], r[0])
	pow0.Mod(pow0, a.P)
	pow1 := new(big.Int).Mul(sk.PartInt[3], r[1])
	pow1.Mod(pow1, a.P)
	pow2 := new(big.Int).Add(r[0], r[1])
	pow2.Mod(pow2, a.P)

	k0 := [3]*bn256.G2{new(bn256.G2).ScalarBaseMult(pow0),
		new(bn256.G2).ScalarBaseMult(pow1),
		new(bn256.G2).ScalarBaseMult(pow2)}

	a0Inv := new(big.Int).ModInverse(sk.PartInt[0], a.P)
	a1Inv := new(big.Int).ModInverse(sk.PartInt[1], a.P)
	aInv := [2]*big.Int{a0Inv, a1Inv}

	k := make([][3]*bn256.G1, len(gamma))
	attribToI := make(map[string]int)
	for i, y := range gamma {
		k[i] = [3]*bn256.G1{new(bn256.G1), new(bn256.G1), new(bn256.G1)}
		gSigma := new(bn256.G1).ScalarBaseMult(sigma[i])
		for t := 0; t < 2; t++ {
			hs0, err := bn256.HashG1(y + " 0 " + strconv.Itoa(t))
			if err != nil {
				return nil, err
			}
			hs0.ScalarMult(hs0, pow0)
			hs1, err := bn256.HashG1(y + " 1 " + strconv.Itoa(t))
			if err != nil {
				return nil, err
			}
			hs1.ScalarMult(hs1, pow1)
			hs2, err := bn256.HashG1(y + " 2 " + strconv.Itoa(t))
			if err != nil {
				return nil, err
			}
			hs2.ScalarMult(hs2, pow2)

			k[i][t].Add(hs0, hs1)
			k[i][t].Add(k[i][t], hs2)
			k[i][t].Add(k[i][t], gSigma)
			k[i][t].ScalarMult(k[i][t], aInv[t])
		}

		k[i][2].ScalarBaseMult(sigma[i])
		k[i][2].Neg(k[i][2])

		attribToI[y] = i
	}

	sigmaPrime, err := sampler.Sample()
	if err != nil {
		return nil, err
	}
	gSigmaPrime := new(bn256.G1).ScalarBaseMult(sigmaPrime)

	k2 := [3]*bn256.G1{new(bn256.G1), new(bn256.G1), new(bn256.G1)}
	for t := 0; t < 2; t++ {
		hs0, err := bn256.HashG1("0 0 0 " + strconv.Itoa(t))
		if err != nil {
			return nil, err
		}
		hs0.ScalarMult(hs0, pow0)
		hs1, err := bn256.HashG1("0 0 1 " + strconv.Itoa(t))
		if err != nil {
			return nil, err
		}
		hs1.ScalarMult(hs1, pow1)
		hs2, err := bn256.HashG1("0 0 2 " + strconv.Itoa(t))
		if err != nil {
			return nil, err
		}
		hs2.ScalarMult(hs2, pow2)

		k2[t].Add(hs0, hs1)
		k2[t].Add(k2[t], hs2)
		k2[t].Add(k2[t], gSigmaPrime)
		k2[t].ScalarMult(k2[t], aInv[t])
		k2[t].Add(k2[t], sk.PartG1[t])
	}

	k2[2].ScalarBaseMult(sigmaPrime)
	k2[2].Neg(k2[2])
	k2[2].Add(k2[2], sk.PartG1[2])

	return &FAMEAttribKeys{K0: k0, K: k, KPrime: k2, AttribToI: attribToI}, nil
}

// Decrypt takes as an input a cipher and an FAMEAttribKeys and tries to decrypt
// the cipher. This is possible only if the set of possessed attributes (and
// corresponding keys FAMEAttribKeys) suffices the encryption policy of the
// cipher. If this is not possible, an error is returned.
func (a *FAME) Decrypt(cipher *FAMECipher, key *FAMEAttribKeys, pk *FAMEPubKey) (string, error) {
	// find out which attributes are owned
	attribMap := make(map[string]bool)
	for k := range key.AttribToI {
		attribMap[k] = true
	}

	countAttrib := 0
	for i := 0; i < len(cipher.Msp.Mat); i++ {
		if attribMap[cipher.Msp.RowToAttrib[i]] {
			countAttrib++
		}
	}

	// create a matrix of needed keys
	preMatForKey := make([]data.Vector, countAttrib)
	ctForKey := make([][3]*bn256.G1, countAttrib)
	rowToAttrib := make([]string, countAttrib)
	countAttrib = 0
	for i := 0; i < len(cipher.Msp.Mat); i++ {
		if attribMap[cipher.Msp.RowToAttrib[i]] {
			preMatForKey[countAttrib] = cipher.Msp.Mat[i]
			ctForKey[countAttrib] = cipher.Ct[i]
			rowToAttrib[countAttrib] = cipher.Msp.RowToAttrib[i]
			countAttrib++
		}
	}

	matForKey, err := data.NewMatrix(preMatForKey)
	if err != nil {
		return "", fmt.Errorf("the provided cipher is faulty")
	}

	// matForKey may have a len of 0 if there is a single condition
	if len(matForKey) == 0 {
		return "", fmt.Errorf("provided key is not sufficient for decryption")
	}

	// get a combination alpha of keys needed to decrypt
	// matForKey may have a len of 0 if there is a single condition
	if len(matForKey) == 0 {
		return "", fmt.Errorf("provided key is not sufficient for decryption")
	}
	oneVec := data.NewConstantVector(len(matForKey[0]), big.NewInt(0))
	oneVec[0].SetInt64(1)
	alpha, err := data.GaussianEliminationSolver(matForKey.Transpose(), oneVec, a.P)
	if err != nil {
		return "", fmt.Errorf("provided key is not sufficient for decryption")
	}

	// get a CBC key needed for the decryption of msg
	keyGt := new(bn256.GT).Set(cipher.CtPrime)

	ctProd := new([3]*bn256.G1)
	keyProd := new([3]*bn256.G1)
	for j := 0; j < 3; j++ {
		ctProd[j] = new(bn256.G1).ScalarBaseMult(big.NewInt(0))
		keyProd[j] = new(bn256.G1).ScalarBaseMult(big.NewInt(0))
		for i, e := range rowToAttrib {
			ctProd[j].Add(ctProd[j], new(bn256.G1).ScalarMult(ctForKey[i][j], alpha[i]))
			keyProd[j].Add(keyProd[j], new(bn256.G1).ScalarMult(key.K[key.AttribToI[e]][j], alpha[i]))
		}
		keyProd[j].Add(keyProd[j], key.KPrime[j])
		ctPairing := bn256.Pair(ctProd[j], key.K0[j])
		keyPairing := bn256.Pair(keyProd[j], cipher.Ct0[j])
		keyPairing.Neg(keyPairing)
		keyGt.Add(keyGt, ctPairing)
		keyGt.Add(keyGt, keyPairing)
	}

	keyCBC := sha256.Sum256([]byte(keyGt.String()))

	c, err := aes.NewCipher(keyCBC[:])
	if err != nil {
		return "", err
	}

	msgPad := make([]byte, len(cipher.SymEnc))
	decrypter := cbc.NewCBCDecrypter(c, cipher.Iv)
	decrypter.CryptBlocks(msgPad, cipher.SymEnc)

	// unpad the message
	padLen := int(msgPad[len(msgPad)-1])
	if (len(msgPad) - padLen) < 0 {
		return "", fmt.Errorf("failed to decrypt")
	}
	msgByte := msgPad[0:(len(msgPad) - padLen)]

	return string(msgByte), nil
}


================================================
FILE: abe/fame_test.go
================================================
/*
 * Copyright (c) 2018 XLAB d.o.o
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package abe_test

import (
	"testing"

	"github.com/fentec-project/gofe/abe"
	"github.com/stretchr/testify/assert"
)

func TestFAME(t *testing.T) {
	// create a new FAME struct with the universe of attributes
	// denoted by integer
	a := abe.NewFAME()

	// generate a public key and a secret key for the scheme
	pubKey, secKey, err := a.GenerateMasterKeys()
	if err != nil {
		t.Fatalf("Failed to generate master keys: %v", err)
	}

	// create a message to be encrypted
	msg := "Attack at dawn!"

	// create a msp struct out of a boolean expression representing the
	// policy specifying which attributes are needed to decrypt the ciphertext;
	// the boolean expression is a string of attributes joined by AND and OR
	// hence the names of the attributes should not include "AND" or "OR"
	// as a substring and '(' or ')' as a character

	// note that safety of the encryption is only proved if the mapping
	// msp.RowToAttrib from the rows of msp.Mat to attributes is injective, i.e.
	// only boolean expressions in which each attribute appears at most once
	// are allowed - if expressions with multiple appearances of an attribute
	// are needed, then this attribute can be split into more sub-attributes
	msp, err := abe.BooleanToMSP("((0 AND 1) OR (2 AND 3)) AND 5", false)
	if err != nil {
		t.Fatalf("Failed to generate the policy: %v", err)
	}

	// encrypt the message msg with the decryption policy specified by the
	// msp structure
	cipher, err := a.Encrypt(msg, msp, pubKey)
	if err != nil {
		t.Fatalf("Failed to encrypt: %v", err)
	}

	// define a set of attributes (a subset of the universe of attributes)
	// that an entity possesses
	gamma := []string{"0", "2", "3", "5"}

	// generate keys for decryption for an entity with
	// attributes gamma
	keys, err := a.GenerateAttribKeys(gamma, secKey)
	if err != nil {
		t.Fatalf("Failed to generate keys: %v", err)
	}

	// decrypt the ciphertext with the keys of an entity
	// that has sufficient attributes
	msgCheck, err := a.Decrypt(cipher, keys, pubKey)
	if err != nil {
		t.Fatalf("Failed to decrypt: %v", err)
	}
	assert.Equal(t, msg, msgCheck)

	// define a set of attributes (a subset of the universe of attributes)
	// that an entity possesses
	gammaInsuff := []string{"1", "3", "5"}

	// generate keys for decryption for an entity with
	// attributes gammaInsuff
	keysInsuff, err := a.GenerateAttribKeys(gammaInsuff, secKey)
	if err != nil {
		t.Fatalf("Failed to generate keys: %v", err)
	}

	// try to decrypt the ciphertext with the keys of an entity
	// that has insufficient attributes
	_, err = a.Decrypt(cipher, keysInsuff, pubKey)
	assert.Error(t, err)

	mspSingleCondition, err := abe.BooleanToMSP("0", false)
	if err != nil {
		t.Fatalf("Failed to generate the policy: %v", err)
	}

	// encrypt the message msg with the decryption policy specified by the
	// msp structure
	cipherSingleCondition, err := a.Encrypt(msg, mspSingleCondition, pubKey)
	if err != nil {
		t.Fatalf("Failed to encrypt: %v", err)
	}

	msgCheckSingleCondition, err := a.Decrypt(cipherSingleCondition, keys, pubKey)
	if err != nil {
		t.Fatalf("Failed to decrypt: %v", err)
	}
	assert.Equal(t, msg, msgCheckSingleCondition)

	_, err = a.Decrypt(cipherSingleCondition, keysInsuff, pubKey)
	assert.Error(t, err)

	// test with Single UUID
	mspSingleUUID, err := abe.BooleanToMSP("123e4567-e89b-12d3-a456-426655440000", false)

	if err != nil {
		t.Fatalf("Failed to generate the policy: %v", err)
	}

	cipherSingleUUID, err := a.Encrypt(msg, mspSingleUUID, pubKey)
	if err != nil {
		t.Fatalf("Failed to encrypt: %v", err)
	}

	// define a set of attributes (a subset of the universe of attributes)
	// that an entity possesses
	gammaUUID := []string{"123e4567-e89b-12d3-a456-426655440000", "123e4567-e89b-12d3-a456-4266554400001"}

	// generate keys for decryption for an entity with
	// attributes gamma
	keysUUID, err := a.GenerateAttribKeys(gammaUUID, secKey)
	if err != nil {
		t.Fatalf("Failed to generate keys: %v", err)
	}

	// decrypt the ciphertext with the keys of an entity
	// that has sufficient attributes
	msgCheckSingleUUID, err := a.Decrypt(cipherSingleUUID, keysUUID, pubKey)
	if err != nil {
		t.Fatalf("Failed to decrypt: %v", err)
	}
	assert.Equal(t, msg, msgCheckSingleUUID)

	// define a set of attributes (a subset of the universe of attributes)
	// that an entity possesses
	gammaInsuffUUID := []string{"123e4567-e89b-12d3-a456-426655440099"}

	// generate keys for decryption for an entity with
	// attributes gammaInsuff
	keysInsuffUUID, err := a.GenerateAttribKeys(gammaInsuffUUID, secKey)
	if err != nil {
		t.Fatalf("Failed to generate keys: %v", err)
	}

	// try to decrypt the ciphertext with the keys of an entity
	// that has insufficient attributes
	_, err = a.Decrypt(cipherSingleUUID, keysInsuffUUID, pubKey)
	assert.Error(t, err)

	//
	// test with Multi UUID
	mspMultiUUID, err := abe.BooleanToMSP("123e4567-e89b-12d3-a456-426655440000 OR 123e4567-e89b-12d3-a456-426655440001", false)
	if err != nil {
		t.Fatalf("Failed to generate the policy: %v", err)
	}

	cipherMultiUUID, err := a.Encrypt(msg, mspMultiUUID, pubKey)
	if err != nil {
		t.Fatalf("Failed to encrypt: %v", err)
	}

	// decrypt the ciphertext with the keys of an entity
	// that has sufficient attributes
	msgCheckMultiUUID, err := a.Decrypt(cipherMultiUUID, keysUUID, pubKey)
	if err != nil {
		t.Fatalf("Failed to decrypt: %v", err)
	}
	assert.Equal(t, msg, msgCheckMultiUUID)

	// try to decrypt the ciphertext with the keys of an entity
	// that has insufficient attributes
	_, err = a.Decrypt(cipherMultiUUID, keysInsuffUUID, pubKey)
	assert.Error(t, err)
}


================================================
FILE: abe/gpsw.go
================================================
/*
 * Copyright (c) 2018 XLAB d.o.o
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package abe

import (
	"crypto/aes"
	cbc "crypto/cipher"
	"crypto/rand"
	"crypto/sha256"
	"fmt"
	"math/big"

	"io"

	"strconv"

	"github.com/fentec-project/bn256"
	"github.com/fentec-project/gofe/data"
	"github.com/fentec-project/gofe/sample"
)

// This is a key policy (KP) attribute based (ABE) scheme based on
// Goyal, Pandey, Sahai, Waters:
// "Attribute-Based Encryption for Fine-Grained Access Control of
// Encrypted Data"
//
// We abbreviated it GPSW scheme to honor the authors. This scheme
// enables encrypting data associated with a set of attributes and
// generating keys associated with boolean expressions determining the
// policy. A user that owns such a key can decrypt the ciphertext
// only if the attributes associated to the ciphertext satisfy the
//policy associated to the key.
// This scheme is a PUBLIC-KEY scheme - no master secret key is needed
// to encrypt the messages.

// GPSWParams represents configuration parameters for the GPSW ABE-scheme instance.
type GPSWParams struct {
	L int      // number of attributes
	P *big.Int // order of the elliptic curve
}

// GPSW represents an GPSW ABE-scheme.
type GPSW struct {
	Params *GPSWParams
}

// NewGPSW configures a new instance of the scheme.
// It accepts l the number of attributes possibly used in
// the scheme. Attributes' names will be considered as
// elements of a set {0, 1,..., l-1}.
func NewGPSW(l int) *GPSW {
	return &GPSW{Params: &GPSWParams{
		L: l,           // number of attributes in the whole universe
		P: bn256.Order, // the order of the pairing groups
	}}
}

// GPSWPubKey represents a public key of the GPSW ABE-scheme.
type GPSWPubKey struct {
	T data.VectorG2
	Y *bn256.GT
}

// GenerateMasterKeys generates a new set of public keys, needed
// for encrypting data, and secret keys needed for generating keys
// for decryption.
func (a *GPSW) GenerateMasterKeys() (*GPSWPubKey, data.Vector, error) {
	sampler := sample.NewUniform(a.Params.P)
	sk, err := data.NewRandomVector(a.Params.L+1, sampler)
	if err != nil {
		return nil, nil, err
	}
	t := sk[:a.Params.L].MulG2()
	y := new(bn256.GT).ScalarBaseMult(sk[a.Params.L])

	return &GPSWPubKey{T: t, Y: y}, sk, nil
}

// GPSWCipher represents a ciphertext of the GPSW ABE-scheme.
type GPSWCipher struct {
	Gamma     []int         // the set of attributes that can be used for policy of decryption
	AttribToI map[int]int   // a map that connects the attributes in gamma with elements of e
	E0        *bn256.GT     // the first part of the encryption
	E         data.VectorG2 // the second part of the encryption
	SymEnc    []byte        // symmetric encryption of the message
	Iv        []byte        // initialization vector for symmetric encryption
}

// Encrypt takes as an input a message msg given as a string, gamma a set (slice)
// of attributes that will be associated with the encryption and a public
// key pk. It returns an encryption of msg. In case of a failed procedure an
// error is returned.
func (a *GPSW) Encrypt(msg string, gamma interface{}, pk *GPSWPubKey) (*GPSWCipher, error) {
	var gammaI []int
	switch gamma.(type) {
	default:
		return nil, fmt.Errorf("attributes should be of type []int or []string of integers")
	case []int:
		gammaI = gamma.([]int)
	case []string:
		gammaI = make([]int, len(gamma.([]string)))
		for i, e := range gamma.([]string) {
			att, err := strconv.Atoi(e)
			if err != nil {
				return nil, err
			}
			gammaI[i] = att
		}
	}

	// msg is encrypted using CBC, with a random key that is encapsulated
	// with GPSW
	_, keyGt, err := bn256.RandomGT(rand.Reader)
	if err != nil {
		return nil, err
	}
	keyCBC := sha256.Sum256([]byte(keyGt.String()))

	c, err := aes.NewCipher(keyCBC[:])
	if err != nil {
		return nil, err
	}

	iv := make([]byte, c.BlockSize())
	_, err = io.ReadFull(rand.Reader, iv)
	if err != nil {
		return nil, err
	}
	encrypterCBC := cbc.NewCBCEncrypter(c, iv)

	msgByte := []byte(msg)
	// message is padded according to pkcs7 standard
	padLen := c.BlockSize() - (len(msgByte) % c.BlockSize())
	msgPad := make([]byte, len(msgByte)+padLen)
	copy(msgPad, msgByte)
	for i := len(msgByte); i < len(msgPad); i++ {
		msgPad[i] = byte(padLen)
	}

	symEnc := make([]byte, len(msgPad))
	encrypterCBC.CryptBlocks(symEnc, msgPad)

	// encapsulate the key with GPSW
	sampler := sample.NewUniform(a.Params.P)
	s, err := sampler.Sample()
	if err != nil {
		return nil, err
	}

	e0 := new(bn256.GT).Add(keyGt, new(bn256.GT).ScalarMult(pk.Y, s))
	e := make(data.VectorG2, len(gammaI))
	attribToI := make(map[int]int)
	for i, el := range gammaI {
		e[i] = new(bn256.G2).ScalarMult(pk.T[el], s)
		attribToI[el] = i
	}

	return &GPSWCipher{Gamma: gammaI,
		AttribToI: attribToI,
		E0:        e0,
		E:         e,
		SymEnc:    symEnc,
		Iv:        iv}, nil
}

// GPSWKey represents a key structure for decrypting a ciphertext. It includes
// a msp structure (policy) associated with the key and a vector D representing
// the main part of the key.
type GPSWKey struct {
	Msp         *MSP
	D           data.VectorG1
}

// GeneratePolicyKey given a monotone span program (MSP) msp and the vector of secret
// keys produces an ABE key associated with the policy given by MSP. In particular,
// this key can be used to decrypt any cipertext associated with attributes that
// satisfy given policy.
func (a *GPSW) GeneratePolicyKey(msp *MSP, sk data.Vector) (*GPSWKey, error) {
	if len(msp.Mat) == 0 || len(msp.Mat[0]) == 0 {
		return nil, fmt.Errorf("empty msp matrix")
	}
	if len(sk) != (a.Params.L + 1) {
		return nil, fmt.Errorf("the secret key has wrong length")
	}

	u, err := getSum(sk[a.Params.L], a.Params.P, len(msp.Mat[0]))
	if err != nil {
		return nil, err
	}

	key := make(data.VectorG1, len(msp.Mat))

	for i := 0; i < len(msp.Mat); i++ {
		attrib, err := strconv.Atoi(msp.RowToAttrib[i])
		if err != nil {
			return nil, err
		}
		if 0 > attrib || a.Params.L <= attrib {
			return nil, fmt.Errorf("attributes of msp not in the universe of a")
		}

		tMapIInv := new(big.Int).ModInverse(sk[attrib], a.Params.P)
		matTimesU, err := msp.Mat[i].Dot(u)
		if err != nil {
			return nil, err
		}
		pow := new(big.Int).Mul(tMapIInv, matTimesU)
		pow.Mod(pow, a.Params.P)
		key[i] = new(bn256.G1).ScalarBaseMult(pow)
	}

	return &GPSWKey{Msp: msp, D: key}, nil
}

// getSum is a helping function that given integers y, p and d generates a
// random d dimensional vector over Z_p whose entries sum to y in Z_p.
func getSum(y *big.Int, p *big.Int, d int) (data.Vector, error) {
	sampler := sample.NewUniform(p)
	ret, err := data.NewRandomVector(d, sampler)
	if err != nil {
		return nil, err
	}
	sum := big.NewInt(0)
	for i := 0; i < d-1; i++ {
		sum.Add(sum, ret[i])
		sum.Mod(sum, p)
	}
	ret[d-1] = new(big.Int).Sub(y, sum)
	ret[d-1].Mod(ret[d-1], p)

	return ret, nil
}

// Decrypt takes as an input a cipher and an GPSWKey key and tries to decrypt
// the cipher. If the GPSWKey is properly generated, this is possible if and
// only if the set of attributes associated with the ciphertext satisfies the
// policy (boolean expression) of the key. This is if and only if the
// rows of the msp matrix in the key associated with the attributes of the
// ciphertext span the vector [1, 1,..., 1]. If this is not possible, an
//error is returned.
func (a *GPSW) Decrypt(cipher *GPSWCipher, key *GPSWKey) (string, error) {
	// get intersection of gamma and attributes used in the key policy
	gammaMap := make(map[int]bool)
	for _, e := range cipher.Gamma {
		gammaMap[e] = true
	}
	intersection := make([]int, 0)
	mat := make(data.Matrix, 0)
	d := make(data.VectorG1, 0)
	for i := 0; i < len(key.Msp.Mat); i++ {
		attrib, err := strconv.Atoi(key.Msp.RowToAttrib[i])
		if err != nil {
			return "", err
		}
		if gammaMap[attrib] {
			intersection = append(intersection, attrib)
			mat = append(mat, key.Msp.Mat[i])
			d = append(d, key.D[i])
		}
	}

	// get a combination alpha of keys needed to decrypt
	ones := data.NewConstantVector(len(mat[0]), big.NewInt(1))
	alpha, err := data.GaussianEliminationSolver(mat.Transpose(), ones, a.Params.P)
	if err != nil {
		return "", fmt.Errorf("the provided key is not sufficient for the decryption")
	}

	// get a CBC key needed for the decryption of msg
	keyGt := new(bn256.GT).Set(cipher.E0)
	for i := 0; i < len(alpha); i++ {
		pair := bn256.Pair(d[i], cipher.E[cipher.AttribToI[intersection[i]]])
		pair.ScalarMult(pair, alpha[i])
		pair.Neg(pair)
		keyGt.Add(keyGt, pair)
	}

	keyCBC := sha256.Sum256([]byte(keyGt.String()))

	c, err := aes.NewCipher(keyCBC[:])
	if err != nil {
		return "", err
	}

	msgPad := make([]byte, len(cipher.SymEnc))
	decrypter := cbc.NewCBCDecrypter(c, cipher.Iv)
	decrypter.CryptBlocks(msgPad, cipher.SymEnc)

	// unpad the message
	padLen := int(msgPad[len(msgPad)-1])
	if (len(msgPad) - padLen) < 0 {
		return "", fmt.Errorf("failed to decrypt")
	}
	msgByte := msgPad[0:(len(msgPad) - padLen)]

	return string(msgByte), nil
}


================================================
FILE: abe/gpsw_test.go
================================================
/*
 * Copyright (c) 2018 XLAB d.o.o
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package abe_test

import (
	"testing"

	"github.com/fentec-project/gofe/abe"
	"github.com/fentec-project/gofe/data"
	"github.com/stretchr/testify/assert"
)

func TestGPSW(t *testing.T) {
	// create a new GPSW struct with the universe of l possible
	// attributes (attributes are denoted by the integers in [0, l))
	l := 10
	a := abe.NewGPSW(l)

	// generate a public key and a secret key for the scheme
	pubKey, secKey, err := a.GenerateMasterKeys()
	if err != nil {
		t.Fatalf("Failed to generate master keys: %v", err)
	}

	// create two messages to be encrypted
	msg1 := "Attack at dawn!"
	msg2 := "More chocolate!"

	// define a set of attributes (a subset of the universe of attributes)
	// that will be associated with the encryptions
	gamma1 := []int{0, 4, 5} // could be given also as []string{"0", "4", "5"}
	gamma2 := []int{0, 1, 4} // could be given also as []string{"0", "1", "4"}

	// encrypt the first message with associated attributes gamma1
	cipher1, err := a.Encrypt(msg1, gamma1, pubKey)
	if err != nil {
		t.Fatalf("Failed to encrypt: %v", err)
	}

	// encrypt the second message with associated attributes gamma2
	cipher2, err := a.Encrypt(msg2, gamma2, pubKey)
	if err != nil {
		t.Fatalf("Failed to encrypt: %v", err)
	}

	// create a msp struct out of a boolean expression representing the
	// policy specifying which attributes are needed to decrypt the ciphertext;
	// the boolean expression is a string of attributes joined by AND and OR
	// where attributes are integers from the interval [0, l)

	// note that the safety of the encryption is only proved if the mapping
	// msp.RowToAttrib from the rows of msp.Mat to attributes is injective, i.e.
	// only boolean expressions in which each attribute appears at most once
	// are allowed - if expressions with multiple appearances of an attribute
	// are needed, then this attribute can be split into more sub-attributes
	msp, err := abe.BooleanToMSP("(1 OR 4) AND (2 OR (0 AND 5))", true)
	if err != nil {
		t.Fatalf("Failed to generate the policy: %v", err)
	}

	// generate a key for decryption that correspond to provided msp struct,
	// i.e. a key that can decrypt a message iff the attributes associated
	// with the ciphertext satisfy the boolean expression
	abeKey, err := a.GeneratePolicyKey(msp, secKey)
	if err != nil {
		t.Fatalf("Failed to generate keys: %v", err)
	}

	// test if error is returned when a bad Msp struct is given
	emptyMsp := &abe.MSP{Mat: make(data.Matrix, 0), RowToAttrib: make([]string, 0)}
	_, err = a.GeneratePolicyKey(emptyMsp, secKey)
	assert.Error(t, err)

	// decrypt the first ciphertext with abeKey
	msgCheck, err := a.Decrypt(cipher1, abeKey)
	if err != nil {
		t.Fatalf("Failed to decrypt: %v", err)
	}
	assert.Equal(t, msg1, msgCheck)

	// try to decrypt the second ciphertext but fail with abeKey
	_, err = a.Decrypt(cipher2, abeKey)
	assert.Error(t, err)
}


================================================
FILE: abe/ma-abe.go
================================================
/*
 * Copyright (c) 2021 XLAB d.o.o
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package abe

import (
    "crypto/aes"
    cbc "crypto/cipher"
    "crypto/rand"
    "crypto/sha256"
    "fmt"
    "math/big"
    "io"
    "github.com/fentec-project/bn256"
    "github.com/fentec-project/gofe/data"
    "github.com/fentec-project/gofe/sample"
)

// This is a ciphertext policy (CP) multi-authority (MA) attribute based
// encryption (ABE) scheme based on the paper "Decentralizing Attribute-Based
// Encryption" by Allison Lewko and Brent Waters, accessible at
// (https://eprint.iacr.org/2010/351.pdf).
//
// This scheme enables encryption based on a boolean expression determining
// which attributes are needed for an entity to be able to decrypt, where the
// attributes can be spread across many different authorities, eliminating the
// need for a central authority. Secret keys, each connected to a single
// attribute, are generated by the relevant authorities, such that only a set
// of keys whose attributes are sufficient according to the boolean formula can
// decrypt the message.

// MAABE represents a MAABE scheme.
type MAABE struct {
    P *big.Int
    G1 *bn256.G1
    G2 *bn256.G2
    Gt *bn256.GT
}

// NewMAABE configures a new instance of the scheme.
func NewMAABE() *MAABE {
    gen1 := new(bn256.G1).ScalarBaseMult(big.NewInt(1))
    gen2 := new(bn256.G2).ScalarBaseMult(big.NewInt(1))
    return &MAABE{
            P: bn256.Order,
            G1: gen1,
            G2: gen2,
            Gt: bn256.Pair(gen1, gen2),
    }
}

// MAABEPubKey represents a public key for an authority.
type MAABEPubKey struct {
    Attribs []string
    EggToAlpha map[string]*bn256.GT
    GToY map[string]*bn256.G2
}

// MAABESecKey represents a secret key for an authority.
type MAABESecKey struct {
    Attribs []string
    Alpha map[string]*big.Int
    Y map[string]*big.Int
}

// MAABEAuth represents an authority in the MAABE scheme.
type MAABEAuth struct {
    ID string
    Maabe *MAABE
    Pk *MAABEPubKey
    Sk *MAABESecKey
}

// NewMAABEAuth configures a new instance of an authority and generates its
// public and secret keys for the given set of attributes. In case of a failed
// procedure an error is returned.
func (a *MAABE) NewMAABEAuth(id string, attribs []string) (*MAABEAuth, error) {
    numattrib := len(attribs)
    // sanity checks
    if numattrib == 0 {
        return nil, fmt.Errorf("empty set of authority attributes")
    }
    if len(id) == 0 {
        return nil, fmt.Errorf("empty id string")
    }
    // rand generator
    sampler := sample.NewUniform(a.P)
    // generate seckey
    alphaI, err := data.NewRandomVector(numattrib, sampler)
    if err != nil {
        return nil, err
    }
    yI, err := data.NewRandomVector(numattrib, sampler)
    if err != nil {
        return nil, err
    }
    alpha := make(map[string]*big.Int)
    y := make(map[string]*big.Int)
    for i, at := range attribs {
        alpha[at] = alphaI[i]
        y[at] = yI[i]
    }
    // generate pubkey
    eggToAlpha := make(map[string]*bn256.GT)
    gToY := make(map[string]*bn256.G2)
    for _, at := range attribs {
        eggToAlpha[at] = new(bn256.GT).ScalarMult(a.Gt, alpha[at])
        gToY[at] = new(bn256.G2).ScalarMult(a.G2, y[at])
    }
    sk := &MAABESecKey{Attribs: attribs, Alpha: alpha, Y: y}
    pk := &MAABEPubKey{Attribs: attribs, EggToAlpha: eggToAlpha, GToY: gToY}
    return &MAABEAuth{
        ID: id,
        Maabe: a,
        Pk: pk,
        Sk: sk,
    }, nil
}

// PubKeys is a getter function that returns a copy of the authority's public
// keys.
func (auth *MAABEAuth) PubKeys() *MAABEPubKey {
    newEggToAlpha := make(map[string]*bn256.GT)
    newGToY := make(map[string]*bn256.G2)
    newAttribs := make([]string, len(auth.Pk.Attribs))
    copy(newAttribs, auth.Pk.Attribs)
    for at, gt := range auth.Pk.EggToAlpha {
        newEggToAlpha[at] = new(bn256.GT).Set(gt)
    }
    for at, g2 := range auth.Pk.GToY {
        newGToY[at] = new(bn256.G2).Set(g2)
    }
    return &MAABEPubKey{
        Attribs: newAttribs,
        EggToAlpha: newEggToAlpha,
        GToY: newGToY,
    }
}

// AddAttribute generates public and secret keys for a new attribute that is
// given as input. In case of a failed procedure an error is returned, and nil
// otherwise.
func (auth *MAABEAuth) AddAttribute(attrib string) error {
    // sanity checks
    if len(attrib) == 0 {
        return fmt.Errorf("attribute cannot be an empty string")
    }
    if auth.Maabe == nil {
        return fmt.Errorf("MAABE struct cannot be nil")
    }
    // attribute should not already exist, separate function
    if auth.Sk.Alpha[attrib] != nil || auth.Sk.Y[attrib] != nil {
        return fmt.Errorf("attribute already exists")
    }
    // generate secret key
    sampler := sample.NewUniform(auth.Maabe.P)
    skVals, err := data.NewRandomVector(2, sampler)
    if err != nil {
        return err
    }
    alpha := skVals[0]
    y := skVals[1]
    // generate public key
    eggToAlpha := new(bn256.GT).ScalarMult(auth.Maabe.Gt, alpha)
    gToY := new(bn256.G2).ScalarMult(auth.Maabe.G2, y)
    // add keys to authority
    auth.Sk.Alpha[attrib] = alpha
    auth.Sk.Y[attrib] = y
    auth.Pk.EggToAlpha[attrib] = eggToAlpha
    auth.Pk.GToY[attrib] = gToY
    auth.Sk.Attribs = append(auth.Sk.Attribs, attrib)
    auth.Pk.Attribs = append(auth.Pk.Attribs, attrib)
    return nil
}

// RegenerateKey generates public and secret keys for an already existing
// attribute that is given as input. In case of a failed procedure an error is
// returned. It is meant to be used in case only a part of the authority's
// secret keys get compromised. Note that the new public keys have to be
// distributed and messages that were encrypted with a policy that contains
// this attribute have to also be reencrypted.
func (auth *MAABEAuth) RegenerateKey(attrib string) error {
    // sanity checks
    if len(attrib) == 0 {
        return fmt.Errorf("attribute cannot be an empty string")
    }
    if auth.Maabe == nil {
        return fmt.Errorf("MAABE struct cannot be nil")
    }
    // attribute must already exist
    if auth.Sk.Alpha[attrib] == nil || auth.Sk.Y[attrib] == nil {
        return fmt.Errorf("attribute does not exist yet")
    }
    // generate secret key
    sampler := sample.NewUniform(auth.Maabe.P)
    skVals, err := data.NewRandomVector(2, sampler)
    if err != nil {
        return err
    }
    alpha := skVals[0]
    y := skVals[1]
    // generate public key
    eggToAlpha := new(bn256.GT).ScalarMult(auth.Maabe.Gt, alpha)
    gToY := new(bn256.G2).ScalarMult(auth.Maabe.G2, y)
    // add keys to authority
    auth.Sk.Alpha[attrib] = alpha
    auth.Sk.Y[attrib] = y
    auth.Pk.EggToAlpha[attrib] = eggToAlpha
    auth.Pk.GToY[attrib] = gToY
    return nil
}

// MAABECipher represents a ciphertext of a MAABE scheme.
type MAABECipher struct {
    C0 *bn256.GT
    C1x map[string]*bn256.GT
    C2x map[string]*bn256.G2
    C3x map[string]*bn256.G2
    Msp *MSP
    SymEnc []byte // symmetric encryption of the string message
    Iv []byte // initialization vector for symmetric encryption
}

// Encrypt takes an input message in string form, a MSP struct representing the
// decryption policy and a list of public keys of the relevant authorities. It
// returns a ciphertext consisting of an AES encrypted message with the secret
// key encrypted according to the MAABE scheme. In case of a failed procedure
// an error is returned.
func (a *MAABE) Encrypt(msg string, msp *MSP, pks []*MAABEPubKey) (*MAABECipher, error) {
    // sanity checks
    if len(msp.Mat) == 0 || len(msp.Mat[0]) == 0 {
        return nil, fmt.Errorf("empty msp matrix")
    }
    mspRows := msp.Mat.Rows()
    mspCols := msp.Mat.Cols()
    attribs := make(map[string]bool)
    for _, i := range msp.RowToAttrib {
        if attribs[i] {
            return nil, fmt.Errorf("some attributes correspond to" +
            "multiple rows of the MSP struct, the scheme is not secure")
        }
        attribs[i] = true
    }
    if len(msg) == 0 {
        return nil, fmt.Errorf("message cannot be empty")
    }
    // msg is encrypted with AES-CBC with a random key that is encrypted with
    // MA-ABE
    // generate secret key
    _, symKey, err := bn256.RandomGT(rand.Reader)
    if err != nil {
        return nil, err
    }
    // generate new AES-CBC params
    keyCBC := sha256.Sum256([]byte(symKey.String()))
    cipherAES, err := aes.NewCipher(keyCBC[:])
    if err != nil {
        return nil, err
    }
    iv := make([]byte, cipherAES.BlockSize())
    _, err = io.ReadFull(rand.Reader, iv)
    if err != nil {
        return nil, err
    }
    encrypterCBC := cbc.NewCBCEncrypter(cipherAES, iv)
    // interpret msg as a byte array and pad it according to PKCS7 standard
    msgByte := []byte(msg)
    padLen := cipherAES.BlockSize() - (len(msgByte) % cipherAES.BlockSize())
    msgPad := make([]byte, len(msgByte) + padLen)
    copy(msgPad, msgByte)
    for i := len(msgByte); i < len(msgPad); i++ {
        msgPad[i] = byte(padLen)
    }
    // encrypt data
    symEnc := make([]byte, len(msgPad))
    encrypterCBC.CryptBlocks(symEnc, msgPad)

    // now encrypt symKey with MA-ABE
    // rand generator
    sampler := sample.NewUniform(a.P)
    // pick random vector v with random s as first element
    v, err := data.NewRandomVector(mspCols, sampler)
    if err != nil {
        return nil, err
    }
    s := v[0]
    if err != nil {
        return nil, err
    }
    lambdaI, err := msp.Mat.MulVec(v)
    if err != nil {
        return nil, err
    }
    if len(lambdaI) != mspRows {
        return nil, fmt.Errorf("wrong lambda len")
    }
    lambda := make(map[string]*big.Int)
    for i, at := range msp.RowToAttrib {
        lambda[at] = lambdaI[i]
    }
    // pick random vector w with 0 as first element
    w, err := data.NewRandomVector(mspCols, sampler)
    if err != nil {
        return nil, err
    }
    w[0] = big.NewInt(0)
    omegaI, err := msp.Mat.MulVec(w)
    if err != nil {
        return nil, err
    }
    if len(omegaI) != mspRows {
        return nil, fmt.Errorf("wrong omega len")
    }
    omega := make(map[string]*big.Int)
    for i, at := range msp.RowToAttrib {
        omega[at] = omegaI[i]
    }
    // calculate ciphertext
    c0 := new(bn256.GT).Add(symKey, new(bn256.GT).ScalarMult(a.Gt, s))
    c1 := make(map[string]*bn256.GT)
    c2 := make(map[string]*bn256.G2)
    c3 := make(map[string]*bn256.G2)
    // get randomness
    rI, err := data.NewRandomVector(mspRows, sampler)
    r := make(map[string]*big.Int)
    for i, at := range msp.RowToAttrib {
        r[at] = rI[i]
    }
    if err != nil {
        return nil, err
    }
    for _, at := range msp.RowToAttrib {
        // find the correct pubkey
        foundPK := false
        for _, pk := range pks {
            if pk.EggToAlpha[at] != nil {
                // CAREFUL: negative numbers do not play well with ScalarMult
                signLambda := lambda[at].Cmp(big.NewInt(0))
                signOmega := omega[at].Cmp(big.NewInt(0))
                var tmpLambda *bn256.GT
                var tmpOmega *bn256.G2
                if signLambda >= 0 {
                    tmpLambda = new(bn256.GT).ScalarMult(a.Gt, lambda[at])
                } else {
                    tmpLambda = new(bn256.GT).ScalarMult(new(bn256.GT).Neg(a.Gt), new(big.Int).Abs(lambda[at]))
                }
                if signOmega >= 0 {
                    tmpOmega = new(bn256.G2).ScalarMult(a.G2, omega[at])
                } else {
                    tmpOmega = new(bn256.G2).ScalarMult(new(bn256.G2).Neg(a.G2), new(big.Int).Abs(omega[at]))
                }
                c1[at] = new(bn256.GT).Add(tmpLambda, new(bn256.GT).ScalarMult(pk.EggToAlpha[at], r[at]))
                c2[at] = new(bn256.G2).ScalarMult(a.G2, r[at])
                c3[at] = new(bn256.G2).Add(new(bn256.G2).ScalarMult(pk.GToY[at], r[at]), tmpOmega)
                foundPK = true
                break
            }
        }
        if !foundPK {
            return nil, fmt.Errorf("attribute not found in any pubkey")
        }
    }
    return &MAABECipher{
        C0: c0,
        C1x: c1,
        C2x: c2,
        C3x: c3,
        Msp: msp,
        SymEnc: symEnc,
        Iv: iv,
    }, nil
}

// MAABEKey represents a key corresponding to an attribute possessed by an
// entity. They are issued by the relevant authorities and are used for
// decryption in a MAABE scheme.
type MAABEKey struct {
    Gid string
    Attrib string
    Key *bn256.G1
}

// GenerateAttribKeys generates a list of attribute keys for the given user
// (represented by its Global ID) that possesses the given list of attributes.
// In case of a failed procedure an error is returned. The relevant authority
// has to check that the entity actually possesses the attributes via some
// other channel.
func (auth *MAABEAuth) GenerateAttribKeys(gid string, attribs []string) ([]*MAABEKey, error) {
    // sanity checks
    if len(gid) == 0 {
        return nil, fmt.Errorf("GID cannot be empty")
    }
    if len(attribs) == 0 {
        return nil, fmt.Errorf("attribute cannot be empty")
    }
    if auth.Maabe == nil {
        return nil, fmt.Errorf("ma-abe scheme cannot be nil")
    }
    hash, err := bn256.HashG1(gid)
    if err != nil {
        return nil, err
    }
    ks := make([]*MAABEKey, len(attribs))
    for i, at := range attribs {
        var k *bn256.G1
        if auth.Sk.Alpha[at] != nil && auth.Sk.Y[at] != nil {
            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]))
            ks[i] = &MAABEKey{
                Gid: gid,
                Attrib: at,
                Key: k,
            }
        } else {
            return nil, fmt.Errorf("attribute not found in secret key")
        }
    }
    return ks, nil
}

// Decrypt takes a ciphertext in a MAABE scheme and a set of attribute keys
// belonging to the same entity, and attempts to decrypt the cipher. This is
// possible only if the set of possessed attributes/keys suffices the
// decryption policy of the ciphertext. In case this is not possible or
// something goes wrong an error is returned.
func (a * MAABE) Decrypt(ct *MAABECipher, ks []*MAABEKey) (string, error) {
    // sanity checks
    if len(ks) == 0 {
        return "", fmt.Errorf("empty set of attribute keys")
    }
    gid := ks[0].Gid
    for _, k := range ks {
        if k.Gid != gid {
            return "", fmt.Errorf("not all GIDs are the same")
        }
    }
    // get hashed GID
    hash, err := bn256.HashG1(gid)
    if err != nil {
        return "", err
    }
    // find out which attributes are valid and extract them
    goodMatRows := make([]data.Vector, 0)
    goodAttribs := make([]string, 0)
    aToK := make(map[string]*MAABEKey)
    for _, k := range ks {
        aToK[k.Attrib] = k
    }
    for i, at := range ct.Msp.RowToAttrib {
        if aToK[at] != nil {
            goodMatRows = append(goodMatRows, ct.Msp.Mat[i])
            goodAttribs = append(goodAttribs, at)
        }
    }
    goodMat, err := data.NewMatrix(goodMatRows)
    if err != nil {
        return "", err
    }
    //choose consts c_x, such that \sum c_x A_x = (1,0,...,0)
    // if they don't exist, keys are not ok
    goodCols := goodMat.Cols()
    if goodCols == 0 {
        return "", fmt.Errorf("no good matrix columns, most likely the keys contain no valid attribute")
    }
    one := data.NewConstantVector(goodCols, big.NewInt(0))
    one[0] = big.NewInt(1)
    c, err := data.GaussianEliminationSolver(goodMat.Transpose(), one, a.P)
    if err != nil {
        return "", err
    }
    cx := make(map[string]*big.Int)
    for i, at := range goodAttribs {
        cx[at] = c[i]
    }
    // compute intermediate values
    eggLambda := make(map[string]*bn256.GT)
    for _, at := range goodAttribs {
        if ct.C1x[at] != nil && ct.C2x[at] != nil && ct.C3x[at] != nil {
            num := new(bn256.GT).Add(ct.C1x[at], bn256.Pair(hash, ct.C3x[at]))
            den := new(bn256.GT).Neg(bn256.Pair(aToK[at].Key, ct.C2x[at]))
            eggLambda[at] = new(bn256.GT).Add(num, den)
        } else {
            return "", fmt.Errorf("attribute %s not in ciphertext dicts", at)
        }
    }
    eggs := new(bn256.GT).ScalarBaseMult(big.NewInt(0))
    for _, at := range goodAttribs {
        if eggLambda[at] != nil {
            sign := cx[at].Cmp(big.NewInt(0))
            if sign == 1 {
                eggs.Add(eggs, new(bn256.GT).ScalarMult(eggLambda[at], cx[at]))
            } else if sign == -1 {
                eggs.Add(eggs, new(bn256.GT).ScalarMult(new(bn256.GT).Neg(eggLambda[at]), new(big.Int).Abs(cx[at])))
            }
        } else {
            return "", fmt.Errorf("missing intermediate result")
        }
    }
    // calculate key for symmetric encryption
    symKey := new(bn256.GT).Add(ct.C0, new(bn256.GT).Neg(eggs))
    // now decrypt message with it
    keyCBC := sha256.Sum256([]byte(symKey.String()))
    cipherAES, err := aes.NewCipher(keyCBC[:])
    if err != nil {
        return "", err
    }
    msgPad := make([]byte, len(ct.SymEnc))
    decrypter := cbc.NewCBCDecrypter(cipherAES, ct.Iv)
    decrypter.CryptBlocks(msgPad, ct.SymEnc)
    // unpad the message
    padLen := int(msgPad[len(msgPad)-1])
    if (len(msgPad) - padLen) < 0 {
        return "", fmt.Errorf("failed to decrypt")
    }
    msgByte := msgPad[0:(len(msgPad) - padLen)]
    return string(msgByte), nil
}


================================================
FILE: abe/ma-abe_test.go
================================================
package abe_test

import (
    "testing"
    "github.com/fentec-project/gofe/abe"
    "github.com/stretchr/testify/assert"
)

func TestMAABE(t *testing.T) {
    // create new MAABE struct with Global Parameters
    maabe := abe.NewMAABE()

    // create three authorities, each with two attributes
    attribs1 := []string{"auth1:at1", "auth1:at2"}
    attribs2 := []string{"auth2:at1", "auth2:at2"}
    attribs3 := []string{"auth3:at1", "auth3:at2"}
    auth1, err:= maabe.NewMAABEAuth("auth1", attribs1)
    if err != nil {
        t.Fatalf("Failed generation authority %s: %v\n", "auth1", err)
    }
    auth2, err:= maabe.NewMAABEAuth("auth2", attribs2)
    if err != nil {
        t.Fatalf("Failed generation authority %s: %v\n", "auth2", err)
    }
    auth3, err:= maabe.NewMAABEAuth("auth3", attribs3)
    if err != nil {
        t.Fatalf("Failed generation authority %s: %v\n", "auth3", err)
    }

    // create a msp struct out of the boolean formula
    msp, err := abe.BooleanToMSP("((auth1:at1 AND auth2:at1) OR (auth1:at2 AND auth2:at2)) OR (auth3:at1 AND auth3:at2)", false)
    if err != nil {
        t.Fatalf("Failed to generate the policy: %v\n", err)
    }

    // define the set of all public keys we use
    pks := []*abe.MAABEPubKey{auth1.PubKeys(), auth2.PubKeys(), auth3.PubKeys()}

    // choose a message
    msg := "Attack at dawn!"

    // encrypt the message with the decryption policy in msp
    ct, err := maabe.Encrypt(msg, msp, pks)
    if err != nil {
        t.Fatalf("Failed to encrypt: %v\n", err)
    }

    // also check for empty message
    msgEmpty := ""
    _, err = maabe.Encrypt(msgEmpty, msp, pks)
    assert.Error(t, err)

    // use a pub keyring that is too small
    pksSmall := []*abe.MAABEPubKey{auth1.PubKeys()}
    _, err = maabe.Encrypt(msg, msp, pksSmall)
    assert.Error(t, err)

    // choose a single user's Global ID
    gid := "gid1"

    // authority 1 issues keys to user
    keys1, err := auth1.GenerateAttribKeys(gid, attribs1)
    if err != nil {
        t.Fatalf("Failed to generate attribute keys: %v\n", err)
    }
    key11, key12 := keys1[0], keys1[1]
    // authority 2 issues keys to user
    keys2, err := auth2.GenerateAttribKeys(gid, attribs2)
    if err != nil {
        t.Fatalf("Failed to generate attribute keys: %v\n", err)
    }
    key21, key22 := keys2[0], keys2[1]
    // authority 3 issues keys to user
    keys3, err := auth3.GenerateAttribKeys(gid, attribs3)
    if err != nil {
        t.Fatalf("Failed to generate attribute keys: %v\n", err)
    }
    key31, key32 := keys3[0], keys3[1]

    // try and generate key for an attribute that does not belong to the
    // authority (or does not exist)
    _, err = auth3.GenerateAttribKeys(gid, []string{"auth3:at3"})
    assert.Error(t, err)

    // user tries to decrypt with different key combos
    ks1 := []*abe.MAABEKey{key11, key21, key31} // ok
    ks2 := []*abe.MAABEKey{key12, key22, key32} // ok
    ks3 := []*abe.MAABEKey{key11, key22} // not ok
    ks4 := []*abe.MAABEKey{key12, key21} // not ok
    ks5 := []*abe.MAABEKey{key31, key32} // ok

    // try to decrypt all messages
    msg1, err := maabe.Decrypt(ct, ks1)
    if err != nil {
        t.Fatalf("Error decrypting with keyset 1: %v\n", err)
    }
    assert.Equal(t, msg, msg1)

    msg2, err := maabe.Decrypt(ct, ks2)
    if err != nil {
        t.Fatalf("Error decrypting with keyset 2: %v\n", err)
    }
    assert.Equal(t, msg, msg2)

    _, err = maabe.Decrypt(ct, ks3)
    assert.Error(t, err)

    _, err = maabe.Decrypt(ct, ks4)
    assert.Error(t, err)

    msg5, err := maabe.Decrypt(ct, ks5)
    if err != nil {
        t.Fatalf("Error decrypting with keyset 5: %v\n", err)
    }
    assert.Equal(t, msg, msg5)

    // generate keys with a different GID
    gid2 := "gid2"
    // authority 1 issues keys to user
    foreignKeys, err := auth1.GenerateAttribKeys(gid2, []string{"auth1:at1"})
    if err != nil {
        t.Fatalf("Failed to generate attribute key for %s: %v\n", "auth1:at1", err)
    }
    foreignKey11 := foreignKeys[0]
    // join two users who have sufficient attributes together, but not on their
    // own
    ks6 := []*abe.MAABEKey{foreignKey11, key21}
    // try and decrypt
    _, err = maabe.Decrypt(ct, ks6)
    assert.Error(t, err)

    // add a new attribute to some authority
    err = auth3.AddAttribute("auth3:at3")
    if err != nil {
        t.Fatalf("Error adding attribute: %v\n", err)
    }
    // now try to generate the key
    _, err = auth3.GenerateAttribKeys(gid, []string{"auth3:at3"})
    if err != nil {
        t.Fatalf("Error generating key for new attribute: %v\n", err)
    }

    // regenerate a compromised key for some authority
    err = auth1.RegenerateKey("auth1:at2")
    if err != nil {
        t.Fatalf("Error regenerating key: %v\n", err)
    }
    // regenerate attrib key for that key and republish pubkey
    keysNew, err := auth1.GenerateAttribKeys(gid, []string{"auth1:at2"})
    if err != nil {
        t.Fatalf("Error generating attrib key for regenerated key: %v\n", err)
    }
    key12New := keysNew[0]
    pks = []*abe.MAABEPubKey{auth1.Pk, auth2.Pk, auth3.Pk}
    // reencrypt msg
    ctNew, err := maabe.Encrypt(msg, msp, pks)
    if err != nil {
        t.Fatalf("Failed to encrypt with new keys")
    }
    ks7 := []*abe.MAABEKey{key12New, key22}
    // decrypt reencrypted msg
    msg7, err := maabe.Decrypt(ctNew, ks7)
    if err != nil {
        t.Fatalf("Failed to decrypt with regenerated keys: %v\n", err)
    }
    assert.Equal(t, msg, msg7)
}



================================================
FILE: abe/policy.go
================================================
/*
 * Copyright (c) 2018 XLAB d.o.o
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package abe

import (
	"math/big"
	"strings"

	"fmt"

	"github.com/fentec-project/gofe/data"
)

// MSP represents a monotone span program (MSP) describing a policy defining which
// attributes are needed to decrypt the ciphertext. It includes a matrix
// mat and a mapping from the rows of the mat to attributes. A MSP policy
// allows decryption of an entity with a set of attributes A if an only if all the
// rows of the matrix mapped to an element of A span the vector [1, 0,..., 0] (or
// vector [1, 1,..., 1] depending on the use case).
type MSP struct {
	P           *big.Int
	Mat         data.Matrix
	RowToAttrib []string
}

// BooleanToMSP takes as an input a boolean expression (without a NOT gate) as
// a string where attributes are joined by AND and OR gates. It outputs a
// msp structure representing the expression, i.e. a matrix whose rows
// correspond to attributes used in the expression and with the property that a
// boolean expression assigning 1 to some attributes is satisfied iff the
// corresponding rows span a vector [1, 1,..., 1] or vector [1, 0,..., 0]
// depending if parameter convertToOnes is set to true or false. Additionally a
// vector is produced whose i-th entry indicates to which attribute the i-th row
// corresponds.
// Example: BooleanToMSP("attrib1 AND (attrib2 OR attrib3)", true)
// The names of the attributes should not include "AND" or "OR" as
// a substring and '(' or ')' as a character, otherwise the function
// will not work properly.
func BooleanToMSP(boolExp string, convertToOnes bool) (*MSP, error) {
	// by the Lewko-Waters algorithm we obtain a MSP struct with the property
	// that is the the boolean expression is satisfied if and only if the corresponding
	// rows of the msp matrix span the vector [1, 0,..., 0]
	vec := make(data.Vector, 1)
	vec[0] = big.NewInt(1)
	msp, _, err := booleanToMSPIterative(boolExp, vec, 1)
	if err != nil {
		return nil, err
	}

	// if convertToOnes is set to true convert the matrix to such a MSP
	// struct so that the boolean expression is satisfied iff the
	// corresponding rows span the vector [1, 1,..., 1]
	if convertToOnes {
		// create an invertible matrix that maps [1, 0,..., 0] to [1,1,...,1]
		invMat := make(data.Matrix, len(msp.Mat[0]))
		for i := 0; i < len(msp.Mat[0]); i++ {
			invMat[i] = make(data.Vector, len(msp.Mat[0]))
			for j := 0; j < len(msp.Mat[0]); j++ {
				if i == 0 || j == i {
					invMat[i][j] = big.NewInt(1)
				} else {
					invMat[i][j] = big.NewInt(0)
				}
			}
		}
		//change the msp matrix by multiplying with it the matrix invMat
		msp.Mat, err = msp.Mat.Mul(invMat)
		if err != nil {
			return nil, err
		}
	}

	return msp, nil
}

// booleanToMspIterative iteratively builds a msp structure by splitting the expression
// into two parts separated by an AND or OR gate, generating a msp structure on each of
// them, and joining both structures together. The structure is such the the boolean expression
// assigning 1 to some attributes is satisfied iff the corresponding rows span a vector
// [1, 0,..., 0]. The algorithm is known as Lewko-Waters algorithm, see Appendix G in
// https://eprint.iacr.org/2010/351.pdf.
func booleanToMSPIterative(boolExp string, vec data.Vector, c int) (*MSP, int, error) {
	boolExp = strings.TrimSpace(boolExp)
	numBrc := 0
	var boolExp1 string
	var boolExp2 string
	var c1 int
	var cOut int
	var msp1 *MSP
	var msp2 *MSP
	var err error
	found := false

	// find the main AND or OR gate and iteratively call the function on
	// both the sub-expressions
	for i, e := range boolExp {
		if e == '(' {
			numBrc++
			continue
		}
		if e == ')' {
			numBrc--
			continue
		}
		if numBrc == 0 && i < len(boolExp)-3 && boolExp[i:i+3] == "AND" {
			boolExp1 = boolExp[:i]
			boolExp2 = boolExp[i+3:]
			vec1, vec2 := makeAndVecs(vec, c)
			msp1, c1, err = booleanToMSPIterative(boolExp1, vec1, c+1)
			if err != nil {
				return nil, 0, err
			}
			msp2, cOut, err = booleanToMSPIterative(boolExp2, vec2, c1)
			if err != nil {
				return nil, 0, err
			}
			found = true
			break
		}
		if numBrc == 0 && i < len(boolExp)-2 && boolExp[i:i+2] == "OR" {
			boolExp1 = boolExp[:i]
			boolExp2 = boolExp[i+2:]
			msp1, c1, err = booleanToMSPIterative(boolExp1, vec, c)
			if err != nil {
				return nil, 0, err
			}
			msp2, cOut, err = booleanToMSPIterative(boolExp2, vec, c1)
			if err != nil {
				return nil, 0, err
			}
			found = true
			break
		}
	}

	// If the AND or OR gate is not found then there are two options,
	// either the whole expression is in brackets, or the the expression
	// is only one attribute. It neither of both is true, then
	// an error is returned while converting the expression into an
	// attribute
	if !found {
		if boolExp[0] == '(' && boolExp[len(boolExp)-1] == ')' {
			boolExp = boolExp[1:(len(boolExp) - 1)]
			return booleanToMSPIterative(boolExp, vec, c)
		}

		if strings.Contains(boolExp, "(") || strings.Contains(boolExp, ")") {
			return nil, 0, fmt.Errorf("bad boolean expression or attributes contain ( or )")
		}

		mat := make(data.Matrix, 1)
		mat[0] = make(data.Vector, c)
		for i := 0; i < c; i++ {
			if i < len(vec) {
				mat[0][i] = new(big.Int).Set(vec[i])
			} else {
				mat[0][i] = big.NewInt(0)
			}
		}

		rowToAttribS := make([]string, 1)
		rowToAttribS[0] = boolExp
		return &MSP{Mat: mat, RowToAttrib: rowToAttribS}, c, nil

	}
	// otherwise we join the two msp structures into one
	mat := make(data.Matrix, len(msp1.Mat)+len(msp2.Mat))
	for i := 0; i < len(msp1.Mat); i++ {
		mat[i] = make(data.Vector, cOut)
		for j := 0; j < len(msp1.Mat[0]); j++ {
			mat[i][j] = msp1.Mat[i][j]
		}
		for j := len(msp1.Mat[0]); j < cOut; j++ {
			mat[i][j] = big.NewInt(0)
		}
	}
	for i := 0; i < len(msp2.Mat); i++ {
		mat[i+len(msp1.Mat)] = msp2.Mat[i]
	}
	rowToAttribS := append(msp1.RowToAttrib, msp2.RowToAttrib...)

	return &MSP{Mat: mat, RowToAttrib: rowToAttribS}, cOut, nil
}

// makeAndVecs is a helping structure that given a vector and and counter
// creates two new vectors used whenever an AND gate is found in a iterative
// step of BooleanToMsp
func makeAndVecs(vec data.Vector, c int) (data.Vector, data.Vector) {
	vec1 := data.NewConstantVector(c+1, big.NewInt(0))
	vec2 := data.NewConstantVector(c+1, big.NewInt(0))
	for i := 0; i < len(vec); i++ {
		vec2[i].Set(vec[i])
	}
	vec1[c] = big.NewInt(-1)
	vec2[c] = big.NewInt(1)

	return vec1, vec2
}


================================================
FILE: abe/policy_test.go
================================================
/*
 * Copyright (c) 2018 XLAB d.o.o
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package abe

import (
	"math/big"
	"testing"

	"github.com/fentec-project/gofe/data"
	"github.com/stretchr/testify/assert"
)

func TestBooleanToMsp(t *testing.T) {
	// create as msp struct out of a boolean expression
	p := big.NewInt(7)
	msp, err := BooleanToMSP("1 AND (((6 OR 7) AND (8 OR 9)) OR ((2 AND 3) OR (4 AND 5)))", true)
	if err != nil {
		t.Fatalf("Error while processing a boolean expression: %v", err)
	}

	// check if having attributes 1, 7 and 9 satisfies the expression, i.e. entries 0, 2, 4
	// of a msp matrix span vector [1, 1,..., 1], using Gaussian elimination
	v := make(data.Vector, len(msp.Mat[0]))
	for i := 0; i < len(v); i++ {
		v[i] = big.NewInt(1)
	}
	m := make(data.Matrix, 3)
	m[0] = msp.Mat[0]
	m[1] = msp.Mat[2]
	m[2] = msp.Mat[4]

	x, err := data.GaussianEliminationSolver(m.Transpose(), v, p)
	if err != nil {
		t.Fatalf("Error finding a vector: %v", err)
	}
	assert.NotNil(t, x)

	// check if an error is generated if the boolean expression is not in a correct form
	_, err = BooleanToMSP("1 AND ((6 OR 7) AND (8 OR 9)) OR ((2 AND 3) OR (4 AND 5)))", true)
	assert.Error(t, err)
}


================================================
FILE: data/doc.go
================================================
/*
 * Copyright (c) 2018 XLAB d.o.o
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// Package data defines basic mathematical structures used
// throughout the library.
package data


================================================
FILE: data/matrix.go
================================================
/*
 * Copyright (c) 2018 XLAB d.o.o
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package data

import (
	"fmt"
	"math/big"

	"github.com/fentec-project/bn256"
	"github.com/fentec-project/gofe/sample"
)

// Matrix wraps a slice of Vector elements. It represents a row-major.
// order matrix.
//
// The j-th element from the i-th vector of the matrix can be obtained
// as m[i][j].
type Matrix []Vector

// NewMatrix accepts a slice of Vector elements and
// returns a new Matrix instance.
// It returns error if not all the vectors have the same number of elements.
func NewMatrix(vectors []Vector) (Matrix, error) {
	l := -1
	newVectors := make([]Vector, len(vectors))

	if len(vectors) > 0 {
		l = len(vectors[0])
	}
	for i, v := range vectors {
		if len(v) != l {
			return nil, fmt.Errorf("all vectors should be of the same length")
		}
		newVectors[i] = NewVector(v)
	}

	return Matrix(newVectors), nil
}

// NewRandomMatrix returns a new Matrix instance
// with random elements sampled by the provided sample.Sampler.
// Returns an error in case of sampling failure.
func NewRandomMatrix(rows, cols int, sampler sample.Sampler) (Matrix, error) {
	mat := make([]Vector, rows)

	for i := 0; i < rows; i++ {
		vec, err := NewRandomVector(cols, sampler)
		if err != nil {
			return nil, err
		}

		mat[i] = vec
	}

	return NewMatrix(mat)
}

// NewRandomDetMatrix returns a new Matrix instance
// with random elements sampled by a pseudo-random
// number generator. Elements are sampled from [0, max) and key
// determines the pseudo-random generator.
func NewRandomDetMatrix(rows, cols int, max *big.Int, key *[32]byte) (Matrix, error) {
	l := rows * cols
	v, err := NewRandomDetVector(l, max, key)
	if err != nil {
		return nil, err
	}

	mat := make([]Vector, rows)
	for i := 0; i < rows; i++ {
		mat[i] = NewVector(v[(i * cols):((i + 1) * cols)])
	}

	return NewMatrix(mat)
}

// NewConstantMatrix returns a new Matrix instance
// with all elements set to constant c.
func NewConstantMatrix(rows, cols int, c *big.Int) Matrix {
	mat := make([]Vector, rows)
	for i := 0; i < rows; i++ {
		mat[i] = NewConstantVector(cols, c)
	}

	return mat
}

// Copy creates a new Matrix with the same values.
func (m Matrix) Copy() Matrix {
	mat := make(Matrix, m.Rows())
	for i := 0; i < m.Rows(); i++ {
		mat[i] = m[i].Copy()
	}

	return mat
}

// Rows returns the number of rows of matrix m.
func (m Matrix) Rows() int {
	return len(m)
}

// Cols returns the number of columns of matrix m.
func (m Matrix) Cols() int {
	if len(m) != 0 {
		return len(m[0])
	}

	return 0
}

// DimsMatch returns a bool indicating whether matrices
// m and other have the same dimensions.
func (m Matrix) DimsMatch(other Matrix) bool {
	return m.Rows() == other.Rows() && m.Cols() == other.Cols()
}

// GetCol returns i-th column of matrix m as a vector.
// It returns error if i >= the number of m's columns.
func (m Matrix) GetCol(i int) (Vector, error) {
	if i >= m.Cols() {
		return nil, fmt.Errorf("column index exceeds matrix dimensions")
	}

	column := make([]*big.Int, m.Rows())
	for j := 0; j < m.Rows(); j++ {
		column[j] = m[j][i]
	}

	return NewVector(column), nil
}

// Transpose transposes matrix m and returns
// the result in a new Matrix.
func (m Matrix) Transpose() Matrix {
	transposed := make([]Vector, m.Cols())
	for i := 0; i < m.Cols(); i++ {
		transposed[i], _ = m.GetCol(i)
	}

	mT, _ := NewMatrix(transposed)

	return mT
}

// CheckBound checks whether all matrix elements are strictly
// smaller than the provided bound.
// It returns error if at least one element is >= bound.
func (m Matrix) CheckBound(bound *big.Int) error {
	for _, v := range m {
		err := v.CheckBound(bound)
		if err != nil {
			return err
		}
	}
	return nil
}

// CheckDims checks whether dimensions of matrix m match
// the provided rows and cols arguments.
func (m Matrix) CheckDims(rows, cols int) bool {
	return m.Rows() == rows && m.Cols() == cols
}

// Mod applies the element-wise modulo operation on matrix m.
// The result is returned in a new Matrix.
func (m Matrix) Mod(modulo *big.Int) Matrix {
	vectors := make([]Vector, m.Rows())

	for i, v := range m {
		vectors[i] = v.Mod(modulo)
	}

	matrix, _ := NewMatrix(vectors)

	return matrix
}

// Apply applies an element-wise function f to matrix m.
// The result is returned in a new Matrix.
func (m Matrix) Apply(f func(*big.Int) *big.Int) Matrix {
	res := make(Matrix, len(m))

	for i, vi := range m {
		res[i] = vi.Apply(f)
	}

	return res
}

// Dot calculates the dot product (inner product) of matrices m and other,
// which we define as the sum of the dot product of rows of both matrices.
// It returns an error if m and other have different dimensions.
func (m Matrix) Dot(other Matrix) (*big.Int, error) {
	if !m.DimsMatch(other) {
		return nil, fmt.Errorf("matrices mismatch in dimensions")
	}

	r := new(big.Int)

	for i := 0; i < m.Rows(); i++ {
		prod, err := m[i].Dot(other[i])
		if err != nil {
			return nil, err
		}
		r = r.Add(r, prod)
	}

	return r, nil
}

// Add adds matrices m and other.
// The result is returned in a new Matrix.
// Error is returned if m and other have different dimensions.
func (m Matrix) Add(other Matrix) (Matrix, error) {
	if !m.DimsMatch(other) {
		return nil, fmt.Errorf("matrices mismatch in dimensions")
	}

	vectors := make([]Vector, m.Rows())

	for i, v := range m {
		vectors[i] = v.Add(other[i])
	}

	matrix, err := NewMatrix(vectors)
	if err != nil {
		return nil, err
	}
	return matrix, nil
}

// Sub adds matrices m and other.
// The result is returned in a new Matrix.
// Error is returned if m and other have different dimensions.
func (m Matrix) Sub(other Matrix) (Matrix, error) {
	if !m.DimsMatch(other) {
		return nil, fmt.Errorf("matrices mismatch in dimensions")
	}

	vecs := make([]Vector, m.Rows())

	for i, v := range m {
		vecs[i] = v.Sub(other[i])
	}

	return NewMatrix(vecs)
}

// Mul multiplies matrices m and other.
// The result is returned in a new Matrix.
// Error is returned if m and other have different dimensions.
func (m Matrix) Mul(other Matrix) (Matrix, error) {
	if m.Cols() != other.Rows() {
		return nil, fmt.Errorf("cannot multiply matrices")
	}

	prod := make([]Vector, m.Rows())
	for i := 0; i < m.Rows(); i++ {
		prod[i] = make([]*big.Int, other.Cols())
		for j := 0; j < other.Cols(); j++ {
			otherCol, _ := other.GetCol(j)
			prod[i][j], _ = m[i].Dot(otherCol)
		}
	}

	return NewMatrix(prod)
}

// MulScalar multiplies elements of matrix m by a scalar x.
// The result is returned in a new Matrix.
func (m Matrix) MulScalar(x *big.Int) Matrix {
	return m.Apply(func(i *big.Int) *big.Int {
		return new(big.Int).Mul(i, x)
	})
}

// MulVec multiplies matrix m and vector v.
// It returns the resulting vector.
// Error is returned if the number of columns of m differs from the number
// of elements of v.
func (m Matrix) MulVec(v Vector) (Vector, error) {
	if m.Cols() != len(v) {
		return nil, fmt.Errorf("cannot multiply matrix by a vector")
	}

	res := make(Vector, m.Rows())
	for i, row := range m {
		res[i], _ = row.Dot(v)
	}

	return res, nil
}

// MulXMatY calculates the function x^T * m * y, where x and y are
// vectors.
func (m Matrix) MulXMatY(x, y Vector) (*big.Int, error) {
	t, err := m.MulVec(y)
	if err != nil {
		return nil, err
	}
	v, err := t.Dot(x)
	if err != nil {
		return nil, err
	}

	return v, nil
}

// Minor returns a matrix obtained from m by removing row i and column j.
// It returns an error if i >= number of rows of m, or if j >= number of
// columns of m.
func (m Matrix) Minor(i int, j int) (Matrix, error) {
	if i >= m.Rows() || j >= m.Cols() {
		return nil, fmt.Errorf("cannot obtain minor - out of bounds")
	}
	mat := make(Matrix, m.Rows()-1)
	for k := 0; k < m.Rows(); k++ {
		if k == i {
			continue
		}
		vec := make(Vector, 0, len(m[0])-1)
		vec = append(vec, m[k][:j]...)
		vec = append(vec, m[k][j+1:]...)
		if k < i {
			mat[k] = vec
		} else {
			mat[k-1] = vec
		}
	}

	return NewMatrix(mat)
}

// Determinant returns the determinant of matrix m.
// It returns an error if the determinant does not exist.
func (m Matrix) Determinant() (*big.Int, error) {
	if m.Rows() == 1 {
		return new(big.Int).Set(m[0][0]), nil
	}
	det := big.NewInt(0)
	sign := big.NewInt(1)
	for i := 0; i < m.Rows(); i++ {
		minor, err := m.Minor(0, i)
		if err != nil {
			return nil, err
		}
		value, err := minor.Determinant()
		if err != nil {
			return nil, err
		}
		value.Mul(value, m[0][i])
		value.Mul(value, sign)
		sign.Neg(sign)
		det.Add(det, value)
	}

	return det, nil
}

// InverseMod returns the inverse matrix of m in the group Z_p.
// Note that as we consider only matrix with integers,
// the inverse exists only in Z_p.
//
// It returns an error in case matrix is not invertible.
func (m Matrix) InverseMod(p *big.Int) (Matrix, error) {
	mat := make(Matrix, m.Rows())
	det, err := m.Determinant()
	if err != nil {
		return nil, err
	}
	det.Mod(det, p)
	if det.Cmp(big.NewInt(0)) == 0 {
		return nil, fmt.Errorf("matrix non-invertable")
	}
	invDet := new(big.Int).ModInverse(det, p)
	if m.Rows() == 1 {
		mat[0] = Vector{invDet}
		return mat, nil
	}
	sign := new(big.Int)
	minusOne := big.NewInt(-1)
	for i := 0; i < m.Rows(); i++ {
		row := make(Vector, m.Cols())
		for j := 0; j < m.Cols(); j++ {
			minor, err := m.Minor(i, j)
			if err != nil {
				return nil, err
			}
			value, err := minor.Determinant()
			if err != nil {
				return nil, err
			}
			value.Mod(value, p)
			sign.Exp(minusOne, big.NewInt(int64(i+j)), nil)
			value.Mul(value, sign)
			value.Mul(value, invDet)
			value.Mod(value, p)
			row[j] = value
		}
		mat[i] = row
	}
	co, err := NewMatrix(mat)
	if err != nil {
		return nil, err
	}

	return co.Transpose(), nil
}

// MulG1 calculates m * [bn256.G1] and returns the
// result in a new MatrixG1 instance.
func (m Matrix) MulG1() MatrixG1 {
	prod := make(MatrixG1, len(m))
	for i := range prod {
		prod[i] = m[i].MulG1()
	}

	return prod
}

// MulG2 calculates m * [bn256.G1] and returns the
// result in a new MatrixG2 instance.
func (m Matrix) MulG2() MatrixG2 {
	prod := make(MatrixG2, len(m))
	for i := range prod {
		prod[i] = m[i].MulG2()
	}

	return prod
}

// MatMulMatG1 multiplies m and other in the sense that
// if other is t * [bn256.G1] for some matrix t, then the
// function returns m * t * [bn256.G1] where m * t is a
// matrix multiplication.
func (m Matrix) MatMulMatG1(other MatrixG1) (MatrixG1, error) {
	if m.Cols() != other.Rows() {
		return nil, fmt.Errorf("cannot multiply matrices")
	}

	prod := make(MatrixG1, m.Rows())
	for i := 0; i < m.Rows(); i++ {
		prod[i] = make([]*bn256.G1, other.Cols())
		for j := 0; j < other.Cols(); j++ {
			prod[i][j] = new(bn256.G1).ScalarBaseMult(big.NewInt(0))
			for k := 0; k < m.Cols(); k++ {
				mik := new(big.Int).Set(m[i][k])
				okj := new(bn256.G1).Set(other[k][j])
				if m[i][k].Sign() == -1 {
					okj.Neg(okj)
					mik.Neg(mik)
				}
				tmp := new(bn256.G1).ScalarMult(okj, mik)
				prod[i][j].Add(tmp, prod[i][j])
			}
		}
	}

	return prod, nil
}

// MatMulMatG2 multiplies m and other in the sense that
// if other is t * [bn256.G2] for some matrix t, then the
// function returns m * t * [bn256.G2] where m * t is a
// matrix multiplication.
func (m Matrix) MatMulMatG2(other MatrixG2) (MatrixG2, error) {
	if m.Cols() != other.Rows() {
		return nil, fmt.Errorf("cannot multiply matrices")
	}

	prod := make(MatrixG2, m.Rows())
	for i := 0; i < m.Rows(); i++ {
		prod[i] = make([]*bn256.G2, other.Cols())
		for j := 0; j < other.Cols(); j++ {
			prod[i][j] = new(bn256.G2).ScalarBaseMult(big.NewInt(0))
			for k := 0; k < m.Cols(); k++ {
				mik := new(big.Int).Set(m[i][k])
				okj := new(bn256.G2).Set(other[k][j])
				if m[i][k].Sign() == -1 {
					okj.Neg(okj)
					mik.Neg(mik)
				}
				tmp := new(bn256.G2).ScalarMult(okj, mik)
				prod[i][j].Add(tmp, prod[i][j])
			}
		}
	}

	return prod, nil
}

// MatMulVecG2 multiplies m and other in the sense that
// if other is t * [bn256.G2] for some vector t, then the
// function returns m * t * [bn256.G2] where m * t is a
// matrix-vector multiplication.
func (m Matrix) MatMulVecG2(other VectorG2) (VectorG2, error) {
	if m.Cols() != len(other) {
		return nil, fmt.Errorf("dimensions don't fit")
	}

	prod := make(VectorG2, m.Rows())
	for j := 0; j < m.Rows(); j++ {
		prod[j] = new(bn256.G2).ScalarBaseMult(big.NewInt(0))
		for k := 0; k < m.Cols(); k++ {
			mjk := new(big.Int).Set(m[j][k])
			ok := new(bn256.G2).Set(other[k])
			if m[j][k].Sign() == -1 {
				ok.Neg(ok)
				mjk.Neg(mjk)
			}
			tmp := new(bn256.G2).ScalarMult(ok, mjk)
			prod[j].Add(tmp, prod[j])
		}
	}

	return prod, nil
}

// GaussianElimination uses Gaussian elimination to transform a matrix
// into an equivalent upper triangular form
func (m Matrix) GaussianElimination(p *big.Int) (Matrix, error) {
	if m.Rows() == 0 || m.Cols() == 0 {
		return nil, fmt.Errorf("the matrix should not be empty")
	}

	// we copy matrix m into res and v into u
	res := make(Matrix, m.Rows())
	for i := 0; i < m.Rows(); i++ {
		res[i] = make(Vector, m.Cols())
		for j := 0; j < m.Cols(); j++ {
			res[i][j] = new(big.Int).Set(m[i][j])
		}
	}

	// res and u are transformed to be in the upper triangular form
	h, k := 0, 0
	for h < m.Rows() && k < res.Cols() {
		zero := true
		for i := h; i < m.Rows(); i++ {
			if res[i][k].Sign() != 0 {
				res[h], res[i] = res[i], res[h]
				zero = false
				break
			}
		}
		if zero {
			k++
			continue
		}
		mHKInv := new(big.Int).ModInverse(res[h][k], p)
		for i := h + 1; i < m.Rows(); i++ {
			f := new(big.Int).Mul(mHKInv, res[i][k])
			res[i][k] = big.NewInt(0)
			for j := k + 1; j < res.Cols(); j++ {
				res[i][j].Sub(res[i][j], new(big.Int).Mul(f, res[h][j]))
				res[i][j].Mod(res[i][j], p)
			}
		}
		k++
		h++
	}

	return res, nil
}

// InverseModGauss returns the inverse matrix of m in the group Z_p.
// The algorithm uses Gaussian elimination. It returns the determinant
// as well. In case the matrix is not invertible it returns an error.
func (m Matrix) InverseModGauss(p *big.Int) (Matrix, *big.Int, error) {
	if m.Rows() == 0 || m.Cols() == 0 {
		return nil, nil, fmt.Errorf("the matrix should not be empty")
	}
	if m.Rows() != m.Cols() {
		return nil, nil, fmt.Errorf("the number of rows must equal the number of columns")
	}

	// we copy matrix m into matExt and extend it with identity
	matExt := make(Matrix, m.Rows())
	for i := 0; i < m.Rows(); i++ {
		matExt[i] = make(Vector, m.Cols()*2)
		for j := 0; j < m.Cols(); j++ {
			matExt[i][j] = new(big.Int).Set(m[i][j])
		}
		for j := m.Cols(); j < 2*m.Cols(); j++ {
			if i+m.Cols() == j {
				matExt[i][j] = big.NewInt(1)
			} else {
				matExt[i][j] = big.NewInt(0)
			}

		}
	}

	triang, err := matExt.GaussianElimination(p)
	if err != nil {
		return nil, nil, err
	}

	// check if the inverse can be computed
	det := big.NewInt(1)
	for i := 0; i < matExt.Rows(); i++ {
		det.Mul(det, triang[i][i])
		det.Mod(det, p)
	}
	if det.Sign() == 0 {
		return nil, det, fmt.Errorf("matrix non-invertable")
	}

	// use the upper triangular form to obtain the solution
	matInv := make(Matrix, m.Rows())
	for k := 0; k < m.Rows(); k++ {
		matInv[k] = make(Vector, m.Cols())
		for i := m.Rows() - 1; i >= 0; i-- {
			for j := m.Rows() - 1; j >= 0; j-- {
				if matInv[k][j] == nil {
					tmpSum, _ := triang[i][j+1 : m.Cols()].Dot(matInv[k][j+1:])
					matInv[k][j] = new(big.Int).Sub(triang[i][m.Cols()+k], tmpSum)
					mHKInv := new(big.Int).ModInverse(triang[i][j], p)
					matInv[k][j].Mul(matInv[k][j], mHKInv)
					matInv[k][j].Mod(matInv[k][j], p)
					break
				}
			}
		}
	}

	return matInv.Transpose(), det, nil
}

// DeterminantGauss returns the determinant of matrix m using Gaussian
// elimination. It returns an error if the determinant does not exist.
func (m Matrix) DeterminantGauss(p *big.Int) (*big.Int, error) {
	if m.Rows() != m.Cols() {
		return nil, fmt.Errorf("number of rows must equal number of columns")
	}
	triang, err := m.GaussianElimination(p)
	if err != nil {
		return nil, err
	}

	ret := big.NewInt(1)
	for i := 0; i < m.Cols(); i++ {
		ret.Mul(ret, triang[i][i])
		ret.Mod(ret, p)
	}

	return ret, nil
}

// GaussianEliminationSolver solves a vector equation mat * x = v and finds vector x,
// using Gaussian elimination. Arithmetic operations are considered to be over
// Z_p, where p should be a prime number. If such x does not exist, then the
// function returns an error.
func GaussianEliminationSolver(mat Matrix, v Vector, p *big.Int) (Vector, error) {
	if mat.Rows() == 0 || mat.Cols() == 0 {
		return nil, fmt.Errorf("the matrix should not be empty")
	}
	if mat.Rows() != len(v) {
		return nil, fmt.Errorf(fmt.Sprintf("dimensions should match: "+
			"rows of the matrix %d, length of the vector %d", mat.Rows(), len(v)))
	}

	// we copy matrix mat into m and v into u
	cpMat := make([]Vector, mat.Rows())
	u := make(Vector, mat.Rows())
	for i := 0; i < mat.Rows(); i++ {
		cpMat[i] = make(Vector, mat.Cols())
		for j := 0; j < mat.Cols(); j++ {
			cpMat[i][j] = new(big.Int).Set(mat[i][j])
		}
		u[i] = new(big.Int).Set(v[i])
	}
	m, _ := NewMatrix(cpMat) // error is impossible to happen

	// m and u are transformed to be in the upper triangular form
	ret := make(Vector, mat.Cols())
	h, k := 0, 0
	for h < mat.Rows() && k < mat.Cols() {
		zero := true
		for i := h; i < mat.Rows(); i++ {
			if m[i][k].Sign() != 0 {
				m[h], m[i] = m[i], m[h]

				u[h], u[i] = u[i], u[h]
				zero = false
				break
			}
		}
		if zero {
			ret[k] = big.NewInt(0)
			k++
			continue
		}
		mHKInv := new(big.Int).ModInverse(m[h][k], p)
		for i := h + 1; i < mat.Rows(); i++ {
			f := new(big.Int).Mul(mHKInv, m[i][k])
			m[i][k] = big.NewInt(0)
			for j := k + 1; j < mat.Cols(); j++ {
				m[i][j].Sub(m[i][j], new(big.Int).Mul(f, m[h][j]))
				m[i][j].Mod(m[i][j], p)
			}
			u[i].Sub(u[i], new(big.Int).Mul(f, u[h]))
			u[i].Mod(u[i], p)
		}
		k++
		h++
	}

	for i := h; i < mat.Rows(); i++ {
		if u[i].Sign() != 0 {
			return nil, fmt.Errorf("no solution")
		}
	}
	for j := k; j < mat.Cols(); j++ {
		ret[j] = big.NewInt(0)
	}

	// use the upper triangular form to obtain the solution
	for i := h - 1; i >= 0; i-- {
		for j := k - 1; j >= 0; j-- {
			if ret[j] == nil {
				tmpSum, _ := m[i][j+1:].Dot(ret[j+1:])
				ret[j] = new(big.Int).Sub(u[i], tmpSum)
				mHKInv := new(big.Int).ModInverse(m[i][j], p)
				ret[j].Mul(ret[j], mHKInv)
				ret[j].Mod(ret[j], p)
				break
			}
		}
	}

	return ret, nil
}

// Tensor creates a tensor product of matrices m and other.
// The result is returned in a new Matrix.
func (m Matrix) Tensor(other Matrix) Matrix {
	prod := make(Matrix, m.Rows()*other.Rows())
	for i := 0; i < prod.Rows(); i++ {
		prod[i] = make(Vector, m.Cols()*other.Cols())
		for j := 0; j < len(prod[i]); j++ {
			prod[i][j] = new(big.Int).Mul(m[i/other.Rows()][j/other.Cols()], other[i%other.Rows()][j%other.Cols()])
		}
	}

	return prod
}

// ToVec creates a vector whose entries are entries of m
// ordered as m_11, m_12,..., m_21, m_22,..., m_kl.
func (m Matrix) ToVec() Vector {
	res := make(Vector, m.Rows()*m.Cols())
	for i := 0; i < m.Rows(); i++ {
		for j := 0; j < m.Cols(); j++ {
			res[m.Cols()*i+j] = new(big.Int).Set(m[i][j])
		}
	}

	return res
}

// JoinCols joins matrices m and other in a new Matrix
// with columns from both matrices.
func (m Matrix) JoinCols(other Matrix) (Matrix, error) {
	if m.Rows() != other.Rows() {
		return nil, fmt.Errorf("dimensions do not fit")
	}

	res := make(Matrix, m.Rows())
	for i := 0; i < m.Rows(); i++ {
		res[i] = make(Vector, m.Cols()+other.Cols())
		for j := 0; j < m.Cols()+other.Cols(); j++ {
			if j < m.Cols() {
				res[i][j] = new(big.Int).Set(m[i][j])
			} else {
				res[i][j] = new(big.Int).Set(other[i][j-m.Cols()])
			}
		}
	}

	return res, nil
}

// JoinRows joins matrices m and other in a new Matrix
// with rows from both matrices.
func (m Matrix) JoinRows(other Matrix) (Matrix, error) {
	if m.Cols() != other.Cols() {
		return nil, fmt.Errorf("dimensions do not fit")
	}

	res := make(Matrix, m.Rows()+other.Rows())
	for i := 0; i < res.Rows(); i++ {
		res[i] = make(Vector, m.Cols())
		for j := 0; j < m.Cols(); j++ {
			if i < m.Rows() {
				res[i][j] = new(big.Int).Set(m[i][j])
			} else {
				res[i][j] = new(big.Int).Set(other[i-m.Rows()][j])
			}
		}
	}

	return res, nil
}

// Identity returns the identity matrix with given dimensions.
func Identity(rows, cols int) Matrix {
	res := NewConstantMatrix(rows, cols, big.NewInt(0))
	for i := 0; i < rows && i < cols; i++ {
		res[i][i].SetInt64(1)
	}

	return res
}


================================================
FILE: data/matrix_bn256.go
================================================
package data

import (
	"math/big"

	"github.com/fentec-project/bn256"
)

// MatrixG1 wraps a slice of VectorG1 elements. It represents a row-major.
// order matrix.
//
// The j-th element from the i-th vector of the matrix can be obtained
// as m[i][j].
type MatrixG1 []VectorG1

// Rows returns the number of rows of matrixG1 m.
func (m MatrixG1) Rows() int {
	return len(m)
}

// Cols returns the number of columns of matrixG1 m.
func (m MatrixG1) Cols() int {
	if len(m) != 0 {
		return len(m[0])
	}

	return 0
}

// Add sums matrices m and other componentwise.
// It returns the result in a new MatrixG1 instance.
func (m MatrixG1) Add(other MatrixG1) MatrixG1 {
	sum := make(MatrixG1, len(m))
	for i := range sum {
		sum[i] = m[i].Add(other[i])
	}

	return sum
}

// MulScalar multiplies matrix m by a scalar s.
// It returns the result in a new MatrixG1 instance.
func (m MatrixG1) MulScalar(s *big.Int) MatrixG1 {
	out := make(MatrixG1, m.Rows())
	for i := range out {
		out[i] = m[i].MulScalar(s)
	}

	return out
}

// MulVector multiplies matrix m by a vector v, i.e if
// m is t * [bn256.G1] for some matrix t, then the result
// is (t * v) [bn256.G1]
func (m MatrixG1) MulVector(v Vector) VectorG1 {
	out := make(VectorG1, m.Rows())
	for i := range out {
		out[i] = new(bn256.G1).ScalarBaseMult(big.NewInt(0))
		for k := 0; k < m.Cols(); k++ {
			mik := new(bn256.G1).Set(m[i][k])
			vk := new(big.Int).Set(v[k])
			if v[k].Sign() == -1 {
				vk.Neg(vk)
				mik.Neg(mik)
			}
			tmp := new(bn256.G1).ScalarMult(mik, vk)
			out[i].Add(tmp, out[i])
		}
	}

	return out
}

// MatrixG2 wraps a slice of VectorG2 elements. It represents a row-major.
// order matrix.
//
// The j-th element from the i-th vector of the matrix can be obtained
// as m[i][j].
type MatrixG2 []VectorG2

// Rows returns the number of rows of matrixG2 m.
func (m MatrixG2) Rows() int {
	return len(m)
}

// Cols returns the number of columns of matrixG2 m.
func (m MatrixG2) Cols() int {
	if len(m) != 0 {
		return len(m[0])
	}

	return 0
}

// MulScalar multiplies matrix m by a scalar s
func (m MatrixG2) MulScalar(s *big.Int) MatrixG2 {
	out := make(MatrixG2, m.Rows())
	for i := range out {
		out[i] = m[i].MulScalar(s)
	}

	return out
}

// MulVector multiplies matrix m by a vector v, i.e if
// m is t * [bn256.G2] for some matrix t, then the result
// is (t * v) [bn256.G2]
func (m MatrixG2) MulVector(v Vector) VectorG2 {
	out := make(VectorG2, m.Rows())
	for i := range out {
		out[i] = new(bn256.G2).ScalarBaseMult(big.NewInt(0))
		for k := 0; k < m.Cols(); k++ {
			mik := new(bn256.G2).Set(m[i][k])
			vk := new(big.Int).Set(v[k])
			if v[k].Sign() == -1 {
				vk.Neg(vk)
				mik.Neg(mik)
			}
			tmp := new(bn256.G2).ScalarMult(mik, vk)
			out[i].Add(tmp, out[i])
		}
	}

	return out
}


================================================
FILE: data/matrix_test.go
================================================
/*
 * Copyright (c) 2018 XLAB d.o.o
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package data

import (
	"math/big"
	"testing"

	"github.com/fentec-project/gofe/sample"
	"github.com/stretchr/testify/assert"
)

func TestMatrix(t *testing.T) {
	rows, cols := 5, 3
	bound := new(big.Int).Exp(big.NewInt(2), big.NewInt(20), big.NewInt(0))
	sampler := sample.NewUniform(bound)

	x, err := NewRandomMatrix(rows, cols, sampler)
	if err != nil {
		t.Fatalf("Error during random generation: %v", err)
	}

	y, err := NewRandomMatrix(rows, cols, sampler)
	if err != nil {
		t.Fatalf("Error during random generation: %v", err)
	}

	add, err := x.Add(y)

	if err != nil {
		t.Fatalf("Error during matrix addition: %v", err)
	}

	modulo := big.NewInt(int64(104729))
	mod := x.Mod(modulo)

	for i := 0; i < rows; i++ {
		for j := 0; j < cols; j++ {
			assert.Equal(t, new(big.Int).Add(x[i][j], y[i][j]), add[i][j], "coordinates should sum correctly")
			assert.Equal(t, new(big.Int).Mod(x[i][j], modulo), mod[i][j], "coordinates should mod correctly")
		}
	}

	sampler = sample.NewUniform(big.NewInt(256))
	var key [32]byte
	for i := range key {
		r, _ := sampler.Sample()
		key[i] = byte(r.Int64())
	}

	_, err = NewRandomDetMatrix(100, 100, big.NewInt(5), &key)
	assert.Equal(t, err, nil)
}

func TestMatrix_Rows(t *testing.T) {
	m, _ := NewRandomMatrix(2, 3, sample.NewUniform(big.NewInt(10)))
	assert.Equal(t, 2, m.Rows())
}

func TestMatrix_Cols(t *testing.T) {
	m, _ := NewRandomMatrix(2, 3, sample.NewUniform(big.NewInt(10)))
	assert.Equal(t, 3, m.Cols())
}

func TestMatrix_Empty(t *testing.T) {
	var m Matrix
	assert.Equal(t, 0, m.Rows())
	assert.Equal(t, 0, m.Cols())
}

func TestMatrix_DimsMatch(t *testing.T) {
	sampler := sample.NewUniform(big.NewInt(10))
	m1, _ := NewRandomMatrix(2, 3, sampler)
	m2, _ := NewRandomMatrix(2, 3, sampler)
	m3, _ := NewRandomMatrix(2, 4, sampler)
	m4, _ := NewRandomMatrix(3, 3, sampler)

	assert.True(t, m1.DimsMatch(m2))
	assert.False(t, m1.DimsMatch(m3))
	assert.False(t, m1.DimsMatch(m4))
}

func TestMatrix_CheckDims(t *testing.T) {
	sampler := sample.NewUniform(big.NewInt(10))
	m, _ := NewRandomMatrix(2, 2, sampler)

	assert.True(t, m.CheckDims(2, 2))
	assert.False(t, m.CheckDims(2, 3))
	assert.False(t, m.CheckDims(3, 2))
	assert.False(t, m.CheckDims(3, 3))
}

func TestMatrix_Dot(t *testing.T) {
	m1 := Matrix{
		Vector{big.NewInt(1), big.NewInt(2)},
		Vector{big.NewInt(3), big.NewInt(4)},
	}
	m2 := Matrix{
		Vector{big.NewInt(4), big.NewInt(3)},
		Vector{big.NewInt(2), big.NewInt(1)},
	}
	mismatched := Matrix{
		Vector{big.NewInt(1), big.NewInt(2)},
	}

	dot, _ := m1.Dot(m2)
	_, err := m1.Dot(mismatched)

	assert.Equal(t, big.NewInt(20), dot, "dot product of matrices does not work correctly")
	assert.Error(t, err, "expected an error to because of dimension mismatch")
}

func TestMatrix_MulScalar(t *testing.T) {
	one := big.NewInt(1)
	two := big.NewInt(2)
	m := Matrix{
		Vector{one, one, one},
		Vector{one, one, one},
	}
	mTimesTwo := Matrix{
		Vector{two, two, two},
		Vector{two, two, two},
	}

	assert.Equal(t, m.MulScalar(two), mTimesTwo)
}

func TestMatrix_MulVec(t *testing.T) {
	m := Matrix{
		Vector{big.NewInt(1), big.NewInt(2), big.NewInt(3)},
		Vector{big.NewInt(4), big.NewInt(5), big.NewInt(6)},
	}
	v := Vector{big.NewInt(2), big.NewInt(2), big.NewInt(2)}
	vMismatched := Vector{big.NewInt(1)}

	mvExpected := Vector{big.NewInt(12), big.NewInt(30)}
	mv, _ := m.MulVec(v)
	_, err := m.MulVec(vMismatched)

	assert.Equal(t, mvExpected, mv, "product of matrix and vector does not work correctly")
	assert.Error(t, err, "expected an error to because of dimension mismatch")
}

func TestMatrix_Mul(t *testing.T) {
	m1 := Matrix{
		Vector{big.NewInt(1), big.NewInt(2), big.NewInt(3)},
		Vector{big.NewInt(4), big.NewInt(5), big.NewInt(6)},
	}
	m2 := Matrix{
		Vector{big.NewInt(1), big.NewInt(2)},
		Vector{big.NewInt(3), big.NewInt(4)},
		Vector{big.NewInt(5), big.NewInt(6)},
	}
	mismatched := Matrix{Vector{big.NewInt(1)}}

	prodExpected := Matrix{
		Vector{big.NewInt(22), big.NewInt(28)},
		Vector{big.NewInt(49), big.NewInt(64)},
	}
	prod, _ := m1.Mul(m2)
	_, err := m1.Mul(mismatched)

	assert.Equal(t, prodExpected, prod, "product of matrices does not work correctly")
	assert.Error(t, err, "expected an error to because of dimension mismatch")
}

func TestMatrix_Determinant(t *testing.T) {
	m := Matrix{
		Vector{big.NewInt(1), big.NewInt(1), big.NewInt(1)},
		Vector{big.NewInt(4), big.NewInt(5), big.NewInt(6)},
		Vector{big.NewInt(4), big.NewInt(4), big.NewInt(3)},
	}
	p := big.NewInt(7)

	det1, err := m.Determinant()
	if err != nil {
		t.Fatalf("Error during computation of determinant: %v", err)
	}
	det1.Mod(det1, p)

	det2, err := m.DeterminantGauss(p)
	if err != nil {
		t.Fatalf("Error during computation of determinant: %v", err)
	}

	assert.Equal(t, det1, det2, "computed determinants are not equal")
}

func TestMatrix_InverseMod(t *testing.T) {
	m := Matrix{
		Vector{big.NewInt(1), big.NewInt(1), big.NewInt(1)},
		Vector{big.NewInt(4), big.NewInt(5), big.NewInt(6)},
		Vector{big.NewInt(4), big.NewInt(4), big.NewInt(3)},
	}
	p := big.NewInt(7)

	mInv1, err := m.InverseMod(p)
	if err != nil {
		t.Fatalf("Error during computation of inverse: %v", err)
	}

	mInv2, _, err := m.InverseModGauss(p)
	if err != nil {
		t.Fatalf("Error during computation of inverse: %v", err)
	}
	for i := 0; i < m.Rows(); i++ {
		for j := 0; j < m.Cols(); j++ {
			assert.Equal(t, mInv1[i][j].Cmp(mInv2[i][j]), 0, "computed inverses are not equal")
		}

	}
}

func TestMatrix_GaussianElimintaion(t *testing.T) {
	// create instances mat, xTest and v for which mat * xTest = v
	// as a matrix vector multiplication over Z_p
	p := big.NewInt(17)
	sampler := sample.NewUniform(p)
	mat, err := NewRandomMatrix(100, 50, sampler)
	if err != nil {
		t.Fatalf("Error during matrix generation: %v", err)
	}

	xTest, err := NewRandomVector(50, sampler)
	if err != nil {
		t.Fatalf("Error during vector generation: %v", err)
	}

	v, err := mat.MulVec(xTest)
	if err != nil {
		t.Fatalf("Error in generating a test vector: %v", err)
	}
	v = v.Mod(p)

	// test the Gaussian elimination algorithm that given v and mat
	// finds x such that mat * x = v
	x, err := GaussianEliminationSolver(mat, v, p)
	if err != nil {
		t.Fatalf("Error in Gaussian elimination: %v", err)
	}

	// test if the obtained x is correct
	vCheck, err := mat.MulVec(x)
	if err != nil {
		t.Fatalf("Error obtainig a check value: %v", err)
	}
	vCheck = vCheck.Mod(p)
	assert.Equal(t, v, vCheck)

	// test if errors are returned if the inputs have a wrong form
	vWrong, err := NewRandomVector(101, sampler)
	if err != nil {
		t.Fatalf("Error during vector generation: %v", err)
	}
	_, err = GaussianEliminationSolver(mat, vWrong, p)
	assert.Error(t, err)

	matWrong := make(Matrix, 0)
	_, err = GaussianEliminationSolver(matWrong, v, p)
	assert.Error(t, err)
}

func TestMatrix_Tensor(t *testing.T) {
	m1 := Matrix{
		Vector{big.NewInt(1), big.NewInt(2)},
		Vector{big.NewInt(3), big.NewInt(4)},
	}
	m2 := Matrix{
		Vector{big.NewInt(1), big.NewInt(2)},
	}

	prodExpected := Matrix{
		Vector{big.NewInt(1), big.NewInt(2), big.NewInt(2), big.NewInt(4)},
		Vector{big.NewInt(3), big.NewInt(6), big.NewInt(4), big.NewInt(8)},
	}
	prod := m1.Tensor(m2)

	assert.Equal(t, prodExpected, prod, "tensor product of matrices does not work correctly")
}


================================================
FILE: data/vector.go
================================================
/*
 * Copyright (c) 2018 XLAB d.o.o
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package data

import (
	"fmt"
	"math/big"

	"github.com/fentec-project/bn256"
	"github.com/fentec-project/gofe/sample"
	"golang.org/x/crypto/salsa20"
)

// Vector wraps a slice of *big.Int elements.
type Vector []*big.Int

// NewVector returns a new Vector instance.
func NewVector(coordinates []*big.Int) Vector {
	return Vector(coordinates)
}

// NewRandomVector returns a new Vector instance
// with random elements sampled by the provided sample.Sampler.
// Returns an error in case of sampling failure.
func NewRandomVector(len int, sampler sample.Sampler) (Vector, error) {
	vec := make([]*big.Int, len)
	var err error

	for i := 0; i < len; i++ {
		vec[i], err = sampler.Sample()
		if err != nil {
			return nil, err
		}
	}

	return NewVector(vec), nil
}

// NewRandomDetVector returns a new Vector instance
// with (deterministic) random elements sampled by a pseudo-random
// number generator. Elements are sampled from [0, max) and key
// determines the pseudo-random generator.
func NewRandomDetVector(len int, max *big.Int, key *[32]byte) (Vector, error) {
	if max.Cmp(big.NewInt(2)) < 0 {
		return nil, fmt.Errorf("upper bound on samples should be at least 2")
	}

	maxBits := new(big.Int).Sub(max, big.NewInt(1)).BitLen()
	maxBytes := (maxBits + 7) / 8
	over := uint((8 * maxBytes) - maxBits)

	lTimesMaxBytes := len * maxBytes
	nonce := make([]byte, 8) // nonce is initialized to zeros
	ret := make([]*big.Int, len)

	for i := 3; true; i++ {
		in := make([]byte, i*lTimesMaxBytes) // input is initialized to zeros

		out := make([]byte, i*lTimesMaxBytes)

		salsa20.XORKeyStream(out, in, nonce, key)

		j := 0
		k := 0
		for j < (i * lTimesMaxBytes) {
			out[j] = out[j] >> over
			ret[k] = new(big.Int).SetBytes(out[j:(j + maxBytes)])
			if ret[k].Cmp(max) < 0 {
				k++
			}
			if k == len {
				break
			}
			j += maxBytes

		}
		if k == len {
			break
		}
	}

	return NewVector(ret), nil
}

// NewConstantVector returns a new Vector instance
// with all elements set to constant c.
func NewConstantVector(len int, c *big.Int) Vector {
	vec := make([]*big.Int, len)
	for i := 0; i < len; i++ {
		vec[i] = new(big.Int).Set(c)
	}

	return vec
}

// Copy creates a new vector with the same values
// of the entries.
func (v Vector) Copy() Vector {
	newVec := make(Vector, len(v))

	for i, c := range v {
		newVec[i] = new(big.Int).Set(c)
	}

	return newVec
}

// MulScalar multiplies vector v by a given scalar x.
// The result is returned in a new Vector.
func (v Vector) MulScalar(x *big.Int) Vector {
	res := make(Vector, len(v))
	for i, vi := range v {
		res[i] = new(big.Int).Mul(x, vi)
	}

	return res
}

// Mod performs modulo operation on vector's elements.
// The result is returned in a new Vector.
func (v Vector) Mod(modulo *big.Int) Vector {
	newCoords := make([]*big.Int, len(v))

	for i, c := range v {
		newCoords[i] = new(big.Int).Mod(c, modulo)
	}

	return NewVector(newCoords)
}

// CheckBound checks whether the absolute values of all vector elements
// are strictly smaller than the provided bound.
// It returns error if at least one element's absolute value is >= bound.
func (v Vector) CheckBound(bound *big.Int) error {
	abs := new(big.Int)
	for _, c := range v {
		abs.Abs(c)
		if abs.Cmp(bound) > 0 {
			return fmt.Errorf("all coordinates of a vector should not be greater than bound")
		}
	}

	return nil
}

// Apply applies an element-wise function f to vector v.
// The result is returned in a new Vector.
func (v Vector) Apply(f func(*big.Int) *big.Int) Vector {
	res := make(Vector, len(v))

	for i, vi := range v {
		res[i] = f(vi)
	}

	return res
}

// Neg returns -v for given vector v.
// The result is returned in a new Vector.
func (v Vector) Neg() Vector {
	neg := make([]*big.Int, len(v))
	for i, c := range v {
		neg[i] = new(big.Int).Neg(c)
	}

	return neg
}

// Add adds vectors v and other.
// The result is returned in a new Vector.
func (v Vector) Add(other Vector) Vector {
	sum := make([]*big.Int, len(v))

	for i, c := range v {
		sum[i] = new(big.Int).Add(c, other[i])
	}

	return NewVector(sum)
}

// Sub subtracts vectors v and other.
// The result is returned in a new Vector.
func (v Vector) Sub(other Vector) Vector {
	sub := make([]*big.Int, len(v))
	for i, c := range v {
		sub[i] = new(big.Int).Sub(c, other[i])
	}

	return sub
}

// Dot calculates the dot product (inner product) of vectors v and other.
// It returns an error if vectors have different numbers of elements.
func (v Vector) Dot(other Vector) (*big.Int, error) {
	prod := big.NewInt(0)

	if len(v) != len(other) {
		return nil, fmt.Errorf("vectors should be of same length")
	}

	for i, c := range v {
		prod = prod.Add(prod, new(big.Int).Mul(c, other[i]))
	}

	return prod, nil
}

// MulAsPolyInRing multiplies vectors v and other as polynomials
// in the ring of polynomials R = Z[x]/((x^n)+1), where n is length of
// the vectors. Note that the input vector [1, 2, 3] represents a
// polynomial Z[x] = x²+2x+3.
// It returns a new polynomial with degree <= n-1.
//
// If vectors differ in size, error is returned.
func (v Vector) MulAsPolyInRing(other Vector) (Vector, error) {
	if len(v) != len(other) {
		return nil, fmt.Errorf("vectors must have the same length")
	}
	n := len(v)

	// Result will be a polynomial with the degree <= n-1
	prod := new(big.Int)
	res := make(Vector, n)

	// Over all degrees, beginning at lowest degree
	for i := 0; i < n; i++ {
		res[i] = big.NewInt(0)
		// Handle products with degrees < n
		for j := 0; j <= i; j++ {
			prod.Mul(v[i-j], other[j]) // Multiply coefficients
			res[i].Add(res[i], prod)
		}
		// Handle products with degrees >= n
		for j := i + 1; j < n; j++ {
			prod.Mul(v[n+i-j], other[j]) // Multiply coefficients
			prod.Neg(prod)               // Negate, because x^n = -1
			res[i].Add(res[i], prod)
		}
	}

	return res, nil
}

// MulG1 calculates bn256.G1 * v (also g1^v in multiplicative notation)
// and returns the result (v[0] * bn256.G1, ... , v[n-1] * bn256.G1) in a
// VectorG1 instance.
func (v Vector) MulG1() VectorG1 {
	prod := make(VectorG1, len(v))
	for i := range prod {
		vi := new(big.Int).Abs(v[i])
		prod[i] = new(bn256.G1).ScalarBaseMult(vi)
		if v[i].Sign() == -1 {
			prod[i].Neg(prod[i])
		}
	}

	return prod
}

// MulVecG1 calculates g1 * v (also g1^v in multiplicative notation)
// and returns the result (v[0] * g1[0], ... , v[n-1] * g1[n-1]) in a
// VectorG1 instance.
func (v Vector) MulVecG1(g1 VectorG1) VectorG1 {
	zero := big.NewInt(0)

	prod := make(VectorG1, len(v))
	for i := range prod {
		vi := new(big.Int).Set(v[i])
		g1i := new(bn256.G1).Set(g1[i])
		if vi.Cmp(zero) == -1 {
			g1i.Neg(g1i)
			vi.Neg(vi)
		}
		prod[i] = new(bn256.G1).ScalarMult(g1i, vi)
	}

	return prod
}

// MulG2 calculates bn256.G2 * v (also g2^v in multiplicative notation)
// and returns the result (v[0] * bn256.G2, ... , v[n-1] * bn256.G2) in a
// VectorG2 instance.
func (v Vector) MulG2() VectorG2 {
	prod := make(VectorG2, len(v))
	for i := range prod {
		vi := new(big.Int).Abs(v[i])
		prod[i] = new(bn256.G2).ScalarBaseMult(vi)
		if v[i].Sign() == -1 {
			prod[i].Neg(prod[i])
		}
	}

	return prod
}

// MulVecG2 calculates g2 * v (also g2^v in multiplicative notation)
// and returns the result (v[0] * g2[0], ... , v[n-1] * g2[n-1]) in a
// VectorG2 instance.
func (v Vector) MulVecG2(g2 VectorG2) VectorG2 {
	zero := big.NewInt(0)

	prod := make(VectorG2, len(v))
	for i := range prod {
		vi := new(big.Int).Set(v[i])
		g2i := new(bn256.G2).Set(g2[i])
		if vi.Cmp(zero) == -1 {
			g2i.Neg(g2i)
			vi.Neg(vi)
		}
		prod[i] = new(bn256.G2).ScalarMult(g2i, vi)
	}

	return prod
}

// String produces a string representation of a vector.
func (v Vector) String() string {
	vStr := ""
	for _, yi := range v {
		vStr = vStr + " " + yi.String()
	}
	return vStr
}

// Tensor creates a tensor product of vectors v and other.
// The result is returned in a new Vector.
func (v Vector) Tensor(other Vector) Vector {
	prod := make(Vector, len(v)*len(other))
	for i := 0; i < len(prod); i++ {
		prod[i] = new(big.Int).Mul(v[i/len(other)], other[i%len(other)])
	}

	return prod
}


================================================
FILE: data/vector_bn256.go
================================================
/*
 * Copyright (c) 2018 XLAB d.o.o
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package data

import (
	"math/big"

	"github.com/fentec-project/bn256"
)

// VectorG1 wraps a slice of elements from elliptic curve BN256.G1 group.
type VectorG1 []*bn256.G1

// Add sums vectors v1 and v2 (also v1 * v2 in multiplicative notation).
// It returns the result in a new VectorG1 instance.
func (v VectorG1) Add(other VectorG1) VectorG1 {
	sum := make(VectorG1, len(v))
	for i := range sum {
		sum[i] = new(bn256.G1).Add(v[i], other[i])
	}

	return sum
}

// Neg returns a new VectorG1 instance with
// values -v in the additive notation.
func (v VectorG1) Neg() VectorG1 {
	neg := make(VectorG1, len(v))
	for i := range neg {
		neg[i] = new(bn256.G1).Neg(v[i])
	}

	return neg
}

// Copy produces a new copy of vector v.
func (v VectorG1) Copy() VectorG1 {
	cp := make(VectorG1, len(v))
	for i := range cp {
		cp[i] = new(bn256.G1).Set(v[i])
	}

	return cp
}

// MulScalar multiplies s * v (in additive notation).
func (v VectorG1) MulScalar(s *big.Int) VectorG1 {
	sTmp := new(big.Int).Set(s)
	out := v.Copy()
	if s.Sign() == -1 {
		sTmp.Neg(s)
		out = out.Neg()
	}

	for i := range out {
		out[i].ScalarMult(out[i], sTmp)
	}

	return out
}

// VectorG2 wraps a slice of elements from elliptic curve BN256.G2 group.
type VectorG2 []*bn256.G2

// Add sums vectors v1 and v2 (also v1 * v2 in multiplicative notation).
// It returns the result in a new VectorG2 instance.
func (v VectorG2) Add(other VectorG2) VectorG2 {
	sum := make(VectorG2, len(v))
	for i := range sum {
		sum[i] = new(bn256.G2).Add(v[i], other[i])
	}

	return sum
}

// Neg returns a new VectorG1 instance with
// values -v in the additive notation.
func (v VectorG2) Neg() VectorG2 {
	neg := make(VectorG2, len(v))
	for i := range neg {
		neg[i] = new(bn256.G2).Neg(v[i])
	}

	return neg
}

// Copy produces a new copy of vector v.
func (v VectorG2) Copy() VectorG2 {
	cp := make(VectorG2, len(v))
	for i := range cp {
		cp[i] = new(bn256.G2).Set(v[i])
	}

	return cp
}

// MulScalar multiplies s * v (in additive notation).
func (v VectorG2) MulScalar(s *big.Int) VectorG2 {
	sTmp := new(big.Int).Set(s)
	out := v.Copy()
	if s.Sign() == -1 {
		sTmp.Neg(s)
		out = out.Neg()
	}

	for i := range out {
		out[i].ScalarMult(out[i], sTmp)
	}

	return out
}

// VectorGT wraps a slice of elements from pairing BN256.GT group.
type VectorGT []*bn256.GT

// Dot multiplies v = (v_1,...,v_n) and other = (o_1,...,o_n) to
// return v1 * o_1 + ... + v_n *o_n (in additive notation)
func (v VectorGT) Dot(other Vector) *bn256.GT {
	prod := new(bn256.GT).ScalarBaseMult(big.NewInt(0))

	for i, c := range v {
		prod.Add(prod, new(bn256.GT).ScalarMult(c, other[i]))
	}

	return prod
}


================================================
FILE: data/vector_test.go
================================================
/*
 * Copyright (c) 2018 XLAB d.o.o
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package data

import (
	"math/big"
	"testing"

	"github.com/fentec-project/gofe/sample"
	"github.com/stretchr/testify/assert"
)

func TestVector(t *testing.T) {
	l := 3
	bound := new(big.Int).Exp(big.NewInt(2), big.NewInt(20), big.NewInt(0))
	sampler := sample.NewUniform(bound)

	x, err := NewRandomVector(l, sampler)
	if err != nil {
		t.Fatalf("Error during random generation: %v", err)
	}

	y, err := NewRandomVector(l, sampler)
	if err != nil {
		t.Fatalf("Error during random generation: %v", err)
	}

	add := x.Add(y)
	mul, err := x.Dot(y)

	if err != nil {
		t.Fatalf("Error during vector multiplication: %v", err)
	}

	modulo := int64(104729)
	mod := x.Mod(big.NewInt(modulo))

	innerProd := big.NewInt(0)
	for i := 0; i < 3; i++ {
		assert.Equal(t, new(big.Int).Add(x[i], y[i]), add[i], "coordinates should sum correctly")
		innerProd = innerProd.Add(innerProd, new(big.Int).Mul(x[i], y[i]))
		assert.Equal(t, new(big.Int).Mod(x[i], big.NewInt(modulo)), mod[i], "coordinates should mod correctly")
	}

	assert.Equal(t, innerProd, mul, "inner product should calculate correctly")

	sampler = sample.NewUniform(big.NewInt(256))
	var key [32]byte
	for i := range key {
		r, _ := sampler.Sample()
		key[i] = byte(r.Int64())
	}

	_, err = NewRandomDetVector(100, big.NewInt(5), &key)
	assert.Equal(t, err, nil)
}

func TestVector_MulAsPolyInRing(t *testing.T) {
	p1 := Vector{big.NewInt(0), big.NewInt(1), big.NewInt(2)}
	p2 := Vector{big.NewInt(2), big.NewInt(1), big.NewInt(0)}
	prod, _ := p1.MulAsPolyInRing(p2)

	assert.Equal(t, prod, Vector{big.NewInt(-2), big.NewInt(2), big.NewInt(5)})
}

func TestVecor_Tensor(t *testing.T) {
	v1 := Vector{big.NewInt(1), big.NewInt(2)}

	v2 := Vector{big.NewInt(1), big.NewInt(2)}

	prodExpected := Vector{big.NewInt(1), big.NewInt(2), big.NewInt(2), big.NewInt(4)}
	prod := v1.Tensor(v2)

	assert.Equal(t, prodExpected, prod, "tensor product of vectors does not work correctly")
}


================================================
FILE: doc.go
================================================
/*
 * Copyright (c) 2018 XLAB d.o.o
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// Package gofe provides implementations of functional encryption
// schemes for linear and quadratic polynomials.
package gofe


================================================
FILE: go.mod
================================================
module github.com/fentec-project/gofe

go 1.17

require (
	github.com/fentec-project/bn256 v0.0.0-20190726093940-0d0fc8bfeed0
	github.com/pkg/errors v0.9.1
	github.com/stretchr/testify v1.7.0
	golang.org/x/crypto v0.0.0-20211115234514-b4de73f9ece8
)

require (
	github.com/davecgh/go-spew v1.1.0 // indirect
	github.com/pmezard/go-difflib v1.0.0 // indirect
	golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 // indirect
	gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
)


================================================
FILE: go.sum
================================================
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fentec-project/bn256 v0.0.0-20190726093940-0d0fc8bfeed0 h1:mkWVpEiA+MMlWxElUXRqTVSH9eETZvqJ21NZTaDaMiI=
github.com/fentec-project/bn256 v0.0.0-20190726093940-0d0fc8bfeed0/go.mod h1:llEBqR6SDQxLj2lH10BjIYPrcoqDAFv6mhsqvHfIzlI=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
golang.org/x/crypto v0.0.0-20211115234514-b4de73f9ece8 h1:5QRxNnVsaJP6NAse0UdkRgL3zHMvCRRkrDVLNdNpdy4=
golang.org/x/crypto v0.0.0-20211115234514-b4de73f9ece8/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=


================================================
FILE: innerprod/doc.go
================================================
/*
 * Copyright (c) 2018 XLAB d.o.o
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// Package innerprod includes functional encryption schemes for inner
// products.
//
// Based on security assumptions, the schemes are organized into
// subpackages simple (s-IND-CPA security), and fullysec
// (e.g. "fully secure", offering adaptive IND-CPA security).
//
// Note that in both packages you will find single input as
// well as multi input schemes. Construction of all multi input
// schemes is based on the work of Abdalla et. al (see paper:
// https://eprint.iacr.org/2017/972.pdf)
package innerprod


================================================
FILE: innerprod/fullysec/damgard.go
================================================
/*
 * Copyright (c) 2018 XLAB d.o.o
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package fullysec

import (
	"fmt"
	"math/big"

	"github.com/fentec-project/gofe/data"
	"github.com/fentec-project/gofe/internal"
	"github.com/fentec-project/gofe/internal/dlog"
	"github.com/fentec-project/gofe/internal/keygen"
	"github.com/fentec-project/gofe/sample"
)

// DamgardParams includes public parameters for the Damgard inner
// product scheme.
// L (int): The length of vectors to be encrypted.
// Bound (int): The value by which coordinates of vectors x and y are bounded.
// G (int): Generator of a cyclic group Z_P: G**(Q) = 1 (mod P).
// H (int): Generator of a cyclic group Z_P: H**(Q) = 1 (mod P).
// P (int): Modulus - we are operating in a cyclic group Z_P.
// Q (int): Multiplicative order of G and H.
type DamgardParams struct {
	L     int
	Bound *big.Int
	G     *big.Int
	H     *big.Int
	P     *big.Int
	Q     *big.Int
}

// Damgard represents a scheme instantiated from the DDH assumption
// based on DDH variant of:
// Agrawal, Shweta, Libert, and Stehle:
// "Fully secure functional encryption for inner products,
// from standard assumptions".
type Damgard struct {
	Params *DamgardParams
}

// NewDamgard configures a new instance of the scheme.
// It accepts the length of input vectors l, the bit length of the
// modulus (we are operating in the Z_p group), and a bound by which
// coordinates of input vectors are bounded.
//
// It returns an error in case the scheme could not be properly
// configured, or if precondition l * bound² is >= order of the cyclic
// group.
func NewDamgard(l, modulusLength int, bound *big.Int) (*Damgard, error) {
	key, err := keygen.NewElGamal(modulusLength)
	if err != nil {
		return nil, err
	}
	zero := big.NewInt(0)
	one := big.NewInt(1)
	two := big.NewInt(2)

	bSquared := new(big.Int).Exp(bound, two, nil)
	prod := new(big.Int).Mul(big.NewInt(int64(2*l)), bSquared)
	if prod.Cmp(key.Q) > 0 {
		return nil, fmt.Errorf("2 * l * bound^2 should be smaller than group order")
	}

	h := new(big.Int)
	for {
		sampler := sample.NewUniformRange(two, key.Q)
		r, err := sampler.Sample()
		if err != nil {
			return nil, err
		}

		// h generated in the following way is always a generator with order q
		h.Exp(key.G, r, key.P)

		// additional checks to avoid some known attacks
		if new(big.Int).Mod(new(big.Int).Sub(key.P, one), h).Cmp(zero) == 0 {
			continue
		}
		hInv := new(big.Int).ModInverse(h, key.P)
		if new(big.Int).Mod(new(big.Int).Sub(key.P, one), hInv).Cmp(zero) == 0 {
			continue
		}
		break
	}

	return &Damgard{
		Params: &DamgardParams{
			L:     l,
			Bound: bound,
			G:     key.G,
			H:     h,
			P:     key.P,
			Q:     key.Q,
		},
	}, nil
}

// NewDamgardPrecomp configures a new instance of the scheme based on
// precomputed prime numbers and generators.
// It accepts the length of input vectors l, the bit length of the
// modulus (we are operating in the Z_p group), and a bound by which
// coordinates of input vectors are bounded. The modulus length should
// be one of values 1024, 1536, 2048, 2560, 3072, or 4096. The precomputed
// prime numbers and generators were simply obtained by running NewDamgard
// function.
//
// It returns an error in case the scheme could not be properly
// configured, or if precondition l * bound² is >= order of the cyclic
// group.
func NewDamgardPrecomp(l, modulusLength int, bound *big.Int) (*Damgard, error) {
	one := big.NewInt(1)
	two := big.NewInt(2)
	g := new(big.Int)
	h := new(big.Int)
	p := new(big.Int)

	if modulusLength == 1024 {
		g.SetString("34902160241479276675539633849372382885917193816560610471607073855548755350834003692485735908635894317735639518678334280193650806072183057417077181724192674928134805218882803812978345229222559213790765817899845072682155064387311523738581388872686127675360979304234957611566801734164757915959042140104663977828", 10)
		h.SetString("15420637599119437909472314391464117244272797175081469344935256550115202257944676665553901111021364396888996244331294748348639524453606317448549098209774792643437849812948134158610698367936877182339463164515756739059909678247548635902607622196992717889883047826579537373927574110724167611850755082659113353814", 10)
		p.SetString("166211269243229118758738154756726384542659478479960313411107431885216572625212662756677338184675400324411541201832214281445670912135683272416408753424543622705770319923251281963485084208425069817917631106045349238686234860629044433560424091289406000897029571960128048529362925472176997104870527051276406995203", 10)
	} else if modulusLength == 1536 {
		g.SetString("676416913692519694440150163403654362412279108516867264953779609011365998625435399420336578530015558254310139891236630566729665914687641028600402606957815727025192669238117788115237116562468680376464346714542467465836552396661693422160454402926392749202926871877212792118140354124110927269910674002861908621272286950597240072605316784317536178700101838123530590145680002962405974024190384775185108002307650499125333676880320808656556635493186351335151559453463208", 10)
		h.SetString("162435356591098080112923949933138473281129080012462876365242296621510003247926800168810467125425312741356845555051398168995345221821254788094709212569083281560861934370026731898947082535853089500762419810631794616608702382341836751059467526394750733484031555507059435514454850206195181859188711511695415306637351122791298103837179337333322817996915750092675310561842474481585085713281105392293555407844591189296291324552036671109998940504540100161197823599243891", 10)
		p.SetString("1851297899986638926486011430658634631676522135433726749065856232802142091866650774719879427474637700607873256035038534449089405369134066444876856913629831069906506096279113968447116822488133963417347136141052507685108634240736100862550194947326287783557220764070479431781692630708747550712729778398000353165406458520850089303530985563143326919073190605085889925484113854496074216626577246143598303709289292397203458923541841135799203967503522114881404128535647507", 10)
	} else if modulusLength == 2048 {
		g.SetString("4006960929413042209594165215465319088439374252008797022450541422457034721098828647078778605657155669917104962611933792130890703423519992986737966991597160684973795472419962788730248050852176194215699504914899438223683843401963466624139534923052671383315398134823370041633710463630745156269175253639670460050105594663691338308037509280576148624454011047879615100156717631945194107791315234171086603775159708325087759679758438868772220133433497821899045165244202228696902434100209752952701657306825368599999359102329396520012735146260911352901326915877502873633420811221206110021993351144711002138373506576799781061829", 10)
		h.SetString("16531397285674350767314702525644915041456240916042269006661016218466751820121367708744665988146094312460459686332899317211264306268688887145182608791297975910105233621322826639428591684097281721326762853220049531036892964645338402521408932284623118973840687103995270506055864839392780688919921574729334863152272712825111303515621796552988450890438067795005159750945818303100847992123152427222482913524403644261704298722743429153705746979942035168013929376597721413830914117313871470498590418693493905967182265847426629997026054543887503362398742858491325979767814095393383666927420156454285653125386823358683247619671", 10)
		p.SetString("28884237504713658990682089080899862128005980675308910325841161962760155725037929764087367167449843609136681034352509183117742758446654629096509285354423361556493020266963222508540306384896802796001914743293196010488452478370041404523014215612960481024232879327123268440037633547483165934132901270561772860319969916305482525766132307669097012989986613879246932730824899649301621408341438037745468033187743673001187803377254713546325789438300798311106106322698517805307792059495696632070953526611920926003483451787562399452650878943515646786958216714025307572678422373120397225912926110031401983688860264234966561627699", 10)
	} else if modulusLength == 2560 {
		g.SetString("283408881721750179985507845260248881237898607313021593637913985490973593382472548378053368228310040484438920416918021737085067966444840449068073874437662089659563355479608930182263107110969154912883370207053052795964658868443319273167870311282045348396320159912742394374241864712808383029954025256232806465551969466207671603658677963161975454703127476120201164519187150268352527923664649275471494757270139533433456630363925187498055211365480086561354743681517539297815712218419607006668655891574362066382949706266666189227897710299445185100212256741698216505337617571970963008519334554537811591236478130526432239803909461119767954934793813410765013072006162612226471775059215628326278458577643374735250370115470812597459244082296191871275203831471332697557979904062571849", 10)
		h.SetString("60603226626244984946015074611399313803245697048858823305998791050960516381707120286785720252208953282756722645401890645185550185014757676697220190895358672768431707069471110996253922983573984124316810681408685350886144002884260922773441021522086311309748129811838078781339054390074111039635714653119513182362870864625376495724028601281359016299631376501745572486338940082085075668612842777510700862160795716160806125722301037965086971367697165162183431144060195434995026056781565232838274115314469024436666926374971029865332455354830888647688402585402990945621351542202067894748432776518006655843916388537951718725340446233164828852013369347111758769617449735121060447630493643403400643959220152005725907208460642317320745167072023561550218217956652950353398499254599742", 10)
		p.SetString("403126381462544353337185732949672984701995200694926494258456907009253008321275627278199160008680481542251933923210212978304159426174307419863781623411302777276318286800690060166638633211627521530173324015527027650548199185539205697958056639406116068885574865579676651743820636201007864067569576455725489531113260031526605827601510665037511961715114944815619491261828558745083975042855063688267346905844510423020844412350570902289599734320004108557140241966071165594059732527795488131297017205383953304055105007982366596746708951250486384299368612656872813778220074826250625689603663742175288397398948456522281031888042417278385238985218731264092285591879578299600853004336936458454638992426900228708418575870946630137618851131144232868141478901063119847104013555395370887", 10)
	} else if modulusLength == 3072 {
		g.SetString("3696261717511684685041982088526264061294500298114921057816954458306445697150348237912729036967670872345042594238223317055749478029025374644864924550052402546275985983344583674703146236623453822520422465163020824494790581472736649085281450730460445260696087738043872307629635997875332076478424042345012004769107421873566499123042621978973433575500345010912635742477932006291250637245855027695943163956584173316781442078828050076620331751405548730676363847526959436516279320074682721438642683731766682502490935962962293815202487144775533102010333956118641968798500514719248831145108532912211817219793191951880318961073149276914867129023978524587935704313755469570162971499124682746476415187933097132047611840762510892175328320025164466873845777990557296853549970943298347924080102740724512079409979152285019931666423541870247789529268168448010024121369388707140296446100906359619586133848407970098685310317291828335700424602208", 10)
		h.SetString("567649039783047480227338473928434756096941793851205367034019596755160950347349183458824085567577717539018304618223485608741105961797110596645149404693961630602136531678036354529574048049387247758318737991227930011620451360293879761672154747784975220369021073972313352929486325631485787131058176462649454317449501920846554754923439009414476391939400343349482311343015897922534760972817588470659148393369453541539857229554365836585067664597417625404552690944486027240221141785988408230137708791844568226402922187996696503785944931820332617839757682381094642917330498053626106798012177968190876620737530689308284333593333125689734905825145119037797011061634852469676220493758348073580817216823443614368951436342741042435481507815482798733572408751161565276006768858533125203508129436766572987021821650216162035709837972268600512594452400036134765839973589301700524293661567605165762293059122431279400652446300525682001019196136", 10)
		p.SetString("4387756306134544957818467663802660683665166110605728231080818705443663402154316615145921798856363268744945754470238000282108344905251127487705736550297997444150840902348669718478564904142834154197029830975532074167513046443903186309497214496864577129616824062991068960005865144004932069025136224356325248036029606434443391988386519658751798077031844645051726026696307027395796695909035405241040411794836124123435225690961994089776517262574417789067836840997650095451062948856617211542724543995145259735683916440579956961657374517806591607068842498749297993409884001044324428640569001916341503645559748760311343179943896427393009949062735145363544745972252566600994034655540841225414736222780096833045470605544717177880459300618917961703559234544541206877026518430276932498602360341258899345739335298856394124351357206871568254540730107127298623178526868418799471896060015463201459762913197633841160710893895836663035998106119", 10)
	} else if modulusLength == 4096 {
		g.SetString("51665588681810560577916524923861643358980285220048008212528567741884121491554604183472728540139463099618903178110360757930742372390027135064809646425064896539133721148335557788263239281487173350543811713890328584918216783142094297306639941000480756707312457878765754357205186485080839623690156744636468433787780205323460166423447602447200754978133176713947189000663528355089645281397174452923418212485422962705227706103188302892660448134233848971142570881089940852441776074246332915421265800026335300100610273942459340241610730244726628211914068945587128124478812632725838440727321816905181830592204023095726270782834020990986443265625389712733369116937470448592846480352222814297792606318850361699893703272484112273500581408730519942517586496563772194165844831300501908379990979449691597045730512107756238377635183257797115883839801779086058652272455400286891699445584526719648220045380141260347316315487340493029966105973850214850475440630205768783542021741101804842248602349004364816943429122368563644935802417389995380389429997320053299323220481603252879925927515844929958940305561718295197935926645561977544440676439150126025681320050786964708227836328341875446457912905977470123640014345655062829575775837287500880054558386787", 10)
		h.SetString("653735051824112393106801492829043654983094810153936916566419297234893790474265474662670688710073348877202869152643983800310336936407217572878666006904653566429370273243928900524622200126090143285935697025102272467307580256707629199315519492688020243538476473287317884073943557740453015512750672402070439254723909940895097629630953500504933411614006835509266155433485165683944804036549172274160941459059251790260424550107135346982158930124883878553492540634625536558325828876220292338217093182644187426663586499630969144324838282516931412124575753931891717246058395623268249929461243359978135742469252500443989584744702727780893623276815417727584978028391169715443458364712495037724857002997953369015075369014382917440895283545982020768248209480534141352756164681807291197719347396848885385564846533227145898299352065862788210851139899108807494649254246247909836864209696565581846420881131639054554828603682225473062422081030815891806059849482326467150974089876248055494734946134244334370720707623963134127685862797676223995758737312498339183154611067568296397353652230198967761004520297654249905695573112921297631619886554083093006856350790194488256889122557656064371766221432744243315870629759094828247037312561620044735468234281300", 10)
		p.SetString("1022249395832567838406986294560330159176972202126664245047364146720891252715766488477689126342364655087193411078517616569887825896401401223927363505007778278205623713273194552498760148834874746839752870298152746450585455651115247220867383465863156721401567161663838310658875672995951663020449772454232797368263754624173026584111779206080723120076751471597509403139249260220696195263597156452889920392585797464801375940661326779247976331028637271512085826066667631423502199894046717721786935806581428328491087482664043743281068318459302242239861275878019857365021173868449409246193470959347916848019032536247915451026158871684654213802886886213841729258073333569276986893577214659899227179735448593265633219968622571880602115519942763955551007919826002851866939641065270816032435114864853636918330698605282572789904941484540512478406984407320963402583009124880812235841866246441862987563989772424040933513333746472128494254253767426962063553015635240386636751473945937412527996558505231385625318878887383161350102080329744822052478052004574860361461762694379860797225344866320388590336321515376486033237159694567932935601775209663052272120524337888258857351777348841323194553467226791591208931619058871750498804369190487499494069660723", 10)
	} else {
		return nil, fmt.Errorf("modulus length should be one of values 1024, 1536, 2048, 2560, 3072, or 4096")
	}

	q := new(big.Int).Sub(p, one)
	q.Div(q, two)

	bSquared := new(big.Int).Exp(bound, two, nil)
	prod := new(big.Int).Mul(big.NewInt(int64(2*l)), bSquared)
	if prod.Cmp(q) > 0 {
		return nil, fmt.Errorf("2 * l * bound^2 should be smaller than group order")
	}

	return &Damgard{
		Params: &DamgardParams{
			L:     l,
			Bound: bound,
			G:     g,
			H:     h,
			P:     p,
			Q:     q,
		},
	}, nil
}

// NewDamgardFromParams takes configuration parameters of an existing
// Damgard scheme instance, and reconstructs the scheme with same configuration
// parameters. It returns a new Damgard instance.
func NewDamgardFromParams(params *DamgardParams) *Damgard {
	return &Damgard{
		Params: params,
	}
}

// DamgardSecKey is a secret key for Damgard scheme.
type DamgardSecKey struct {
	S data.Vector
	T data.Vector
}

// GenerateMasterKeys generates a master secret key and master
// public key for the scheme. It returns an error in case master keys
// could not be generated.
func (d *Damgard) GenerateMasterKeys() (*DamgardSecKey, data.Vector, error) {
	// both part of masterSecretKey
	mskS := make(data.Vector, d.Params.L)
	mskT := make(data.Vector, d.Params.L)

	masterPubKey := make([]*big.Int, d.Params.L)
	sampler := sample.NewUniformRange(big.NewInt(2), d.Params.Q)

	for i := 0; i < d.Params.L; i++ {
		s, err := sampler.Sample()
		if err != nil {
			return nil, nil, err
		}
		mskS[i] = s

		t, err := sampler.Sample()
		if err != nil {
			return nil, nil, err
		}
		mskT[i] = t

		y1 := new(big.Int).Exp(d.Params.G, s, d.Params.P)
		y2 := new(big.Int).Exp(d.Params.H, t, d.Params.P)

		masterPubKey[i] = new(big.Int).Mod(new(big.Int).Mul(y1, y2), d.Params.P)
	}

	return &DamgardSecKey{S: mskS, T: mskT}, masterPubKey, nil
}

// DamgardDerivedKey is a functional encryption key for Damgard scheme.
type DamgardDerivedKey struct {
	Key1 *big.Int
	Key2 *big.Int
}

// DeriveKey takes master secret key and input vector y, and returns the
// functional encryption key. In case the key could not be derived, it
// returns an error.
func (d *Damgard) DeriveKey(masterSecKey *DamgardSecKey, y data.Vector) (*DamgardDerivedKey, error) {
	if err := y.CheckBound(d.Params.Bound); err != nil {
		return nil, err
	}

	key1, err := masterSecKey.S.Dot(y)
	if err != nil {
		return nil, err
	}

	key2, err := masterSecKey.T.Dot(y)
	if err != nil {
		return nil, err
	}

	k1 := new(big.Int).Mod(key1, d.Params.Q)
	k2 := new(big.Int).Mod(key2, d.Params.Q)

	return &DamgardDerivedKey{Key1: k1, Key2: k2}, nil
}

// Encrypt encrypts input vector x with the provided master public key.
// It returns a ciphertext vector. If encryption failed, error is returned.
func (d *Damgard) Encrypt(x, masterPubKey data.Vector) (data.Vector, error) {
	if err := x.CheckBound(d.Params.Bound); err != nil {
		return nil, err
	}

	sampler := sample.NewUniformRange(big.NewInt(2), d.Params.Q)
	r, err := sampler.Sample()
	if err != nil {
		return nil, err
	}

	ciphertext := make([]*big.Int, len(x)+2)
	// c = g^r
	// dd = h^r
	c := new(big.Int).Exp(d.Params.G, r, d.Params.P)
	ciphertext[0] = c
	dd := new(big.Int).Exp(d.Params.H, r, d.Params.P)
	ciphertext[1] = dd

	for i := 0; i < len(x); i++ {
		// e_i = h_i^r * g^x_i
		// e_i = mpk[i]^r * g^x_i
		t1 := new(big.Int).Exp(masterPubKey[i], r, d.Params.P)
		t2 := internal.ModExp(d.Params.G, x[i], d.Params.P)
		ct := new(big.Int).Mod(new(big.Int).Mul(t1, t2), d.Params.P)
		ciphertext[i+2] = ct
	}

	return data.NewVector(ciphertext), nil
}

// Decrypt accepts the encrypted vector, functional encryption key, and
// a plaintext vector y. It returns the inner product of x and y.
// If decryption failed, error is returned.
func (d *Damgard) Decrypt(cipher data.Vector, key *DamgardDerivedKey, y data.Vector) (*big.Int, error) {
	if err := y.CheckBound(d.Params.Bound); err != nil {
		return nil, err
	}

	num := big.NewInt(1)
	for i, ct := range cipher[2:] {
		t1 := internal.ModExp(ct, y[i], d.Params.P)
		num = num.Mod(new(big.Int).Mul(num, t1), d.Params.P)
	}

	t1 := new(big.Int).Exp(cipher[0], key.Key1, d.Params.P)
	t2 := new(big.Int).Exp(cipher[1], key.Key2, d.Params.P)

	denom := new(big.Int).Mod(new(big.Int).Mul(t1, t2), d.Params.P)
	denomInv := new(big.Int).ModInverse(denom, d.Params.P)
	r := new(big.Int).Mod(new(big.Int).Mul(num, denomInv), d.Params.P)

	bSquared := new(big.Int).Exp(d.Params.Bound, big.NewInt(2), big.NewInt(0))
	bound := new(big.Int).Mul(big.NewInt(int64(d.Params.L)), bSquared)

	calc, err := dlog.NewCalc().InZp(d.Params.P, d.Params.Q)
	if err != nil {
		return nil, err
	}
	calc = calc.WithNeg()

	res, err := calc.WithBound(bound).BabyStepGiantStep(r, d.Params.G)
	return res, err
}


================================================
FILE: innerprod/fullysec/damgard_dec_multi.go
================================================
/*
 * Copyright (c) 2018 XLAB d.o.o
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package fullysec

import (
	"crypto/sha256"
	"fmt"
	"math/big"

	"github.com/fentec-project/gofe/data"
	"github.com/fentec-project/gofe/sample"
)

// DamgardDecMultiClient represents a client in a decentralized
// multi client variant of the underlying multi client (dmagard_multi)
// scheme based. The decentralization is based on
// Abdalla, Benhamouda, Kohlweiss,and Waldner:
// "Decentralizing Inner-Product Functional Encryption".
// The participants in the scheme are clients without a central authority.
// They interactively generate private keys for each client so that client i
// can encrypt vector x_i. The scheme allows the clients to interactively
// generate a key_Y, depending on a matrix Y with rows y_i, so that
// given key_y and the ciphertext the decryptor can compute value
// Σ_i <x_i, y_i> (sum of dot products).
type DamgardDecMultiClient struct {
	// number of encryptors
	Idx int
	*DamgardMulti
	ClientPubKey *big.Int
	ClientSecKey *big.Int
	Share        data.Matrix
}

// NewDamgardDecMultiClient configures a new client in the decentralized scheme
// based on a underlying DamgardMulti scheme.
// It accepts the identification of the client (an integer from [0, numClients))
// and the underlying DamgardMulti scheme (which contains all the shared parameters)
//
// It returns an error in case the scheme cannot be properly initialized.
func NewDamgardDecMultiClient(idx int, damgardMulti *DamgardMulti) (*DamgardDecMultiClient, error) {
	sampler := sample.NewUniform(damgardMulti.Params.Q)
	sec, err := sampler.Sample()
	if err != nil {
		return nil, fmt.Errorf("could not generate random value")
	}
	pub := new(big.Int).Exp(damgardMulti.Params.G, sec, damgardMulti.Params.P)

	return &DamgardDecMultiClient{
		Idx:          idx,
		DamgardMulti: damgardMulti,
		ClientPubKey: pub,
		ClientSecKey: sec,
	}, nil
}

// SetShare sets a shared key for client c, based on the public keys of all the
// clients involved in the scheme. It assumes that Idx of a client indicates
// which is the corresponding public key in pubKeys. Shared keys are such that
// each client has a random key but all the shared keys sum to 0.
func (c *DamgardDecMultiClient) SetShare(pubKeys []*big.Int) error {
	c.Share = data.NewConstantMatrix(c.NumClients, c.Params.L, big.NewInt(0))
	var add data.Matrix
	var err error
	for k := 0; k < len(pubKeys); k++ {
		if k == c.Idx {
			continue
		}
		sharedNum := new(big.Int).Exp(pubKeys[k], c.ClientSecKey, c.Params.P)
		sharedKey := sha256.Sum256([]byte(sharedNum.String()))

		add, err = data.NewRandomDetMatrix(c.NumClients, c.Params.L, c.Params.Q, &sharedKey)
		if err != nil {
			return err
		}

		if k < c.Idx {
			c.Share, err = c.Share.Add(add)
			if err != nil {
				return err
			}
		} else {
			c.Share, err = c.Share.Sub(add)
			if err != nil {
				return err
			}
		}
		c.Share = c.Share.Mod(c.Params.Q)
	}

	return nil
}

// DamgardDecMultiSecKey is a secret key that each client has.
type DamgardDecMultiSecKey struct {
	sk     *DamgardSecKey
	pk     data.Vector
	OtpKey data.Vector
}

// GenerateKeys generates the secret key for each client.
//
// It returns an error in case master keys could not be generated.
func (c *DamgardDecMultiClient) GenerateKeys() (*DamgardDecMultiSecKey, error) {
	masterSecretKey, masterPublicKey, err := c.Damgard.GenerateMasterKeys()

	if err != nil {
		return nil, fmt.Errorf("error in master key generation")
	}

	otpVector, err := data.NewRandomVector(c.Damgard.Params.L,
		sample.NewUniform(c.Damgard.Params.Q))
	if err != nil {
		return nil, fmt.Errorf("error in random vector generation")
	}

	return &DamgardDecMultiSecKey{sk: masterSecretKey,
		pk:     masterPublicKey,
		OtpKey: otpVector}, nil
}

// Encrypt generates a ciphertext from the input vector x
// with the provided secret key.
// If encryption failed, error is returned.
func (c *DamgardDecMultiClient) Encrypt(x data.Vector, key *DamgardDecMultiSecKey) (data.Vector, error) {
	if err := x.CheckBound(c.Params.Bound); err != nil {
		return nil, err
	}

	xAddOtp := x.Add(key.OtpKey)
	otpModulo := xAddOtp.Mod(c.Params.Q)

	return c.Damgard.Encrypt(otpModulo, key.pk)
}

// DamgardDecMultiDerivedKeyPart is functional encryption key for decentralized
// Damgrad Scheme.
type DamgardDecMultiDerivedKeyPart struct {
	KeyPart    *DamgardDerivedKey
	OTPKeyPart *big.Int
}

// DeriveKeyShare is run by a client. It takes a secret key and
// a matrix y comprised of input vectors, and returns a part of
// the functional encryption key.
// In case the key could not be derived, it returns an error.
func (c *DamgardDecMultiClient) DeriveKeyShare(secKey *DamgardDecMultiSecKey, y data.Matrix) (*DamgardDecMultiDerivedKeyPart, error) {
	if err := y.CheckBound(c.Damgard.Params.Bound); err != nil {
		return nil, err
	}

	yPart := data.NewVector(y[c.Idx])
	z1, err := secKey.OtpKey.Dot(yPart)
	if err != nil {
		return nil, err
	}

	z2, err := c.Share.Dot(y)
	if err != nil {
		return nil, err
	}

	zPart := new(big.Int).Add(z1, z2)
	zPart.Mod(zPart, c.Damgard.Params.Q)
	key, err := c.Damgard.DeriveKey(secKey.sk, yPart)
	if err != nil {
		return nil, err
	}

	return &DamgardDecMultiDerivedKeyPart{key, zPart}, nil
}

// DamgardDecMultiDec represents a decryptor for the decentralized variant of the
// underlying multi input Damgard scheme.
type DamgardDecMultiDec struct {
	*DamgardMulti
}

// NewDamgardDecMultiDec takes the underlying DamgardMulti and instantiates a
// new DamgardDecMultiDec struct.
func NewDamgardDecMultiDec(damgardMulti *DamgardMulti) *DamgardDecMultiDec {
	return &DamgardDecMultiDec{
		DamgardMulti: NewDamgardMultiFromParams(damgardMulti.NumClients, damgardMulti.Bound, damgardMulti.Params),
	}
}

// Decrypt accepts an array of ciphertexts comprised of encrypted vectors,
// an array of partial functional encryption keys, and a matrix y representing
// the inner-product vectors. It returns the sum of inner products.
// If decryption failed, an error is returned.
func (dc *DamgardDecMultiDec) Decrypt(cipher []data.Vector, partKeys []*DamgardDecMultiDerivedKeyPart, y data.Matrix) (*big.Int, error) {
	if err := y.CheckBound(dc.Params.Bound); err != nil {
		return nil, err
	}
	if len(cipher) != len(partKeys) {
		return nil, fmt.Errorf("the number of keys does not match the number of ciphertexts")
	}

	keys := make([]*DamgardDerivedKey, len(partKeys))
	z := big.NewInt(0)
	for i := 0; i < len(partKeys); i++ {
		z.Add(z, partKeys[i].OTPKeyPart)
		keys[i] = partKeys[i].KeyPart
	}
	z.Mod(z, dc.Params.Q)
	key := &DamgardMultiDerivedKey{Keys: keys,
		Z: z,
	}

	return dc.DamgardMulti.Decrypt(cipher, key, y)
}


================================================
FILE: innerprod/fullysec/damgard_dec_multi_test.go
================================================
/*
 * Copyright (c) 2018 XLAB d.o.o
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package fullysec_test

import (
	"math/big"
	"testing"

	"github.com/fentec-project
Download .txt
gitextract_ii1m5ucw/

├── .circleci/
│   └── config.yml
├── .gitignore
├── AUTHORS.md
├── LICENSE
├── README.md
├── abe/
│   ├── dippe.go
│   ├── dippe_test.go
│   ├── doc.go
│   ├── fame.go
│   ├── fame_test.go
│   ├── gpsw.go
│   ├── gpsw_test.go
│   ├── ma-abe.go
│   ├── ma-abe_test.go
│   ├── policy.go
│   └── policy_test.go
├── data/
│   ├── doc.go
│   ├── matrix.go
│   ├── matrix_bn256.go
│   ├── matrix_test.go
│   ├── vector.go
│   ├── vector_bn256.go
│   └── vector_test.go
├── doc.go
├── go.mod
├── go.sum
├── innerprod/
│   ├── doc.go
│   ├── fullysec/
│   │   ├── damgard.go
│   │   ├── damgard_dec_multi.go
│   │   ├── damgard_dec_multi_test.go
│   │   ├── damgard_multi.go
│   │   ├── damgard_multi_test.go
│   │   ├── damgard_test.go
│   │   ├── dmcfe.go
│   │   ├── dmcfe_test.go
│   │   ├── doc.go
│   │   ├── fh_multi_ipe.go
│   │   ├── fh_multi_ipe_test.go
│   │   ├── fhipe.go
│   │   ├── fhipe_test.go
│   │   ├── lwe.go
│   │   ├── lwe_test.go
│   │   ├── paillier.go
│   │   ├── paillier_multi.go
│   │   ├── paillier_multi_test.go
│   │   ├── paillier_test.go
│   │   ├── part_fh_ipe.go
│   │   └── part_fh_ipe_test.go
│   └── simple/
│       ├── ddh.go
│       ├── ddh_multi.go
│       ├── ddh_multi_test.go
│       ├── ddh_test.go
│       ├── doc.go
│       ├── lwe.go
│       ├── lwe_test.go
│       ├── ringlwe.go
│       └── ringlwe_test.go
├── internal/
│   ├── dlog/
│   │   ├── brute_force.go
│   │   ├── brute_force_test.go
│   │   ├── calc.go
│   │   ├── calc_test.go
│   │   ├── dlog_test.go
│   │   ├── doc.go
│   │   ├── pollard_rho.go
│   │   └── pollard_rho_test.go
│   ├── errors.go
│   ├── keygen/
│   │   ├── elgamal.go
│   │   └── prime.go
│   └── mod_exp.go
├── quadratic/
│   ├── doc.go
│   ├── quad.go
│   ├── quad_test.go
│   ├── sgp.go
│   └── sgp_test.go
└── sample/
    ├── doc.go
    ├── normal.go
    ├── normal_cdt.go
    ├── normal_cdt_test.go
    ├── normal_cumulative.go
    ├── normal_cumulative_test.go
    ├── normal_double.go
    ├── normal_double_constant.go
    ├── normal_double_constant_test.go
    ├── normal_double_test.go
    ├── normal_negative.go
    ├── normal_negative_test.go
    ├── normal_test.go
    ├── sampler.go
    └── uniform.go
Download .txt
SYMBOL INDEX (434 symbols across 72 files)

FILE: abe/dippe.go
  type DIPPE (line 39) | type DIPPE struct
    method NewDIPPEAuth (line 109) | func (d *DIPPE) NewDIPPEAuth(id int) (*DIPPEAuth, error) {
    method Encrypt (line 158) | func (d *DIPPE) Encrypt(msg string, x data.Vector, pubKeys []*DIPPEPub...
    method Decrypt (line 274) | func (d *DIPPE) Decrypt(cipher *DIPPECipher, keys []data.VectorG2, v d...
    method ExactThresholdPolicyVecInit (line 347) | func (d DIPPE) ExactThresholdPolicyVecInit(attrib []int, threshold int...
    method ConjunctionPolicyVecInit (line 366) | func (d DIPPE) ConjunctionPolicyVecInit(attrib []int, numAttrib int) (...
    method AttributeVecInit (line 390) | func (d DIPPE) AttributeVecInit(attrib []int, numAttrib int) (data.Vec...
  type DIPPEPubKey (line 47) | type DIPPEPubKey struct
  type DIPPESecKey (line 54) | type DIPPESecKey struct
  type DIPPEAuth (line 61) | type DIPPEAuth struct
    method DeriveKeyShare (line 225) | func (a *DIPPEAuth) DeriveKeyShare(v data.Vector, pubKeys []*DIPPEPubK...
  type DIPPECipher (line 68) | type DIPPECipher struct
  function NewDIPPE (line 80) | func NewDIPPE(secLevel int) (*DIPPE, error) {

FILE: abe/dippe_test.go
  function TestDIPPE (line 29) | func TestDIPPE(t *testing.T) {
  function TestDIPPE_ABE_threshold (line 84) | func TestDIPPE_ABE_threshold(t *testing.T) {
  function TestDIPPE_ABE_conjugation (line 157) | func TestDIPPE_ABE_conjugation(t *testing.T) {

FILE: abe/fame.go
  type FAME (line 51) | type FAME struct
    method GenerateMasterKeys (line 75) | func (a *FAME) GenerateMasterKeys() (*FAMEPubKey, *FAMESecKey, error) {
    method Encrypt (line 112) | func (a *FAME) Encrypt(msg string, msp *MSP, pk *FAMEPubKey) (*FAMECip...
    method GenerateAttribKeys (line 231) | func (a *FAME) GenerateAttribKeys(gamma []string, sk *FAMESecKey) (*FA...
    method Decrypt (line 333) | func (a *FAME) Decrypt(cipher *FAMECipher, key *FAMEAttribKeys, pk *FA...
  function NewFAME (line 56) | func NewFAME() *FAME {
  type FAMESecKey (line 61) | type FAMESecKey struct
  type FAMEPubKey (line 67) | type FAMEPubKey struct
  type FAMECipher (line 98) | type FAMECipher struct
  type FAMEAttribKeys (line 221) | type FAMEAttribKeys struct

FILE: abe/fame_test.go
  function TestFAME (line 26) | func TestFAME(t *testing.T) {

FILE: abe/gpsw.go
  type GPSWParams (line 51) | type GPSWParams struct
  type GPSW (line 57) | type GPSW struct
    method GenerateMasterKeys (line 81) | func (a *GPSW) GenerateMasterKeys() (*GPSWPubKey, data.Vector, error) {
    method Encrypt (line 107) | func (a *GPSW) Encrypt(msg string, gamma interface{}, pk *GPSWPubKey) ...
    method GeneratePolicyKey (line 192) | func (a *GPSW) GeneratePolicyKey(msp *MSP, sk data.Vector) (*GPSWKey, ...
    method Decrypt (line 255) | func (a *GPSW) Decrypt(cipher *GPSWCipher, key *GPSWKey) (string, erro...
  function NewGPSW (line 65) | func NewGPSW(l int) *GPSW {
  type GPSWPubKey (line 73) | type GPSWPubKey struct
  type GPSWCipher (line 94) | type GPSWCipher struct
  type GPSWKey (line 183) | type GPSWKey struct
  function getSum (line 231) | func getSum(y *big.Int, p *big.Int, d int) (data.Vector, error) {

FILE: abe/gpsw_test.go
  function TestGPSW (line 27) | func TestGPSW(t *testing.T) {

FILE: abe/ma-abe.go
  type MAABE (line 46) | type MAABE struct
    method NewMAABEAuth (line 90) | func (a *MAABE) NewMAABEAuth(id string, attribs []string) (*MAABEAuth,...
    method Encrypt (line 242) | func (a *MAABE) Encrypt(msg string, msp *MSP, pks []*MAABEPubKey) (*MA...
    method Decrypt (line 438) | func (a * MAABE) Decrypt(ct *MAABECipher, ks []*MAABEKey) (string, err...
  function NewMAABE (line 54) | func NewMAABE() *MAABE {
  type MAABEPubKey (line 66) | type MAABEPubKey struct
  type MAABESecKey (line 73) | type MAABESecKey struct
  type MAABEAuth (line 80) | type MAABEAuth struct
    method PubKeys (line 135) | func (auth *MAABEAuth) PubKeys() *MAABEPubKey {
    method AddAttribute (line 156) | func (auth *MAABEAuth) AddAttribute(attrib string) error {
    method RegenerateKey (line 195) | func (auth *MAABEAuth) RegenerateKey(attrib string) error {
    method GenerateAttribKeys (line 401) | func (auth *MAABEAuth) GenerateAttribKeys(gid string, attribs []string...
  type MAABECipher (line 227) | type MAABECipher struct
  type MAABEKey (line 390) | type MAABEKey struct

FILE: abe/ma-abe_test.go
  function TestMAABE (line 9) | func TestMAABE(t *testing.T) {

FILE: abe/policy.go
  type MSP (line 34) | type MSP struct
  function BooleanToMSP (line 53) | func BooleanToMSP(boolExp string, convertToOnes bool) (*MSP, error) {
  function booleanToMSPIterative (line 96) | func booleanToMSPIterative(boolExp string, vec data.Vector, c int) (*MSP...
  function makeAndVecs (line 202) | func makeAndVecs(vec data.Vector, c int) (data.Vector, data.Vector) {

FILE: abe/policy_test.go
  function TestBooleanToMsp (line 27) | func TestBooleanToMsp(t *testing.T) {

FILE: data/matrix.go
  type Matrix (line 32) | type Matrix
    method Copy (line 103) | func (m Matrix) Copy() Matrix {
    method Rows (line 113) | func (m Matrix) Rows() int {
    method Cols (line 118) | func (m Matrix) Cols() int {
    method DimsMatch (line 128) | func (m Matrix) DimsMatch(other Matrix) bool {
    method GetCol (line 134) | func (m Matrix) GetCol(i int) (Vector, error) {
    method Transpose (line 149) | func (m Matrix) Transpose() Matrix {
    method CheckBound (line 163) | func (m Matrix) CheckBound(bound *big.Int) error {
    method CheckDims (line 175) | func (m Matrix) CheckDims(rows, cols int) bool {
    method Mod (line 181) | func (m Matrix) Mod(modulo *big.Int) Matrix {
    method Apply (line 195) | func (m Matrix) Apply(f func(*big.Int) *big.Int) Matrix {
    method Dot (line 208) | func (m Matrix) Dot(other Matrix) (*big.Int, error) {
    method Add (line 229) | func (m Matrix) Add(other Matrix) (Matrix, error) {
    method Sub (line 250) | func (m Matrix) Sub(other Matrix) (Matrix, error) {
    method Mul (line 267) | func (m Matrix) Mul(other Matrix) (Matrix, error) {
    method MulScalar (line 286) | func (m Matrix) MulScalar(x *big.Int) Matrix {
    method MulVec (line 296) | func (m Matrix) MulVec(v Vector) (Vector, error) {
    method MulXMatY (line 311) | func (m Matrix) MulXMatY(x, y Vector) (*big.Int, error) {
    method Minor (line 327) | func (m Matrix) Minor(i int, j int) (Matrix, error) {
    method Determinant (line 351) | func (m Matrix) Determinant() (*big.Int, error) {
    method InverseMod (line 380) | func (m Matrix) InverseMod(p *big.Int) (Matrix, error) {
    method MulG1 (line 427) | func (m Matrix) MulG1() MatrixG1 {
    method MulG2 (line 438) | func (m Matrix) MulG2() MatrixG2 {
    method MatMulMatG1 (line 451) | func (m Matrix) MatMulMatG1(other MatrixG1) (MatrixG1, error) {
    method MatMulMatG2 (line 481) | func (m Matrix) MatMulMatG2(other MatrixG2) (MatrixG2, error) {
    method MatMulVecG2 (line 511) | func (m Matrix) MatMulVecG2(other VectorG2) (VectorG2, error) {
    method GaussianElimination (line 536) | func (m Matrix) GaussianElimination(p *big.Int) (Matrix, error) {
    method InverseModGauss (line 584) | func (m Matrix) InverseModGauss(p *big.Int) (Matrix, *big.Int, error) {
    method DeterminantGauss (line 647) | func (m Matrix) DeterminantGauss(p *big.Int) (*big.Int, error) {
    method Tensor (line 752) | func (m Matrix) Tensor(other Matrix) Matrix {
    method ToVec (line 766) | func (m Matrix) ToVec() Vector {
    method JoinCols (line 779) | func (m Matrix) JoinCols(other Matrix) (Matrix, error) {
    method JoinRows (line 801) | func (m Matrix) JoinRows(other Matrix) (Matrix, error) {
  function NewMatrix (line 37) | func NewMatrix(vectors []Vector) (Matrix, error) {
  function NewRandomMatrix (line 57) | func NewRandomMatrix(rows, cols int, sampler sample.Sampler) (Matrix, er...
  function NewRandomDetMatrix (line 76) | func NewRandomDetMatrix(rows, cols int, max *big.Int, key *[32]byte) (Ma...
  function NewConstantMatrix (line 93) | func NewConstantMatrix(rows, cols int, c *big.Int) Matrix {
  function GaussianEliminationSolver (line 669) | func GaussianEliminationSolver(mat Matrix, v Vector, p *big.Int) (Vector...
  function Identity (line 822) | func Identity(rows, cols int) Matrix {

FILE: data/matrix_bn256.go
  type MatrixG1 (line 14) | type MatrixG1
    method Rows (line 17) | func (m MatrixG1) Rows() int {
    method Cols (line 22) | func (m MatrixG1) Cols() int {
    method Add (line 32) | func (m MatrixG1) Add(other MatrixG1) MatrixG1 {
    method MulScalar (line 43) | func (m MatrixG1) MulScalar(s *big.Int) MatrixG1 {
    method MulVector (line 55) | func (m MatrixG1) MulVector(v Vector) VectorG1 {
  type MatrixG2 (line 79) | type MatrixG2
    method Rows (line 82) | func (m MatrixG2) Rows() int {
    method Cols (line 87) | func (m MatrixG2) Cols() int {
    method MulScalar (line 96) | func (m MatrixG2) MulScalar(s *big.Int) MatrixG2 {
    method MulVector (line 108) | func (m MatrixG2) MulVector(v Vector) VectorG2 {

FILE: data/matrix_test.go
  function TestMatrix (line 27) | func TestMatrix(t *testing.T) {
  function TestMatrix_Rows (line 69) | func TestMatrix_Rows(t *testing.T) {
  function TestMatrix_Cols (line 74) | func TestMatrix_Cols(t *testing.T) {
  function TestMatrix_Empty (line 79) | func TestMatrix_Empty(t *testing.T) {
  function TestMatrix_DimsMatch (line 85) | func TestMatrix_DimsMatch(t *testing.T) {
  function TestMatrix_CheckDims (line 97) | func TestMatrix_CheckDims(t *testing.T) {
  function TestMatrix_Dot (line 107) | func TestMatrix_Dot(t *testing.T) {
  function TestMatrix_MulScalar (line 127) | func TestMatrix_MulScalar(t *testing.T) {
  function TestMatrix_MulVec (line 142) | func TestMatrix_MulVec(t *testing.T) {
  function TestMatrix_Mul (line 158) | func TestMatrix_Mul(t *testing.T) {
  function TestMatrix_Determinant (line 181) | func TestMatrix_Determinant(t *testing.T) {
  function TestMatrix_InverseMod (line 203) | func TestMatrix_InverseMod(t *testing.T) {
  function TestMatrix_GaussianElimintaion (line 228) | func TestMatrix_GaussianElimintaion(t *testing.T) {
  function TestMatrix_Tensor (line 277) | func TestMatrix_Tensor(t *testing.T) {

FILE: data/vector.go
  type Vector (line 29) | type Vector
    method Copy (line 112) | func (v Vector) Copy() Vector {
    method MulScalar (line 124) | func (v Vector) MulScalar(x *big.Int) Vector {
    method Mod (line 135) | func (v Vector) Mod(modulo *big.Int) Vector {
    method CheckBound (line 148) | func (v Vector) CheckBound(bound *big.Int) error {
    method Apply (line 162) | func (v Vector) Apply(f func(*big.Int) *big.Int) Vector {
    method Neg (line 174) | func (v Vector) Neg() Vector {
    method Add (line 185) | func (v Vector) Add(other Vector) Vector {
    method Sub (line 197) | func (v Vector) Sub(other Vector) Vector {
    method Dot (line 208) | func (v Vector) Dot(other Vector) (*big.Int, error) {
    method MulAsPolyInRing (line 229) | func (v Vector) MulAsPolyInRing(other Vector) (Vector, error) {
    method MulG1 (line 261) | func (v Vector) MulG1() VectorG1 {
    method MulVecG1 (line 277) | func (v Vector) MulVecG1(g1 VectorG1) VectorG1 {
    method MulG2 (line 297) | func (v Vector) MulG2() VectorG2 {
    method MulVecG2 (line 313) | func (v Vector) MulVecG2(g2 VectorG2) VectorG2 {
    method String (line 331) | func (v Vector) String() string {
    method Tensor (line 341) | func (v Vector) Tensor(other Vector) Vector {
  function NewVector (line 32) | func NewVector(coordinates []*big.Int) Vector {
  function NewRandomVector (line 39) | func NewRandomVector(len int, sampler sample.Sampler) (Vector, error) {
  function NewRandomDetVector (line 57) | func NewRandomDetVector(len int, max *big.Int, key *[32]byte) (Vector, e...
  function NewConstantVector (line 101) | func NewConstantVector(len int, c *big.Int) Vector {

FILE: data/vector_bn256.go
  type VectorG1 (line 26) | type VectorG1
    method Add (line 30) | func (v VectorG1) Add(other VectorG1) VectorG1 {
    method Neg (line 41) | func (v VectorG1) Neg() VectorG1 {
    method Copy (line 51) | func (v VectorG1) Copy() VectorG1 {
    method MulScalar (line 61) | func (v VectorG1) MulScalar(s *big.Int) VectorG1 {
  type VectorG2 (line 77) | type VectorG2
    method Add (line 81) | func (v VectorG2) Add(other VectorG2) VectorG2 {
    method Neg (line 92) | func (v VectorG2) Neg() VectorG2 {
    method Copy (line 102) | func (v VectorG2) Copy() VectorG2 {
    method MulScalar (line 112) | func (v VectorG2) MulScalar(s *big.Int) VectorG2 {
  type VectorGT (line 128) | type VectorGT
    method Dot (line 132) | func (v VectorGT) Dot(other Vector) *bn256.GT {

FILE: data/vector_test.go
  function TestVector (line 27) | func TestVector(t *testing.T) {
  function TestVector_MulAsPolyInRing (line 72) | func TestVector_MulAsPolyInRing(t *testing.T) {
  function TestVecor_Tensor (line 80) | func TestVecor_Tensor(t *testing.T) {

FILE: innerprod/fullysec/damgard.go
  type DamgardParams (line 38) | type DamgardParams struct
  type Damgard (line 52) | type Damgard struct
    method GenerateMasterKeys (line 199) | func (d *Damgard) GenerateMasterKeys() (*DamgardSecKey, data.Vector, e...
    method DeriveKey (line 238) | func (d *Damgard) DeriveKey(masterSecKey *DamgardSecKey, y data.Vector...
    method Encrypt (line 261) | func (d *Damgard) Encrypt(x, masterPubKey data.Vector) (data.Vector, e...
    method Decrypt (line 295) | func (d *Damgard) Decrypt(cipher data.Vector, key *DamgardDerivedKey, ...
  function NewDamgard (line 64) | func NewDamgard(l, modulusLength int, bound *big.Int) (*Damgard, error) {
  function NewDamgardPrecomp (line 125) | func NewDamgardPrecomp(l, modulusLength int, bound *big.Int) (*Damgard, ...
  function NewDamgardFromParams (line 184) | func NewDamgardFromParams(params *DamgardParams) *Damgard {
  type DamgardSecKey (line 191) | type DamgardSecKey struct
  type DamgardDerivedKey (line 230) | type DamgardDerivedKey struct

FILE: innerprod/fullysec/damgard_dec_multi.go
  type DamgardDecMultiClient (line 39) | type DamgardDecMultiClient struct
    method SetShare (line 74) | func (c *DamgardDecMultiClient) SetShare(pubKeys []*big.Int) error {
    method GenerateKeys (line 117) | func (c *DamgardDecMultiClient) GenerateKeys() (*DamgardDecMultiSecKey...
    method Encrypt (line 138) | func (c *DamgardDecMultiClient) Encrypt(x data.Vector, key *DamgardDec...
    method DeriveKeyShare (line 160) | func (c *DamgardDecMultiClient) DeriveKeyShare(secKey *DamgardDecMulti...
  function NewDamgardDecMultiClient (line 54) | func NewDamgardDecMultiClient(idx int, damgardMulti *DamgardMulti) (*Dam...
  type DamgardDecMultiSecKey (line 108) | type DamgardDecMultiSecKey struct
  type DamgardDecMultiDerivedKeyPart (line 151) | type DamgardDecMultiDerivedKeyPart struct
  type DamgardDecMultiDec (line 188) | type DamgardDecMultiDec struct
    method Decrypt (line 204) | func (dc *DamgardDecMultiDec) Decrypt(cipher []data.Vector, partKeys [...
  function NewDamgardDecMultiDec (line 194) | func NewDamgardDecMultiDec(damgardMulti *DamgardMulti) *DamgardDecMultiD...

FILE: innerprod/fullysec/damgard_dec_multi_test.go
  function testFullySecDamgardDecMultiFromParam (line 29) | func testFullySecDamgardDecMultiFromParam(t *testing.T, param damgardTes...
  function TestFullySec_DamgardDecMulti (line 123) | func TestFullySec_DamgardDecMulti(t *testing.T) {

FILE: innerprod/fullysec/damgard_multi.go
  type DamgardMulti (line 44) | type DamgardMulti struct
    method GenerateMasterKeys (line 160) | func (dm *DamgardMulti) GenerateMasterKeys() (*DamgardMultiSecKeys, er...
    method DeriveKey (line 212) | func (dm *DamgardMulti) DeriveKey(secKey *DamgardMultiSecKeys, y data....
    method Decrypt (line 239) | func (dm *DamgardMulti) Decrypt(cipher []data.Vector, key *DamgardMult...
  type DamgardMultiClient (line 52) | type DamgardMultiClient struct
    method Encrypt (line 192) | func (e *DamgardMultiClient) Encrypt(x data.Vector, pubKey, otp data.V...
  function NewDamgardMulti (line 66) | func NewDamgardMulti(numClients, l, modulusLength int, bound *big.Int) (...
  function NewDamgardMultiPrecomp (line 102) | func NewDamgardMultiPrecomp(numClients, l, modulusLength int, bound *big...
  function NewDamgardMultiClientFromParams (line 129) | func NewDamgardMultiClientFromParams(bound *big.Int, params *DamgardPara...
  function NewDamgardMultiFromParams (line 141) | func NewDamgardMultiFromParams(numClients int, bound *big.Int, params *D...
  type DamgardMultiSecKeys (line 151) | type DamgardMultiSecKeys struct
  type DamgardMultiDerivedKey (line 204) | type DamgardMultiDerivedKey struct

FILE: innerprod/fullysec/damgard_multi_test.go
  function testFullySecDamgardMultiDDHFromParam (line 29) | func testFullySecDamgardMultiDDHFromParam(t *testing.T, param damgardTes...
  function TestFullySec_DamgardMultiDDH (line 110) | func TestFullySec_DamgardMultiDDH(t *testing.T) {

FILE: innerprod/fullysec/damgard_test.go
  type damgardTestParam (line 29) | type damgardTestParam struct
  function testFullySecDamgardDDHFromParam (line 35) | func testFullySecDamgardDDHFromParam(t *testing.T, param damgardTestPara...
  function TestFullySec_DamgardDDH (line 98) | func TestFullySec_DamgardDDH(t *testing.T) {

FILE: innerprod/fullysec/dmcfe.go
  type DMCFEClient (line 33) | type DMCFEClient struct
    method SetShare (line 69) | func (c *DMCFEClient) SetShare(pubKeys []*bn256.G1) error {
    method Encrypt (line 103) | func (c *DMCFEClient) Encrypt(x *big.Int, label string) (*bn256.G1, er...
    method DeriveKeyShare (line 127) | func (c *DMCFEClient) DeriveKeyShare(y data.Vector) (data.VectorG2, er...
  function NewDMCFEClient (line 45) | func NewDMCFEClient(idx int) (*DMCFEClient, error) {
  function DMCFEDecrypt (line 158) | func DMCFEDecrypt(ciphers []*bn256.G1, keyShares []data.VectorG2, y data...

FILE: innerprod/fullysec/dmcfe_test.go
  function Test_DMCFE (line 31) | func Test_DMCFE(t *testing.T) {

FILE: innerprod/fullysec/fh_multi_ipe.go
  type FHMultiIPEParams (line 36) | type FHMultiIPEParams struct
  type FHMultiIPE (line 60) | type FHMultiIPE struct
    method GenerateKeys (line 91) | func (f FHMultiIPE) GenerateKeys() (*FHMultiIPESecKey, *bn256.GT, erro...
    method DeriveKey (line 157) | func (f FHMultiIPE) DeriveKey(y data.Matrix, secKey *FHMultiIPESecKey)...
    method Encrypt (line 195) | func (f FHMultiIPE) Encrypt(x data.Vector, partSecKey data.Matrix) (da...
    method Decrypt (line 224) | func (f *FHMultiIPE) Decrypt(cipher data.MatrixG1, key data.MatrixG2, ...
  type FHMultiIPESecKey (line 65) | type FHMultiIPESecKey struct
  function NewFHMultiIPE (line 73) | func NewFHMultiIPE(secLevel, numClients, vecLen int, boundX, boundY *big...
  function NewFHMultiIPEFromParams (line 82) | func NewFHMultiIPEFromParams(params *FHMultiIPEParams) *FHMultiIPE {
  function randomOB (line 134) | func randomOB(l int, mu *big.Int) (data.Matrix, data.Matrix, error) {

FILE: innerprod/fullysec/fh_multi_ipe_test.go
  function TestFH_Multi_IPE (line 29) | func TestFH_Multi_IPE(t *testing.T) {

FILE: innerprod/fullysec/fhipe.go
  type FHIPEParams (line 35) | type FHIPEParams struct
  type FHIPE (line 49) | type FHIPE struct
    method GenerateMasterKey (line 93) | func (d *FHIPE) GenerateMasterKey() (*FHIPESecKey, error) {
    method DeriveKey (line 129) | func (d *FHIPE) DeriveKey(y data.Vector, masterKey *FHIPESecKey) (*FHI...
    method Encrypt (line 177) | func (d *FHIPE) Encrypt(x data.Vector, masterKey *FHIPESecKey) (*FHIPE...
    method Decrypt (line 214) | func (d *FHIPE) Decrypt(cipher *FHIPECipher, key *FHIPEDerivedKey) (*b...
  function NewFHIPE (line 60) | func NewFHIPE(l int, boundX, boundY *big.Int) (*FHIPE, error) {
  function NewFHIPEFromParams (line 77) | func NewFHIPEFromParams(params *FHIPEParams) *FHIPE {
  type FHIPESecKey (line 84) | type FHIPESecKey struct
  type FHIPEDerivedKey (line 121) | type FHIPEDerivedKey struct
  type FHIPECipher (line 170) | type FHIPECipher struct

FILE: innerprod/fullysec/fhipe_test.go
  function TestFHIPE (line 29) | func TestFHIPE(t *testing.T) {

FILE: innerprod/fullysec/lwe.go
  type LWEParams (line 31) | type LWEParams struct
  type LWE (line 69) | type LWE struct
    method GenerateSecretKey (line 215) | func (s *LWE) GenerateSecretKey() (data.Matrix, error) {
    method GeneratePublicKey (line 246) | func (s *LWE) GeneratePublicKey(Z data.Matrix) (data.Matrix, error) {
    method DeriveKey (line 261) | func (s *LWE) DeriveKey(y data.Vector, Z data.Matrix) (data.Vector, er...
    method Encrypt (line 282) | func (s *LWE) Encrypt(x data.Vector, U data.Matrix) (data.Vector, erro...
    method Decrypt (line 329) | func (s *LWE) Decrypt(cipher, zY, y data.Vector) (*big.Int, error) {
  function NewLWE (line 87) | func NewLWE(l, n int, boundX, boundY *big.Int) (*LWE, error) {

FILE: innerprod/fullysec/lwe_test.go
  function TestFullySec_LWE (line 29) | func TestFullySec_LWE(t *testing.T) {
  function testVectorData (line 84) | func testVectorData(len int, boundX, boundY *big.Int) (data.Vector, data...

FILE: innerprod/fullysec/paillier.go
  type PaillierParams (line 31) | type PaillierParams struct
  type Paillier (line 47) | type Paillier struct
    method GenerateMasterKeys (line 156) | func (s *Paillier) GenerateMasterKeys() (data.Vector, data.Vector, err...
    method DeriveKey (line 177) | func (s *Paillier) DeriveKey(masterSecKey data.Vector, y data.Vector) ...
    method Encrypt (line 189) | func (s *Paillier) Encrypt(x, masterPubKey data.Vector) (data.Vector, ...
    method Decrypt (line 223) | func (s *Paillier) Decrypt(cipher data.Vector, key *big.Int, y data.Ve...
  function NewPaillier (line 64) | func NewPaillier(l, lambda, bitLen int, boundX, boundY *big.Int) (*Paill...
  function NewPaillierFromParams (line 147) | func NewPaillierFromParams(params *PaillierParams) *Paillier {

FILE: innerprod/fullysec/paillier_multi.go
  type PaillierMulti (line 43) | type PaillierMulti struct
    method GenerateMasterKeys (line 131) | func (dm *PaillierMulti) GenerateMasterKeys() (*PaillierMultiSecKeys, ...
    method DeriveKey (line 185) | func (dm *PaillierMulti) DeriveKey(secKey *PaillierMultiSecKeys, y dat...
    method Decrypt (line 213) | func (dm *PaillierMulti) Decrypt(cipher []data.Vector, key *PaillierMu...
  type PaillierMultiClient (line 51) | type PaillierMultiClient struct
    method Encrypt (line 163) | func (e *PaillierMultiClient) Encrypt(x data.Vector, pubKey, otp data....
  function NewPaillierMulti (line 70) | func NewPaillierMulti(numClients, l, lambda, bitLength int, boundX, boun...
  function NewPaillierMultiClientFromParams (line 99) | func NewPaillierMultiClientFromParams(params *PaillierParams, boundX, bo...
  function NewPaillierMultiFromParams (line 112) | func NewPaillierMultiFromParams(numClients int, boundX, boundY *big.Int,...
  type PaillierMultiSecKeys (line 123) | type PaillierMultiSecKeys struct
  type PaillierMultiDerivedKey (line 177) | type PaillierMultiDerivedKey struct

FILE: innerprod/fullysec/paillier_multi_test.go
  function TestFullySec_PaillierMulti (line 29) | func TestFullySec_PaillierMulti(t *testing.T) {

FILE: innerprod/fullysec/paillier_test.go
  function TestFullySec_Paillier (line 29) | func TestFullySec_Paillier(t *testing.T) {

FILE: innerprod/fullysec/part_fh_ipe.go
  type PartFHIPEParams (line 33) | type PartFHIPEParams struct
  type PartFHIPE (line 52) | type PartFHIPE struct
    method GenerateKeys (line 113) | func (d *PartFHIPE) GenerateKeys(M data.Matrix) (*PartFHIPEPubKey, *Pa...
    method DeriveKey (line 172) | func (d *PartFHIPE) DeriveKey(y data.Vector, secKey *PartFHIPESecKey) ...
    method Encrypt (line 216) | func (d *PartFHIPE) Encrypt(t data.Vector, pubKey *PartFHIPEPubKey) (d...
    method SecEncrypt (line 251) | func (d *PartFHIPE) SecEncrypt(x data.Vector, pubKey *PartFHIPEPubKey,...
    method PartDecrypt (line 290) | func (d *PartFHIPE) PartDecrypt(cipher data.VectorG1, feKey data.Vecto...
    method Decrypt (line 305) | func (d *PartFHIPE) Decrypt(cipher data.VectorG1, feKey data.VectorG2)...
  function NewPartFHIPE (line 63) | func NewPartFHIPE(l int, bound *big.Int) (*PartFHIPE, error) {
  function NewPartFHIPEFromParams (line 85) | func NewPartFHIPEFromParams(params *PartFHIPEParams) *PartFHIPE {
  type PartFHIPESecKey (line 93) | type PartFHIPESecKey struct
  type PartFHIPEPubKey (line 101) | type PartFHIPEPubKey struct

FILE: innerprod/fullysec/part_fh_ipe_test.go
  function TestPartFHIPE (line 29) | func TestPartFHIPE(te *testing.T) {

FILE: innerprod/simple/ddh.go
  type DDHParams (line 31) | type DDHParams struct
  type DDH (line 48) | type DDH struct
    method GenerateMasterKeys (line 155) | func (d *DDH) GenerateMasterKeys() (data.Vector, data.Vector, error) {
    method DeriveKey (line 176) | func (d *DDH) DeriveKey(masterSecKey, y data.Vector) (*big.Int, error) {
    method Encrypt (line 190) | func (d *DDH) Encrypt(x, masterPubKey data.Vector) (data.Vector, error) {
    method Decrypt (line 221) | func (d *DDH) Decrypt(cipher data.Vector, key *big.Int, y data.Vector)...
  function NewDDH (line 60) | func NewDDH(l, modulusLength int, bound *big.Int) (*DDH, error) {
  function NewDDHPrecomp (line 93) | func NewDDHPrecomp(l, modulusLength int, bound *big.Int) (*DDH, error) {
  function NewDDHFromParams (line 146) | func NewDDHFromParams(params *DDHParams) *DDH {

FILE: innerprod/simple/ddh_multi.go
  type DDHMulti (line 32) | type DDHMulti struct
    method GenerateMasterKeys (line 125) | func (dm *DDHMulti) GenerateMasterKeys() (data.Matrix, *DDHMultiSecKey...
    method DeriveKey (line 188) | func (dm *DDHMulti) DeriveKey(secKey *DDHMultiSecKey, y data.Matrix) (...
    method Decrypt (line 217) | func (dm *DDHMulti) Decrypt(cipher []data.Vector, key *DDHMultiDerived...
  type DDHMultiClient (line 43) | type DDHMultiClient struct
    method Encrypt (line 168) | func (e *DDHMultiClient) Encrypt(x data.Vector, pubKey, otp data.Vecto...
  function NewDDHMulti (line 55) | func NewDDHMulti(slots, l, modulusLength int, bound *big.Int) (*DDHMulti...
  function NewDDHMultiPrecomp (line 77) | func NewDDHMultiPrecomp(slots, l, modulusLength int, bound *big.Int) (*D...
  function NewDDHMultiFromParams (line 94) | func NewDDHMultiFromParams(slots int, params *DDHParams) *DDHMulti {
  function NewDDHMultiClient (line 109) | func NewDDHMultiClient(params *DDHParams) *DDHMultiClient {
  type DDHMultiSecKey (line 116) | type DDHMultiSecKey struct
  type DDHMultiDerivedKey (line 180) | type DDHMultiDerivedKey struct

FILE: innerprod/simple/ddh_multi_test.go
  function testSimpleMultiDDHFromParam (line 29) | func testSimpleMultiDDHFromParam(t *testing.T, param ddhTestParam) {
  function TestSimple_MultiDDH (line 120) | func TestSimple_MultiDDH(t *testing.T) {

FILE: innerprod/simple/ddh_test.go
  type ddhTestParam (line 29) | type ddhTestParam struct
  function testSimpleDDHFromParam (line 35) | func testSimpleDDHFromParam(t *testing.T, param ddhTestParam) {
  function TestSimple_DDH (line 98) | func TestSimple_DDH(t *testing.T) {

FILE: innerprod/simple/lwe.go
  type LWEParams (line 35) | type LWEParams struct
  type LWE (line 58) | type LWE struct
    method GenerateSecretKey (line 154) | func (s *LWE) GenerateSecretKey() (data.Matrix, error) {
    method GeneratePublicKey (line 163) | func (s *LWE) GeneratePublicKey(SK data.Matrix) (data.Matrix, error) {
    method DeriveKey (line 192) | func (s *LWE) DeriveKey(y data.Vector, SK data.Matrix) (data.Vector, e...
    method Encrypt (line 214) | func (s *LWE) Encrypt(x data.Vector, PK data.Matrix) (data.Vector, err...
    method center (line 254) | func (s *LWE) center(v data.Vector) data.Vector {
    method Decrypt (line 269) | func (s *LWE) Decrypt(ct, skY, y data.Vector) (*big.Int, error) {
  function NewLWE (line 77) | func NewLWE(l int, boundX, boundY *big.Int, n int) (*LWE, error) {

FILE: innerprod/simple/lwe_test.go
  function TestSimple_LWE (line 29) | func TestSimple_LWE(t *testing.T) {
  function testVectorData (line 77) | func testVectorData(len int, boundX, boundY *big.Int) (data.Vector, data...

FILE: innerprod/simple/ringlwe.go
  type RingLWEParams (line 30) | type RingLWEParams struct
  type RingLWE (line 61) | type RingLWE struct
    method GenerateSecretKey (line 158) | func (s *RingLWE) GenerateSecretKey() (data.Matrix, error) {
    method GeneratePublicKey (line 169) | func (s *RingLWE) GeneratePublicKey(SK data.Matrix) (data.Matrix, erro...
    method DeriveKey (line 200) | func (s *RingLWE) DeriveKey(y data.Vector, SK data.Matrix) (data.Vecto...
    method center (line 220) | func (s *RingLWE) center(X data.Matrix) data.Matrix {
    method Encrypt (line 247) | func (s *RingLWE) Encrypt(X data.Matrix, PK data.Matrix) (*RingLWECiph...
    method Decrypt (line 308) | func (s *RingLWE) Decrypt(CT *RingLWECipher, skY, y data.Vector) (data...
  function NewRingLWE (line 72) | func NewRingLWE(sec, l int, boundX, boundY *big.Int) (*RingLWE, error) {
  type RingLWECipher (line 235) | type RingLWECipher struct

FILE: innerprod/simple/ringlwe_test.go
  function TestSimple_RingLWE (line 29) | func TestSimple_RingLWE(t *testing.T) {

FILE: internal/dlog/brute_force.go
  function bruteForce (line 27) | func bruteForce(h, g, p, bound *big.Int) (*big.Int, error) {
  function bruteForceBN256 (line 42) | func bruteForceBN256(h, g *bn256.GT, bound *big.Int) (*big.Int, error) {

FILE: internal/dlog/brute_force_test.go
  function TestBruteForceBN256 (line 29) | func TestBruteForceBN256(t *testing.T) {
  function TestBruteForce (line 49) | func TestBruteForce(t *testing.T) {

FILE: internal/dlog/calc.go
  type Calc (line 35) | type Calc struct
    method InZp (line 53) | func (*Calc) InZp(p, order *big.Int) (*CalcZp, error) {
    method InBN256 (line 253) | func (*Calc) InBN256() *CalcBN256 {
  function NewCalc (line 38) | func NewCalc() *Calc {
  type CalcZp (line 44) | type CalcZp struct
    method WithBound (line 81) | func (c *CalcZp) WithBound(bound *big.Int) *CalcZp {
    method WithNeg (line 98) | func (c *CalcZp) WithNeg() *CalcZp {
    method BabyStepGiantStep (line 114) | func (c *CalcZp) BabyStepGiantStep(h, g *big.Int) (*big.Int, error) {
    method runBabyStepGiantStep (line 153) | func (c *CalcZp) runBabyStepGiantStep(h, g *big.Int, retChan chan *big...
    method runBabyStepGiantStepIterative (line 191) | func (c *CalcZp) runBabyStepGiantStepIterative(h, g *big.Int, retChan ...
  type CalcBN256 (line 243) | type CalcBN256 struct
    method WithBound (line 264) | func (c *CalcBN256) WithBound(bound *big.Int) *CalcBN256 {
    method WithNeg (line 282) | func (c *CalcBN256) WithNeg() *CalcBN256 {
    method Precompute (line 294) | func (c *CalcBN256) Precompute(maxBits int) error {
    method BabyStepGiantStepStd (line 327) | func (c *CalcBN256) BabyStepGiantStepStd(h, g *bn256.GT) (*big.Int, er...
    method BabyStepGiantStep (line 359) | func (c *CalcBN256) BabyStepGiantStep(h, g *bn256.GT) (*big.Int, error) {
    method runBabyStepGiantStepIterative (line 406) | func (c *CalcBN256) runBabyStepGiantStepIterative(h, g *bn256.GT, retC...

FILE: internal/dlog/calc_test.go
  function TestCalcZp_BabyStepGiantStep_ElGamal (line 30) | func TestCalcZp_BabyStepGiantStep_ElGamal(t *testing.T) {
  function TestCalcBN256_BabyStepGiantStep (line 79) | func TestCalcBN256_BabyStepGiantStep(t *testing.T) {

FILE: internal/dlog/dlog_test.go
  type params (line 28) | type params struct
  function getParams (line 32) | func getParams() (*params, error) {
  function TestDLog (line 45) | func TestDLog(t *testing.T) {

FILE: internal/dlog/pollard_rho.go
  function pollardRho (line 28) | func pollardRho(h, g, p, order *big.Int) (*big.Int, error) {
  type triple (line 105) | type triple struct
  function process (line 111) | func process(x, a, b *big.Int, iterate func(x, a, b *big.Int), c chan<- ...
  function pollardRhoParallel (line 131) | func pollardRhoParallel(h, g, p, order *big.Int) (*big.Int, error) {
  constant cycleSizeBound (line 222) | cycleSizeBound = 1024 * 1024
  function pollardRhoFactorization (line 229) | func pollardRhoFactorization(n, b *big.Int) (map[string]int, error) {
  function pollardRhoCycle (line 283) | func pollardRhoCycle(n *big.Int) (*big.Int, error) {
  function runCycle (line 303) | func runCycle(n, x *big.Int) *big.Int {

FILE: internal/dlog/pollard_rho_test.go
  function TestPollardRho (line 30) | func TestPollardRho(t *testing.T) {
  function TestPollardRhoParallel (line 54) | func TestPollardRhoParallel(t *testing.T) {
  function TestPollardRhoFactorization (line 77) | func TestPollardRhoFactorization(t *testing.T) {
  function TestPollardRhoElGamal (line 94) | func TestPollardRhoElGamal(t *testing.T) {
  function checkFactorization (line 120) | func checkFactorization(factorization map[string]int, n *big.Int, t *tes...
  function TestPollardRhoFactorizationHard (line 137) | func TestPollardRhoFactorizationHard(t *testing.T) {
  function TestPollardRhoFactorizationBounded (line 153) | func TestPollardRhoFactorizationBounded(t *testing.T) {
  function getSmoothNumber (line 165) | func getSmoothNumber(B, numPrimes, maxPower int) *big.Int {

FILE: internal/keygen/elgamal.go
  type ElGamal (line 27) | type ElGamal struct
  function NewElGamal (line 36) | func NewElGamal(modulusLength int) (*ElGamal, error) {

FILE: internal/keygen/prime.go
  function GetSafePrime (line 27) | func GetSafePrime(bits int) (p *big.Int, err error) {
  function GetGermainPrime (line 43) | func GetGermainPrime(bits int) (p *big.Int) {
  function germainPrime (line 74) | func germainPrime(bits int, c chan *big.Int, quit chan int) (p *big.Int,...

FILE: internal/mod_exp.go
  function ModExp (line 22) | func ModExp(g, x, m *big.Int) *big.Int {

FILE: quadratic/quad.go
  type QuadParams (line 36) | type QuadParams struct
  type Quad (line 55) | type Quad struct
    method GenerateKeys (line 119) | func (q *Quad) GenerateKeys() (*QuadPubKey, *QuadSecKey, error) {
    method Encrypt (line 217) | func (q *Quad) Encrypt(x, y data.Vector, pubKey *QuadPubKey) (*QuadCip...
    method DeriveKey (line 261) | func (q *Quad) DeriveKey(secKey *QuadSecKey, F data.Matrix) (data.Vect...
    method Decrypt (line 288) | func (q *Quad) Decrypt(c *QuadCipher, feKey data.VectorG2, F data.Matr...
  function NewQuad (line 63) | func NewQuad(n, m int, b *big.Int) (*Quad, error) {
  function NewQuadFromParams (line 92) | func NewQuadFromParams(params *QuadParams) *Quad {
  type QuadPubKey (line 101) | type QuadPubKey struct
  type QuadSecKey (line 110) | type QuadSecKey struct
  type QuadCipher (line 208) | type QuadCipher struct

FILE: quadratic/quad_test.go
  function TestQuad (line 29) | func TestQuad(t *testing.T) {

FILE: quadratic/sgp.go
  type SGP (line 39) | type SGP struct
    method GenerateMasterKey (line 86) | func (q *SGP) GenerateMasterKey() (*SGPSecKey, error) {
    method Encrypt (line 122) | func (q *SGP) Encrypt(x, y data.Vector, msk *SGPSecKey) (*SGPCipher, e...
    method DeriveKey (line 176) | func (q *SGP) DeriveKey(msk *SGPSecKey, F data.Matrix) (*bn256.G2, err...
    method Decrypt (line 196) | func (q *SGP) Decrypt(c *SGPCipher, key *bn256.G2, F data.Matrix) (*bi...
  function NewSGP (line 57) | func NewSGP(n int, b *big.Int) *SGP {
  type SGPSecKey (line 70) | type SGPSecKey struct
  function NewSGPSecKey (line 76) | func NewSGPSecKey(s, t data.Vector) *SGPSecKey {
  type SGPCipher (line 103) | type SGPCipher struct
  function NewSGPCipher (line 110) | func NewSGPCipher(g1MulGamma *bn256.G1, aMulG1 []data.VectorG1,

FILE: quadratic/sgp_test.go
  function TestSGP (line 29) | func TestSGP(t *testing.T) {

FILE: sample/normal.go
  type normal (line 28) | type normal struct
    method precompExp (line 125) | func (c normal) precompExp() []*big.Float {
    method isExpGreater (line 146) | func (c normal) isExpGreater(y *big.Float, x *big.Int) bool {
  function newNormal (line 42) | func newNormal(sigma *big.Float, n uint) *normal {
  function Bernoulli (line 84) | func Bernoulli(t *big.Int, lSquareInv *big.Float) (bool, error) {
  function taylorExp (line 182) | func taylorExp(x *big.Int, alpha *big.Float, k uint, n uint) *big.Float {

FILE: sample/normal_cdt.go
  type NormalCDT (line 55) | type NormalCDT struct
    method Sample (line 67) | func (c *NormalCDT) Sample() (*big.Int, error) {
  function NewNormalCDT (line 60) | func NewNormalCDT() *NormalCDT {

FILE: sample/normal_cdt_test.go
  function TestNormalCDT (line 25) | func TestNormalCDT(t *testing.T) {

FILE: sample/normal_cumulative.go
  type NormalCumulative (line 32) | type NormalCumulative struct
    method Sample (line 62) | func (c *NormalCumulative) Sample() (*big.Int, error) {
    method precompute (line 81) | func (c *NormalCumulative) precompute() {
  function NewNormalCumulative (line 47) | func NewNormalCumulative(sigma *big.Float, n uint, twoSided bool) *Norma...

FILE: sample/normal_cumulative_test.go
  function TestNormalCumulative (line 26) | func TestNormalCumulative(t *testing.T) {

FILE: sample/normal_double.go
  type NormalDouble (line 33) | type NormalDouble struct
    method Sample (line 67) | func (s *NormalDouble) Sample() (*big.Int, error) {
  function NewNormalDouble (line 47) | func NewNormalDouble(sigma *big.Float, n uint, firstSigma *big.Float) (*...

FILE: sample/normal_double_constant.go
  type NormalDoubleConstant (line 38) | type NormalDoubleConstant struct
    method Sample (line 72) | func (s *NormalDoubleConstant) Sample() (*big.Int, error) {
  function NewNormalDoubleConstant (line 52) | func NewNormalDoubleConstant(l *big.Int) *NormalDoubleConstant {

FILE: sample/normal_double_constant_test.go
  function TestNormalDoubleConstant (line 26) | func TestNormalDoubleConstant(t *testing.T) {

FILE: sample/normal_double_test.go
  function TestNewNormalDouble (line 27) | func TestNewNormalDouble(t *testing.T) {
  function TestNormalDouble (line 57) | func TestNormalDouble(t *testing.T) {

FILE: sample/normal_negative.go
  type NormalNegative (line 30) | type NormalNegative struct
    method Sample (line 58) | func (c *NormalNegative) Sample() (*big.Int, error) {
  function NewNormalNegative (line 41) | func NewNormalNegative(sigma *big.Float, n uint) *NormalNegative {

FILE: sample/normal_negative_test.go
  function TestNormalNegative (line 27) | func TestNormalNegative(t *testing.T) {

FILE: sample/normal_test.go
  function mean (line 28) | func mean(vec []*big.Int) *big.Float {
  function variance (line 38) | func variance(vec []*big.Int) *big.Float {
  type paramBounds (line 52) | type paramBounds struct
  function testNormalSampler (line 59) | func testNormalSampler(t *testing.T, s sample.Sampler, bounds paramBound...

FILE: sample/sampler.go
  type Sampler (line 26) | type Sampler interface

FILE: sample/uniform.go
  type UniformRange (line 25) | type UniformRange struct
    method Sample (line 40) | func (u *UniformRange) Sample() (*big.Int, error) {
  function NewUniformRange (line 32) | func NewUniformRange(min, max *big.Int) *UniformRange {
  type Uniform (line 53) | type Uniform struct
    method Sample (line 64) | func (u *Uniform) Sample() (*big.Int, error) {
  function NewUniform (line 59) | func NewUniform(max *big.Int) *UniformRange {
  type Bit (line 69) | type Bit struct
  function NewBit (line 74) | func NewBit() *UniformRange {
Condensed preview — 89 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (497K chars).
[
  {
    "path": ".circleci/config.yml",
    "chars": 326,
    "preview": "version: 2\njobs:\n  build:\n    docker:\n      - image: circleci/golang:1.14\n\n    working_directory: /go/src/github.com/fen"
  },
  {
    "path": ".gitignore",
    "chars": 103,
    "preview": "# 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",
    "chars": 318,
    "preview": "# Authors\nA list of code contributors to GoFE library for\nfunctional encryption.\n\n## Maintainer\nThe team from [XLAB d.o."
  },
  {
    "path": "LICENSE",
    "chars": 11356,
    "preview": "                                 Apache License\n                           Version 2.0, January 2004\n                   "
  },
  {
    "path": "README.md",
    "chars": 18950,
    "preview": "# GoFE - Functional Encryption library\n[![Build Status](https://circleci.com/gh/fentec-project/gofe.svg?style=svg)](http"
  },
  {
    "path": "abe/dippe.go",
    "chars": 11601,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "abe/dippe_test.go",
    "chars": 7001,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "abe/doc.go",
    "chars": 676,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "abe/fame.go",
    "chars": 12704,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "abe/fame_test.go",
    "chars": 6218,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "abe/gpsw.go",
    "chars": 9503,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "abe/gpsw_test.go",
    "chars": 3476,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "abe/ma-abe.go",
    "chars": 18075,
    "preview": "/*\n * Copyright (c) 2021 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "abe/ma-abe_test.go",
    "chars": 5547,
    "preview": "package abe_test\n\nimport (\n    \"testing\"\n    \"github.com/fentec-project/gofe/abe\"\n    \"github.com/stretchr/testify/asser"
  },
  {
    "path": "abe/policy.go",
    "chars": 6978,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "abe/policy_test.go",
    "chars": 1713,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "data/doc.go",
    "chars": 694,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "data/matrix.go",
    "chars": 21044,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "data/matrix_bn256.go",
    "chars": 2783,
    "preview": "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"
  },
  {
    "path": "data/matrix_test.go",
    "chars": 7881,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "data/vector.go",
    "chars": 8681,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "data/vector_bn256.go",
    "chars": 3249,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "data/vector_test.go",
    "chars": 2524,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "doc.go",
    "chars": 723,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "go.mod",
    "chars": 490,
    "preview": "module github.com/fentec-project/gofe\n\ngo 1.17\n\nrequire (\n\tgithub.com/fentec-project/bn256 v0.0.0-20190726093940-0d0fc8b"
  },
  {
    "path": "go.sum",
    "chars": 2353,
    "preview": "github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=\ngithub.com/davecgh/go-spew v1.1.0/go.m"
  },
  {
    "path": "innerprod/doc.go",
    "chars": 1113,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "innerprod/fullysec/damgard.go",
    "chars": 22360,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "innerprod/fullysec/damgard_dec_multi.go",
    "chars": 7200,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "innerprod/fullysec/damgard_dec_multi_test.go",
    "chars": 4391,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "innerprod/fullysec/damgard_multi.go",
    "chars": 9524,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "innerprod/fullysec/damgard_multi_test.go",
    "chars": 4030,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "innerprod/fullysec/damgard_test.go",
    "chars": 2900,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "innerprod/fullysec/dmcfe.go",
    "chars": 5913,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "innerprod/fullysec/dmcfe_test.go",
    "chars": 2956,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "innerprod/fullysec/doc.go",
    "chars": 1383,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "innerprod/fullysec/fh_multi_ipe.go",
    "chars": 8551,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "innerprod/fullysec/fh_multi_ipe_test.go",
    "chars": 2979,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "innerprod/fullysec/fhipe.go",
    "chars": 7027,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "innerprod/fullysec/fhipe_test.go",
    "chars": 2591,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "innerprod/fullysec/lwe.go",
    "chars": 11286,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "innerprod/fullysec/lwe_test.go",
    "chars": 2975,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "innerprod/fullysec/paillier.go",
    "chars": 8328,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "innerprod/fullysec/paillier_multi.go",
    "chars": 8282,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "innerprod/fullysec/paillier_multi_test.go",
    "chars": 3522,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "innerprod/fullysec/paillier_test.go",
    "chars": 2409,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "innerprod/fullysec/part_fh_ipe.go",
    "chars": 9179,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "innerprod/fullysec/part_fh_ipe_test.go",
    "chars": 4039,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "innerprod/simple/ddh.go",
    "chars": 15924,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "innerprod/simple/ddh_multi.go",
    "chars": 6955,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "innerprod/simple/ddh_multi_test.go",
    "chars": 4131,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "innerprod/simple/ddh_test.go",
    "chars": 2887,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "innerprod/simple/doc.go",
    "chars": 1387,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "innerprod/simple/lwe.go",
    "chars": 9792,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "innerprod/simple/lwe_test.go",
    "chars": 2544,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "innerprod/simple/ringlwe.go",
    "chars": 10798,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "innerprod/simple/ringlwe_test.go",
    "chars": 2597,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "internal/dlog/brute_force.go",
    "chars": 1504,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "internal/dlog/brute_force_test.go",
    "chars": 1939,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "internal/dlog/calc.go",
    "chars": 14350,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "internal/dlog/calc_test.go",
    "chars": 3041,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "internal/dlog/dlog_test.go",
    "chars": 1852,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "internal/dlog/doc.go",
    "chars": 835,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "internal/dlog/pollard_rho.go",
    "chars": 13506,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "internal/dlog/pollard_rho_test.go",
    "chars": 4951,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "internal/errors.go",
    "chars": 1272,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "internal/keygen/elgamal.go",
    "chars": 2027,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "internal/keygen/prime.go",
    "chars": 5249,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "internal/mod_exp.go",
    "chars": 888,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "quadratic/doc.go",
    "chars": 717,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "quadratic/quad.go",
    "chars": 9086,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "quadratic/quad_test.go",
    "chars": 2564,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "quadratic/sgp.go",
    "chars": 6415,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "quadratic/sgp_test.go",
    "chars": 1950,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "sample/doc.go",
    "chars": 1085,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "sample/normal.go",
    "chars": 6597,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "sample/normal_cdt.go",
    "chars": 2776,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "sample/normal_cdt_test.go",
    "chars": 1077,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "sample/normal_cumulative.go",
    "chars": 3788,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "sample/normal_cumulative_test.go",
    "chars": 1274,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "sample/normal_double.go",
    "chars": 3724,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "sample/normal_double_constant.go",
    "chars": 3599,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "sample/normal_double_constant_test.go",
    "chars": 1801,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "sample/normal_double_test.go",
    "chars": 2240,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "sample/normal_negative.go",
    "chars": 2485,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "sample/normal_negative_test.go",
    "chars": 1170,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "sample/normal_test.go",
    "chars": 2222,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "sample/sampler.go",
    "chars": 930,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  },
  {
    "path": "sample/uniform.go",
    "chars": 1946,
    "preview": "/*\n * Copyright (c) 2018 XLAB d.o.o\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not"
  }
]

About this extraction

This page contains the full source code of the fentec-project/gofe GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 89 files (452.9 KB), approximately 139.9k tokens, and a symbol index with 434 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!