Compare commits
1 commit
master
...
feat/speed
Author | SHA1 | Date | |
---|---|---|---|
|
68db0ca698 |
48 changed files with 2089 additions and 1345 deletions
12
.circleci/config.yml
Normal file
12
.circleci/config.yml
Normal file
|
@ -0,0 +1,12 @@
|
|||
# Golang CircleCI 2.0 configuration file
|
||||
#
|
||||
# Check https://circleci.com/docs/2.0/language-go/ for more details
|
||||
version: 2
|
||||
jobs:
|
||||
build:
|
||||
docker:
|
||||
- image: circleci/golang:1.11
|
||||
working_directory: ~/{{ORG_NAME}}/{{REPO_NAME}}
|
||||
steps:
|
||||
- checkout
|
||||
- run: go test -v ./...
|
1
.github/CODEOWNERS
vendored
1
.github/CODEOWNERS
vendored
|
@ -1 +0,0 @@
|
|||
* @TrueCloudLab/storage-core @TrueCloudLab/storage-services @TrueCloudLab/committers
|
35
.gitignore
vendored
35
.gitignore
vendored
|
@ -1,27 +1,12 @@
|
|||
# IDE
|
||||
.idea
|
||||
.vscode
|
||||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
*.exe~
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
# Vendoring
|
||||
vendor
|
||||
# Test binary, build with `go test -c`
|
||||
*.test
|
||||
|
||||
# tempfiles
|
||||
.DS_Store
|
||||
*~
|
||||
.cache
|
||||
|
||||
temp
|
||||
tmp
|
||||
|
||||
# binary
|
||||
bin/
|
||||
release/
|
||||
|
||||
# coverage
|
||||
coverage.txt
|
||||
coverage.html
|
||||
|
||||
# testing
|
||||
cmd/test
|
||||
/plugins/
|
||||
testfile
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
10
.gitlint
10
.gitlint
|
@ -1,10 +0,0 @@
|
|||
[general]
|
||||
fail-without-commits=true
|
||||
contrib=CC1
|
||||
|
||||
[title-match-regex]
|
||||
regex=^\[\#[0-9]+\]\s
|
||||
|
||||
[ignore-by-title]
|
||||
regex=^Release(.*)
|
||||
ignore=title-match-regex
|
|
@ -1,30 +0,0 @@
|
|||
ci:
|
||||
autofix_prs: false
|
||||
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v4.4.0
|
||||
hooks:
|
||||
- id: check-added-large-files
|
||||
- id: check-case-conflict
|
||||
- id: check-executables-have-shebangs
|
||||
- id: check-shebang-scripts-are-executable
|
||||
- id: check-merge-conflict
|
||||
- id: check-json
|
||||
- id: check-xml
|
||||
- id: check-yaml
|
||||
- id: trailing-whitespace
|
||||
args: [--markdown-linebreak-ext=md]
|
||||
- id: end-of-file-fixer
|
||||
exclude: ".key$"
|
||||
|
||||
- repo: https://github.com/golangci/golangci-lint
|
||||
rev: v1.51.2
|
||||
hooks:
|
||||
- id: golangci-lint
|
||||
|
||||
- repo: https://github.com/jorisroovers/gitlint
|
||||
rev: v0.18.0
|
||||
hooks:
|
||||
- id: gitlint
|
||||
stages: [commit-msg]
|
155
CONTRIBUTING.md
155
CONTRIBUTING.md
|
@ -1,155 +0,0 @@
|
|||
# Contribution guide
|
||||
|
||||
First, thank you for contributing! We love and encourage pull requests from
|
||||
everyone. Please follow the guidelines:
|
||||
|
||||
- Check the open [issues](https://git.frostfs.info/TrueCloudLab/tzhash/issues) and
|
||||
[pull requests](https://git.frostfs.info/TrueCloudLab/tzhash/pulls) for existing
|
||||
discussions.
|
||||
|
||||
- Open an issue first, to discuss a new feature or enhancement.
|
||||
|
||||
- Write tests, and make sure the test suite passes locally and on CI.
|
||||
|
||||
- Open a pull request, and reference the relevant issue(s).
|
||||
|
||||
- Make sure your commits are logically separated and have good comments
|
||||
explaining the details of your change.
|
||||
|
||||
- After receiving feedback, amend your commits or add new ones as
|
||||
appropriate.
|
||||
|
||||
- **Have fun!**
|
||||
|
||||
## Development Workflow
|
||||
|
||||
Start by forking the `tzhash` repository, make changes in a branch and then
|
||||
send a pull request. We encourage pull requests to discuss code changes. Here
|
||||
are the steps in details:
|
||||
|
||||
### Set up your GitHub Repository
|
||||
Fork [TZHash upstream](https://git.frostfs.info/TrueCloudLab/tzhash/fork) source
|
||||
repository to your own personal repository. Copy the URL of your fork (you will
|
||||
need it for the `git clone` command below).
|
||||
|
||||
```sh
|
||||
$ git clone https://git.frostfs.info/TrueCloudLab/tzhash
|
||||
```
|
||||
|
||||
### Set up git remote as ``upstream``
|
||||
```sh
|
||||
$ cd tzhash
|
||||
$ git remote add upstream https://git.frostfs.info/TrueCloudLab/tzhash
|
||||
$ git fetch upstream
|
||||
$ git merge upstream/master
|
||||
...
|
||||
```
|
||||
|
||||
### Create your feature branch
|
||||
Before making code changes, make sure you create a separate branch for these
|
||||
changes. Maybe you will find it convenient to name branch in
|
||||
`<type>/<Issue>-<changes_topic>` format.
|
||||
|
||||
```
|
||||
$ git checkout -b feature/123-something_awesome
|
||||
```
|
||||
|
||||
### Test your changes
|
||||
After your code changes, make sure
|
||||
|
||||
- To add test cases for the new code.
|
||||
- To squash your commits into a single commit or a series of logically separated
|
||||
commits run `git rebase -i`. It's okay to force update your pull request.
|
||||
- To run `make test` and `make all` completes.
|
||||
|
||||
### Commit changes
|
||||
After verification, commit your changes. This is a [great
|
||||
post](https://chris.beams.io/posts/git-commit/) on how to write useful commit
|
||||
messages. Try following this template:
|
||||
|
||||
```
|
||||
[#Issue] <component> Summary
|
||||
|
||||
Description
|
||||
|
||||
<Macros>
|
||||
|
||||
<Sign-Off>
|
||||
```
|
||||
|
||||
```
|
||||
$ git commit -sam '[#123] Add some feature'
|
||||
```
|
||||
|
||||
### Push to the branch
|
||||
Push your locally committed changes to the remote origin (your fork)
|
||||
```
|
||||
$ git push origin feature/123-something_awesome
|
||||
```
|
||||
|
||||
### Create a Pull Request
|
||||
Pull requests can be created via GitHub. Refer to [this
|
||||
document](https://help.github.com/articles/creating-a-pull-request/) for
|
||||
detailed steps on how to create a pull request. After a Pull Request gets peer
|
||||
reviewed and approved, it will be merged.
|
||||
|
||||
## DCO Sign off
|
||||
|
||||
All authors to the project retain copyright to their work. However, to ensure
|
||||
that they are only submitting work that they have rights to, we are requiring
|
||||
everyone to acknowledge this by signing their work.
|
||||
|
||||
Any copyright notices in this repository should specify the authors as "the
|
||||
contributors".
|
||||
|
||||
To sign your work, just add a line like this at the end of your commit message:
|
||||
|
||||
```
|
||||
Signed-off-by: Samii Sakisaka <samii@ivunojikan.co.jp>
|
||||
|
||||
```
|
||||
|
||||
This can easily be done with the `--signoff` option to `git commit`.
|
||||
|
||||
By doing this you state that you can certify the following (from [The Developer
|
||||
Certificate of Origin](https://developercertificate.org/)):
|
||||
|
||||
```
|
||||
Developer Certificate of Origin
|
||||
Version 1.1
|
||||
|
||||
Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
|
||||
1 Letterman Drive
|
||||
Suite D4700
|
||||
San Francisco, CA, 94129
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim copies of this
|
||||
license document, but changing it is not allowed.
|
||||
|
||||
|
||||
Developer's Certificate of Origin 1.1
|
||||
|
||||
By making a contribution to this project, I certify that:
|
||||
|
||||
(a) The contribution was created in whole or in part by me and I
|
||||
have the right to submit it under the open source license
|
||||
indicated in the file; or
|
||||
|
||||
(b) The contribution is based upon previous work that, to the best
|
||||
of my knowledge, is covered under an appropriate open source
|
||||
license and I have the right under that license to submit that
|
||||
work with modifications, whether created in whole or in part
|
||||
by me, under the same open source license (unless I am
|
||||
permitted to submit under a different license), as indicated
|
||||
in the file; or
|
||||
|
||||
(c) The contribution was provided directly to me by some other
|
||||
person who certified (a), (b) or (c) and I have not modified
|
||||
it.
|
||||
|
||||
(d) I understand and agree that this project and the contribution
|
||||
are public and that a record of the contribution (including all
|
||||
personal information I submit with it, including my sign-off) is
|
||||
maintained indefinitely and may be redistributed consistent with
|
||||
this project or the open source license(s) involved.
|
||||
```
|
|
@ -1,4 +1,4 @@
|
|||
FROM golang:1-alpine as builder
|
||||
FROM golang:1.11-alpine3.8 as builder
|
||||
|
||||
RUN set -x \
|
||||
&& apk add --no-cache \
|
||||
|
@ -28,7 +28,7 @@ RUN set -x \
|
|||
&& go build -mod=vendor -o /go/bin/homo ./cmd/homo/main.go
|
||||
|
||||
# Executable image
|
||||
FROM alpine:3.11
|
||||
FROM alpine:3.8
|
||||
|
||||
WORKDIR /fixtures
|
||||
|
||||
|
|
809
LICENSE
809
LICENSE
|
@ -1,201 +1,674 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
1. Definitions.
|
||||
Preamble
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
"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.
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
"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.
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
"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).
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
"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.
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
"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."
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
"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.
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
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.
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
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.
|
||||
0. Definitions.
|
||||
|
||||
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:
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
(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
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
(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.
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
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.
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
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.
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
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.
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
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.
|
||||
1. Source Code.
|
||||
|
||||
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.
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
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.
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
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.
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
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
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
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.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
||||
|
|
91
Makefile
Executable file → Normal file
91
Makefile
Executable file → Normal file
|
@ -1,61 +1,42 @@
|
|||
#!/usr/bin/make -f
|
||||
SHELL = bash
|
||||
B=\033[0;1m
|
||||
G=\033[0;92m
|
||||
R=\033[0m
|
||||
|
||||
REPO ?= $(shell go list -m)
|
||||
VERSION ?= $(shell git describe --tags --dirty --match "v*" --always --abbrev=8 2>/dev/null || cat VERSION 2>/dev/null || echo "develop")
|
||||
NAME ?= homo
|
||||
|
||||
BIN = bin
|
||||
DIRS = $(BIN)
|
||||
.PHONY: help attach auto up down
|
||||
# Show this help prompt
|
||||
help:
|
||||
@echo ' Usage:'
|
||||
@echo ''
|
||||
@echo ' make <target>'
|
||||
@echo ''
|
||||
@echo ' Targets:'
|
||||
@echo ''
|
||||
@awk '/^#/{ comment = substr($$0,3) } comment && /^[a-zA-Z][a-zA-Z0-9_-]+ ?:/{ print " ", $$1, comment }' $(MAKEFILE_LIST) | column -t -s ':' | grep -v 'IGNORE' | sort | uniq
|
||||
|
||||
# List of binaries to build.
|
||||
CMDS = $(notdir $(basename $(wildcard cmd/*)))
|
||||
BINS = $(addprefix $(BIN)/, $(CMDS))
|
||||
# Auto Tillich-Zémor hasher demo
|
||||
auto: down
|
||||
@echo "\n${B}${G}build container${R}\n"
|
||||
@time docker build -t poc-demo .
|
||||
@echo "\n${B}${G}Bootup container:${R}\n"
|
||||
@time docker run -d --rm -it --name hash-demo poc-demo:latest sh
|
||||
@bash ./auto.sh
|
||||
|
||||
.PHONY: all help clean
|
||||
# Stop demo container
|
||||
down:
|
||||
@echo "\n${B}${G}Stop container${R}\n"
|
||||
@docker stop hash-demo || true
|
||||
@docker rm hash-demo || true
|
||||
|
||||
# To build a specific binary, use it's name prefix with bin/ as a target
|
||||
# For example `make bin/tzsum` will build only storage node binary
|
||||
# Just `make` will build all possible binaries
|
||||
all: $(DIRS) $(BINS)
|
||||
# Run Tillich-Zémor hasher demo
|
||||
up: down
|
||||
@echo "\n${B}${G}build container${R}\n"
|
||||
@time docker build -t poc-demo .
|
||||
@echo "\n${B}${G}enter inside container:${R}\n"
|
||||
@time docker run --rm -it --name hash-demo poc-demo:latest sh
|
||||
|
||||
# help target
|
||||
include help.mk
|
||||
|
||||
$(BINS): $(DIRS) dep
|
||||
@echo "⇒ Build $@"
|
||||
CGO_ENABLED=0 \
|
||||
go build -v -trimpath \
|
||||
-ldflags "-X $(REPO)/misc.Version=$(VERSION)" \
|
||||
-o $@ ./cmd/$(notdir $@)
|
||||
|
||||
$(DIRS):
|
||||
@echo "⇒ Ensure dir: $@"
|
||||
@mkdir -p $@
|
||||
|
||||
# Pull go dependencies
|
||||
dep:
|
||||
@printf "⇒ Download requirements: "
|
||||
CGO_ENABLED=0 \
|
||||
go mod download && echo OK
|
||||
@printf "⇒ Tidy requirements : "
|
||||
CGO_ENABLED=0 \
|
||||
go mod tidy -v && echo OK
|
||||
|
||||
# Run Unit Test with go test
|
||||
test:
|
||||
@echo "⇒ Running go test"
|
||||
@go test ./...
|
||||
|
||||
# Run Unit Test with go test
|
||||
test.generic:
|
||||
@echo "⇒ Running go test with generic tag"
|
||||
@go test ./... --tags=generic
|
||||
|
||||
# Print version
|
||||
version:
|
||||
@echo $(VERSION)
|
||||
|
||||
clean:
|
||||
rm -rf vendor
|
||||
rm -rf .cache
|
||||
rm -rf $(BIN)
|
||||
# Attach to existing container
|
||||
attach:
|
||||
@echo "\n${B}${G} attach to hash-container ${R}\n"
|
||||
@time docker exec -it --name hash-demo /bin/sh
|
||||
|
|
66
README.md
66
README.md
|
@ -5,74 +5,60 @@
|
|||
**In project root:**
|
||||
|
||||
```bash
|
||||
$ make
|
||||
...
|
||||
$ ./demo.sh
|
||||
|
||||
# show help
|
||||
make
|
||||
# run auto demo
|
||||
make auto
|
||||
```
|
||||
|
||||
# Homomorphic hashing in golang
|
||||
|
||||
Package `tz` contains pure-Go (with some Assembly) implementation of hashing
|
||||
function described by [Tillich and
|
||||
Zémor](https://link.springer.com/content/pdf/10.1007/3-540-48658-5_5.pdf).
|
||||
Package `tz` containts pure-Go implementation of hashing function described by Tillich and Źemor in [1] .
|
||||
|
||||
There are [existing implementations](https://github.com/srijs/hwsl2-core)
|
||||
already, however they are written in C.
|
||||
There are existing implementations already (e.g. [2]), however they are written in C.
|
||||
|
||||
Package `gf127` contains arithmetic in `GF(2^127)` with `x^127+x^63+1` as reduction polynomial.
|
||||
|
||||
# Description
|
||||
|
||||
TZ Hash can be used instead of Merkle-tree for data-validation, because
|
||||
homomorphic hashes are concatenable: hash sum of data can be calculated based on
|
||||
hashes of chunks.
|
||||
It can be used instead of Merkle-tree for data-validation, because homomorphic hashes
|
||||
are concatenable: hash sum of data can be calculated based on hashes of chunks.
|
||||
|
||||
The example of how it works can be seen in tests and demo.
|
||||
The example of how it works can be seen in tests.
|
||||
|
||||
# Benchmarks
|
||||
|
||||
## go vs AVX vs AVX2 version
|
||||
## AVX vs AVX2 version
|
||||
|
||||
```
|
||||
BenchmarkSum/AVX_digest-8 308 3889484 ns/op 25.71 MB/s 5 allocs/op
|
||||
BenchmarkSum/AVXInline_digest-8 457 2455437 ns/op 40.73 MB/s 5 allocs/op
|
||||
BenchmarkSum/AVX2_digest-8 399 3031102 ns/op 32.99 MB/s 3 allocs/op
|
||||
BenchmarkSum/AVX2Inline_digest-8 602 2077719 ns/op 48.13 MB/s 3 allocs/op
|
||||
BenchmarkSum/PureGo_digest-8 68 17795480 ns/op 5.62 MB/s 5 allocs/op
|
||||
BenchmarkAVX-8 500 3492019 ns/op 28.64 MB/s 64 B/op 4 allocs/op
|
||||
BenchmarkAVX2-8 500 2752693 ns/op 36.33 MB/s 64 B/op 2 allocs/op
|
||||
BenchmarkAVX2Inline-8 1000 1877260 ns/op 53.27 MB/s 64 B/op 2 allocs/op
|
||||
```
|
||||
|
||||
# Contributing
|
||||
|
||||
At this moment, we do not accept contributions. Follow us.
|
||||
|
||||
# Makefile
|
||||
|
||||
``` bash
|
||||
```
|
||||
→ make
|
||||
Usage:
|
||||
|
||||
make <target>
|
||||
|
||||
Targets:
|
||||
|
||||
all Just `make` will build all possible binaries
|
||||
clean Print version
|
||||
dep Pull go dependencies
|
||||
attach Attach to existing container
|
||||
auto Auto Tillich-Zémor hasher demo
|
||||
down Stop demo container
|
||||
help Show this help prompt
|
||||
test Run Unit Test with go test
|
||||
version Print version
|
||||
up Run Tillich-Zémor hasher demo
|
||||
```
|
||||
|
||||
# Contributing
|
||||
# Links
|
||||
|
||||
Feel free to contribute to this project after reading the [contributing
|
||||
guidelines](CONTRIBUTING.md).
|
||||
[1] https://link.springer.com/content/pdf/10.1007/3-540-48658-5_5.pdf
|
||||
|
||||
Before starting to work on a certain topic, create a new issue first, describing
|
||||
the feature/topic you are going to implement.
|
||||
|
||||
# License
|
||||
|
||||
This project is licensed under the Apache 2.0 License -
|
||||
see the [LICENSE](LICENSE) file for details
|
||||
|
||||
# References
|
||||
|
||||
- [https://link.springer.com/content/pdf/10.1007/3-540-48658-5_5.pdf](https://link.springer.com/content/pdf/10.1007/3-540-48658-5_5.pdf)
|
||||
- [https://github.com/srijs/hwsl2-core](https://github.com/srijs/hwsl2-core)
|
||||
[2] https://github.com/srijs/hwsl2-core
|
35
auto.sh
Executable file
35
auto.sh
Executable file
|
@ -0,0 +1,35 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
B="\033[0;1m"
|
||||
G="\033[0;92m"
|
||||
R="\033[0m"
|
||||
|
||||
echo -e "${B}${G}Let's make some hash${R}"
|
||||
|
||||
echo -e "\n${B}${G} - cleanup environment${R}"
|
||||
echo -e "remove files: small.hash, large.hash, large.txt"
|
||||
docker exec -it hash-demo sh -c "rm -rf small.hash"
|
||||
docker exec -it hash-demo sh -c "rm -rf large.hash"
|
||||
docker exec -it hash-demo sh -c "rm -rf large.txt"
|
||||
|
||||
echo -e "\n${B}${G} - make large file (concat small files)${R}"
|
||||
for i in $(seq -f "%02g" 10)
|
||||
do
|
||||
echo " #> cat $i.txt >> large.txt"
|
||||
docker exec -it hash-demo sh -c "cat $i.txt >> large.txt"
|
||||
done
|
||||
|
||||
echo -e "\n${B}${G} - make hash of small files${R}"
|
||||
for i in $(seq -f "%02g" 10)
|
||||
do
|
||||
echo -e " #> homo -file $i.txt | tee -a small.hash"
|
||||
docker exec -it hash-demo sh -c "homo -file $i.txt | tee -a small.hash"
|
||||
done
|
||||
|
||||
echo -e "\n${B}${G} - make hash of large${R}"
|
||||
echo -e " #> homo -file large.txt | homo -concat"
|
||||
docker exec -it hash-demo sh -c 'homo -file large.txt | homo -concat'
|
||||
|
||||
echo -e "\n${B}${G} - make hash of pieces${R}"
|
||||
echo -e " #> cat small.hash | homo -concat"
|
||||
docker exec -it hash-demo sh -c 'cat small.hash | homo -concat '
|
13
benchmark
Executable file
13
benchmark
Executable file
|
@ -0,0 +1,13 @@
|
|||
#!/bin/bash
|
||||
#tmpfile=$(mktemp /tmp/random-file.XXXXXX)
|
||||
#size=$1
|
||||
#dd if=/dev/urandom of=$tmpfile bs=$size count=1
|
||||
|
||||
tmpfile=$1
|
||||
|
||||
go build ./cmd/tzsum && \
|
||||
for impl in avx avx2 avx2inline purego; do
|
||||
echo $impl implementation:
|
||||
/usr/bin/env time -f "time: %e seconds" ./tzsum -name $tmpfile -impl $impl
|
||||
echo
|
||||
done
|
12
benchmark.sh
12
benchmark.sh
|
@ -1,12 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
BLOCK_SIZE=${1:-1G} # gigabyte by default
|
||||
OUT="${OUT:-$(mktemp /tmp/random-file.XXXXXX)}"
|
||||
|
||||
dd if=/dev/urandom of="$OUT" bs="$BLOCK_SIZE" count=1
|
||||
|
||||
for impl in avx avx2 generic; do
|
||||
echo $impl implementation:
|
||||
time ./bin/tzsum -name "$OUT" -impl $impl
|
||||
echo
|
||||
done
|
|
@ -7,7 +7,7 @@ import (
|
|||
"fmt"
|
||||
"os"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/tzhash/tz"
|
||||
"github.com/nspcc-dev/tzhash/tz"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
@ -10,8 +10,7 @@ import (
|
|||
"runtime"
|
||||
"runtime/pprof"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/tzhash/tz"
|
||||
"golang.org/x/sys/cpu"
|
||||
"github.com/nspcc-dev/tzhash/tz"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -47,23 +46,18 @@ func main() {
|
|||
f = os.Stdin
|
||||
}
|
||||
|
||||
// Override CPU feature flags to make sure a proper backend is used.
|
||||
var h hash.Hash
|
||||
switch *hashimpl {
|
||||
case "avx":
|
||||
cpu.X86.HasAVX = true
|
||||
cpu.X86.HasAVX2 = false
|
||||
h = tz.New()
|
||||
h = tz.NewWith(tz.AVX)
|
||||
case "avx2":
|
||||
cpu.X86.HasAVX = true
|
||||
cpu.X86.HasAVX2 = true
|
||||
h = tz.New()
|
||||
case "generic":
|
||||
cpu.X86.HasAVX = false
|
||||
cpu.X86.HasAVX2 = false
|
||||
h = tz.New()
|
||||
h = tz.NewWith(tz.AVX2)
|
||||
case "avx2inline":
|
||||
h = tz.NewWith(tz.AVX2Inline)
|
||||
case "purego":
|
||||
h = tz.NewWith(tz.PureGo)
|
||||
default:
|
||||
log.Fatalf("Invalid backend: %s", *hashimpl)
|
||||
h = tz.New()
|
||||
}
|
||||
|
||||
if _, err := io.Copy(h, f); err != nil {
|
||||
|
|
38
demo.sh
38
demo.sh
|
@ -1,38 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
#set -x
|
||||
|
||||
BLOCK_SIZE=${1:-100M} # 100Mb by default
|
||||
TMPDIR="${TMPDIR:-$(mktemp -d)}"
|
||||
|
||||
OUT="${OUT:-"${TMPDIR}/bighash"}"
|
||||
|
||||
echo "Preparing big file at ${OUT}..."
|
||||
dd if=/dev/urandom of="$OUT" bs="$BLOCK_SIZE" count=1
|
||||
|
||||
echo "Make 4 smaller parts from ${OUT}..."
|
||||
split -dn 4 "${OUT}" "${TMPDIR}/"
|
||||
|
||||
echo -n "Big file hash: "
|
||||
TZALL=$(./bin/tzsum -impl avx2 -name "${OUT}" | awk '{print $1}')
|
||||
echo "${TZALL}"
|
||||
|
||||
for i in $(seq -f "%02g" 0 3)
|
||||
do
|
||||
echo -n "Part ${i} hash: "
|
||||
PART=$(./bin/tzsum -impl avx2 -name "${TMPDIR}/${i}" | awk '{print $1}')
|
||||
echo "${PART}" | tee -a "${TMPDIR}/part.hashes"
|
||||
done
|
||||
|
||||
echo -n "Cumulative: "
|
||||
TZCUM=$(./bin/homo -concat -file "${TMPDIR}/part.hashes")
|
||||
echo "${TZCUM}"
|
||||
|
||||
if [[ "$TZCUM" == "$TZALL" ]]; then
|
||||
echo "Original and cumulative hashes are equal!"
|
||||
else
|
||||
echo "Original and cumulative hashes are NOT equal!"
|
||||
fi
|
||||
|
||||
echo -ne "Cleaning up .. "
|
||||
rm -rf "${TMPDIR}"
|
||||
echo "Done!"
|
|
@ -1,7 +0,0 @@
|
|||
// Package gf127 implements the GF(2^127) arithmetic
|
||||
// modulo reduction polynomial x^127 + x^63 + 1 .
|
||||
// gf127.go contains common definitions.
|
||||
// Other files contain architecture-specific implementations.
|
||||
//
|
||||
// Copyright 2019 (c) NSPCC
|
||||
package gf127
|
158
gf127/gf127.go
158
gf127/gf127.go
|
@ -1,3 +1,10 @@
|
|||
// Copyright 2018 (c) NSPCC
|
||||
//
|
||||
// Package gf127 implements the GF(2^127) arithmetic
|
||||
// modulo reduction polynomial x^127 + x^63 + 1 .
|
||||
// This is rather straight-forward re-implementation of C library
|
||||
// available here https://github.com/srijs/hwsl2-core .
|
||||
// Interfaces are highly influenced by math/big .
|
||||
package gf127
|
||||
|
||||
import (
|
||||
|
@ -12,13 +19,17 @@ import (
|
|||
type GF127 [2]uint64
|
||||
|
||||
const (
|
||||
msb64 = uint64(0x8000000000000000)
|
||||
byteSize = 16
|
||||
maxUint64 = ^uint64(0)
|
||||
msb64 = uint64(1) << 63
|
||||
)
|
||||
|
||||
// x127x631 is reduction polynomial x^127 + x^63 + 1
|
||||
var x127x631 = GF127{msb64 + 1, msb64}
|
||||
var (
|
||||
// x127x63 represents x^127 + x^63. Used in assembly file.
|
||||
x127x63 = GF127{msb64, msb64}
|
||||
|
||||
// x126x631 is reduction polynomial x^127+x^63+1
|
||||
x127x631 = GF127{msb64 + 1, msb64}
|
||||
)
|
||||
|
||||
// New constructs new element of GF(2^127) as hi*x^64 + lo.
|
||||
// It is assumed that hi has zero MSB.
|
||||
|
@ -26,47 +37,48 @@ func New(lo, hi uint64) *GF127 {
|
|||
return &GF127{lo, hi}
|
||||
}
|
||||
|
||||
func addGeneric(a, b, c *GF127) {
|
||||
c[0] = a[0] ^ b[0]
|
||||
c[1] = a[1] ^ b[1]
|
||||
// Random returns random element from GF(2^127).
|
||||
// Is used mostly for testing.
|
||||
func Random() *GF127 {
|
||||
return &GF127{rand.Uint64(), rand.Uint64() >> 1}
|
||||
}
|
||||
|
||||
func mulGeneric(a, b, c *GF127) {
|
||||
r := new(GF127)
|
||||
d := *a
|
||||
for i := uint(0); i < 64; i++ {
|
||||
if b[0]&(1<<i) != 0 {
|
||||
addGeneric(r, &d, r)
|
||||
}
|
||||
mul10Generic(&d, &d)
|
||||
}
|
||||
for i := uint(0); i < 63; i++ {
|
||||
if b[1]&(1<<i) != 0 {
|
||||
addGeneric(r, &d, r)
|
||||
}
|
||||
mul10Generic(&d, &d)
|
||||
}
|
||||
*c = *r
|
||||
// String returns hex-encoded representation, starting with MSB.
|
||||
func (c *GF127) String() string {
|
||||
return hex.EncodeToString(c.ByteArray())
|
||||
}
|
||||
|
||||
func mul10Generic(a, b *GF127) {
|
||||
c := a[0] >> 63
|
||||
b[0] = a[0] << 1
|
||||
b[1] = (a[1] << 1) ^ c
|
||||
|
||||
mask := b[1] & msb64
|
||||
b[0] ^= mask | (mask >> 63)
|
||||
b[1] ^= mask
|
||||
// Equals checks if two reduced (zero MSB) elements of GF(2^127) are equal
|
||||
func (c *GF127) Equals(b *GF127) bool {
|
||||
return c[0] == b[0] && c[1] == b[1]
|
||||
}
|
||||
|
||||
func mul11Generic(a, b *GF127) {
|
||||
c := a[0] >> 63
|
||||
b[0] = a[0] ^ (a[0] << 1)
|
||||
b[1] = a[1] ^ (a[1] << 1) ^ c
|
||||
// ByteArray represents element of GF(2^127) as byte array of length 16.
|
||||
func (c *GF127) ByteArray() (buf []byte) {
|
||||
buf = make([]byte, 16)
|
||||
binary.BigEndian.PutUint64(buf[:8], c[1])
|
||||
binary.BigEndian.PutUint64(buf[8:], c[0])
|
||||
return
|
||||
}
|
||||
|
||||
mask := b[1] & msb64
|
||||
b[0] ^= mask | (mask >> 63)
|
||||
b[1] ^= mask
|
||||
// MarshalBinary implements encoding.BinaryMarshaler.
|
||||
func (c *GF127) MarshalBinary() (data []byte, err error) {
|
||||
return c.ByteArray(), nil
|
||||
}
|
||||
|
||||
// UnmarshalBinary implements encoding.BinaryUnmarshaler.
|
||||
func (c *GF127) UnmarshalBinary(data []byte) error {
|
||||
if len(data) != byteSize {
|
||||
return errors.New("data must be 16-bytes long")
|
||||
}
|
||||
|
||||
c[0] = binary.BigEndian.Uint64(data[8:])
|
||||
c[1] = binary.BigEndian.Uint64(data[:8])
|
||||
if c[1]&msb64 != 0 {
|
||||
return errors.New("MSB must be zero")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Inv sets b to a^-1
|
||||
|
@ -95,7 +107,7 @@ func Inv(a, b *GF127) {
|
|||
Mul(x, &v, t)
|
||||
Add(&u, t, &u)
|
||||
|
||||
// becasuse mulAVX performs reduction on t, we need
|
||||
// becasuse mul performs reduction on t, we need
|
||||
// manually reduce u at first step
|
||||
if msb(&u) == 127 {
|
||||
Add(&u, &x127x631, &u)
|
||||
|
@ -122,10 +134,22 @@ func msb(a *GF127) (x int) {
|
|||
return 127 - x
|
||||
}
|
||||
|
||||
// Mul1 copies b into a.
|
||||
// Mul sets c to the product a*b and returns c.
|
||||
func (c *GF127) Mul(a, b *GF127) *GF127 {
|
||||
Mul(a, b, c)
|
||||
return c
|
||||
}
|
||||
|
||||
// Add sets c to the sum a+b and returns c.
|
||||
func (c *GF127) Add(a, b *GF127) *GF127 {
|
||||
Add(a, b, c)
|
||||
return c
|
||||
}
|
||||
|
||||
// Mul1 copies a to b.
|
||||
func Mul1(a, b *GF127) {
|
||||
a[0] = b[0]
|
||||
a[1] = b[1]
|
||||
b[0] = a[0]
|
||||
b[1] = a[1]
|
||||
}
|
||||
|
||||
// And sets c to a & b (bitwise-and).
|
||||
|
@ -134,48 +158,14 @@ func And(a, b, c *GF127) {
|
|||
c[1] = a[1] & b[1]
|
||||
}
|
||||
|
||||
// Random returns random element from GF(2^127).
|
||||
// Is used mostly for testing.
|
||||
func Random() *GF127 {
|
||||
return &GF127{rand.Uint64(), rand.Uint64() >> 1}
|
||||
}
|
||||
// Add sets c to a+b.
|
||||
func Add(a, b, c *GF127)
|
||||
|
||||
// String returns hex-encoded representation, starting with MSB.
|
||||
func (c *GF127) String() string {
|
||||
buf := c.Bytes()
|
||||
return hex.EncodeToString(buf[:])
|
||||
}
|
||||
// Mul sets c to a*b.
|
||||
func Mul(a, b, c *GF127)
|
||||
|
||||
// Equals checks if two reduced (zero MSB) elements of GF(2^127) are equal
|
||||
func (c *GF127) Equals(b *GF127) bool {
|
||||
return c[0] == b[0] && c[1] == b[1]
|
||||
}
|
||||
// Mul10 sets b to a*x.
|
||||
func Mul10(a, b *GF127)
|
||||
|
||||
// Bytes represents element of GF(2^127) as byte array of length 16.
|
||||
func (c *GF127) Bytes() [16]byte {
|
||||
var buf [16]byte
|
||||
binary.BigEndian.PutUint64(buf[:8], c[1])
|
||||
binary.BigEndian.PutUint64(buf[8:], c[0])
|
||||
return buf
|
||||
}
|
||||
|
||||
// MarshalBinary implements encoding.BinaryMarshaler.
|
||||
func (c *GF127) MarshalBinary() (data []byte, err error) {
|
||||
buf := c.Bytes()
|
||||
return buf[:], nil
|
||||
}
|
||||
|
||||
// UnmarshalBinary implements encoding.BinaryUnmarshaler.
|
||||
func (c *GF127) UnmarshalBinary(data []byte) error {
|
||||
if len(data) != byteSize {
|
||||
return errors.New("data must be 16-bytes long")
|
||||
}
|
||||
|
||||
c[0] = binary.BigEndian.Uint64(data[8:])
|
||||
c[1] = binary.BigEndian.Uint64(data[:8])
|
||||
if c[1]&msb64 != 0 {
|
||||
return errors.New("MSB must be zero")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
// Mul11 sets b to a*(x+1).
|
||||
func Mul11(a, b *GF127)
|
||||
|
|
|
@ -1,55 +0,0 @@
|
|||
//go:build amd64 && !generic
|
||||
// +build amd64,!generic
|
||||
|
||||
// Package gf127 implements the GF(2^127) arithmetic
|
||||
// modulo reduction polynomial x^127 + x^63 + 1 .
|
||||
// This is rather straight-forward re-implementation of C library
|
||||
// available here https://github.com/srijs/hwsl2-core .
|
||||
// Interfaces are highly influenced by math/big .
|
||||
package gf127
|
||||
|
||||
import "golang.org/x/sys/cpu"
|
||||
|
||||
// x127x63 represents x^127 + x^63
|
||||
var x127x63 = GF127{msb64, msb64} //nolint:unused
|
||||
|
||||
// Add sets c to a+b.
|
||||
func Add(a, b, c *GF127) {
|
||||
if cpu.X86.HasAVX {
|
||||
addAVX(a, b, c)
|
||||
} else {
|
||||
addGeneric(a, b, c)
|
||||
}
|
||||
}
|
||||
|
||||
// Mul sets c to a*b.
|
||||
func Mul(a, b, c *GF127) {
|
||||
if cpu.X86.HasAVX {
|
||||
mulAVX(a, b, c)
|
||||
} else {
|
||||
mulGeneric(a, b, c)
|
||||
}
|
||||
}
|
||||
|
||||
// Mul10 sets b to a*x.
|
||||
func Mul10(a, b *GF127) {
|
||||
if cpu.X86.HasAVX {
|
||||
mul10AVX(a, b)
|
||||
} else {
|
||||
mul10Generic(a, b)
|
||||
}
|
||||
}
|
||||
|
||||
// Mul11 sets b to a*(x+1).
|
||||
func Mul11(a, b *GF127) {
|
||||
if cpu.X86.HasAVX {
|
||||
mul11AVX(a, b)
|
||||
} else {
|
||||
mul11Generic(a, b)
|
||||
}
|
||||
}
|
||||
|
||||
func addAVX(a, b, c *GF127)
|
||||
func mulAVX(a, b, c *GF127)
|
||||
func mul10AVX(a, b *GF127)
|
||||
func mul11AVX(a, b *GF127)
|
|
@ -1,7 +1,7 @@
|
|||
#include "textflag.h"
|
||||
|
||||
// func Add(a, b, c *[2]uint64)
|
||||
TEXT ·addAVX(SB), NOSPLIT, $0
|
||||
TEXT ·Add(SB),NOSPLIT,$0
|
||||
MOVQ a+0(FP), AX
|
||||
MOVUPD (AX), X0
|
||||
MOVQ b+8(FP), BX
|
||||
|
@ -12,7 +12,7 @@ TEXT ·addAVX(SB), NOSPLIT, $0
|
|||
RET
|
||||
|
||||
// func Mul10(a, b *[2]uint64)
|
||||
TEXT ·mul10AVX(SB), NOSPLIT, $0
|
||||
TEXT ·Mul10(SB),NOSPLIT,$0
|
||||
MOVQ a+0(FP), AX
|
||||
MOVUPD (AX), X0
|
||||
VPSLLQ $1, X0, X1
|
||||
|
@ -27,8 +27,24 @@ TEXT ·mul10AVX(SB), NOSPLIT, $0
|
|||
MOVUPD X1, (AX)
|
||||
RET
|
||||
|
||||
// func Mul10x2(a, b) *[4]uint64
|
||||
TEXT ·Mul10x2(SB),NOSPLIT,$0
|
||||
MOVQ a+0(FP), AX
|
||||
VMOVDQA (AX), Y0
|
||||
VPSLLQ $1, Y0, Y1
|
||||
VPALIGNR $8, Y1, Y0, Y2
|
||||
VPSRLQ $63, Y2, Y2
|
||||
VPXOR Y1, Y2, Y2
|
||||
VPSRLQ $63, Y1, Y3
|
||||
VPSLLQ $63, Y3, Y3
|
||||
VPUNPCKHQDQ Y3, Y3, Y3
|
||||
VPXOR Y2, Y3, Y3
|
||||
MOVQ b+8(FP), AX
|
||||
VMOVDQA Y3, (AX)
|
||||
RET
|
||||
|
||||
// func Mul11(a, b *[2]uint64)
|
||||
TEXT ·mul11AVX(SB), NOSPLIT, $0
|
||||
TEXT ·Mul11(SB),NOSPLIT,$0
|
||||
MOVQ a+0(FP), AX
|
||||
MOVUPD (AX), X0
|
||||
VPSLLQ $1, X0, X1
|
||||
|
@ -44,8 +60,25 @@ TEXT ·mul11AVX(SB), NOSPLIT, $0
|
|||
MOVUPD X1, (AX)
|
||||
RET
|
||||
|
||||
// func Mul11x2(a, b) *[4]uint64
|
||||
TEXT ·Mul11x2(SB),NOSPLIT,$0
|
||||
MOVQ a+0(FP), AX
|
||||
VMOVDQA (AX), Y0
|
||||
VPSLLQ $1, Y0, Y1
|
||||
VPALIGNR $8, Y1, Y0, Y2
|
||||
VPSRLQ $63, Y2, Y2
|
||||
VPXOR Y1, Y2, Y2
|
||||
VPSRLQ $63, Y1, Y3
|
||||
VPSLLQ $63, Y3, Y3
|
||||
VPUNPCKHQDQ Y3, Y3, Y3
|
||||
VPXOR Y2, Y3, Y3
|
||||
VPXOR Y0, Y3, Y3
|
||||
MOVQ b+8(FP), AX
|
||||
VMOVDQA Y3, (AX)
|
||||
RET
|
||||
|
||||
// func Mul(a, b, c *[2]uint64)
|
||||
TEXT ·mulAVX(SB), NOSPLIT, $0
|
||||
TEXT ·Mul(SB),NOSPLIT,$0
|
||||
MOVQ a+0(FP), AX // X0 = a0 . a1
|
||||
MOVUPD (AX), X0 // X0 = a0 . a1
|
||||
MOVQ b+8(FP), BX // X1 = b0 . b1
|
||||
|
@ -56,11 +89,11 @@ TEXT ·mulAVX(SB), NOSPLIT, $0
|
|||
PCLMULQDQ $0x10, X3, X3 // X3 = (a0 + a1) * (b0 + b1)
|
||||
VPCLMULQDQ $0x00, X0, X1, X4 // X4 = a0 * b0
|
||||
VPCLMULQDQ $0x11, X0, X1, X5 // X5 = a1 * b1
|
||||
XORPD X4, X3
|
||||
XORPD X4, X3 //
|
||||
XORPD X5, X3 // X3 = a0 * b1 + a1 * b0
|
||||
VPSLLDQ $8, X3, X2
|
||||
VPSLLDQ $8, X3, X2 //
|
||||
XORPD X2, X4 // X4 = a0 * b0 + lo(X3)
|
||||
VPSRLDQ $8, X3, X6
|
||||
VPSRLDQ $8, X3, X6 //
|
||||
XORPD X6, X5 // X5 = a1 * b1 + hi(X3)
|
||||
|
||||
// at this point, a * b = X4 . X5 (as 256-bit number)
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
//go:build !amd64 || generic
|
||||
// +build !amd64 generic
|
||||
|
||||
package gf127
|
||||
|
||||
// Add sets c to a+b.
|
||||
func Add(a, b, c *GF127) {
|
||||
addGeneric(a, b, c)
|
||||
}
|
||||
|
||||
// Mul sets c to a*b.
|
||||
func Mul(a, b, c *GF127) {
|
||||
mulGeneric(a, b, c)
|
||||
}
|
||||
|
||||
// Mul10 sets b to a*x.
|
||||
func Mul10(a, b *GF127) {
|
||||
mul10Generic(a, b)
|
||||
}
|
||||
|
||||
// Mul11 sets b to a*(x+1).
|
||||
func Mul11(a, b *GF127) {
|
||||
mul11Generic(a, b)
|
||||
}
|
|
@ -6,6 +6,8 @@ import (
|
|||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
const maxUint64 = ^uint64(0)
|
||||
|
||||
func TestAdd(t *testing.T) {
|
||||
var (
|
||||
a = Random()
|
||||
|
@ -13,7 +15,7 @@ func TestAdd(t *testing.T) {
|
|||
e = &GF127{a[0] ^ b[0], a[1] ^ b[1]}
|
||||
c = new(GF127)
|
||||
)
|
||||
Add(a, b, c)
|
||||
c.Add(a, b)
|
||||
require.Equal(t, e, c)
|
||||
}
|
||||
|
||||
|
@ -36,21 +38,6 @@ func TestMul(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestMulInPlace(t *testing.T) {
|
||||
for _, tc := range testCasesMul {
|
||||
a := *tc[0]
|
||||
b := *tc[1]
|
||||
Mul(&a, &b, &b)
|
||||
require.Equal(t, a, *tc[0])
|
||||
require.Equal(t, b, *tc[2])
|
||||
|
||||
b = *tc[1]
|
||||
Mul(&a, &b, &a)
|
||||
require.Equal(t, b, *tc[1])
|
||||
require.Equal(t, a, *tc[2])
|
||||
}
|
||||
}
|
||||
|
||||
var testCasesMul10 = [][2]*GF127{
|
||||
{&GF127{123, 0}, &GF127{246, 0}},
|
||||
{&GF127{maxUint64, 2}, &GF127{maxUint64 - 1, 5}},
|
||||
|
|
|
@ -8,16 +8,6 @@ import (
|
|||
// GF127x2 represents a pair of elements of GF(2^127) stored together.
|
||||
type GF127x2 [2]GF127
|
||||
|
||||
func mul10x2Generic(a, b *GF127x2) {
|
||||
mul10Generic(&a[0], &b[0])
|
||||
mul10Generic(&a[1], &b[1])
|
||||
}
|
||||
|
||||
func mul11x2Generic(a, b *GF127x2) {
|
||||
mul11Generic(&a[0], &b[0])
|
||||
mul11Generic(&a[1], &b[1])
|
||||
}
|
||||
|
||||
// Split returns 2 components of pair without additional allocations.
|
||||
func Split(a *GF127x2) (*GF127, *GF127) {
|
||||
return &a[0], &a[1]
|
||||
|
@ -37,15 +27,22 @@ func (a *GF127x2) Equal(b *GF127x2) bool {
|
|||
// String returns hex-encoded representation, starting with MSB.
|
||||
// Elements of pair are separated by comma.
|
||||
func (a *GF127x2) String() string {
|
||||
b := a.Bytes()
|
||||
b := a.ByteArray()
|
||||
return hex.EncodeToString(b[:16]) + " , " + hex.EncodeToString(b[16:])
|
||||
}
|
||||
|
||||
// Bytes represents element of GF(2^127) as byte array of length 32.
|
||||
func (a *GF127x2) Bytes() (buf [32]byte) {
|
||||
binary.BigEndian.PutUint64(buf[:], a[0][1])
|
||||
// ByteArray represents element of GF(2^127) as byte array of length 32.
|
||||
func (a *GF127x2) ByteArray() (buf []byte) {
|
||||
buf = make([]byte, 32)
|
||||
binary.BigEndian.PutUint64(buf, a[0][1])
|
||||
binary.BigEndian.PutUint64(buf[8:], a[0][0])
|
||||
binary.BigEndian.PutUint64(buf[16:], a[1][1])
|
||||
binary.BigEndian.PutUint64(buf[24:], a[1][0])
|
||||
return
|
||||
}
|
||||
|
||||
// Mul10x2 sets (b1, b2) to (a1*x, a2*x)
|
||||
func Mul10x2(a, b *GF127x2)
|
||||
|
||||
// Mul10x2 sets (b1, b2) to (a1*(x+1), a2*(x+1))
|
||||
func Mul11x2(a, b *GF127x2)
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
//go:build amd64 && !generic
|
||||
// +build amd64,!generic
|
||||
|
||||
package gf127
|
||||
|
||||
import "golang.org/x/sys/cpu"
|
||||
|
||||
// Mul10x2 sets (b1, b2) to (a1*x, a2*x)
|
||||
func Mul10x2(a, b *GF127x2) {
|
||||
if cpu.X86.HasAVX && cpu.X86.HasAVX2 {
|
||||
mul10x2AVX2(a, b)
|
||||
} else {
|
||||
mul10x2Generic(a, b)
|
||||
}
|
||||
}
|
||||
|
||||
// Mul11x2 sets (b1, b2) to (a1*(x+1), a2*(x+1))
|
||||
func Mul11x2(a, b *GF127x2) {
|
||||
if cpu.X86.HasAVX && cpu.X86.HasAVX2 {
|
||||
mul11x2AVX2(a, b)
|
||||
} else {
|
||||
mul11x2Generic(a, b)
|
||||
}
|
||||
}
|
||||
|
||||
func mul10x2AVX2(a, b *GF127x2)
|
||||
func mul11x2AVX2(a, b *GF127x2)
|
|
@ -1,34 +0,0 @@
|
|||
#include "textflag.h"
|
||||
|
||||
// func Mul10x2(a, b) *[4]uint64
|
||||
TEXT ·mul10x2AVX2(SB), NOSPLIT, $0
|
||||
MOVQ a+0(FP), AX
|
||||
VMOVDQA (AX), Y0
|
||||
VPSLLQ $1, Y0, Y1
|
||||
VPALIGNR $8, Y1, Y0, Y2
|
||||
VPSRLQ $63, Y2, Y2
|
||||
VPXOR Y1, Y2, Y2
|
||||
VPSRLQ $63, Y1, Y3
|
||||
VPSLLQ $63, Y3, Y3
|
||||
VPUNPCKHQDQ Y3, Y3, Y3
|
||||
VPXOR Y2, Y3, Y3
|
||||
MOVQ b+8(FP), AX
|
||||
VMOVDQA Y3, (AX)
|
||||
RET
|
||||
|
||||
// func Mul11x2(a, b) *[4]uint64
|
||||
TEXT ·mul11x2AVX2(SB), NOSPLIT, $0
|
||||
MOVQ a+0(FP), AX
|
||||
VMOVDQA (AX), Y0
|
||||
VPSLLQ $1, Y0, Y1
|
||||
VPALIGNR $8, Y1, Y0, Y2
|
||||
VPSRLQ $63, Y2, Y2
|
||||
VPXOR Y1, Y2, Y2
|
||||
VPSRLQ $63, Y1, Y3
|
||||
VPSLLQ $63, Y3, Y3
|
||||
VPUNPCKHQDQ Y3, Y3, Y3
|
||||
VPXOR Y2, Y3, Y3
|
||||
VPXOR Y0, Y3, Y3
|
||||
MOVQ b+8(FP), AX
|
||||
VMOVDQA Y3, (AX)
|
||||
RET
|
|
@ -1,14 +0,0 @@
|
|||
//go:build !(amd64 && !generic)
|
||||
// +build !amd64 generic
|
||||
|
||||
package gf127
|
||||
|
||||
// Mul10x2 sets (b1, b2) to (a1*x, a2*x)
|
||||
func Mul10x2(a, b *GF127x2) {
|
||||
mul10x2Generic(a, b)
|
||||
}
|
||||
|
||||
// Mul11x2 sets (b1, b2) to (a1*(x+1), a2*(x+1))
|
||||
func Mul11x2(a, b *GF127x2) {
|
||||
mul11x2Generic(a, b)
|
||||
}
|
11
go.mod
11
go.mod
|
@ -1,10 +1,5 @@
|
|||
module git.frostfs.info/TrueCloudLab/tzhash
|
||||
module github.com/nspcc-dev/tzhash
|
||||
|
||||
go 1.16
|
||||
go 1.12
|
||||
|
||||
require (
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/stretchr/testify v1.7.0
|
||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||
)
|
||||
require github.com/stretchr/testify v1.3.0
|
||||
|
|
15
go.sum
15
go.sum
|
@ -1,15 +1,8 @@
|
|||
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/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
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 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
|
||||
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/sys v0.0.0-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8pY/4yfcXrddB8qAbU0=
|
||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
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/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
|
|
125
gogf127/gf127_test.go
Normal file
125
gogf127/gf127_test.go
Normal file
|
@ -0,0 +1,125 @@
|
|||
package gogf127
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
const maxUint64 = ^uint64(0)
|
||||
|
||||
func TestAdd(t *testing.T) {
|
||||
var (
|
||||
a = Random()
|
||||
b = Random()
|
||||
e = &GF127{a[0] ^ b[0], a[1] ^ b[1]}
|
||||
c = new(GF127)
|
||||
)
|
||||
Add(a, b, c)
|
||||
require.Equal(t, e, c)
|
||||
}
|
||||
|
||||
var testCasesMul = [][3]*GF127{
|
||||
// (x+1)*(x^63+x^62+...+1) == x^64+1
|
||||
{&GF127{3, 0}, &GF127{maxUint64, 0}, &GF127{1, 1}},
|
||||
|
||||
// x^126 * x^2 == x^128 == x^64 + x
|
||||
{&GF127{0, 1 << 62}, &GF127{4, 0}, &GF127{2, 1}},
|
||||
|
||||
// (x^64+x^63+1) * (x^64+x) == x^128+x^65+x^127+x^64+x^64+x == x^65+x^64+x^63+1
|
||||
{&GF127{1 + 1<<63, 1}, &GF127{2, 1}, &GF127{0x8000000000000001, 3}},
|
||||
}
|
||||
|
||||
func TestMul(t *testing.T) {
|
||||
c := new(GF127)
|
||||
for _, tc := range testCasesMul {
|
||||
Mul(tc[0], tc[1], c)
|
||||
require.Equal(t, tc[2], c)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMulInPlace(t *testing.T) {
|
||||
for _, tc := range testCasesMul {
|
||||
a := *tc[0]
|
||||
b := *tc[1]
|
||||
Mul(&a, &b, &b)
|
||||
require.Equal(t, a, *tc[0])
|
||||
require.Equal(t, b, *tc[2])
|
||||
|
||||
b = *tc[1]
|
||||
Mul(&a, &b, &a)
|
||||
require.Equal(t, b, *tc[1])
|
||||
require.Equal(t, a, *tc[2])
|
||||
}
|
||||
}
|
||||
|
||||
var testCasesMul10 = [][2]*GF127{
|
||||
{&GF127{123, 0}, &GF127{246, 0}},
|
||||
{&GF127{maxUint64, 2}, &GF127{maxUint64 - 1, 5}},
|
||||
{&GF127{0, maxUint64 >> 1}, &GF127{1 + 1<<63, maxUint64>>1 - 1}},
|
||||
}
|
||||
|
||||
func TestMul10(t *testing.T) {
|
||||
c := new(GF127)
|
||||
for _, tc := range testCasesMul10 {
|
||||
Mul10(tc[0], c)
|
||||
require.Equal(t, tc[1], c)
|
||||
}
|
||||
}
|
||||
|
||||
var testCasesMul11 = [][2]*GF127{
|
||||
{&GF127{123, 0}, &GF127{141, 0}},
|
||||
{&GF127{maxUint64, 2}, &GF127{1, 7}},
|
||||
{&GF127{0, maxUint64 >> 1}, &GF127{1 + 1<<63, 1}},
|
||||
}
|
||||
|
||||
func TestMul11(t *testing.T) {
|
||||
c := new(GF127)
|
||||
for _, tc := range testCasesMul11 {
|
||||
Mul11(tc[0], c)
|
||||
require.Equal(t, tc[1], c)
|
||||
}
|
||||
}
|
||||
|
||||
var testCasesInv = [][2]*GF127{
|
||||
{&GF127{1, 0}, &GF127{1, 0}},
|
||||
{&GF127{3, 0}, &GF127{msb64, ^msb64}},
|
||||
{&GF127{54321, 12345}, &GF127{8230555108620784737, 3929873967650665114}},
|
||||
}
|
||||
|
||||
func TestInv(t *testing.T) {
|
||||
var a, b, c = new(GF127), new(GF127), new(GF127)
|
||||
for _, tc := range testCasesInv {
|
||||
Inv(tc[0], c)
|
||||
require.Equal(t, tc[1], c)
|
||||
}
|
||||
|
||||
for i := 0; i < 3; i++ {
|
||||
// 0 has no inverse
|
||||
if a = Random(); a.Equals(&GF127{0, 0}) {
|
||||
continue
|
||||
}
|
||||
Inv(a, b)
|
||||
Mul(a, b, c)
|
||||
require.Equal(t, &GF127{1, 0}, c)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGF127_MarshalBinary(t *testing.T) {
|
||||
a := New(0xFF, 0xEE)
|
||||
data, err := a.MarshalBinary()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, data, []byte{0, 0, 0, 0, 0, 0, 0, 0xEE, 0, 0, 0, 0, 0, 0, 0, 0xFF})
|
||||
|
||||
a = Random()
|
||||
data, err = a.MarshalBinary()
|
||||
require.NoError(t, err)
|
||||
|
||||
b := new(GF127)
|
||||
err = b.UnmarshalBinary(data)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, a, b)
|
||||
|
||||
err = b.UnmarshalBinary([]byte{0, 1, 2, 3})
|
||||
require.Error(t, err)
|
||||
}
|
201
gogf127/gogf127.go
Normal file
201
gogf127/gogf127.go
Normal file
|
@ -0,0 +1,201 @@
|
|||
// Copyright 2019 (c) NSPCC
|
||||
//
|
||||
// Package gf127 implements the GF(2^127) arithmetic
|
||||
// modulo reduction polynomial x^127 + x^63 + 1 .
|
||||
// Implementation is in pure Go.
|
||||
package gogf127
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"math/bits"
|
||||
"math/rand"
|
||||
)
|
||||
|
||||
// GF127 represents element of GF(2^127)
|
||||
type GF127 [2]uint64
|
||||
|
||||
const (
|
||||
msb64 = uint64(0x8000000000000000)
|
||||
byteSize = 16
|
||||
)
|
||||
|
||||
var (
|
||||
// x126x631 is reduction polynomial x^127+x^63+1
|
||||
x127x631 = GF127{msb64 + 1, msb64}
|
||||
)
|
||||
|
||||
// New constructs new element of GF(2^127) as hi*x^64 + lo.
|
||||
// It is assumed that hi has zero MSB.
|
||||
func New(lo, hi uint64) *GF127 {
|
||||
return &GF127{lo, hi}
|
||||
}
|
||||
|
||||
// Random returns random element from GF(2^127).
|
||||
// Is used mostly for testing.
|
||||
func Random() *GF127 {
|
||||
return &GF127{rand.Uint64(), rand.Uint64() >> 1}
|
||||
}
|
||||
|
||||
// String returns hex-encoded representation, starting with MSB.
|
||||
func (c *GF127) String() string {
|
||||
return hex.EncodeToString(c.ByteArray())
|
||||
}
|
||||
|
||||
// Equals checks if two reduced (zero MSB) elements of GF(2^127) are equal
|
||||
func (c *GF127) Equals(b *GF127) bool {
|
||||
return c[0] == b[0] && c[1] == b[1]
|
||||
}
|
||||
|
||||
// ByteArray represents element of GF(2^127) as byte array of length 16.
|
||||
func (c *GF127) ByteArray() (buf []byte) {
|
||||
buf = make([]byte, 16)
|
||||
binary.BigEndian.PutUint64(buf[:8], c[1])
|
||||
binary.BigEndian.PutUint64(buf[8:], c[0])
|
||||
return
|
||||
}
|
||||
|
||||
// MarshalBinary implements encoding.BinaryMarshaler.
|
||||
func (c *GF127) MarshalBinary() (data []byte, err error) {
|
||||
return c.ByteArray(), nil
|
||||
}
|
||||
|
||||
// UnmarshalBinary implements encoding.BinaryUnmarshaler.
|
||||
func (c *GF127) UnmarshalBinary(data []byte) error {
|
||||
if len(data) != byteSize {
|
||||
return errors.New("data must be 16-bytes long")
|
||||
}
|
||||
|
||||
c[0] = binary.BigEndian.Uint64(data[8:])
|
||||
c[1] = binary.BigEndian.Uint64(data[:8])
|
||||
if c[1]&msb64 != 0 {
|
||||
return errors.New("MSB must be zero")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Inv sets b to a^-1
|
||||
// Algorithm is based on Extended Euclidean Algorithm
|
||||
// and is described by Hankerson, Hernandez, Menezes in
|
||||
// https://link.springer.com/content/pdf/10.1007/3-540-44499-8_1.pdf
|
||||
func Inv(a, b *GF127) {
|
||||
var (
|
||||
v = x127x631
|
||||
u = *a
|
||||
c, d = &GF127{1, 0}, &GF127{0, 0}
|
||||
t = new(GF127)
|
||||
x *GF127
|
||||
)
|
||||
|
||||
// degree of polynomial is a position of most significant bit
|
||||
for du, dv := msb(&u), msb(&v); du != 0; du, dv = msb(&u), msb(&v) {
|
||||
if du < dv {
|
||||
v, u = u, v
|
||||
dv, du = du, dv
|
||||
d, c = c, d
|
||||
}
|
||||
|
||||
x = xN(du - dv)
|
||||
|
||||
Mul(x, &v, t)
|
||||
Add(&u, t, &u)
|
||||
|
||||
// becasuse mul performs reduction on t, we need
|
||||
// manually reduce u at first step
|
||||
if msb(&u) == 127 {
|
||||
Add(&u, &x127x631, &u)
|
||||
}
|
||||
|
||||
Mul(x, d, t)
|
||||
Add(c, t, c)
|
||||
}
|
||||
*b = *c
|
||||
}
|
||||
|
||||
func xN(n int) *GF127 {
|
||||
if n < 64 {
|
||||
return &GF127{1 << uint(n), 0}
|
||||
}
|
||||
return &GF127{0, 1 << uint(n-64)}
|
||||
}
|
||||
|
||||
func msb(a *GF127) (x int) {
|
||||
x = bits.LeadingZeros64(a[1])
|
||||
if x == 64 {
|
||||
x = bits.LeadingZeros64(a[0]) + 64
|
||||
}
|
||||
return 127 - x
|
||||
}
|
||||
|
||||
// Mul sets c to the product a*b and returns c.
|
||||
func (c *GF127) Mul(a, b *GF127) *GF127 {
|
||||
Mul(a, b, c)
|
||||
return c
|
||||
}
|
||||
|
||||
// Add sets c to the sum a+b and returns c.
|
||||
func (c *GF127) Add(a, b *GF127) *GF127 {
|
||||
Add(a, b, c)
|
||||
return c
|
||||
}
|
||||
|
||||
// Mul1 copies a to b.
|
||||
func Mul1(a, b *GF127) {
|
||||
b[0] = a[0]
|
||||
b[1] = a[1]
|
||||
}
|
||||
|
||||
// And sets c to a & b (bitwise-and).
|
||||
func And(a, b, c *GF127) {
|
||||
c[0] = a[0] & b[0]
|
||||
c[1] = a[1] & b[1]
|
||||
}
|
||||
|
||||
// Add sets c to a+b.
|
||||
func Add(a, b, c *GF127) {
|
||||
c[0] = a[0] ^ b[0]
|
||||
c[1] = a[1] ^ b[1]
|
||||
}
|
||||
|
||||
// Mul sets c to a*b.
|
||||
func Mul(a, b, c *GF127) {
|
||||
r := new(GF127)
|
||||
d := *a
|
||||
for i := uint(0); i < 64; i++ {
|
||||
if b[0]&(1<<i) != 0 {
|
||||
Add(r, &d, r)
|
||||
}
|
||||
Mul10(&d, &d)
|
||||
}
|
||||
for i := uint(0); i < 63; i++ {
|
||||
if b[1]&(1<<i) != 0 {
|
||||
Add(r, &d, r)
|
||||
}
|
||||
Mul10(&d, &d)
|
||||
}
|
||||
*c = *r
|
||||
}
|
||||
|
||||
// Mul10 sets b to a*x.
|
||||
func Mul10(a, b *GF127) {
|
||||
c := (a[0] & msb64) >> 63
|
||||
b[0] = a[0] << 1
|
||||
b[1] = (a[1] << 1) ^ c
|
||||
if b[1]&msb64 != 0 {
|
||||
b[0] ^= x127x631[0]
|
||||
b[1] ^= x127x631[1]
|
||||
}
|
||||
}
|
||||
|
||||
// Mul11 sets b to a*(x+1).
|
||||
func Mul11(a, b *GF127) {
|
||||
c := (a[0] & msb64) >> 63
|
||||
b[0] = a[0] ^ (a[0] << 1)
|
||||
b[1] = a[1] ^ (a[1] << 1) ^ c
|
||||
if b[1]&msb64 != 0 {
|
||||
b[0] ^= x127x631[0]
|
||||
b[1] ^= x127x631[1]
|
||||
}
|
||||
}
|
11
help.mk
11
help.mk
|
@ -1,11 +0,0 @@
|
|||
.PHONY: help
|
||||
|
||||
# Show this help prompt
|
||||
help:
|
||||
@echo ' Usage:'
|
||||
@echo ''
|
||||
@echo ' make <target>'
|
||||
@echo ''
|
||||
@echo ' Targets:'
|
||||
@echo ''
|
||||
@awk '/^#/{ comment = substr($$0,3) } comment && /^[a-zA-Z][a-zA-Z0-9_-]+ ?:/{ print " ", $$1, comment }' $(MAKEFILE_LIST) | column -t -s ':' | grep -v 'IGNORE' | sort | uniq
|
77
internal/cpuid/cpuid_x86.go
Normal file
77
internal/cpuid/cpuid_x86.go
Normal file
|
@ -0,0 +1,77 @@
|
|||
// Copyright (c) 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// +build 386 amd64 amd64p32
|
||||
|
||||
package cpuid
|
||||
|
||||
const (
|
||||
bitOSXSAVE = 1 << 27
|
||||
bitAVX = 1 << 28
|
||||
bitAVX2 = 1 << 5
|
||||
)
|
||||
|
||||
var (
|
||||
hasAVX bool
|
||||
hasAVX2 bool
|
||||
)
|
||||
|
||||
func init() {
|
||||
maxID, _, _, _ := cpuid(0, 0)
|
||||
if maxID < 1 {
|
||||
return
|
||||
}
|
||||
|
||||
_, _, ecx1, _ := cpuid(1, 0)
|
||||
hasOSXSAVE := isSet(ecx1, bitOSXSAVE)
|
||||
|
||||
osSupportsAVX := false
|
||||
if hasOSXSAVE {
|
||||
eax, _ := xgetbv()
|
||||
osSupportsAVX = isSet(eax, 1<<1) && isSet(eax, 1<<2)
|
||||
}
|
||||
|
||||
hasAVX = isSet(ecx1, bitAVX) && osSupportsAVX
|
||||
|
||||
if maxID < 7 {
|
||||
return
|
||||
}
|
||||
|
||||
_, ebx7, _, _ := cpuid(7, 0)
|
||||
hasAVX2 = isSet(ebx7, bitAVX2) && osSupportsAVX
|
||||
}
|
||||
|
||||
func HasAVX() bool { return hasAVX }
|
||||
func HasAVX2() bool { return hasAVX2 }
|
||||
|
||||
func isSet(hwc uint32, value uint32) bool {
|
||||
return hwc&value != 0
|
||||
}
|
||||
|
||||
func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32)
|
||||
func xgetbv() (eax, edx uint32)
|
48
internal/cpuid/cpuid_x86.s
Normal file
48
internal/cpuid/cpuid_x86.s
Normal file
|
@ -0,0 +1,48 @@
|
|||
// Copyright (c) 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
// func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32)
|
||||
TEXT ·cpuid(SB), NOSPLIT, $0-24
|
||||
MOVL eaxArg+0(FP), AX
|
||||
MOVL ecxArg+4(FP), CX
|
||||
CPUID
|
||||
MOVL AX, eax+8(FP)
|
||||
MOVL BX, ebx+12(FP)
|
||||
MOVL CX, ecx+16(FP)
|
||||
MOVL DX, edx+20(FP)
|
||||
RET
|
||||
|
||||
// func xgetbv() (eax, edx uint32)
|
||||
TEXT ·xgetbv(SB),NOSPLIT,$0-8
|
||||
MOVL $0, CX
|
||||
XGETBV
|
||||
MOVL AX, eax+0(FP)
|
||||
MOVL DX, edx+4(FP)
|
||||
RET
|
83
tz/avx.go
Normal file
83
tz/avx.go
Normal file
|
@ -0,0 +1,83 @@
|
|||
// Copyright 2018 (c) NSPCC
|
||||
//
|
||||
// This file contains AVX implementation.
|
||||
package tz
|
||||
|
||||
import (
|
||||
"hash"
|
||||
"math"
|
||||
|
||||
"github.com/nspcc-dev/tzhash/gf127"
|
||||
)
|
||||
|
||||
type digest struct {
|
||||
x [4]gf127.GF127
|
||||
}
|
||||
|
||||
// type assertion
|
||||
var _ hash.Hash = (*digest)(nil)
|
||||
|
||||
var (
|
||||
minmax = [2]gf127.GF127{{0, 0}, {math.MaxUint64, math.MaxUint64}}
|
||||
x127x63 = gf127.GF127{1 << 63, 1 << 63}
|
||||
)
|
||||
|
||||
func newAVX() *digest {
|
||||
d := new(digest)
|
||||
d.Reset()
|
||||
return d
|
||||
}
|
||||
|
||||
func (d *digest) Sum(in []byte) []byte {
|
||||
// Make a copy of d so that caller can keep writing and summing.
|
||||
d0 := *d
|
||||
h := d0.checkSum()
|
||||
return append(in, h[:]...)
|
||||
}
|
||||
|
||||
func (d *digest) checkSum() [hashSize]byte {
|
||||
return d.byteArray()
|
||||
}
|
||||
|
||||
func (d *digest) byteArray() (b [hashSize]byte) {
|
||||
copy(b[:], d.x[0].ByteArray())
|
||||
copy(b[16:], d.x[1].ByteArray())
|
||||
copy(b[32:], d.x[2].ByteArray())
|
||||
copy(b[48:], d.x[3].ByteArray())
|
||||
return
|
||||
}
|
||||
|
||||
func (d *digest) Reset() {
|
||||
d.x[0] = gf127.GF127{1, 0}
|
||||
d.x[1] = gf127.GF127{0, 0}
|
||||
d.x[2] = gf127.GF127{0, 0}
|
||||
d.x[3] = gf127.GF127{1, 0}
|
||||
}
|
||||
|
||||
func (d *digest) Write(data []byte) (n int, err error) {
|
||||
n = len(data)
|
||||
for _, b := range data {
|
||||
mulByteRight(&d.x[0], &d.x[1], &d.x[2], &d.x[3], b)
|
||||
// mulBitRight(&d.x[0], &d.x[1], &d.x[2], &d.x[3], &minmax[(b>>7)&1])
|
||||
// mulBitRight(&d.x[0], &d.x[1], &d.x[2], &d.x[3], &minmax[(b>>6)&1])
|
||||
// mulBitRight(&d.x[0], &d.x[1], &d.x[2], &d.x[3], &minmax[(b>>5)&1])
|
||||
// mulBitRight(&d.x[0], &d.x[1], &d.x[2], &d.x[3], &minmax[(b>>4)&1])
|
||||
// mulBitRight(&d.x[0], &d.x[1], &d.x[2], &d.x[3], &minmax[(b>>3)&1])
|
||||
// mulBitRight(&d.x[0], &d.x[1], &d.x[2], &d.x[3], &minmax[(b>>2)&1])
|
||||
// mulBitRight(&d.x[0], &d.x[1], &d.x[2], &d.x[3], &minmax[(b>>1)&1])
|
||||
// mulBitRight(&d.x[0], &d.x[1], &d.x[2], &d.x[3], &minmax[(b>>0)&1])
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (d *digest) Size() int {
|
||||
return hashSize
|
||||
}
|
||||
|
||||
func (d *digest) BlockSize() int {
|
||||
return hashBlockSize
|
||||
}
|
||||
|
||||
func mulBitRight(c00, c01, c10, c11, e *gf127.GF127)
|
||||
|
||||
func mulByteRight(c00, c01, c10, c11 *gf127.GF127, b byte)
|
65
tz/avx2.go
Normal file
65
tz/avx2.go
Normal file
|
@ -0,0 +1,65 @@
|
|||
// Copyright 2019 (c) NSPCC
|
||||
//
|
||||
// This file contains AVX2 implementation.
|
||||
package tz
|
||||
|
||||
import (
|
||||
"hash"
|
||||
|
||||
"github.com/nspcc-dev/tzhash/gf127"
|
||||
)
|
||||
|
||||
type digest2 struct {
|
||||
x [2]gf127.GF127x2
|
||||
}
|
||||
|
||||
// type assertion
|
||||
var _ hash.Hash = (*digest2)(nil)
|
||||
|
||||
func newAVX2() *digest2 {
|
||||
d := new(digest2)
|
||||
d.Reset()
|
||||
return d
|
||||
}
|
||||
|
||||
func (d *digest2) Write(data []byte) (n int, err error) {
|
||||
n = len(data)
|
||||
for _, b := range data {
|
||||
mulBitRightx2(&d.x[0], &d.x[1], &minmax[(b>>7)&1])
|
||||
mulBitRightx2(&d.x[0], &d.x[1], &minmax[(b>>6)&1])
|
||||
mulBitRightx2(&d.x[0], &d.x[1], &minmax[(b>>5)&1])
|
||||
mulBitRightx2(&d.x[0], &d.x[1], &minmax[(b>>4)&1])
|
||||
mulBitRightx2(&d.x[0], &d.x[1], &minmax[(b>>3)&1])
|
||||
mulBitRightx2(&d.x[0], &d.x[1], &minmax[(b>>2)&1])
|
||||
mulBitRightx2(&d.x[0], &d.x[1], &minmax[(b>>1)&1])
|
||||
mulBitRightx2(&d.x[0], &d.x[1], &minmax[(b>>0)&1])
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (d *digest2) Sum(in []byte) []byte {
|
||||
// Make a copy of d so that caller can keep writing and summing.
|
||||
d0 := *d
|
||||
h := d0.checkSum()
|
||||
return append(in, h[:]...)
|
||||
}
|
||||
func (d *digest2) Reset() {
|
||||
d.x[0] = gf127.GF127x2{gf127.GF127{1, 0}, gf127.GF127{0, 0}}
|
||||
d.x[1] = gf127.GF127x2{gf127.GF127{0, 0}, gf127.GF127{1, 0}}
|
||||
}
|
||||
func (d *digest2) Size() int { return hashSize }
|
||||
func (d *digest2) BlockSize() int { return hashBlockSize }
|
||||
func (d *digest2) checkSum() (b [hashSize]byte) {
|
||||
// Matrix is stored transposed,
|
||||
// but we need to use order consistent with digest.
|
||||
h := d.x[0].ByteArray()
|
||||
copy(b[:], h[:16])
|
||||
copy(b[32:], h[16:])
|
||||
|
||||
h = d.x[1].ByteArray()
|
||||
copy(b[16:], h[:16])
|
||||
copy(b[48:], h[16:])
|
||||
return
|
||||
}
|
||||
|
||||
func mulBitRightx2(c00c10 *gf127.GF127x2, c01c11 *gf127.GF127x2, e *gf127.GF127)
|
59
tz/avx2_inline.go
Normal file
59
tz/avx2_inline.go
Normal file
|
@ -0,0 +1,59 @@
|
|||
// Copyright 2019 (c) NSPCC
|
||||
//
|
||||
// This file contains AVX2 implementation with inlined
|
||||
// assembly calls.
|
||||
package tz
|
||||
|
||||
import (
|
||||
"hash"
|
||||
|
||||
"github.com/nspcc-dev/tzhash/gf127"
|
||||
)
|
||||
|
||||
type digest3 struct {
|
||||
x [2]gf127.GF127x2
|
||||
}
|
||||
|
||||
// type assertion
|
||||
var _ hash.Hash = (*digest3)(nil)
|
||||
|
||||
func newAVX2Inline() *digest3 {
|
||||
d := new(digest3)
|
||||
d.Reset()
|
||||
return d
|
||||
}
|
||||
|
||||
func (d *digest3) Write(data []byte) (n int, err error) {
|
||||
n = len(data)
|
||||
for _, b := range data {
|
||||
mulByteRightx2(&d.x[0], &d.x[1], b)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (d *digest3) Sum(in []byte) []byte {
|
||||
// Make a copy of d so that caller can keep writing and summing.
|
||||
d0 := *d
|
||||
h := d0.checkSum()
|
||||
return append(in, h[:]...)
|
||||
}
|
||||
func (d *digest3) Reset() {
|
||||
d.x[0] = gf127.GF127x2{gf127.GF127{1, 0}, gf127.GF127{0, 0}}
|
||||
d.x[1] = gf127.GF127x2{gf127.GF127{0, 0}, gf127.GF127{1, 0}}
|
||||
}
|
||||
func (d *digest3) Size() int { return hashSize }
|
||||
func (d *digest3) BlockSize() int { return hashBlockSize }
|
||||
func (d *digest3) checkSum() (b [hashSize]byte) {
|
||||
// Matrix is stored transposed,
|
||||
// but we need to use order consistent with digest.
|
||||
h := d.x[0].ByteArray()
|
||||
copy(b[:], h[:16])
|
||||
copy(b[32:], h[16:])
|
||||
|
||||
h = d.x[1].ByteArray()
|
||||
copy(b[16:], h[:16])
|
||||
copy(b[48:], h[16:])
|
||||
return
|
||||
}
|
||||
|
||||
func mulByteRightx2(c00c10 *gf127.GF127x2, c01c11 *gf127.GF127x2, b byte)
|
46
tz/avx2_inline_amd64.s
Normal file
46
tz/avx2_inline_amd64.s
Normal file
|
@ -0,0 +1,46 @@
|
|||
#include "textflag.h"
|
||||
|
||||
#define mask(bit, src, tmp, to1, to2) \
|
||||
MOVQ src, tmp \
|
||||
SHRQ bit, tmp \
|
||||
ANDQ $1, tmp \
|
||||
NEGQ tmp \
|
||||
MOVQ tmp, to1 \
|
||||
VPBROADCASTB to1, to2
|
||||
|
||||
#define mulBit(bit) \
|
||||
VPSLLQ $1, Y0, Y1 \
|
||||
VPALIGNR $8, Y1, Y0, Y2 \
|
||||
VPSRLQ $63, Y2, Y2 \
|
||||
VPXOR Y1, Y2, Y2 \
|
||||
VPSRLQ $63, Y1, Y3 \
|
||||
VPSLLQ $63, Y3, Y3 \
|
||||
VPUNPCKHQDQ Y3, Y3, Y3 \
|
||||
VPXOR Y2, Y3, Y3 \
|
||||
mask(bit, CX, DX, X1, Y2) \
|
||||
VPXOR Y3, Y8, Y3 \
|
||||
VPAND Y3, Y2, Y4 \
|
||||
VPXOR Y4, Y0, Y8 \
|
||||
VMOVDQA Y3, Y0
|
||||
|
||||
// func mulByteRightx2(c00c10, c01c11 *[4]uint64, b byte)
|
||||
TEXT ·mulByteRightx2(SB),NOSPLIT,$0
|
||||
MOVQ c00c10+0(FP), AX
|
||||
VMOVDQA (AX), Y0
|
||||
MOVQ c01c11+8(FP), BX
|
||||
VMOVDQA (BX), Y8
|
||||
MOVB b+16(FP), CX
|
||||
|
||||
mulBit($7)
|
||||
mulBit($6)
|
||||
mulBit($5)
|
||||
mulBit($4)
|
||||
mulBit($3)
|
||||
mulBit($2)
|
||||
mulBit($1)
|
||||
mulBit($0)
|
||||
|
||||
VMOVDQA Y8, (BX)
|
||||
VMOVDQA Y0, (AX)
|
||||
|
||||
RET
|
127
tz/avx_amd64.s
Normal file
127
tz/avx_amd64.s
Normal file
|
@ -0,0 +1,127 @@
|
|||
#include "textflag.h"
|
||||
|
||||
// mul2 multiplicates FROM by 2, stores result in R1
|
||||
// and uses R1, R2 and R3 for internal computations.
|
||||
#define mul2(FROM, TO, R2, R3) \
|
||||
VPSLLQ $1, FROM, TO \
|
||||
VPALIGNR $8, TO, FROM, R2 \
|
||||
PSRLQ $63, R2 \
|
||||
MOVUPD ·x127x63(SB), R3 \
|
||||
ANDPD TO, R3 \
|
||||
VPUNPCKHQDQ R3, R3, R3 \
|
||||
XORPD R2, TO \
|
||||
XORPD R3, TO
|
||||
|
||||
|
||||
#define mask(bit, src, tmp, to1, to2) \
|
||||
MOVQ src, tmp \
|
||||
SHRQ bit, tmp \
|
||||
ANDQ $1, tmp \
|
||||
NEGQ tmp \
|
||||
MOVQ tmp, to1 \
|
||||
VPBROADCASTB to1, to2
|
||||
// FIXME VPBROADCASTB is AVX2 instruction
|
||||
//https://software.intel.com/en-us/forums/intel-isa-extensions/topic/301461
|
||||
|
||||
#define mulBit(bit) \
|
||||
MOVUPD X0, X8 \
|
||||
MOVUPD X2, X9 \
|
||||
mul2(X0, X5, X6, X7) \
|
||||
VXORPD X1, X5, X0 \
|
||||
mul2(X2, X5, X6, X7) \
|
||||
VXORPD X3, X5, X2 \
|
||||
mask(bit, CX, DX, X6, X5) \
|
||||
VANDPD X0, X5, X1 \
|
||||
XORPD X8, X1 \
|
||||
VANDPD X2, X5, X3 \
|
||||
XORPD X9, X3
|
||||
|
||||
|
||||
// func mulBitRight(c00, c01, c10, c11 *[2]uint64, byte)
|
||||
TEXT ·mulByteRight(SB),NOSPLIT,$0
|
||||
MOVQ c00+0(FP), AX
|
||||
MOVUPD (AX), X0
|
||||
MOVQ c01+8(FP), BX
|
||||
MOVUPD (BX), X1
|
||||
MOVQ c10+16(FP), CX
|
||||
MOVUPD (CX), X2
|
||||
MOVQ c11+24(FP), DX
|
||||
MOVUPD (DX), X3
|
||||
MOVB e+32(FP), CX
|
||||
|
||||
mulBit($7)
|
||||
mulBit($6)
|
||||
mulBit($5)
|
||||
mulBit($4)
|
||||
mulBit($3)
|
||||
mulBit($2)
|
||||
mulBit($1)
|
||||
mulBit($0)
|
||||
|
||||
MOVUPD X0, (AX)
|
||||
MOVQ c10+16(FP), CX
|
||||
MOVUPD X2, (CX)
|
||||
MOVUPD X1, (BX)
|
||||
MOVQ c11+24(FP), DX
|
||||
MOVUPD X3, (DX)
|
||||
|
||||
RET
|
||||
|
||||
|
||||
// func mulBitRight(c00, c01, c10, c11, e *[2]uint64)
|
||||
TEXT ·mulBitRight(SB),NOSPLIT,$0
|
||||
MOVQ c00+0(FP), AX
|
||||
MOVUPD (AX), X0
|
||||
MOVUPD X0, X8 // remember c00 value
|
||||
MOVQ c01+8(FP), BX
|
||||
MOVUPD (BX), X1
|
||||
MOVQ c10+16(FP), CX
|
||||
MOVUPD (CX), X2
|
||||
MOVUPD X2, X9 // remember c10 value
|
||||
MOVQ c11+24(FP), DX
|
||||
MOVUPD (DX), X3
|
||||
|
||||
mul2(X0, X5, X6, X7)
|
||||
VXORPD X1, X5, X0
|
||||
mul2(X2, X5, X6, X7)
|
||||
VXORPD X3, X5, X2
|
||||
MOVQ e+32(FP), CX
|
||||
MOVUPD (CX), X5
|
||||
VANDPD X0, X5, X1
|
||||
XORPD X8, X1
|
||||
VANDPD X2, X5, X3
|
||||
XORPD X9, X3
|
||||
|
||||
MOVUPD X0, (AX)
|
||||
MOVQ c10+16(FP), CX
|
||||
MOVUPD X2, (CX)
|
||||
MOVUPD X1, (BX)
|
||||
MOVUPD X3, (DX)
|
||||
|
||||
RET
|
||||
|
||||
// func mulBitRightx2(c00c10, c01c11 *[4]uint64, e *[2]uint64)
|
||||
TEXT ·mulBitRightx2(SB),NOSPLIT,$0
|
||||
MOVQ c00c10+0(FP), AX
|
||||
VMOVDQA (AX), Y0
|
||||
MOVQ c01c11+8(FP), BX
|
||||
VMOVDQA (BX), Y8
|
||||
|
||||
VPSLLQ $1, Y0, Y1
|
||||
VPALIGNR $8, Y1, Y0, Y2
|
||||
VPSRLQ $63, Y2, Y2
|
||||
VPXOR Y1, Y2, Y2
|
||||
VPSRLQ $63, Y1, Y3
|
||||
VPSLLQ $63, Y3, Y3
|
||||
VPUNPCKHQDQ Y3, Y3, Y3
|
||||
VPXOR Y2, Y3, Y3
|
||||
|
||||
MOVQ e+16(FP), CX
|
||||
VBROADCASTI128 (CX), Y2
|
||||
|
||||
VPXOR Y3, Y8, Y3
|
||||
VPAND Y3, Y2, Y4
|
||||
VPXOR Y4, Y0, Y8
|
||||
VMOVDQA Y8, (BX)
|
||||
VMOVDQA Y3, (AX)
|
||||
RET
|
124
tz/digest.go
124
tz/digest.go
|
@ -1,124 +0,0 @@
|
|||
package tz
|
||||
|
||||
import (
|
||||
"git.frostfs.info/TrueCloudLab/tzhash/gf127"
|
||||
)
|
||||
|
||||
const (
|
||||
// Size is the size of a Tillich-Zémor hash sum in bytes.
|
||||
Size = 64
|
||||
hashBlockSize = 128
|
||||
)
|
||||
|
||||
type digest struct {
|
||||
// Stores matrix cells in the following order:
|
||||
// [ 0 2 ]
|
||||
// [ 1 3 ]
|
||||
// This is done to reuse the same digest between generic
|
||||
// and AVX2 implementation.
|
||||
x [4]GF127
|
||||
}
|
||||
|
||||
// New returns a new hash.Hash computing the Tillich-Zémor checksum.
|
||||
func New() *digest {
|
||||
d := new(digest)
|
||||
d.Reset()
|
||||
return d
|
||||
}
|
||||
|
||||
// Sum returns Tillich-Zémor checksum of data.
|
||||
func Sum(data []byte) [Size]byte {
|
||||
d := new(digest)
|
||||
d.Reset()
|
||||
_, _ = d.Write(data) // no errors
|
||||
return d.checkSum()
|
||||
}
|
||||
|
||||
// Sum implements hash.Hash.
|
||||
func (d *digest) Sum(in []byte) []byte {
|
||||
// Make a copy of d so that caller can keep writing and summing.
|
||||
d0 := *d
|
||||
h := d0.checkSum()
|
||||
return append(in, h[:]...)
|
||||
}
|
||||
|
||||
func (d *digest) checkSum() (b [Size]byte) {
|
||||
t := d.x[0].Bytes()
|
||||
copy(b[:], t[:])
|
||||
|
||||
t = d.x[2].Bytes()
|
||||
copy(b[16:], t[:])
|
||||
|
||||
t = d.x[1].Bytes()
|
||||
copy(b[32:], t[:])
|
||||
|
||||
t = d.x[3].Bytes()
|
||||
copy(b[48:], t[:])
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Reset implements hash.Hash.
|
||||
func (d *digest) Reset() {
|
||||
d.x[0] = GF127{1, 0}
|
||||
d.x[1] = GF127{0, 0}
|
||||
d.x[2] = GF127{0, 0}
|
||||
d.x[3] = GF127{1, 0}
|
||||
}
|
||||
|
||||
// Write implements hash.Hash.
|
||||
func (d *digest) Write(data []byte) (n int, err error) {
|
||||
return write(d, data)
|
||||
}
|
||||
|
||||
func writeGeneric(d *digest, data []byte) (n int, err error) {
|
||||
n = len(data)
|
||||
tmp := new(GF127)
|
||||
for _, b := range data {
|
||||
mulBitRightGeneric(&d.x[0], &d.x[1], &d.x[2], &d.x[3], b&0x80 != 0, tmp)
|
||||
mulBitRightGeneric(&d.x[0], &d.x[1], &d.x[2], &d.x[3], b&0x40 != 0, tmp)
|
||||
mulBitRightGeneric(&d.x[0], &d.x[1], &d.x[2], &d.x[3], b&0x20 != 0, tmp)
|
||||
mulBitRightGeneric(&d.x[0], &d.x[1], &d.x[2], &d.x[3], b&0x10 != 0, tmp)
|
||||
mulBitRightGeneric(&d.x[0], &d.x[1], &d.x[2], &d.x[3], b&0x08 != 0, tmp)
|
||||
mulBitRightGeneric(&d.x[0], &d.x[1], &d.x[2], &d.x[3], b&0x04 != 0, tmp)
|
||||
mulBitRightGeneric(&d.x[0], &d.x[1], &d.x[2], &d.x[3], b&0x02 != 0, tmp)
|
||||
mulBitRightGeneric(&d.x[0], &d.x[1], &d.x[2], &d.x[3], b&0x01 != 0, tmp)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Size implements hash.Hash.
|
||||
func (d *digest) Size() int {
|
||||
return Size
|
||||
}
|
||||
|
||||
// BlockSize implements hash.Hash.
|
||||
func (d *digest) BlockSize() int {
|
||||
return hashBlockSize
|
||||
}
|
||||
|
||||
func mulBitRightGeneric(c00, c10, c01, c11 *GF127, bit bool, tmp *GF127) {
|
||||
if bit {
|
||||
*tmp = *c00
|
||||
gf127.Mul10(c00, c00)
|
||||
gf127.Add(c00, c01, c00)
|
||||
gf127.Mul11(tmp, tmp)
|
||||
gf127.Add(c01, tmp, c01)
|
||||
|
||||
*tmp = *c10
|
||||
gf127.Mul10(c10, c10)
|
||||
gf127.Add(c10, c11, c10)
|
||||
gf127.Mul11(tmp, tmp)
|
||||
gf127.Add(c11, tmp, c11)
|
||||
} else {
|
||||
*tmp = *c00
|
||||
gf127.Mul10(c00, c00)
|
||||
gf127.Add(c00, c01, c00)
|
||||
*c01 = *tmp
|
||||
|
||||
*tmp = *c10
|
||||
gf127.Mul10(c10, c10)
|
||||
gf127.Add(c10, c11, c10)
|
||||
*c11 = *tmp
|
||||
}
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
#include "textflag.h"
|
||||
|
||||
#define mulBit(bit, in_1, in_2, out_1, out_2) \
|
||||
VPSLLW bit, Y10, Y11 \
|
||||
VPSLLQ $1, in_1, Y1 \
|
||||
VPSRAW $15, Y11, Y12 \
|
||||
VPALIGNR $8, Y1, in_1, Y2 \
|
||||
VPAND Y1, Y14, Y3 \
|
||||
VPSRLQ $63, Y2, Y2 \
|
||||
VPUNPCKHQDQ Y3, Y3, Y3 \
|
||||
VPXOR Y1, Y2, Y7 \
|
||||
VPXOR Y3, in_2, out_1 \
|
||||
VPXOR Y7, out_1, out_1 \
|
||||
VPAND out_1, Y12, Y4 \
|
||||
VPXOR Y4, in_1, out_2 \
|
||||
|
||||
// func mulByteSliceRightx2(c00c10, c01c11 *[4]uint64, n int, data *byte)
|
||||
TEXT ·mulByteSliceRightx2(SB), NOSPLIT, $0
|
||||
MOVQ c00c10+0(FP), AX
|
||||
MOVQ c01c11+8(FP), BX
|
||||
|
||||
VPXOR Y13, Y13, Y13 // Y13 = 0x0000...
|
||||
VPCMPEQB Y14, Y14, Y14 // Y14 = 0xFFFF...
|
||||
VPSUBQ Y14, Y13, Y10
|
||||
VPSLLQ $63, Y10, Y14 // Y14 = 0x10000000... (packed quad-words with HSB set)
|
||||
|
||||
MOVQ n+16(FP), CX
|
||||
MOVQ data+24(FP), DX
|
||||
|
||||
VMOVDQU (AX), Y0
|
||||
VMOVDQU (BX), Y8
|
||||
|
||||
loop:
|
||||
CMPQ CX, $0
|
||||
JEQ finish
|
||||
|
||||
VPBROADCASTB (DX), Y10
|
||||
ADDQ $1, DX
|
||||
SUBQ $1, CX
|
||||
|
||||
mulBit($8, Y0, Y8, Y5, Y6)
|
||||
mulBit($9, Y5, Y6, Y0, Y8)
|
||||
mulBit($10, Y0, Y8, Y5, Y6)
|
||||
mulBit($11, Y5, Y6, Y0, Y8)
|
||||
mulBit($12, Y0, Y8, Y5, Y6)
|
||||
mulBit($13, Y5, Y6, Y0, Y8)
|
||||
mulBit($14, Y0, Y8, Y5, Y6)
|
||||
mulBit($15, Y5, Y6, Y0, Y8)
|
||||
|
||||
JMP loop
|
||||
|
||||
finish:
|
||||
VMOVDQU Y0, (AX)
|
||||
VMOVDQU Y8, (BX)
|
||||
|
||||
RET
|
|
@ -1,70 +0,0 @@
|
|||
#include "textflag.h"
|
||||
|
||||
// mul2 multiplicates FROM by 2, stores result in R1
|
||||
// and uses R1, R2 and R3 for internal computations.
|
||||
#define mul2(FROM, TO, R2, R3) \
|
||||
VPSLLQ $1, FROM, TO \
|
||||
VPALIGNR $8, TO, FROM, R2 \
|
||||
VPSRLQ $63, R2, R2 \
|
||||
VANDPD TO, X14, R3 \
|
||||
VPUNPCKHQDQ R3, R3, R3 \
|
||||
VXORPD R2, TO, TO \
|
||||
VXORPD R3, TO, TO
|
||||
|
||||
#define mask(bit, tmp, to) \
|
||||
VPSRLW bit, X10, tmp \
|
||||
VPAND X12, tmp, to \ // to = 0x000<bit>000<bit>...
|
||||
VPSUBW to, X13, to // to = 0xFFFF.. or 0x0000 depending on bit
|
||||
|
||||
#define mulBit(bit) \
|
||||
VMOVDQU X0, X8 \
|
||||
VMOVDQU X2, X9 \
|
||||
mul2(X0, X5, X6, X7) \
|
||||
VXORPD X1, X5, X0 \
|
||||
mul2(X2, X5, X6, X7) \
|
||||
VXORPD X3, X5, X2 \
|
||||
mask(bit, X6, X5) \
|
||||
VANDPD X0, X5, X1 \
|
||||
VXORPD X8, X1, X1 \
|
||||
VANDPD X2, X5, X3 \
|
||||
VXORPD X9, X3, X3
|
||||
|
||||
TEXT ·mulByteRight(SB), NOSPLIT, $0
|
||||
MOVQ c00+0(FP), AX
|
||||
VMOVDQU (AX), X0
|
||||
MOVQ c10+8(FP), CX
|
||||
VMOVDQU (CX), X2
|
||||
MOVQ c01+16(FP), BX
|
||||
VMOVDQU (BX), X1
|
||||
MOVQ c11+24(FP), DX
|
||||
VMOVDQU (DX), X3
|
||||
MOVQ $0, CX
|
||||
MOVB b+32(FP), CX
|
||||
|
||||
VPXOR X13, X13, X13 // X13 = 0x0000...
|
||||
VPCMPEQB X14, X14, X14 // X14 = 0xFFFF...
|
||||
VPSUBQ X14, X13, X10
|
||||
VPSUBW X14, X13, X12 // X12 = 0x00010001... (packed words of 1)
|
||||
VPSLLQ $63, X10, X14 // X14 = 0x10000000... (packed quad-words with HSB set)
|
||||
|
||||
MOVQ CX, X10
|
||||
VPSHUFLW $0, X10, X11
|
||||
VPSHUFD $0, X11, X10
|
||||
|
||||
mulBit($7)
|
||||
mulBit($6)
|
||||
mulBit($5)
|
||||
mulBit($4)
|
||||
mulBit($3)
|
||||
mulBit($2)
|
||||
mulBit($1)
|
||||
mulBit($0)
|
||||
|
||||
VMOVDQU X0, (AX)
|
||||
MOVQ c10+8(FP), CX
|
||||
VMOVDQU X2, (CX)
|
||||
VMOVDQU X1, (BX)
|
||||
MOVQ c11+24(FP), DX
|
||||
VMOVDQU X3, (DX)
|
||||
|
||||
RET
|
|
@ -1,8 +0,0 @@
|
|||
//go:build !(amd64 && !generic)
|
||||
// +build !amd64 generic
|
||||
|
||||
package tz
|
||||
|
||||
func write(d *digest, data []byte) (int, error) {
|
||||
return writeGeneric(d, data)
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
//go:build amd64 && !generic
|
||||
// +build amd64,!generic
|
||||
|
||||
package tz
|
||||
|
||||
import (
|
||||
"git.frostfs.info/TrueCloudLab/tzhash/gf127"
|
||||
"golang.org/x/sys/cpu"
|
||||
)
|
||||
|
||||
func write(d *digest, data []byte) (n int, err error) {
|
||||
switch {
|
||||
case cpu.X86.HasAVX && cpu.X86.HasAVX2:
|
||||
return writeAVX2(d, data)
|
||||
case cpu.X86.HasAVX:
|
||||
return writeAVX(d, data)
|
||||
default:
|
||||
return writeGeneric(d, data)
|
||||
}
|
||||
}
|
||||
|
||||
func writeAVX2(d *digest, data []byte) (n int, err error) {
|
||||
n = len(data)
|
||||
if len(data) != 0 {
|
||||
mulByteSliceRightx2(&d.x[0], &d.x[2], n, &data[0])
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func writeAVX(d *digest, data []byte) (n int, err error) {
|
||||
n = len(data)
|
||||
for _, b := range data {
|
||||
mulByteRight(&d.x[0], &d.x[1], &d.x[2], &d.x[3], b)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func mulByteRight(c00, c01, c10, c11 *GF127, b byte)
|
||||
func mulByteSliceRightx2(c00c10 *gf127.GF127, c01c11 *gf127.GF127, n int, data *byte)
|
90
tz/hash.go
90
tz/hash.go
|
@ -1,13 +1,93 @@
|
|||
// Package tz contains Tillich-Zemor checksum implementations
|
||||
// using different backends.
|
||||
// Copyright 2018 (c) NSPCC
|
||||
//
|
||||
// Copyright 2022 (c) NSPCC
|
||||
// Package tz implements general Tillich-Zemo
|
||||
package tz
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"hash"
|
||||
|
||||
"github.com/nspcc-dev/tzhash/internal/cpuid"
|
||||
)
|
||||
|
||||
type Implementation int
|
||||
|
||||
const (
|
||||
hashSize = 64
|
||||
hashBlockSize = 128
|
||||
|
||||
_ Implementation = iota
|
||||
AVX
|
||||
AVX2
|
||||
AVX2Inline
|
||||
PureGo
|
||||
)
|
||||
|
||||
var (
|
||||
hasAVX = cpuid.HasAVX()
|
||||
// Having AVX2 does not guarantee
|
||||
// that AVX is also present.
|
||||
hasAVX2 = cpuid.HasAVX2() && hasAVX
|
||||
)
|
||||
|
||||
func (impl Implementation) String() string {
|
||||
switch impl {
|
||||
case AVX:
|
||||
return "AVX"
|
||||
case AVX2:
|
||||
return "AVX2"
|
||||
case AVX2Inline:
|
||||
return "AVX2Inline"
|
||||
case PureGo:
|
||||
return "PureGo"
|
||||
default:
|
||||
return "UNKNOWN"
|
||||
}
|
||||
}
|
||||
|
||||
func NewWith(impl Implementation) hash.Hash {
|
||||
switch impl {
|
||||
case AVX:
|
||||
return newAVX()
|
||||
case AVX2:
|
||||
return newAVX2()
|
||||
case AVX2Inline:
|
||||
return newAVX2Inline()
|
||||
case PureGo:
|
||||
return newPure()
|
||||
default:
|
||||
return New()
|
||||
}
|
||||
}
|
||||
|
||||
// New returns a new hash.Hash computing the Tillich-Zémor checksum.
|
||||
func New() hash.Hash {
|
||||
if hasAVX2 {
|
||||
return newAVX2Inline()
|
||||
} else if hasAVX {
|
||||
return newAVX()
|
||||
} else {
|
||||
return newPure()
|
||||
}
|
||||
}
|
||||
|
||||
// Sum returns Tillich-Zémor checksum of data.
|
||||
func Sum(data []byte) [hashSize]byte {
|
||||
if hasAVX2 {
|
||||
d := newAVX2Inline()
|
||||
_, _ = d.Write(data) // no errors
|
||||
return d.checkSum()
|
||||
} else if hasAVX {
|
||||
d := newAVX()
|
||||
_, _ = d.Write(data) // no errors
|
||||
return d.checkSum()
|
||||
} else {
|
||||
d := newPure()
|
||||
_, _ = d.Write(data) // no errors
|
||||
return d.checkSum()
|
||||
}
|
||||
}
|
||||
|
||||
// Concat performs combining of hashes based on homomorphic property.
|
||||
func Concat(hs [][]byte) ([]byte, error) {
|
||||
var b, c sl2
|
||||
|
@ -26,11 +106,11 @@ func Concat(hs [][]byte) ([]byte, error) {
|
|||
func Validate(h []byte, hs [][]byte) (bool, error) {
|
||||
var (
|
||||
b []byte
|
||||
got, expected [Size]byte
|
||||
got, expected [hashSize]byte
|
||||
err error
|
||||
)
|
||||
|
||||
if len(h) != Size {
|
||||
if len(h) != hashSize {
|
||||
return false, errors.New("invalid hash")
|
||||
} else if len(hs) == 0 {
|
||||
return false, errors.New("empty slice")
|
||||
|
|
|
@ -2,29 +2,34 @@ package tz
|
|||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/rand"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"golang.org/x/sys/cpu"
|
||||
)
|
||||
|
||||
const benchDataSize = 100000
|
||||
|
||||
type arch struct {
|
||||
HasAVX bool
|
||||
HasAVX2 bool
|
||||
var providers = []Implementation{
|
||||
AVX,
|
||||
AVX2,
|
||||
AVX2Inline,
|
||||
PureGo,
|
||||
}
|
||||
|
||||
var backends = []struct {
|
||||
Name string
|
||||
arch
|
||||
}{
|
||||
{"AVX", arch{true, false}},
|
||||
{"AVX2", arch{true, true}},
|
||||
{"Generic", arch{false, false}},
|
||||
func TestNewWith(t *testing.T) {
|
||||
d := NewWith(AVX)
|
||||
require.IsType(t, (*digest)(nil), d)
|
||||
|
||||
d = NewWith(AVX2)
|
||||
require.IsType(t, (*digest2)(nil), d)
|
||||
|
||||
d = NewWith(AVX2Inline)
|
||||
require.IsType(t, (*digest3)(nil), d)
|
||||
|
||||
d = NewWith(PureGo)
|
||||
require.IsType(t, (*digestp)(nil), d)
|
||||
}
|
||||
|
||||
var testCases = []struct {
|
||||
|
@ -35,34 +40,6 @@ var testCases = []struct {
|
|||
[]byte{},
|
||||
"00000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001",
|
||||
},
|
||||
{
|
||||
[]byte{0},
|
||||
"00000000000000000000000000000151000000000000000000000000000000800000000000000000000000000000008000000000000000000000000000000051",
|
||||
},
|
||||
{
|
||||
[]byte{1, 2},
|
||||
"000000000000000000000000000139800000000000000000000000000000c0010000000000000000000000000000b98100000000000000000000000000007981",
|
||||
},
|
||||
{
|
||||
[]byte{2, 0, 1},
|
||||
"00000000000000000000000001f980d10000000000000000000000000139805100000000000000000000000000c001d100000000000000000000000000b98080",
|
||||
},
|
||||
{
|
||||
[]byte{3, 2, 1, 0},
|
||||
"0000000000000000000000015540398000000000000000000000000082a1a88100000000000000000000000082a1d10100000000000000000000000050006881",
|
||||
},
|
||||
{
|
||||
[]byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
|
||||
"0000000000000000000001bb00ba00ba000000000000000000000101010101010000000000000000000000ff00ff00ff0000000000000000000000ba01bb01bb",
|
||||
},
|
||||
{
|
||||
[]byte{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
||||
"000000000000000000016ad06ad16bd100000000000000000000ff00ff00ff0000000000000000000000808080808080000000000000000000006bd16bd06ad1",
|
||||
},
|
||||
{
|
||||
[]byte{0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55},
|
||||
"0000000000000000018c8c118d9d009d00000000000000000169680169680168000000000000000000f0f000f0f000f00000000000000000009d9c109c8d018d",
|
||||
},
|
||||
{
|
||||
[]byte{0, 1, 2, 3, 4, 5, 6, 7, 8},
|
||||
"00000000000001e4a545e5b90fb6882b00000000000000c849cd88f79307f67100000000000000cd0c898cb68356e624000000000000007cbcdc7c5e89b16e4b",
|
||||
|
@ -74,12 +51,10 @@ var testCases = []struct {
|
|||
}
|
||||
|
||||
func TestHash(t *testing.T) {
|
||||
for i, b := range backends {
|
||||
t.Run(b.Name+" digest", func(t *testing.T) {
|
||||
prepareArch(t, backends[i].arch)
|
||||
|
||||
fmt.Println("FEATURES:", cpu.X86.HasAVX, cpu.X86.HasAVX2)
|
||||
d := New()
|
||||
for i := range providers {
|
||||
p := providers[i]
|
||||
t.Run("test "+p.String()+" digest", func(t *testing.T) {
|
||||
d := NewWith(p)
|
||||
for _, tc := range testCases {
|
||||
d.Reset()
|
||||
_, _ = d.Write(tc.input)
|
||||
|
@ -90,20 +65,6 @@ func TestHash(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func prepareArch(t testing.TB, b arch) {
|
||||
realCPU := cpu.X86
|
||||
if !realCPU.HasAVX2 && b.HasAVX2 || !realCPU.HasAVX && b.HasAVX {
|
||||
t.Skip("Underlying CPU doesn't support necessary features")
|
||||
} else {
|
||||
t.Cleanup(func() {
|
||||
cpu.X86.HasAVX = realCPU.HasAVX
|
||||
cpu.X86.HasAVX2 = realCPU.HasAVX2
|
||||
})
|
||||
cpu.X86.HasAVX = b.HasAVX
|
||||
cpu.X86.HasAVX2 = b.HasAVX2
|
||||
}
|
||||
}
|
||||
|
||||
func newBuffer() (data []byte) {
|
||||
data = make([]byte, benchDataSize)
|
||||
|
||||
|
@ -117,20 +78,20 @@ func newBuffer() (data []byte) {
|
|||
|
||||
func BenchmarkSum(b *testing.B) {
|
||||
data := newBuffer()
|
||||
size := int64(len(data))
|
||||
|
||||
for i := range backends {
|
||||
b.Run(backends[i].Name+" digest", func(b *testing.B) {
|
||||
prepareArch(b, backends[i].arch)
|
||||
|
||||
for i := range providers {
|
||||
p := providers[i]
|
||||
b.Run("bench"+p.String()+"digest", func(b *testing.B) {
|
||||
b.ResetTimer()
|
||||
b.ReportAllocs()
|
||||
d := New()
|
||||
d := NewWith(p)
|
||||
for i := 0; i < b.N; i++ {
|
||||
d.Reset()
|
||||
_, _ = d.Write(data)
|
||||
d.Sum(nil)
|
||||
}
|
||||
b.SetBytes(int64(len(data)))
|
||||
b.SetBytes(size)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -140,7 +101,7 @@ func TestHomomorphism(t *testing.T) {
|
|||
c1, c2 sl2
|
||||
n int
|
||||
err error
|
||||
h, h1, h2 [Size]byte
|
||||
h, h1, h2 [hashSize]byte
|
||||
b []byte
|
||||
)
|
||||
|
||||
|
@ -151,7 +112,6 @@ func TestHomomorphism(t *testing.T) {
|
|||
|
||||
// Test if our hashing is really homomorphic
|
||||
h = Sum(b)
|
||||
require.NotEqual(t, [64]byte{}, h)
|
||||
h1 = Sum(b[:32])
|
||||
h2 = Sum(b[32:])
|
||||
|
||||
|
@ -161,7 +121,7 @@ func TestHomomorphism(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
|
||||
c1.Mul(&c1, &c2)
|
||||
require.Equal(t, h, c1.Bytes())
|
||||
require.Equal(t, h, c1.ByteArray())
|
||||
}
|
||||
|
||||
var testCasesConcat = []struct {
|
||||
|
|
92
tz/pure.go
Normal file
92
tz/pure.go
Normal file
|
@ -0,0 +1,92 @@
|
|||
package tz
|
||||
|
||||
import (
|
||||
"github.com/nspcc-dev/tzhash/gogf127"
|
||||
)
|
||||
|
||||
type digestp struct {
|
||||
x [4]gogf127.GF127
|
||||
}
|
||||
|
||||
// New returns a new hash.Hash computing the Tillich-Zémor checksum.
|
||||
func newPure() *digestp {
|
||||
d := new(digestp)
|
||||
d.Reset()
|
||||
return d
|
||||
}
|
||||
|
||||
func (d *digestp) Sum(in []byte) []byte {
|
||||
// Make a copy of d so that caller can keep writing and summing.
|
||||
d0 := *d
|
||||
h := d0.checkSum()
|
||||
return append(in, h[:]...)
|
||||
}
|
||||
|
||||
func (d *digestp) checkSum() [hashSize]byte {
|
||||
return d.byteArray()
|
||||
}
|
||||
|
||||
func (d *digestp) byteArray() (b [hashSize]byte) {
|
||||
for i := 0; i < 4; i++ {
|
||||
t := d.x[i].ByteArray()
|
||||
copy(b[i*16:], t[:])
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (d *digestp) Reset() {
|
||||
d.x[0] = gogf127.GF127{1, 0}
|
||||
d.x[1] = gogf127.GF127{0, 0}
|
||||
d.x[2] = gogf127.GF127{0, 0}
|
||||
d.x[3] = gogf127.GF127{1, 0}
|
||||
}
|
||||
|
||||
func (d *digestp) Write(data []byte) (n int, err error) {
|
||||
n = len(data)
|
||||
tmp := new(gogf127.GF127)
|
||||
for _, b := range data {
|
||||
mulBitRightPure(&d.x[0], &d.x[1], &d.x[2], &d.x[3], b&0x80 != 0, tmp)
|
||||
mulBitRightPure(&d.x[0], &d.x[1], &d.x[2], &d.x[3], b&0x40 != 0, tmp)
|
||||
mulBitRightPure(&d.x[0], &d.x[1], &d.x[2], &d.x[3], b&0x20 != 0, tmp)
|
||||
mulBitRightPure(&d.x[0], &d.x[1], &d.x[2], &d.x[3], b&0x10 != 0, tmp)
|
||||
mulBitRightPure(&d.x[0], &d.x[1], &d.x[2], &d.x[3], b&0x08 != 0, tmp)
|
||||
mulBitRightPure(&d.x[0], &d.x[1], &d.x[2], &d.x[3], b&0x04 != 0, tmp)
|
||||
mulBitRightPure(&d.x[0], &d.x[1], &d.x[2], &d.x[3], b&0x02 != 0, tmp)
|
||||
mulBitRightPure(&d.x[0], &d.x[1], &d.x[2], &d.x[3], b&0x01 != 0, tmp)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (d *digestp) Size() int {
|
||||
return hashSize
|
||||
}
|
||||
|
||||
func (d *digestp) BlockSize() int {
|
||||
return hashBlockSize
|
||||
}
|
||||
|
||||
func mulBitRightPure(c00, c01, c10, c11 *gogf127.GF127, bit bool, tmp *gogf127.GF127) {
|
||||
if bit {
|
||||
*tmp = *c00
|
||||
gogf127.Mul10(c00, c00)
|
||||
gogf127.Add(c00, c01, c00)
|
||||
gogf127.Mul11(tmp, tmp)
|
||||
gogf127.Add(c01, tmp, c01)
|
||||
|
||||
*tmp = *c10
|
||||
gogf127.Mul10(c10, c10)
|
||||
gogf127.Add(c10, c11, c10)
|
||||
gogf127.Mul11(tmp, tmp)
|
||||
gogf127.Add(c11, tmp, c11)
|
||||
} else {
|
||||
*tmp = *c00
|
||||
gogf127.Mul10(c00, c00)
|
||||
gogf127.Add(c00, c01, c00)
|
||||
*c01 = *tmp
|
||||
|
||||
*tmp = *c10
|
||||
gogf127.Mul10(c10, c10)
|
||||
gogf127.Add(c10, c11, c10)
|
||||
*c11 = *tmp
|
||||
}
|
||||
}
|
104
tz/sl2.go
104
tz/sl2.go
|
@ -3,27 +3,32 @@ package tz
|
|||
import (
|
||||
"errors"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/tzhash/gf127"
|
||||
"github.com/nspcc-dev/tzhash/gf127"
|
||||
"github.com/nspcc-dev/tzhash/gogf127"
|
||||
)
|
||||
|
||||
type (
|
||||
GF127 = gf127.GF127
|
||||
|
||||
sl2 [2][2]GF127
|
||||
)
|
||||
type sl2 [2][2]gf127.GF127
|
||||
|
||||
var id = sl2{
|
||||
{GF127{1, 0}, GF127{0, 0}},
|
||||
{GF127{0, 0}, GF127{1, 0}},
|
||||
{gf127.GF127{1, 0}, gf127.GF127{0, 0}},
|
||||
{gf127.GF127{0, 0}, gf127.GF127{1, 0}},
|
||||
}
|
||||
|
||||
var mul func(a, b, c *sl2, x *[4]gf127.GF127)
|
||||
|
||||
func init() {
|
||||
if hasAVX {
|
||||
mul = mulSL2AVX
|
||||
} else {
|
||||
mul = mulSL2Pure
|
||||
}
|
||||
}
|
||||
|
||||
// MarshalBinary implements encoding.BinaryMarshaler.
|
||||
func (c *sl2) MarshalBinary() (data []byte, err error) {
|
||||
s := c.Bytes()
|
||||
s := c.ByteArray()
|
||||
return s[:], nil
|
||||
}
|
||||
|
||||
// UnmarshalBinary implements encoding.BinaryUnmarshaler.
|
||||
func (c *sl2) UnmarshalBinary(data []byte) (err error) {
|
||||
if len(data) != 64 {
|
||||
return errors.New("data must be 64-bytes long")
|
||||
|
@ -45,7 +50,7 @@ func (c *sl2) UnmarshalBinary(data []byte) (err error) {
|
|||
return
|
||||
}
|
||||
|
||||
func (c *sl2) mulStrassen(a, b *sl2, x *[8]GF127) *sl2 { //nolint:unused
|
||||
func (c *sl2) mulStrassen(a, b *sl2, x *[8]gf127.GF127) *sl2 {
|
||||
// strassen algorithm
|
||||
gf127.Add(&a[0][0], &a[1][1], &x[0])
|
||||
gf127.Add(&b[0][0], &b[1][1], &x[1])
|
||||
|
@ -85,8 +90,40 @@ func (c *sl2) mulStrassen(a, b *sl2, x *[8]GF127) *sl2 { //nolint:unused
|
|||
return c
|
||||
}
|
||||
|
||||
func mulSL2AVX(a, b, c *sl2, x *[4]gf127.GF127) {
|
||||
gf127.Mul(&a[0][0], &b[0][0], &x[0])
|
||||
gf127.Mul(&a[0][0], &b[0][1], &x[1])
|
||||
gf127.Mul(&a[1][0], &b[0][0], &x[2])
|
||||
gf127.Mul(&a[1][0], &b[0][1], &x[3])
|
||||
|
||||
gf127.Mul(&a[0][1], &b[1][0], &c[0][0])
|
||||
gf127.Add(&c[0][0], &x[0], &c[0][0])
|
||||
gf127.Mul(&a[0][1], &b[1][1], &c[0][1])
|
||||
gf127.Add(&c[0][1], &x[1], &c[0][1])
|
||||
gf127.Mul(&a[1][1], &b[1][0], &c[1][0])
|
||||
gf127.Add(&c[1][0], &x[2], &c[1][0])
|
||||
gf127.Mul(&a[1][1], &b[1][1], &c[1][1])
|
||||
gf127.Add(&c[1][1], &x[3], &c[1][1])
|
||||
}
|
||||
|
||||
func mulSL2Pure(a, b, c *sl2, x *[4]gf127.GF127) {
|
||||
gogf127.Mul((*gogf127.GF127)(&a[0][0]), (*gogf127.GF127)(&b[0][0]), (*gogf127.GF127)(&x[0]))
|
||||
gogf127.Mul((*gogf127.GF127)(&a[0][0]), (*gogf127.GF127)(&b[0][1]), (*gogf127.GF127)(&x[1]))
|
||||
gogf127.Mul((*gogf127.GF127)(&a[1][0]), (*gogf127.GF127)(&b[0][0]), (*gogf127.GF127)(&x[2]))
|
||||
gogf127.Mul((*gogf127.GF127)(&a[1][0]), (*gogf127.GF127)(&b[0][1]), (*gogf127.GF127)(&x[3]))
|
||||
|
||||
gogf127.Mul((*gogf127.GF127)(&a[0][1]), (*gogf127.GF127)(&b[1][0]), (*gogf127.GF127)(&c[0][0]))
|
||||
gogf127.Add((*gogf127.GF127)(&c[0][0]), (*gogf127.GF127)(&x[0]), (*gogf127.GF127)(&c[0][0]))
|
||||
gogf127.Mul((*gogf127.GF127)(&a[0][1]), (*gogf127.GF127)(&b[1][1]), (*gogf127.GF127)(&c[0][1]))
|
||||
gogf127.Add((*gogf127.GF127)(&c[0][1]), (*gogf127.GF127)(&x[1]), (*gogf127.GF127)(&c[0][1]))
|
||||
gogf127.Mul((*gogf127.GF127)(&a[1][1]), (*gogf127.GF127)(&b[1][0]), (*gogf127.GF127)(&c[1][0]))
|
||||
gogf127.Add((*gogf127.GF127)(&c[1][0]), (*gogf127.GF127)(&x[2]), (*gogf127.GF127)(&c[1][0]))
|
||||
gogf127.Mul((*gogf127.GF127)(&a[1][1]), (*gogf127.GF127)(&b[1][1]), (*gogf127.GF127)(&c[1][1]))
|
||||
gogf127.Add((*gogf127.GF127)(&c[1][1]), (*gogf127.GF127)(&x[3]), (*gogf127.GF127)(&c[1][1]))
|
||||
}
|
||||
|
||||
func (c *sl2) MulA() *sl2 {
|
||||
var a GF127
|
||||
var a gf127.GF127
|
||||
|
||||
gf127.Mul10(&c[0][0], &a)
|
||||
gf127.Mul1(&c[0][0], &c[0][1])
|
||||
|
@ -100,7 +137,7 @@ func (c *sl2) MulA() *sl2 {
|
|||
}
|
||||
|
||||
func (c *sl2) MulB() *sl2 {
|
||||
var a GF127
|
||||
var a gf127.GF127
|
||||
|
||||
gf127.Mul1(&c[0][0], &a)
|
||||
gf127.Mul10(&c[0][0], &c[0][0])
|
||||
|
@ -115,34 +152,19 @@ func (c *sl2) MulB() *sl2 {
|
|||
return c
|
||||
}
|
||||
|
||||
// Mul returns a * b in GL_2(GF(2^127))
|
||||
func (c *sl2) Mul(a, b *sl2) *sl2 {
|
||||
var x [4]GF127
|
||||
|
||||
gf127.Mul(&a[0][0], &b[0][0], &x[0])
|
||||
gf127.Mul(&a[0][0], &b[0][1], &x[1])
|
||||
gf127.Mul(&a[1][0], &b[0][0], &x[2])
|
||||
gf127.Mul(&a[1][0], &b[0][1], &x[3])
|
||||
|
||||
gf127.Mul(&a[0][1], &b[1][0], &c[0][0])
|
||||
gf127.Add(&c[0][0], &x[0], &c[0][0])
|
||||
gf127.Mul(&a[0][1], &b[1][1], &c[0][1])
|
||||
gf127.Add(&c[0][1], &x[1], &c[0][1])
|
||||
gf127.Mul(&a[1][1], &b[1][0], &c[1][0])
|
||||
gf127.Add(&c[1][0], &x[2], &c[1][0])
|
||||
gf127.Mul(&a[1][1], &b[1][1], &c[1][1])
|
||||
gf127.Add(&c[1][1], &x[3], &c[1][1])
|
||||
mul(a, b, c, new([4]gf127.GF127))
|
||||
return c
|
||||
}
|
||||
|
||||
// Inv returns inverse of a in GL_2(GF(2^127))
|
||||
func Inv(a *sl2) (b *sl2) {
|
||||
b = new(sl2)
|
||||
inv(a, b, new([2]GF127))
|
||||
inv(a, b, new([2]gf127.GF127))
|
||||
return
|
||||
}
|
||||
|
||||
func inv(a, b *sl2, t *[2]GF127) {
|
||||
func inv(a, b *sl2, t *[2]gf127.GF127) {
|
||||
gf127.Mul(&a[0][0], &a[1][1], &t[0])
|
||||
gf127.Mul(&a[0][1], &a[1][0], &t[1])
|
||||
gf127.Add(&t[0], &t[1], &t[0])
|
||||
|
@ -159,18 +181,18 @@ func (c *sl2) String() string {
|
|||
c[1][0].String() + c[1][1].String()
|
||||
}
|
||||
|
||||
func (c *sl2) Bytes() (b [Size]byte) {
|
||||
t := c[0][0].Bytes()
|
||||
copy(b[:], t[:])
|
||||
func (c *sl2) ByteArray() (b [hashSize]byte) {
|
||||
t := c[0][0].ByteArray()
|
||||
copy(b[:], t)
|
||||
|
||||
t = c[0][1].Bytes()
|
||||
copy(b[16:], t[:])
|
||||
t = c[0][1].ByteArray()
|
||||
copy(b[16:], t)
|
||||
|
||||
t = c[1][0].Bytes()
|
||||
copy(b[32:], t[:])
|
||||
t = c[1][0].ByteArray()
|
||||
copy(b[32:], t)
|
||||
|
||||
t = c[1][1].Bytes()
|
||||
copy(b[48:], t[:])
|
||||
t = c[1][1].ByteArray()
|
||||
copy(b[48:], t)
|
||||
|
||||
return
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/tzhash/gf127"
|
||||
"github.com/nspcc-dev/tzhash/gf127"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
|
|
Loading…
Reference in a new issue