@@ -0,0 +1,66 @@ | |||
Looks some GO compiler bug. Please see below for more details to validate and confirm about bug. | |||
A bug which occurs only in plugins with assembly code. | |||
The package consists of a bn256 crypto implementation which has amd64 assembly code and also a generic implementation. | |||
The assembly implementation is default and generic implementation can be enabled using the "generic" tag. | |||
The plugin when compiled as a binary runs OK with both assembly and go implementation. | |||
The plugin when compiled as a plugin FAILS with assembly code but runs OK with generic implementation. | |||
As far as my understanding goes, everything should be running okay. | |||
Please see attached source code and test on x86_64 linux system. | |||
go version : 1.15.7 ( however go version 1.14 and 1.16beta1 also show same error behaviour) | |||
OS: linux x86_64 | |||
My initial guess is some sort of corruption ( or wrong code generation) by the go compiler/assembler. | |||
TESTING: | |||
--------- | |||
Run plugin directly to see correct result. | |||
go run plugin/plugin.go | |||
Compile as plugin. | |||
go build -buildmode=plugin -o /tmp/plugin.so ../compiler_bug/plugin/ | |||
Running plugin will trigger error | |||
go run runplugin/main.go | |||
However, if the plugin is compiled with generic tag (To disable asm code, the bug doesn't occur), Some register corruption occurs due to wrong code being generated. | |||
go build -buildmode=plugin -tags generic -o /tmp/plugin.so ../compiler_bug/plugin/ | |||
Running plugin will not cause an error. | |||
go run runplugin/main.go | |||
Maybe to detect such case, test cases can also be run in plugin mode to detect such cases. | |||
This can be done by adding another argument to go test for plugin mode testing. | |||
Actual behaviour: | |||
----------------- | |||
./demo.sh | |||
Actual a01f9bcc1208dee302769931ad378a4c0c4b2c21b0cfb3e752607e12d2b6fa6425 | |||
Expected a01f9bcc1208dee302769931ad378a4c0c4b2c21b0cfb3e752607e12d2b6fa6425 | |||
running plugin | |||
panic: Decode point err bn256: malformed point err | |||
goroutine 1 [running]: | |||
_/tmp/compiler_bug/plugin.Export() | |||
/tmp/compiler_bug/plugin/plugin.go:23 +0x2d7 | |||
main.main() | |||
/tmp/compiler_bug/runplugin/main.go:24 +0x107 | |||
exit status 2 | |||
----------------------------- | |||
Expected behaviour: | |||
------------------- | |||
./demo.sh | |||
Actual a01f9bcc1208dee302769931ad378a4c0c4b2c21b0cfb3e752607e12d2b6fa6425 | |||
Expected a01f9bcc1208dee302769931ad378a4c0c4b2c21b0cfb3e752607e12d2b6fa6425 | |||
running plugin | |||
Actual a01f9bcc1208dee302769931ad378a4c0c4b2c21b0cfb3e752607e12d2b6fa6425 | |||
Expected a01f9bcc1208dee302769931ad378a4c0c4b2c21b0cfb3e752607e12d2b6fa6425 | |||
--------------------------- |
@@ -0,0 +1,20 @@ | |||
#!/bin/bash | |||
unset GOPATH | |||
#run plugin directly to see correct result | |||
go run plugin/plugin.go | |||
#compile as plugin | |||
go build -buildmode=plugin -o /tmp/plugin.so ../compiler_bug/plugin/ | |||
#running plugin will trigger error | |||
go run runplugin/main.go | |||
#However, if the plugin is compiled with generic tag (To disable asm code, the bug doesn't occur), Some register corruption occurs due to wrong code being generated. | |||
#go build -buildmode=plugin -tags generic -o /tmp/plugin.so ../compiler_bug/plugin/ | |||
#running plugin will not cause an error | |||
#go run runplugin/main.go | |||
@@ -0,0 +1,47 @@ | |||
# Contributor Covenant Code of Conduct | |||
## Our Pledge | |||
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. | |||
## Our Standards | |||
Examples of behavior that contributes to creating a positive environment include: | |||
* Using welcoming and inclusive language | |||
* Being respectful of differing viewpoints and experiences | |||
* Gracefully accepting constructive criticism | |||
* Focusing on what is best for the community | |||
* Showing empathy towards other community members | |||
Examples of unacceptable behavior by participants include: | |||
* The use of sexualized language or imagery and unwelcome sexual attention or advances | |||
* Trolling, insulting/derogatory comments, and personal or political attacks | |||
* Public or private harassment | |||
* Publishing others' private information, such as a physical or electronic address, without explicit permission | |||
* Other conduct which could reasonably be considered inappropriate in a professional setting | |||
## Our Responsibilities | |||
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. | |||
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. | |||
## Scope | |||
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. | |||
## Enforcement | |||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at [opensource@clearmatics.com][email]. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. | |||
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. | |||
## Attribution | |||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] | |||
[email]: mailto:opensource@clearmatics.com | |||
[homepage]: http://contributor-covenant.org | |||
[version]: http://contributor-covenant.org/version/1/4/ |
@@ -0,0 +1,27 @@ | |||
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. |
@@ -0,0 +1,34 @@ | |||
SHELL = bash | |||
GO_FILES = $(shell find . -name "*.go" | grep -vE ".git") | |||
GO_COVER_FILE = `find . -name "coverage.out"` | |||
.PHONY: all test format cover-clean check fmt vet lint | |||
test: $(GO_FILES) | |||
go test ./... | |||
format: | |||
gofmt -s -w ${GO_FILES} | |||
cover: $(GO_FILES) | |||
go test -coverprofile=coverage.out ./... | |||
go tool cover -html=coverage.out | |||
cover-clean: | |||
rm -f $(GO_COVER_FILE) | |||
deps: | |||
go mod download | |||
check: | |||
if [ -n "$(shell gofmt -l ${GO_FILES})" ]; then \ | |||
echo 1>&2 'The following files need to be formatted:'; \ | |||
gofmt -l .; \ | |||
exit 1; \ | |||
fi | |||
vet: | |||
go vet $(GO_FILES) | |||
lint: | |||
golint $(GO_FILES) |
@@ -0,0 +1,33 @@ | |||
# BN256 | |||
[](https://travis-ci.org/clearmatics/bn256) | |||
This package implements a [particular](https://eprint.iacr.org/2013/507.pdf) bilinear group. | |||
The code is imported from https://github.com/ethereum/go-ethereum/tree/master/crypto/bn256/cloudflare | |||
:rotating_light: **WARNING** This package originally claimed to operate at a 128-bit level. However, [recent work](https://ellipticnews.wordpress.com/2016/05/02/kim-barbulescu-variant-of-the-number-field-sieve-to-compute-discrete-logarithms-in-finite-fields/) suggest that **this is no longer the case**. | |||
## A note on the selection of the bilinear group | |||
The parameters defined in the `constants.go` file follow the parameters used in [alt-bn128 (libff)](https://github.com/scipr-lab/libff/blob/master/libff/algebra/curves/alt_bn128/alt_bn128_init.cpp). These parameters were selected so that `r−1` has a high 2-adic order. This is key to improve efficiency of the key and proof generation algorithms of the SNARK used. | |||
## Installation | |||
go get github.com/clearmatics/bn256 | |||
## Development | |||
This project uses [go modules](https://github.com/golang/go/wiki/Modules). | |||
If you develop in your `GOPATH` and use GO 1.11, make sure to run: | |||
```bash | |||
export GO111MODULE=on | |||
``` | |||
In fact: | |||
> (Inside $GOPATH/src, for compatibility, the go command still runs in the old GOPATH mode, even if a go.mod is found.) | |||
See: https://blog.golang.org/using-go-modules | |||
> For more fine-grained control, the module support in Go 1.11 respects a temporary environment variable, GO111MODULE, which can be set to one of three string values: off, on, or auto (the default). If GO111MODULE=off, then the go command never uses the new module support. Instead it looks in vendor directories and GOPATH to find dependencies; we now refer to this as "GOPATH mode." If GO111MODULE=on, then the go command requires the use of modules, never consulting GOPATH. We refer to this as the command being module-aware or running in "module-aware mode". If GO111MODULE=auto or is unset, then the go command enables or disables module support based on the current directory. Module support is enabled only when the current directory is outside GOPATH/src and itself contains a go.mod file or is below a directory containing a go.mod file. | |||
See: https://golang.org/cmd/go/#hdr-Preliminary_module_support | |||
The project follows standard Go conventions using `gofmt`. If you wish to contribute to the project please follow standard Go conventions. The CI server automatically runs these checks. |
@@ -0,0 +1,490 @@ | |||
// Package bn256 implements a particular bilinear group at the 128-bit security | |||
// level. | |||
// | |||
// Bilinear groups are the basis of many of the new cryptographic protocols that | |||
// have been proposed over the past decade. They consist of a triplet of groups | |||
// (G₁, G₂ and GT) such that there exists a function e(g₁ˣ,g₂ʸ)=gTˣʸ (where gₓ | |||
// is a generator of the respective group). That function is called a pairing | |||
// function. | |||
// | |||
// This package specifically implements the Optimal Ate pairing over a 256-bit | |||
// Barreto-Naehrig curve as described in | |||
// http://cryptojedi.org/papers/dclxvi-20100714.pdf. Its output is compatible | |||
// with the implementation described in that paper. | |||
package bn256 | |||
import ( | |||
"crypto/rand" | |||
"errors" | |||
"io" | |||
"math/big" | |||
) | |||
func randomK(r io.Reader) (k *big.Int, err error) { | |||
for { | |||
k, err = rand.Int(r, Order) | |||
if k.Sign() > 0 || err != nil { | |||
return | |||
} | |||
} | |||
} | |||
// G1 is an abstract cyclic group. The zero value is suitable for use as the | |||
// output of an operation, but cannot be used as an input. | |||
type G1 struct { | |||
p *curvePoint | |||
} | |||
// RandomG1 returns x and g₁ˣ where x is a random, non-zero number read from r. | |||
func RandomG1(r io.Reader) (*big.Int, *G1, error) { | |||
k, err := randomK(r) | |||
if err != nil { | |||
return nil, nil, err | |||
} | |||
return k, new(G1).ScalarBaseMult(k), nil | |||
} | |||
func (e *G1) String() string { | |||
return "bn256.G1" + e.p.String() | |||
} | |||
// ScalarBaseMult sets e to g*k where g is the generator of the group and then | |||
// returns e. | |||
func (e *G1) ScalarBaseMult(k *big.Int) *G1 { | |||
if e.p == nil { | |||
e.p = &curvePoint{} | |||
} | |||
e.p.Mul(curveGen, k) | |||
return e | |||
} | |||
// ScalarMult sets e to a*k and then returns e. | |||
func (e *G1) ScalarMult(a *G1, k *big.Int) *G1 { | |||
if e.p == nil { | |||
e.p = &curvePoint{} | |||
} | |||
e.p.Mul(a.p, k) | |||
return e | |||
} | |||
// Add sets e to a+b and then returns e. | |||
func (e *G1) Add(a, b *G1) *G1 { | |||
if e.p == nil { | |||
e.p = &curvePoint{} | |||
} | |||
e.p.Add(a.p, b.p) | |||
return e | |||
} | |||
// Neg sets e to -a and then returns e. | |||
func (e *G1) Neg(a *G1) *G1 { | |||
if e.p == nil { | |||
e.p = &curvePoint{} | |||
} | |||
e.p.Neg(a.p) | |||
return e | |||
} | |||
// Set sets e to a and then returns e. | |||
func (e *G1) Set(a *G1) *G1 { | |||
if e.p == nil { | |||
e.p = &curvePoint{} | |||
} | |||
e.p.Set(a.p) | |||
return e | |||
} | |||
// Marshal converts e to a byte slice. | |||
func (e *G1) Marshal() []byte { | |||
// Each value is a 256-bit number. | |||
const numBytes = 256 / 8 | |||
if e.p == nil { | |||
e.p = &curvePoint{} | |||
} | |||
e.p.MakeAffine() | |||
ret := make([]byte, numBytes*2) | |||
if e.p.IsInfinity() { | |||
return ret | |||
} | |||
temp := &gfP{} | |||
montDecode(temp, &e.p.x) | |||
temp.Marshal(ret) | |||
montDecode(temp, &e.p.y) | |||
temp.Marshal(ret[numBytes:]) | |||
return ret | |||
} | |||
// Unmarshal sets e to the result of converting the output of Marshal back into | |||
// a group element and then returns e. | |||
func (e *G1) Unmarshal(m []byte) ([]byte, error) { | |||
// Each value is a 256-bit number. | |||
const numBytes = 256 / 8 | |||
if len(m) < 2*numBytes { | |||
return nil, errors.New("bn256: not enough data") | |||
} | |||
// Unmarshal the points and check their caps | |||
if e.p == nil { | |||
e.p = &curvePoint{} | |||
} else { | |||
e.p.x, e.p.y = gfP{0}, gfP{0} | |||
} | |||
var err error | |||
if err = e.p.x.Unmarshal(m); err != nil { | |||
return nil, err | |||
} | |||
if err = e.p.y.Unmarshal(m[numBytes:]); err != nil { | |||
return nil, err | |||
} | |||
// Encode into Montgomery form and ensure it's on the curve | |||
montEncode(&e.p.x, &e.p.x) | |||
montEncode(&e.p.y, &e.p.y) | |||
zero := gfP{0} | |||
if e.p.x == zero && e.p.y == zero { | |||
// This is the point at infinity. | |||
e.p.y = *newGFp(1) | |||
e.p.z = gfP{0} | |||
e.p.t = gfP{0} | |||
} else { | |||
e.p.z = *newGFp(1) | |||
e.p.t = *newGFp(1) | |||
if !e.p.IsOnCurve() { | |||
return nil, errors.New("bn256: malformed point") | |||
} | |||
} | |||
return m[2*numBytes:], nil | |||
} | |||
// G2 is an abstract cyclic group. The zero value is suitable for use as the | |||
// output of an operation, but cannot be used as an input. | |||
type G2 struct { | |||
p *twistPoint | |||
} | |||
// RandomG2 returns x and g₂ˣ where x is a random, non-zero number read from r. | |||
func RandomG2(r io.Reader) (*big.Int, *G2, error) { | |||
k, err := randomK(r) | |||
if err != nil { | |||
return nil, nil, err | |||
} | |||
return k, new(G2).ScalarBaseMult(k), nil | |||
} | |||
func (e *G2) String() string { | |||
return "bn256.G2" + e.p.String() | |||
} | |||
// ScalarBaseMult sets e to g*k where g is the generator of the group and then | |||
// returns out. | |||
func (e *G2) ScalarBaseMult(k *big.Int) *G2 { | |||
if e.p == nil { | |||
e.p = &twistPoint{} | |||
} | |||
e.p.Mul(twistGen, k) | |||
return e | |||
} | |||
// ScalarMult sets e to a*k and then returns e. | |||
func (e *G2) ScalarMult(a *G2, k *big.Int) *G2 { | |||
if e.p == nil { | |||
e.p = &twistPoint{} | |||
} | |||
e.p.Mul(a.p, k) | |||
return e | |||
} | |||
// Add sets e to a+b and then returns e. | |||
func (e *G2) Add(a, b *G2) *G2 { | |||
if e.p == nil { | |||
e.p = &twistPoint{} | |||
} | |||
e.p.Add(a.p, b.p) | |||
return e | |||
} | |||
// Neg sets e to -a and then returns e. | |||
func (e *G2) Neg(a *G2) *G2 { | |||
if e.p == nil { | |||
e.p = &twistPoint{} | |||
} | |||
e.p.Neg(a.p) | |||
return e | |||
} | |||
// Set sets e to a and then returns e. | |||
func (e *G2) Set(a *G2) *G2 { | |||
if e.p == nil { | |||
e.p = &twistPoint{} | |||
} | |||
e.p.Set(a.p) | |||
return e | |||
} | |||
// Marshal converts e into a byte slice. | |||
func (e *G2) Marshal() []byte { | |||
// Each value is a 256-bit number. | |||
const numBytes = 256 / 8 | |||
if e.p == nil { | |||
e.p = &twistPoint{} | |||
} | |||
e.p.MakeAffine() | |||
ret := make([]byte, numBytes*4) | |||
if e.p.IsInfinity() { | |||
return ret | |||
} | |||
temp := &gfP{} | |||
montDecode(temp, &e.p.x.x) | |||
temp.Marshal(ret) | |||
montDecode(temp, &e.p.x.y) | |||
temp.Marshal(ret[numBytes:]) | |||
montDecode(temp, &e.p.y.x) | |||
temp.Marshal(ret[2*numBytes:]) | |||
montDecode(temp, &e.p.y.y) | |||
temp.Marshal(ret[3*numBytes:]) | |||
return ret | |||
} | |||
// Unmarshal sets e to the result of converting the output of Marshal back into | |||
// a group element and then returns e. | |||
func (e *G2) Unmarshal(m []byte) ([]byte, error) { | |||
// Each value is a 256-bit number. | |||
const numBytes = 256 / 8 | |||
if len(m) < 4*numBytes { | |||
return nil, errors.New("bn256: not enough data") | |||
} | |||
// Unmarshal the points and check their caps | |||
if e.p == nil { | |||
e.p = &twistPoint{} | |||
} | |||
var err error | |||
if err = e.p.x.x.Unmarshal(m); err != nil { | |||
return nil, err | |||
} | |||
if err = e.p.x.y.Unmarshal(m[numBytes:]); err != nil { | |||
return nil, err | |||
} | |||
if err = e.p.y.x.Unmarshal(m[2*numBytes:]); err != nil { | |||
return nil, err | |||
} | |||
if err = e.p.y.y.Unmarshal(m[3*numBytes:]); err != nil { | |||
return nil, err | |||
} | |||
// Encode into Montgomery form and ensure it's on the curve | |||
montEncode(&e.p.x.x, &e.p.x.x) | |||
montEncode(&e.p.x.y, &e.p.x.y) | |||
montEncode(&e.p.y.x, &e.p.y.x) | |||
montEncode(&e.p.y.y, &e.p.y.y) | |||
if e.p.x.IsZero() && e.p.y.IsZero() { | |||
// This is the point at infinity. | |||
e.p.y.SetOne() | |||
e.p.z.SetZero() | |||
e.p.t.SetZero() | |||
} else { | |||
e.p.z.SetOne() | |||
e.p.t.SetOne() | |||
if !e.p.IsOnCurve() { | |||
return nil, errors.New("bn256: malformed point") | |||
} | |||
} | |||
return m[4*numBytes:], nil | |||
} | |||
// GT is an abstract cyclic group. The zero value is suitable for use as the | |||
// output of an operation, but cannot be used as an input. | |||
type GT struct { | |||
p *gfP12 | |||
} | |||
// Pair calculates an Optimal Ate pairing. | |||
func Pair(g1 *G1, g2 *G2) *GT { | |||
return >{optimalAte(g2.p, g1.p)} | |||
} | |||
// PairingCheck calculates the Optimal Ate pairing for a set of points. | |||
func PairingCheck(a []*G1, b []*G2) bool { | |||
acc := new(gfP12) | |||
acc.SetOne() | |||
for i := 0; i < len(a); i++ { | |||
if a[i].p.IsInfinity() || b[i].p.IsInfinity() { | |||
continue | |||
} | |||
acc.Mul(acc, miller(b[i].p, a[i].p)) | |||
} | |||
return finalExponentiation(acc).IsOne() | |||
} | |||
// Miller applies Miller's algorithm, which is a bilinear function from the | |||
// source groups to F_p^12. Miller(g1, g2).Finalize() is equivalent to Pair(g1, | |||
// g2). | |||
func Miller(g1 *G1, g2 *G2) *GT { | |||
return >{miller(g2.p, g1.p)} | |||
} | |||
func (e *GT) String() string { | |||
return "bn256.GT" + e.p.String() | |||
} | |||
// ScalarMult sets e to a*k and then returns e. | |||
func (e *GT) ScalarMult(a *GT, k *big.Int) *GT { | |||
if e.p == nil { | |||
e.p = &gfP12{} | |||
} | |||
e.p.Exp(a.p, k) | |||
return e | |||
} | |||
// Add sets e to a+b and then returns e. | |||
func (e *GT) Add(a, b *GT) *GT { | |||
if e.p == nil { | |||
e.p = &gfP12{} | |||
} | |||
e.p.Mul(a.p, b.p) | |||
return e | |||
} | |||
// Neg sets e to -a and then returns e. | |||
func (e *GT) Neg(a *GT) *GT { | |||
if e.p == nil { | |||
e.p = &gfP12{} | |||
} | |||
e.p.Conjugate(a.p) | |||
return e | |||
} | |||
// Set sets e to a and then returns e. | |||
func (e *GT) Set(a *GT) *GT { | |||
if e.p == nil { | |||
e.p = &gfP12{} | |||
} | |||
e.p.Set(a.p) | |||
return e | |||
} | |||
// Finalize is a linear function from F_p^12 to GT. | |||
func (e *GT) Finalize() *GT { | |||
ret := finalExponentiation(e.p) | |||
e.p.Set(ret) | |||
return e | |||
} | |||
// Marshal converts e into a byte slice. | |||
func (e *GT) Marshal() []byte { | |||
// Each value is a 256-bit number. | |||
const numBytes = 256 / 8 | |||
if e.p == nil { | |||
e.p = &gfP12{} | |||
e.p.SetOne() | |||
} | |||
ret := make([]byte, numBytes*12) | |||
temp := &gfP{} | |||
montDecode(temp, &e.p.x.x.x) | |||
temp.Marshal(ret) | |||
montDecode(temp, &e.p.x.x.y) | |||
temp.Marshal(ret[numBytes:]) | |||
montDecode(temp, &e.p.x.y.x) | |||
temp.Marshal(ret[2*numBytes:]) | |||
montDecode(temp, &e.p.x.y.y) | |||
temp.Marshal(ret[3*numBytes:]) | |||
montDecode(temp, &e.p.x.z.x) | |||
temp.Marshal(ret[4*numBytes:]) | |||
montDecode(temp, &e.p.x.z.y) | |||
temp.Marshal(ret[5*numBytes:]) | |||
montDecode(temp, &e.p.y.x.x) | |||
temp.Marshal(ret[6*numBytes:]) | |||
montDecode(temp, &e.p.y.x.y) | |||
temp.Marshal(ret[7*numBytes:]) | |||
montDecode(temp, &e.p.y.y.x) | |||
temp.Marshal(ret[8*numBytes:]) | |||
montDecode(temp, &e.p.y.y.y) | |||
temp.Marshal(ret[9*numBytes:]) | |||
montDecode(temp, &e.p.y.z.x) | |||
temp.Marshal(ret[10*numBytes:]) | |||
montDecode(temp, &e.p.y.z.y) | |||
temp.Marshal(ret[11*numBytes:]) | |||
return ret | |||
} | |||
// Unmarshal sets e to the result of converting the output of Marshal back into | |||
// a group element and then returns e. | |||
func (e *GT) Unmarshal(m []byte) ([]byte, error) { | |||
// Each value is a 256-bit number. | |||
const numBytes = 256 / 8 | |||
if len(m) < 12*numBytes { | |||
return nil, errors.New("bn256: not enough data") | |||
} | |||
if e.p == nil { | |||
e.p = &gfP12{} | |||
} | |||
var err error | |||
if err = e.p.x.x.x.Unmarshal(m); err != nil { | |||
return nil, err | |||
} | |||
if err = e.p.x.x.y.Unmarshal(m[numBytes:]); err != nil { | |||
return nil, err | |||
} | |||
if err = e.p.x.y.x.Unmarshal(m[2*numBytes:]); err != nil { | |||
return nil, err | |||
} | |||
if err = e.p.x.y.y.Unmarshal(m[3*numBytes:]); err != nil { | |||
return nil, err | |||
} | |||
if err = e.p.x.z.x.Unmarshal(m[4*numBytes:]); err != nil { | |||
return nil, err | |||
} | |||
if err = e.p.x.z.y.Unmarshal(m[5*numBytes:]); err != nil { | |||
return nil, err | |||
} | |||
if err = e.p.y.x.x.Unmarshal(m[6*numBytes:]); err != nil { | |||
return nil, err | |||
} | |||
if err = e.p.y.x.y.Unmarshal(m[7*numBytes:]); err != nil { | |||
return nil, err | |||
} | |||
if err = e.p.y.y.x.Unmarshal(m[8*numBytes:]); err != nil { | |||
return nil, err | |||
} | |||
if err = e.p.y.y.y.Unmarshal(m[9*numBytes:]); err != nil { | |||
return nil, err | |||
} | |||
if err = e.p.y.z.x.Unmarshal(m[10*numBytes:]); err != nil { | |||
return nil, err | |||
} | |||
if err = e.p.y.z.y.Unmarshal(m[11*numBytes:]); err != nil { | |||
return nil, err | |||
} | |||
montEncode(&e.p.x.x.x, &e.p.x.x.x) | |||
montEncode(&e.p.x.x.y, &e.p.x.x.y) | |||
montEncode(&e.p.x.y.x, &e.p.x.y.x) | |||
montEncode(&e.p.x.y.y, &e.p.x.y.y) | |||
montEncode(&e.p.x.z.x, &e.p.x.z.x) | |||
montEncode(&e.p.x.z.y, &e.p.x.z.y) | |||
montEncode(&e.p.y.x.x, &e.p.y.x.x) | |||
montEncode(&e.p.y.x.y, &e.p.y.x.y) | |||
montEncode(&e.p.y.y.x, &e.p.y.y.x) | |||
montEncode(&e.p.y.y.y, &e.p.y.y.y) | |||
montEncode(&e.p.y.z.x, &e.p.y.z.x) | |||
montEncode(&e.p.y.z.y, &e.p.y.z.y) | |||
return m[12*numBytes:], nil | |||
} |
@@ -0,0 +1,116 @@ | |||
package bn256 | |||
import ( | |||
"bytes" | |||
"crypto/rand" | |||
"testing" | |||
) | |||
func TestG1Marshal(t *testing.T) { | |||
_, Ga, err := RandomG1(rand.Reader) | |||
if err != nil { | |||
t.Fatal(err) | |||
} | |||
ma := Ga.Marshal() | |||
Gb := new(G1) | |||
_, err = Gb.Unmarshal(ma) | |||
if err != nil { | |||
t.Fatal(err) | |||
} | |||
mb := Gb.Marshal() | |||
if !bytes.Equal(ma, mb) { | |||
t.Fatal("bytes are different") | |||
} | |||
} | |||
func TestG2Marshal(t *testing.T) { | |||
_, Ga, err := RandomG2(rand.Reader) | |||
if err != nil { | |||
t.Fatal(err) | |||
} | |||
ma := Ga.Marshal() | |||
Gb := new(G2) | |||
_, err = Gb.Unmarshal(ma) | |||
if err != nil { | |||
t.Fatal(err) | |||
} | |||
mb := Gb.Marshal() | |||
if !bytes.Equal(ma, mb) { | |||
t.Fatal("bytes are different") | |||
} | |||
} | |||
func TestBilinearity(t *testing.T) { | |||
for i := 0; i < 2; i++ { | |||
a, p1, _ := RandomG1(rand.Reader) | |||
b, p2, _ := RandomG2(rand.Reader) | |||
e1 := Pair(p1, p2) | |||
e2 := Pair(&G1{curveGen}, &G2{twistGen}) | |||
e2.ScalarMult(e2, a) | |||
e2.ScalarMult(e2, b) | |||
if *e1.p != *e2.p { | |||
t.Fatalf("bad pairing result: %s", e1) | |||
} | |||
} | |||
} | |||
func TestTripartiteDiffieHellman(t *testing.T) { | |||
a, _ := rand.Int(rand.Reader, Order) | |||
b, _ := rand.Int(rand.Reader, Order) | |||
c, _ := rand.Int(rand.Reader, Order) | |||
pa, pb, pc := new(G1), new(G1), new(G1) | |||
qa, qb, qc := new(G2), new(G2), new(G2) | |||
pa.Unmarshal(new(G1).ScalarBaseMult(a).Marshal()) | |||
qa.Unmarshal(new(G2).ScalarBaseMult(a).Marshal()) | |||
pb.Unmarshal(new(G1).ScalarBaseMult(b).Marshal()) | |||
qb.Unmarshal(new(G2).ScalarBaseMult(b).Marshal()) | |||
pc.Unmarshal(new(G1).ScalarBaseMult(c).Marshal()) | |||
qc.Unmarshal(new(G2).ScalarBaseMult(c).Marshal()) | |||
k1 := Pair(pb, qc) | |||
k1.ScalarMult(k1, a) | |||
k1Bytes := k1.Marshal() | |||
k2 := Pair(pc, qa) | |||
k2.ScalarMult(k2, b) | |||
k2Bytes := k2.Marshal() | |||
k3 := Pair(pa, qb) | |||
k3.ScalarMult(k3, c) | |||
k3Bytes := k3.Marshal() | |||
if !bytes.Equal(k1Bytes, k2Bytes) || !bytes.Equal(k2Bytes, k3Bytes) { | |||
t.Errorf("keys didn't agree") | |||
} | |||
} | |||
func BenchmarkG1(b *testing.B) { | |||
x, _ := rand.Int(rand.Reader, Order) | |||
b.ResetTimer() | |||
for i := 0; i < b.N; i++ { | |||
new(G1).ScalarBaseMult(x) | |||
} | |||
} | |||
func BenchmarkG2(b *testing.B) { | |||
x, _ := rand.Int(rand.Reader, Order) | |||
b.ResetTimer() | |||
for i := 0; i < b.N; i++ { | |||
new(G2).ScalarBaseMult(x) | |||
} | |||
} | |||
func BenchmarkPairing(b *testing.B) { | |||
for i := 0; i < b.N; i++ { | |||
Pair(&G1{curveGen}, &G2{twistGen}) | |||
} | |||
} |
@@ -0,0 +1,79 @@ | |||
// Copyright 2012 The Go Authors. All rights reserved. | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
package bn256 | |||
import ( | |||
"math/big" | |||
) | |||
func bigFromBase10(s string) *big.Int { | |||
n, _ := new(big.Int).SetString(s, 10) | |||
return n | |||
} | |||
// u is the BN parameter. | |||
var u = bigFromBase10("4965661367192848881") | |||
// Order is the number of elements in both G₁ and G₂: 36u⁴+36u³+18u²+6u+1. | |||
var Order = bigFromBase10("21888242871839275222246405745257275088548364400416034343698204186575808495617") | |||
// P is a prime over which we form a basic field: 36u⁴+36u³+24u²+6u+1. | |||
var P = bigFromBase10("21888242871839275222246405745257275088696311157297823662689037894645226208583") | |||
// p2 is p, represented as little-endian 64-bit words. | |||
var p2 = [4]uint64{0x3c208c16d87cfd47, 0x97816a916871ca8d, 0xb85045b68181585d, 0x30644e72e131a029} | |||
// np is the negative inverse of p, mod 2^256. | |||
var np = [4]uint64{0x87d20782e4866389, 0x9ede7d651eca6ac9, 0xd8afcbd01833da80, 0xf57a22b791888c6b} | |||
// <sage> | |||
// p = 21888242871839275222246405745257275088696311157297823662689037894645226208583; Fp = GF(p) | |||
// r = Fp(2^256) # 6350874878119819312338956282401532409788428879151445726012394534686998597021 | |||
// rInv = 1/r # 20988524275117001072002809824448087578619730785600314334253784976379291040311 | |||
// hex(20988524275117001072002809824448087578619730785600314334253784976379291040311) | |||
// # 2e67157159e5c639 cf63e9cfb74492d9 eb2022850278edf8 ed84884a014afa37 | |||
// <\sage> | |||
// | |||
// rN1 is R^-1 where R = 2^256 mod p. | |||
var rN1 = &gfP{0xed84884a014afa37, 0xeb2022850278edf8, 0xcf63e9cfb74492d9, 0x2e67157159e5c639} | |||
// <sage> | |||
// r2 = r^2 # 3096616502983703923843567936837374451735540968419076528771170197431451843209 | |||
// hex(3096616502983703923843567936837374451735540968419076528771170197431451843209) | |||
// # 06d89f71cab8351f 47ab1eff0a417ff6 b5e71911d44501fb f32cfc5b538afa89 | |||
// <\sage> | |||
// | |||
// r2 is R^2 where R = 2^256 mod p. | |||
var r2 = &gfP{0xf32cfc5b538afa89, 0xb5e71911d44501fb, 0x47ab1eff0a417ff6, 0x06d89f71cab8351f} | |||
// r3 is R^3 where R = 2^256 mod p. | |||
var r3 = &gfP{0xb1cd6dafda1530df, 0x62f210e6a7283db6, 0xef7f0b0c0ada0afb, 0x20fd6e902d592544} | |||
// <sage> | |||
// xiToPMinus1Over6 = Fp2(i + 9) ^ ((p-1)/6); xiToPMinus1Over6 | |||
// # 16469823323077808223889137241176536799009286646108169935659301613961712198316*i + 8376118865763821496583973867626364092589906065868298776909617916018768340080 | |||
// <\sage> | |||
// | |||
// The value of `xiToPMinus1Over6` below is the same as the one obtained in sage, but where every field element is montgomery encoded | |||
// xiToPMinus1Over6 is ξ^((p-1)/6) where ξ = i+9. | |||
var xiToPMinus1Over6 = &gfP2{gfP{0xa222ae234c492d72, 0xd00f02a4565de15b, 0xdc2ff3a253dfc926, 0x10a75716b3899551}, gfP{0xaf9ba69633144907, 0xca6b1d7387afb78a, 0x11bded5ef08a2087, 0x02f34d751a1f3a7c}} | |||
// xiToPMinus1Over3 is ξ^((p-1)/3) where ξ = i+9. | |||
var xiToPMinus1Over3 = &gfP2{gfP{0x6e849f1ea0aa4757, 0xaa1c7b6d89f89141, 0xb6e713cdfae0ca3a, 0x26694fbb4e82ebc3}, gfP{0xb5773b104563ab30, 0x347f91c8a9aa6454, 0x7a007127242e0991, 0x1956bcd8118214ec}} | |||
// xiToPMinus1Over2 is ξ^((p-1)/2) where ξ = i+9. | |||
var xiToPMinus1Over2 = &gfP2{gfP{0xa1d77ce45ffe77c7, 0x07affd117826d1db, 0x6d16bd27bb7edc6b, 0x2c87200285defecc}, gfP{0xe4bbdd0c2936b629, 0xbb30f162e133bacb, 0x31a9d1b6f9645366, 0x253570bea500f8dd}} | |||
// xiToPSquaredMinus1Over3 is ξ^((p²-1)/3) where ξ = i+9. | |||
var xiToPSquaredMinus1Over3 = &gfP{0x3350c88e13e80b9c, 0x7dce557cdb5e56b9, 0x6001b4b8b615564a, 0x2682e617020217e0} | |||
// xiTo2PSquaredMinus2Over3 is ξ^((2p²-2)/3) where ξ = i+9 (a cubic root of unity, mod p). | |||
var xiTo2PSquaredMinus2Over3 = &gfP{0x71930c11d782e155, 0xa6bb947cffbe3323, 0xaa303344d4741444, 0x2c3b3f0d26594943} | |||
// xiToPSquaredMinus1Over6 is ξ^((1p²-1)/6) where ξ = i+9 (a cubic root of -1, mod p). | |||
var xiToPSquaredMinus1Over6 = &gfP{0xca8d800500fa1bf2, 0xf0c5d61468b39769, 0x0e201271ad0d4418, 0x04290f65bad856e6} | |||
// xiTo2PMinus2Over3 is ξ^((2p-2)/3) where ξ = i+9. | |||
var xiTo2PMinus2Over3 = &gfP2{gfP{0x5dddfd154bd8c949, 0x62cb29a5a4445b60, 0x37bc870a0c7dd2b9, 0x24830a9d3171f0fd}, gfP{0x7361d77f843abe92, 0xa5bb2bd3273411fb, 0x9c941f314b3e2399, 0x15df9cddbb9fd3ec}} |
@@ -0,0 +1,240 @@ | |||
package bn256 | |||
import ( | |||
"math/big" | |||
) | |||
// curvePoint implements the elliptic curve y²=x³+3. Points are kept in Jacobian | |||
// form and t=z² when valid. G₁ is the set of points of this curve on GF(p). | |||
type curvePoint struct { | |||
x, y, z, t gfP | |||
} | |||
var curveB = newGFp(3) | |||
// curveGen is the generator of G₁. | |||
var curveGen = &curvePoint{ | |||
x: *newGFp(1), | |||
y: *newGFp(2), | |||
z: *newGFp(1), | |||
t: *newGFp(1), | |||
} | |||
func (c *curvePoint) String() string { | |||
c.MakeAffine() | |||
x, y := &gfP{}, &gfP{} | |||
montDecode(x, &c.x) | |||
montDecode(y, &c.y) | |||
return "(" + x.String() + ", " + y.String() + ")" | |||
} | |||
func (c *curvePoint) Set(a *curvePoint) { | |||
c.x.Set(&a.x) | |||
c.y.Set(&a.y) | |||
c.z.Set(&a.z) | |||
c.t.Set(&a.t) | |||
} | |||
// IsOnCurve returns true iff c is on the curve. | |||
func (c *curvePoint) IsOnCurve() bool { | |||
c.MakeAffine() | |||
if c.IsInfinity() { | |||
return true | |||
} | |||
y2, x3 := &gfP{}, &gfP{} | |||
gfpMul(y2, &c.y, &c.y) | |||
gfpMul(x3, &c.x, &c.x) | |||
gfpMul(x3, x3, &c.x) | |||
gfpAdd(x3, x3, curveB) | |||
return *y2 == *x3 | |||
} | |||
func (c *curvePoint) SetInfinity() { | |||
c.x = gfP{0} | |||
c.y = *newGFp(1) | |||
c.z = gfP{0} | |||
c.t = gfP{0} | |||
} | |||
func (c *curvePoint) IsInfinity() bool { | |||
return c.z == gfP{0} | |||
} | |||
func (c *curvePoint) Add(a, b *curvePoint) { | |||
if a.IsInfinity() { | |||
c.Set(b) | |||
return | |||
} | |||
if b.IsInfinity() { | |||
c.Set(a) | |||
return | |||
} | |||
// See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/addition/add-2007-bl.op3 | |||
// Normalize the points by replacing a = [x1:y1:z1] and b = [x2:y2:z2] | |||
// by [u1:s1:z1·z2] and [u2:s2:z1·z2] | |||
// where u1 = x1·z2², s1 = y1·z2³ and u1 = x2·z1², s2 = y2·z1³ | |||
z12, z22 := &gfP{}, &gfP{} | |||
gfpMul(z12, &a.z, &a.z) | |||
gfpMul(z22, &b.z, &b.z) | |||
u1, u2 := &gfP{}, &gfP{} | |||
gfpMul(u1, &a.x, z22) | |||
gfpMul(u2, &b.x, z12) | |||
t, s1 := &gfP{}, &gfP{} | |||
gfpMul(t, &b.z, z22) | |||
gfpMul(s1, &a.y, t) | |||
s2 := &gfP{} | |||
gfpMul(t, &a.z, z12) | |||
gfpMul(s2, &b.y, t) | |||
// Compute x = (2h)²(s²-u1-u2) | |||
// where s = (s2-s1)/(u2-u1) is the slope of the line through | |||
// (u1,s1) and (u2,s2). The extra factor 2h = 2(u2-u1) comes from the value of z below. | |||
// This is also: | |||
// 4(s2-s1)² - 4h²(u1+u2) = 4(s2-s1)² - 4h³ - 4h²(2u1) | |||
// = r² - j - 2v | |||
// with the notations below. | |||
h := &gfP{} | |||
gfpSub(h, u2, u1) | |||
xEqual := *h == gfP{0} | |||
gfpAdd(t, h, h) | |||
// i = 4h² | |||
i := &gfP{} | |||
gfpMul(i, t, t) | |||
// j = 4h³ | |||
j := &gfP{} | |||
gfpMul(j, h, i) | |||
gfpSub(t, s2, s1) | |||
yEqual := *t == gfP{0} | |||
if xEqual && yEqual { | |||
c.Double(a) | |||
return | |||
} | |||
r := &gfP{} | |||
gfpAdd(r, t, t) | |||
v := &gfP{} | |||
gfpMul(v, u1, i) | |||
// t4 = 4(s2-s1)² | |||
t4, t6 := &gfP{}, &gfP{} | |||
gfpMul(t4, r, r) | |||
gfpAdd(t, v, v) | |||
gfpSub(t6, t4, j) | |||
gfpSub(&c.x, t6, t) | |||
// Set y = -(2h)³(s1 + s*(x/4h²-u1)) | |||
// This is also | |||
// y = - 2·s1·j - (s2-s1)(2x - 2i·u1) = r(v-x) - 2·s1·j | |||
gfpSub(t, v, &c.x) // t7 | |||
gfpMul(t4, s1, j) // t8 | |||
gfpAdd(t6, t4, t4) // t9 | |||
gfpMul(t4, r, t) // t10 | |||
gfpSub(&c.y, t4, t6) | |||
// Set z = 2(u2-u1)·z1·z2 = 2h·z1·z2 | |||
gfpAdd(t, &a.z, &b.z) // t11 | |||
gfpMul(t4, t, t) // t12 | |||
gfpSub(t, t4, z12) // t13 | |||
gfpSub(t4, t, z22) // t14 | |||
gfpMul(&c.z, t4, h) | |||
} | |||
func (c *curvePoint) Double(a *curvePoint) { | |||
// See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/doubling/dbl-2009-l.op3 | |||
A, B, C := &gfP{}, &gfP{}, &gfP{} | |||
gfpMul(A, &a.x, &a.x) | |||
gfpMul(B, &a.y, &a.y) | |||
gfpMul(C, B, B) | |||
t, t2 := &gfP{}, &gfP{} | |||
gfpAdd(t, &a.x, B) | |||
gfpMul(t2, t, t) | |||
gfpSub(t, t2, A) | |||
gfpSub(t2, t, C) | |||
d, e, f := &gfP{}, &gfP{}, &gfP{} | |||
gfpAdd(d, t2, t2) | |||
gfpAdd(t, A, A) | |||
gfpAdd(e, t, A) | |||
gfpMul(f, e, e) | |||
gfpAdd(t, d, d) | |||
gfpSub(&c.x, f, t) | |||
gfpAdd(t, C, C) | |||
gfpAdd(t2, t, t) | |||
gfpAdd(t, t2, t2) | |||
gfpSub(&c.y, d, &c.x) | |||
gfpMul(t2, e, &c.y) | |||
gfpSub(&c.y, t2, t) | |||
gfpMul(t, &a.y, &a.z) | |||
gfpAdd(&c.z, t, t) | |||
} | |||
func (c *curvePoint) Mul(a *curvePoint, scalar *big.Int) { | |||
precomp := [1 << 2]*curvePoint{nil, {}, {}, {}} | |||
precomp[1].Set(a) | |||
precomp[2].Set(a) | |||
gfpMul(&precomp[2].x, &precomp[2].x, xiTo2PSquaredMinus2Over3) | |||
precomp[3].Add(precomp[1], precomp[2]) | |||
multiScalar := curveLattice.Multi(scalar) | |||
sum := &curvePoint{} | |||
sum.SetInfinity() | |||
t := &curvePoint{} | |||
for i := len(multiScalar) - 1; i >= 0; i-- { | |||
t.Double(sum) | |||
if multiScalar[i] == 0 { | |||
sum.Set(t) | |||
} else { | |||
sum.Add(t, precomp[multiScalar[i]]) | |||
} | |||
} | |||
c.Set(sum) | |||
} | |||
// Transforms Jacobian coordinates to Affine coordinates | |||
// (X' : Y' : Z) -> (X'/(Z^2) : Y'/(Z^3) : 1) | |||
func (c *curvePoint) MakeAffine() { | |||
if c.z == *newGFp(1) { | |||
return | |||
} else if c.z == *newGFp(0) { // return point at infinity if z = 0 | |||
c.x = gfP{0} | |||
c.y = *newGFp(1) | |||
c.t = gfP{0} | |||
return | |||
} | |||
zInv := &gfP{} | |||
zInv.Invert(&c.z) | |||
t, zInv2 := &gfP{}, &gfP{} | |||
gfpMul(t, &c.y, zInv) // t = y/z | |||
gfpMul(zInv2, zInv, zInv) // zInv2 = 1/(z^2) | |||
gfpMul(&c.x, &c.x, zInv2) // x = x/(z^2) | |||
gfpMul(&c.y, t, zInv2) // y = y/(z^3) | |||
c.z = *newGFp(1) | |||
c.t = *newGFp(1) | |||
} | |||
func (c *curvePoint) Neg(a *curvePoint) { | |||
c.x.Set(&a.x) | |||
gfpNeg(&c.y, &a.y) | |||
c.z.Set(&a.z) | |||
c.t = gfP{0} | |||
} |
@@ -0,0 +1,51 @@ | |||
// Copyright 2012 The Go Authors. All rights reserved. | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
package bn256 | |||
import ( | |||
"crypto/rand" | |||
"testing" | |||
"github.com/stretchr/testify/require" | |||
) | |||
func TestExamplePair(t *testing.T) { | |||
// This implements the tripartite Diffie-Hellman algorithm from "A One | |||
// Round Protocol for Tripartite Diffie-Hellman", A. Joux. | |||
// http://www.springerlink.com/content/cddc57yyva0hburb/fulltext.pdf | |||
// Each of three parties, a, b and c, generate a private value. | |||
a, _ := rand.Int(rand.Reader, Order) | |||
b, _ := rand.Int(rand.Reader, Order) | |||
c, _ := rand.Int(rand.Reader, Order) | |||
// Then each party calculates g₁ and g₂ times their private value. | |||
pa := new(G1).ScalarBaseMult(a) | |||
qa := new(G2).ScalarBaseMult(a) | |||
pb := new(G1).ScalarBaseMult(b) | |||
qb := new(G2).ScalarBaseMult(b) | |||
pc := new(G1).ScalarBaseMult(c) | |||
qc := new(G2).ScalarBaseMult(c) | |||
// Now each party exchanges its public values with the other two and | |||
// all parties can calculate the shared key. | |||
k1 := Pair(pb, qc) | |||
k1.ScalarMult(k1, a) | |||
k2 := Pair(pc, qa) | |||
k2.ScalarMult(k2, b) | |||
k3 := Pair(pa, qb) | |||
k3.ScalarMult(k3, c) | |||
// k1, k2 and k3 will all be equal. | |||
require.Equal(t, k1, k2) | |||
require.Equal(t, k1, k3) | |||
require.Equal(t, len(np), 4) //Avoid gometalinter varcheck err on np | |||
} |
@@ -0,0 +1,388 @@ | |||
// Package bn256 implements a particular bilinear group at the 128-bit security | |||
// level. | |||
// | |||
// Bilinear groups are the basis of many of the new cryptographic protocols that | |||
// have been proposed over the past decade. They consist of a triplet of groups | |||
// (G₁, G₂ and GT) such that there exists a function e(g₁ˣ,g₂ʸ)=gTˣʸ (where gₓ | |||
// is a generator of the respective group). That function is called a pairing | |||
// function. | |||
// | |||
// This package specifically implements the Optimal Ate pairing over a 256-bit | |||
// Barreto-Naehrig curve as described in | |||
// http://cryptojedi.org/papers/dclxvi-20100714.pdf. Its output is compatible | |||
// with the implementation described in that paper. | |||
package bn256 | |||
// This file implement some util functions for the MPC | |||
// especially the serialization and deserialization functions for points in G1 | |||
import ( | |||
"errors" | |||
"math/big" | |||
) | |||
// Constants related to the bn256 pairing friendly curve | |||
const ( | |||
FqElementSize = 32 | |||
G1CompressedSize = FqElementSize + 1 // + 1 accounts for the additional byte used for masking | |||
G1UncompressedSize = 2*FqElementSize + 1 // + 1 accounts for the additional byte used for masking | |||
) | |||
// https://github.com/ebfull/pairing/tree/master/src/bls12_381#serialization | |||
// Bytes used to detect the formatting. By reading the first byte of the encoded point we can know it's nature | |||
// ie: we can know if the point is the point at infinity, if it is encoded uncompressed or if it is encoded compressed | |||
// Bit masking used to detect the serialization of the points and their nature | |||
// | |||
// The BSL12-381 curve is built over a 381-bit prime field. | |||
// Thus each point coordinate is represented over 381 bits = 47bytes + 5bits | |||
// Thus, to represent a point we need to have 48bytes, but the last 3 bits of the 48th byte will be set to 0 | |||
// These are these bits that are used to implement the masking, hence why the masking proposed by ebfull was: | |||
const ( | |||
serializationMask = (1 << 5) - 1 // 0001 1111 // Enable to pick the 3 MSB corresponding to the serialization flag | |||
serializationCompressed = 1 << 7 // 1000 0000 | |||
serializationInfinity = 1 << 6 // 0100 0000 | |||
serializationBigY = 1 << 5 // 0010 0000 | |||
) | |||
// IsHigherY is used to distinguish between the 2 points of E | |||
// that have the same x-coordinate | |||
// The point e is assumed to be given in the affine form | |||
func (e *G1) IsHigherY() bool { | |||
// Check nil pointers | |||
if e.p == nil { | |||
e.p = &curvePoint{} | |||
} | |||
yCoord := &gfP{} | |||
yCoord.Set(&e.p.y) | |||
yCoordNeg := &gfP{} | |||
gfpNeg(yCoordNeg, yCoord) | |||
res := gfpCmp(yCoord, yCoordNeg) | |||
if res == 1 { // yCoord > yCoordNeg | |||
return true | |||
} else if res == -1 { | |||
return false | |||
} | |||
return false | |||
} | |||
// EncodeCompressed converts the compressed point e into bytes | |||
// This function takes a point in the Jacobian form | |||
// This function does not modify the point e | |||
// (the variable `temp` is introduced to avoid to modify e) | |||
func (e *G1) EncodeCompressed() []byte { | |||
// Check nil pointers | |||
if e.p == nil { | |||
e.p = &curvePoint{} | |||
} | |||
e.p.MakeAffine() | |||
ret := make([]byte, G1CompressedSize) | |||
// Flag the encoding with the compressed flag | |||
ret[0] |= serializationCompressed | |||
if e.p.IsInfinity() { | |||
// Flag the encoding with the infinity flag | |||
ret[0] |= serializationInfinity | |||
return ret | |||
} | |||
if e.IsHigherY() { | |||
// Flag the encoding with the bigY flag | |||
ret[0] |= serializationBigY | |||
} | |||
// We start the serializagtion of the coordinates at the index 1 | |||
// Since the index 0 in the `ret` corresponds to the masking | |||
temp := &gfP{} | |||
montDecode(temp, &e.p.x) | |||
temp.Marshal(ret[1:]) | |||
return ret | |||
} | |||
// EncodeUncompressed converts the compressed point e into bytes | |||
// Take a point P in Jacobian form (where each coordinate is MontEncoded) | |||
// and encodes it by going back to affine coordinates and montDecode all coordinates | |||
// This function does not modify the point e | |||
// (the variable `temp` is introduced to avoid to modify e) | |||
/* | |||
func (e *G1) EncodeUncompressed() []byte { | |||
// Check nil pointers | |||
if e.p == nil { | |||
e.p = &curvePoint{} | |||
} | |||
e.p.MakeAffine() | |||
ret := make([]byte, G1UncompressedSize) | |||
if e.p.IsInfinity() { | |||
// Flag the encoding with the infinity flag | |||
ret[0] |= serializationInfinity | |||
return ret | |||
} | |||
// We start the serialization of the coordinates at the index 1 | |||
// Since the index 0 in the `ret` corresponds to the masking | |||
temp := &gfP{} | |||
montDecode(temp, &e.p.x) // Store the montgomery decoding in temp | |||
temp.Marshal(ret[1:33]) // Write temp in the `ret` slice, this is the x-coordinate | |||
montDecode(temp, &e.p.y) | |||
temp.Marshal(ret[33:]) // this is the y-coordinate | |||
return ret | |||
} | |||
*/ | |||
func (e *G1) EncodeUncompressed() []byte { | |||
// Check nil pointers | |||
if e.p == nil { | |||
e.p = &curvePoint{} | |||
} | |||
// Set the right flags | |||
ret := make([]byte, G1UncompressedSize) | |||
if e.p.IsInfinity() { | |||
// Flag the encoding with the infinity flag | |||
ret[0] |= serializationInfinity | |||
return ret | |||
} | |||
// Marshal | |||
marshal := e.Marshal() | |||
// The encoding = flags || marshalledPoint | |||
copy(ret[1:], marshal) | |||
return ret | |||
} | |||
// Takes a MontEncoded x and finds the corresponding y (one of the two possible y's) | |||
func getYFromMontEncodedX(x *gfP) (*gfP, error) { | |||
// Check nil pointers | |||
if x == nil { | |||
return nil, errors.New("Cannot retrieve the y-coordinate form a nil pointer") | |||
} | |||
// Operations on montgomery encoded field elements | |||
x2 := &gfP{} | |||
gfpMul(x2, x, x) | |||
x3 := &gfP{} | |||
gfpMul(x3, x2, x) | |||
rhs := &gfP{} | |||
gfpAdd(rhs, x3, curveB) // curveB is MontEncoded, since it is create with newGFp | |||
// Montgomery decode rhs | |||
// Needed because when we create a GFp element | |||
// with gfP{}, then it is not montEncoded. However | |||
// if we create an element of GFp by using `newGFp()` | |||
// then this field element is Montgomery encoded | |||
// Above, we have been working on Montgomery encoded field elements | |||
// here we solve the quad. resid. over F (not encoded) | |||
// and then we encode back and return the encoded result | |||
// | |||
// Eg: | |||
// - Px := &gfP{1} => 0000000000000000000000000000000000000000000000000000000000000001 | |||
// - PxNew := newGFp(1) => 0e0a77c19a07df2f666ea36f7879462c0a78eb28f5c70b3dd35d438dc58f0d9d | |||
montDecode(rhs, rhs) | |||
rhsBig, err := rhs.gFpToBigInt() | |||
if err != nil { | |||
return nil, err | |||
} | |||
// Note, if we use the ModSqrt method, we don't need the exponent, so we can comment these lines | |||
yCoord := big.NewInt(0) | |||
res := yCoord.ModSqrt(rhsBig, P) | |||
if res == nil { | |||
return nil, errors.New("not a square mod P") | |||
} | |||
yCoordGFp := newGFpFromBigInt(yCoord) | |||
montEncode(yCoordGFp, yCoordGFp) | |||
return yCoordGFp, nil | |||
} | |||
// DecodeCompressed decodes a point in the compressed form | |||
// Take a point P encoded (ie: written in affine form where each coordinate is MontDecoded) | |||
// and encodes it by going back to Jacobian coordinates and montEncode all coordinates | |||
func (e *G1) DecodeCompressed(encoding []byte) error { | |||
if len(encoding) != G1CompressedSize { | |||
return errors.New("wrong encoded point size") | |||
} | |||
if encoding[0]&serializationCompressed == 0 { // Also test the length of the encoding to make sure it is 33bytes | |||
return errors.New("point isn't compressed") | |||
} | |||
// Unmarshal the points and check their caps | |||
if e.p == nil { | |||
e.p = &curvePoint{} | |||
} else { | |||
e.p.x, e.p.y = gfP{0}, gfP{0} | |||
e.p.z, e.p.t = *newGFp(1), *newGFp(1) | |||
} | |||
// Removes the bits of the masking (This does a bitwise AND with `0001 1111`) | |||
// And thus removes the first 3 bits corresponding to the masking | |||
bin := make([]byte, G1CompressedSize) | |||
copy(bin, encoding) | |||
bin[0] &= serializationMask | |||
// Decode the point at infinity in the compressed form | |||
if encoding[0]&serializationInfinity != 0 { | |||
if encoding[0]&serializationBigY != 0 { | |||
return errors.New("high Y bit improperly set") | |||
} | |||
// Similar to `for i:=0; i<len(bin); i++ {}` | |||
for i := range bin { | |||
// Makes sense to check that all bytes of bin are 0x0 since we removed the masking above | |||
if bin[i] != 0 { | |||
return errors.New("invalid infinity encoding") | |||
} | |||
} | |||
e.p.SetInfinity() | |||
return nil | |||
} | |||
// Decompress the point P (P =/= ∞) | |||
var err error | |||
if err = e.p.x.Unmarshal(bin[1:]); err != nil { | |||
return err | |||
} | |||
// MontEncode our field elements for fast finite field arithmetic | |||
// Needs to be done since the z and t coordinates are also encoded (ie: created with newGFp) | |||
montEncode(&e.p.x, &e.p.x) | |||
y, err := getYFromMontEncodedX(&e.p.x) | |||
if err != nil { | |||
return err | |||
} | |||
e.p.y = *y | |||
// The flag serializationBigY is set (so the point pt with the higher Y is encoded) | |||
// but the point e retrieved from the `getYFromX` is NOT the higher, then we inverse | |||
if !e.IsHigherY() { | |||
if encoding[0]&serializationBigY != 0 { | |||
e.Neg(e) | |||
} | |||
} else { | |||
if encoding[0]&serializationBigY == 0 { // The point given by getYFromX is the higher but the mask is not set for higher y | |||
e.Neg(e) | |||
} | |||
} | |||
// No need to check that the point e.p is on the curve | |||
// since we retrieved y from x by using the curve equation. | |||
// Adding it would be redundant | |||
return nil | |||
} | |||
// DecodeUncompressed decodes a point in the uncompressed form | |||
// Take a point P encoded (ie: written in affine form where each coordinate is MontDecoded) | |||
// and encodes it by going back to Jacobian coordinates and montEncode all coordinates | |||
/* | |||
func (e *G1) DecodeUncompressed(encoding []byte) error { | |||
if len(encoding) != G1UncompressedSize { | |||
return errors.New("wrong encoded point size") | |||
} | |||
if encoding[0]&serializationCompressed != 0 { // Also test the length of the encoding to make sure it is 65bytes | |||
return errors.New("point is compressed") | |||
} | |||
if encoding[0]&serializationBigY != 0 { // Also test that the bigY flag if not set | |||
return errors.New("bigY flag should not be set") | |||
} | |||
// Unmarshal the points and check their caps | |||
if e.p == nil { | |||
e.p = &curvePoint{} | |||
} else { | |||
e.p.x, e.p.y = gfP{0}, gfP{0} | |||
e.p.z, e.p.t = *newGFp(1), *newGFp(1) | |||
} | |||
// Removes the bits of the masking (This does a bitwise AND with `0001 1111`) | |||
// And thus removes the first 3 bits corresponding to the masking | |||
// Useless for now because in bn256, we added a full byte to enable masking | |||
// However, this is needed if we work over BLS12 and its underlying field | |||
bin := make([]byte, G1UncompressedSize) | |||
copy(bin, encoding) | |||
bin[0] &= serializationMask | |||
// Decode the point at infinity in the compressed form | |||
if encoding[0]&serializationInfinity != 0 { | |||
// Makes sense to check that all bytes of bin are 0x0 since we removed the masking above} | |||
for i := range bin { | |||
if bin[i] != 0 { | |||
return errors.New("invalid infinity encoding") | |||
} | |||
} | |||
e.p.SetInfinity() | |||
return nil | |||
} | |||
// Decode the point P (P =/= ∞) | |||
var err error | |||
// Decode the x-coordinate | |||
if err = e.p.x.Unmarshal(bin[1:33]); err != nil { | |||
return err | |||
} | |||
// Decode the y-coordinate | |||
if err = e.p.y.Unmarshal(bin[33:]); err != nil { | |||
return err | |||
} | |||
// MontEncode our field elements for fast finite field arithmetic | |||
montEncode(&e.p.x, &e.p.x) | |||
montEncode(&e.p.y, &e.p.y) | |||
if !e.p.IsOnCurve() { | |||
return errors.New("malformed point: Not on the curve") | |||
} | |||
return nil | |||
} | |||
*/ | |||
func (e *G1) DecodeUncompressed(encoding []byte) error { | |||
if len(encoding) != G1UncompressedSize { | |||
return errors.New("wrong encoded point size") | |||
} | |||
if encoding[0]&serializationCompressed != 0 { // Also test the length of the encoding to make sure it is 65bytes | |||
return errors.New("point is compressed") | |||
} | |||
if encoding[0]&serializationBigY != 0 { // Also test that the bigY flag if not set | |||
return errors.New("bigY flag should not be set") | |||
} | |||
// Unmarshal the points and check their caps | |||
if e.p == nil { | |||
e.p = &curvePoint{} | |||
} | |||
// Removes the bits of the masking (This does a bitwise AND with `0001 1111`) | |||
// And thus removes the first 3 bits corresponding to the masking | |||
// Useless for now because in bn256, we added a full byte to enable masking | |||
// However, this is needed if we work over BLS12 and its underlying field | |||
bin := make([]byte, G1UncompressedSize) | |||
copy(bin, encoding) | |||
bin[0] &= serializationMask | |||
// Decode the point at infinity in the compressed form | |||
if encoding[0]&serializationInfinity != 0 { | |||
// Makes sense to check that all bytes of bin are 0x0 since we removed the masking above} | |||
for i := range bin { | |||
if bin[i] != 0 { | |||
return errors.New("invalid infinity encoding") | |||
} | |||
} | |||
e.p.SetInfinity() | |||
return nil | |||
} | |||
// We remote the flags and unmarshall the data | |||
_, err := e.Unmarshal(encoding[1:]) | |||
return err | |||
} |
@@ -0,0 +1,241 @@ | |||
package bn256 | |||
import ( | |||
"crypto/rand" | |||
"fmt" | |||
"math/big" | |||
"testing" | |||
"github.com/stretchr/testify/assert" | |||
) | |||
func assertGFpEqual(t *testing.T, a, b *gfP) { | |||
for i := 0; i < FpUint64Size; i++ { | |||
assert.Equal(t, a[i], b[i], fmt.Sprintf("The %d's elements differ between the 2 field elements", i)) | |||
} | |||
} | |||
func TestEncodeCompressed(t *testing.T) { | |||
// Case1: Create random point (Jacobian form) | |||
_, GaInit, err := RandomG1(rand.Reader) | |||
if err != nil { | |||
t.Fatal(err) | |||
} | |||
// Affine form of GaInit | |||
GaAffine := new(G1) | |||
GaAffine.Set(GaInit) | |||
GaAffine.p.MakeAffine() | |||
// Encode GaCopy1 with the EncodeCompress function | |||
GaCopy1 := new(G1) | |||
GaCopy1.Set(GaInit) | |||
compressed := GaCopy1.EncodeCompressed() | |||
// Encode GaCopy2 with the Marshal function | |||
GaCopy2 := new(G1) | |||
GaCopy2.Set(GaInit) | |||
marshalled := GaCopy2.Marshal() // Careful Marshal modifies the point since it makes it an affine point! | |||
// Make sure that the x-coordinate is encoded as it is when we call the Marshal function | |||
assert.Equal( | |||
t, | |||
compressed[1:], // Ignore the masking byte | |||
marshalled[:32], // Get only the x-coordinate | |||
"The EncodeCompressed and Marshal function yield different results for the x-coordinate") | |||
// Unmarshal the point Ga with the unmarshal function | |||
Gb1 := new(G1) | |||
_, err = Gb1.Unmarshal(marshalled) | |||
assert.Nil(t, err) | |||
assert.Equal(t, GaAffine.p.x.String(), Gb1.p.x.String(), "The x-coord of the unmarshalled point should equal the x-coord of the intial point") | |||
assert.Equal(t, GaAffine.p.y.String(), Gb1.p.y.String(), "The y-coord of the unmarshalled point should equal the y-coord of the intial point") | |||
// Decode the point Ga with the decodeCompress function | |||
Gb2 := new(G1) | |||
err = Gb2.DecodeCompressed(compressed) | |||
assert.Nil(t, err) | |||
assert.Equal(t, GaAffine.p.x.String(), Gb2.p.x.String(), "The x-coord of the decompressed point should equal the x-coord of the intial point") | |||
assert.Equal(t, GaAffine.p.y.String(), Gb2.p.y.String(), "The y-coord of the decompressed point should equal the y-coord of the intial point") | |||
// Case2: Encode the point at infinity | |||
GInfinity := new(G1) | |||
GInfinity.p = &curvePoint{} | |||
GInfinity.p.SetInfinity() | |||
// Get the point in affine form | |||
GInfinityAffine := new(G1) | |||
GInfinityAffine.Set(GInfinity) | |||
GInfinityAffine.p.MakeAffine() | |||
// Encode GaCopy1 with the EncodeCompress function | |||
GInfinityCopy1 := new(G1) | |||
GInfinityCopy1.Set(GInfinity) | |||
compressed = GInfinityCopy1.EncodeCompressed() | |||
// Encode GaCopy2 with the Marshal function | |||
GInfinityCopy2 := new(G1) | |||
GInfinityCopy2.Set(GInfinity) | |||
marshalled = GInfinityCopy2.Marshal() // Careful Marshal modifies the point since it makes it an affine point! | |||
// Make sure that the x-coordinate is encoded as it is when we call the Marshal function | |||
assert.Equal( | |||
t, | |||
compressed[1:], // Ignore the masking byte | |||
marshalled[:32], | |||
"The EncodeCompressed and Marshal function yield different results") | |||
// Unmarshal the point Ga with the unmarshal function | |||
Gb1 = new(G1) | |||
_, err = Gb1.Unmarshal(marshalled) | |||
assert.Nil(t, err) | |||
assert.Equal(t, GInfinityAffine.p.x.String(), Gb1.p.x.String(), "The x-coord of the unmarshalled point should equal the x-coord of the intial point") | |||
assert.Equal(t, GInfinityAffine.p.y.String(), Gb1.p.y.String(), "The y-coord of the unmarshalled point should equal the y-coord of the intial point") | |||
// Decode the point Ga with the decodeCompress function | |||
Gb2 = new(G1) | |||
err = Gb2.DecodeCompressed(compressed) | |||
assert.Nil(t, err) | |||
assert.Equal(t, GInfinityAffine.p.x.String(), Gb2.p.x.String(), "The x-coord of the decompressed point should equal the x-coord of the intial point") | |||
assert.Equal(t, GInfinityAffine.p.y.String(), Gb2.p.y.String(), "The y-coord of the decompressed point should equal the y-coord of the intial point") | |||
} | |||
func TestIsHigherY(t *testing.T) { | |||
_, Ga, err := RandomG1(rand.Reader) | |||
if err != nil { | |||
t.Fatal(err) | |||
} | |||
Ga.p.MakeAffine() | |||
GaYString := Ga.p.y.String() | |||
GaYBig := new(big.Int) | |||
_, ok := GaYBig.SetString(GaYString, 16) | |||
assert.True(t, ok, "ok should be True") | |||
GaNeg := new(G1) | |||
GaNeg.Neg(Ga) | |||
GaNeg.p.MakeAffine() | |||
GaNegYString := GaNeg.p.y.String() | |||
GaNegYBig := new(big.Int) | |||
_, ok = GaNegYBig.SetString(GaNegYString, 16) | |||
assert.True(t, ok, "ok should be True") | |||
// Verify that Ga.p.y + GaNeg.p.y == 0 | |||
sumYs := &gfP{} | |||
fieldZero := newGFp(0) | |||
gfpAdd(sumYs, &Ga.p.y, &GaNeg.p.y) | |||
assert.Equal(t, *sumYs, *fieldZero, "The y-coordinates of P and -P should add up to zero") | |||
// Find which point between Ga and GaNeg is the one witht eh higher Y | |||
res := gfpCmp(&GaNeg.p.y, &Ga.p.y) | |||
if res > 0 { // GaNeg.p.y > Ga.p.y | |||
assert.True(t, GaNeg.IsHigherY(), "GaNeg.IsHigherY should be true if GaNeg.p.y > Ga.p.y") | |||
// Test the comparision of the big int also, should be the same result | |||
assert.Equal(t, GaNegYBig.Cmp(GaYBig), 1, "GaNegYBig should be bigger than GaYBig") | |||
} else if res < 0 { // GaNeg.p.y < Ga.p.y | |||
assert.False(t, GaNeg.IsHigherY(), "GaNeg.IsHigherY should be false if GaNeg.p.y < Ga.p.y") | |||
// Test the comparision of the big int also, should be the same result | |||
assert.Equal(t, GaYBig.Cmp(GaNegYBig), 1, "GaYBig should be bigger than GaNegYBig") | |||
} | |||
} | |||
func TestGetYFromMontEncodedX(t *testing.T) { | |||
// We know that the generator of the curve is P = (x: 1, y: 2, z: 1, t: 1) | |||
// We take x = 1 and we see if we retrieve P such that y = 2 or -P such that y' = Inv(2) | |||
// Create the GFp element 1 and MontEncode it | |||
PxMontEncoded := newGFp(1) | |||
yRetrieved, err := getYFromMontEncodedX(PxMontEncoded) | |||
assert.Nil(t, err) | |||
smallYMontEncoded := newGFp(2) | |||
bigYMontEncoded := &gfP{} | |||
gfpNeg(bigYMontEncoded, smallYMontEncoded) | |||
testCondition := (*yRetrieved == *smallYMontEncoded) || (*yRetrieved == *bigYMontEncoded) | |||
assert.True(t, testCondition, "The retrieved Y should either equal 2 or Inv(2)") | |||
} | |||
func TestEncodeUncompressed(t *testing.T) { | |||
// Case1: Create random point (Jacobian form) | |||
_, GaInit, err := RandomG1(rand.Reader) | |||
if err != nil { | |||
t.Fatal(err) | |||
} | |||
// Affine form of GaInit | |||
GaAffine := new(G1) | |||
GaAffine.Set(GaInit) | |||
GaAffine.p.MakeAffine() | |||
// Encode GaCopy1 with the EncodeUncompress function | |||
GaCopy1 := new(G1) | |||
GaCopy1.Set(GaInit) | |||
encoded := GaCopy1.EncodeUncompressed() | |||
// Encode GaCopy2 with the Marshal function | |||
GaCopy2 := new(G1) | |||
GaCopy2.Set(GaInit) | |||
marshalled := GaCopy2.Marshal() // Careful Marshal modifies the point since it makes it an affine point! | |||
// Make sure that the x-coordinate is encoded as it is when we call the Marshal function | |||
assert.Equal( | |||
t, | |||
encoded[1:], // Ignore the masking byte | |||
marshalled[:], | |||
"The EncodeUncompressed and Marshal function yield different results") | |||
// Unmarshal the point Ga with the unmarshal function | |||
Gb1 := new(G1) | |||
_, err = Gb1.Unmarshal(marshalled) | |||
assert.Nil(t, err) | |||
assert.Equal(t, GaAffine.p.x.String(), Gb1.p.x.String(), "The x-coord of the unmarshalled point should equal the x-coord of the intial point") | |||
assert.Equal(t, GaAffine.p.y.String(), Gb1.p.y.String(), "The y-coord of the unmarshalled point should equal the y-coord of the intial point") | |||
// Decode the point Ga with the decodeUncompress function | |||
Gb2 := new(G1) | |||
err = Gb2.DecodeUncompressed(encoded) | |||
assert.Nil(t, err) | |||
assert.Equal(t, GaAffine.p.x.String(), Gb2.p.x.String(), "The x-coord of the decoded point should equal the x-coord of the intial point") | |||
assert.Equal(t, GaAffine.p.y.String(), Gb2.p.y.String(), "The y-coord of the decoded point should equal the y-coord of the intial point") | |||
// Case2: Encode the point at infinity | |||
GInfinity := new(G1) | |||
GInfinity.p = &curvePoint{} | |||
GInfinity.p.SetInfinity() | |||
// Get the point in affine form | |||
GInfinityAffine := new(G1) | |||
GInfinityAffine.Set(GInfinity) | |||
GInfinityAffine.p.MakeAffine() | |||
// Encode GaCopy1 with the EncodeUncompress function | |||
GInfinityCopy1 := new(G1) | |||
GInfinityCopy1.Set(GInfinity) | |||
encoded = GInfinityCopy1.EncodeUncompressed() | |||
// Encode GaCopy2 with the Marshal function | |||
GInfinityCopy2 := new(G1) | |||
GInfinityCopy2.Set(GInfinity) | |||
marshalled = GInfinityCopy2.Marshal() // Careful Marshal modifies the point since it makes it an affine point! | |||
// Make sure that the x-coordinate is encoded as it is when we call the Marshal function | |||
assert.Equal( | |||
t, | |||
encoded[1:], // Ignore the masking byte | |||
marshalled[:], | |||
"The EncodeUncompressed and Marshal function yield different results") | |||
// Unmarshal the point Ga with the unmarshal function | |||
Gb1 = new(G1) | |||
_, err = Gb1.Unmarshal(marshalled) | |||
assert.Nil(t, err) | |||
assert.Equal(t, GInfinityAffine.p.x.String(), Gb1.p.x.String(), "The x-coord of the unmarshalled point should equal the x-coord of the intial point") | |||
assert.Equal(t, GInfinityAffine.p.y.String(), Gb1.p.y.String(), "The y-coord of the unmarshalled point should equal the y-coord of the intial point") | |||
// Decode the point Ga with the decodeCompress function | |||
Gb2 = new(G1) | |||
err = Gb2.DecodeUncompressed(encoded) | |||
assert.Nil(t, err) | |||
assert.Equal(t, GInfinityAffine.p.x.String(), Gb2.p.x.String(), "The x-coord of the decompressed point should equal the x-coord of the intial point") | |||
assert.Equal(t, GInfinityAffine.p.y.String(), Gb2.p.y.String(), "The y-coord of the decompressed point should equal the y-coord of the intial point") | |||
} |
@@ -0,0 +1,266 @@ | |||
// Package bn256 implements a particular bilinear group at the 128-bit security | |||
// level. | |||
// | |||
// Bilinear groups are the basis of many of the new cryptographic protocols that | |||
// have been proposed over the past decade. They consist of a triplet of groups | |||
// (G₁, G₂ and GT) such that there exists a function e(g₁ˣ,g₂ʸ)=gTˣʸ (where gₓ | |||
// is a generator of the respective group). That function is called a pairing | |||
// function. | |||
// | |||
// This package specifically implements the Optimal Ate pairing over a 256-bit | |||
// Barreto-Naehrig curve as described in | |||
// http://cryptojedi.org/papers/dclxvi-20100714.pdf. Its output is compatible | |||
// with the implementation described in that paper. | |||
package bn256 | |||
import ( | |||
"errors" | |||
) | |||
// This file implement some util functions for the MPC | |||
// especially the serialization and deserialization functions for points in G1 | |||
// Constants related to the bn256 pairing friendly curve | |||
const ( | |||
Fq2ElementSize = 2 * FqElementSize | |||
G2CompressedSize = Fq2ElementSize + 1 // + 1 accounts for the additional byte used for masking | |||
G2UncompressedSize = 2*Fq2ElementSize + 1 // + 1 accounts for the additional byte used for masking | |||
) | |||
// EncodeUncompressed converts the compressed point e into bytes | |||
// Take a point P in Jacobian form (where each coordinate is MontEncoded) | |||
// and encodes it by going back to affine coordinates and montDecode all coordinates | |||
// This function does not modify the point e | |||
// (the variable `temp` is introduced to avoid to modify e) | |||
func (e *G2) EncodeUncompressed() []byte { | |||
// Check nil pointers | |||
if e.p == nil { | |||
e.p = &twistPoint{} | |||
} | |||
// Set the right flags | |||
ret := make([]byte, G2UncompressedSize) | |||
if e.p.IsInfinity() { | |||
// Flag the encoding with the infinity flag | |||
ret[0] |= serializationInfinity | |||
return ret | |||
} | |||
// Marshal | |||
marshal := e.Marshal() | |||
// The encoding = flags || marshalledPoint | |||
copy(ret[1:], marshal) | |||
return ret | |||
} | |||
// DecodeUncompressed decodes a point in the uncompressed form | |||
// Take a point P encoded (ie: written in affine form where each coordinate is MontDecoded) | |||
// and encodes it by going back to Jacobian coordinates and montEncode all coordinates | |||
func (e *G2) DecodeUncompressed(encoding []byte) error { | |||
if len(encoding) != G2UncompressedSize { | |||
return errors.New("wrong encoded point size") | |||
} | |||
if encoding[0]&serializationCompressed != 0 { // Also test the length of the encoding to make sure it is 65bytes | |||
return errors.New("point is compressed") | |||
} | |||
if encoding[0]&serializationBigY != 0 { // Also test that the bigY flag if not set | |||
return errors.New("bigY flag should not be set") | |||
} | |||
// Unmarshal the points and check their caps | |||
if e.p == nil { | |||
e.p = &twistPoint{} | |||
} | |||
// Removes the bits of the masking (This does a bitwise AND with `0001 1111`) | |||
// And thus removes the first 3 bits corresponding to the masking | |||
// Useless for now because in bn256, we added a full byte to enable masking | |||
// However, this is needed if we work over BLS12 and its underlying field | |||
bin := make([]byte, G2UncompressedSize) | |||
copy(bin, encoding) | |||
bin[0] &= serializationMask | |||
// Decode the point at infinity in the compressed form | |||
if encoding[0]&serializationInfinity != 0 { | |||
// Makes sense to check that all bytes of bin are 0x0 since we removed the masking above} | |||
for i := range bin { | |||
if bin[i] != 0 { | |||
return errors.New("invalid infinity encoding") | |||
} | |||
} | |||
e.p.SetInfinity() | |||
return nil | |||
} | |||
// We remove the flags and unmarshal the data | |||
_, err := e.Unmarshal(encoding[1:]) | |||
return err | |||
} | |||
func (e *G2) IsHigherY() bool { | |||
// Check nil pointers | |||
if e.p == nil { | |||
e.p = &twistPoint{} | |||
e.p.MakeAffine() | |||
} | |||
// Note: the structures attributes are quite confusing here | |||
// In fact, each element of Fp2 is a polynomial with 2 terms | |||
// the `x` and `y` denote these coefficients, ie: xi + y | |||
// However, `x` and `y` are also used to denote the x and y **coordinates** | |||
// of an elliptic curve point. Hence, e.p.y represents the y-coordinate of the | |||
// point e, and e.p.y.y represents the **coefficient** y of the y-coordinate | |||
// of the elliptic curve point e. | |||
// | |||
// TODO: Rename the coefficients of the elements of Fp2 as c0 and c1 to clarify the code | |||
yCoordY := &gfP{} | |||
yCoordY.Set(&e.p.y.y) | |||
yCoordYNeg := &gfP{} | |||
gfpNeg(yCoordYNeg, yCoordY) | |||
res := gfpCmp(yCoordY, yCoordYNeg) | |||
if res == 1 { // yCoordY > yCoordNegY | |||
return true | |||
} else if res == -1 { | |||
return false | |||
} | |||
return false | |||
} | |||
func (e *G2) EncodeCompressed() []byte { | |||
// Check nil pointers | |||
if e.p == nil { | |||
e.p = &twistPoint{} | |||
} | |||
e.p.MakeAffine() | |||
ret := make([]byte, G2CompressedSize) | |||
// Flag the encoding with the compressed flag | |||
ret[0] |= serializationCompressed | |||
if e.p.IsInfinity() { | |||
// Flag the encoding with the infinity flag | |||
ret[0] |= serializationInfinity | |||
return ret | |||
} | |||
if e.IsHigherY() { | |||
// Flag the encoding with the bigY flag | |||
ret[0] |= serializationBigY | |||
} | |||
// We start the serialization of the coordinates at the index 1 | |||
// Since the index 0 in the `ret` corresponds to the masking | |||
// | |||
// `temp` contains the the x-coordinate of the point | |||
// Thus, to fully encode `temp`, we need to Marshal it's x coefficient and y coefficient | |||
temp := gfP2Decode(&e.p.x) | |||
temp.x.Marshal(ret[1:]) | |||
temp.y.Marshal(ret[FqElementSize+1:]) | |||
return ret | |||
} | |||
// Takes a MontEncoded x and finds the corresponding y (one of the two possible y's) | |||
func getYFromMontEncodedXG2(x *gfP2) (*gfP2, error) { | |||
// Check nil pointers | |||
if x == nil { | |||
return nil, errors.New("Cannot retrieve the y-coordinate from a nil pointer") | |||
} | |||
x2 := new(gfP2).Mul(x, x) | |||
x3 := new(gfP2).Mul(x2, x) | |||
rhs := new(gfP2).Add(x3, twistB) // twistB is MontEncoded, since it is create with newGFp | |||
yCoord, err := rhs.Sqrt() | |||
if err != nil { | |||
return nil, err | |||
} | |||
return yCoord, nil | |||
} | |||
// DecodeCompressed decodes a point in the compressed form | |||
// Take a point P in G2 decoded (ie: written in affine form where each coordinate is MontDecoded) | |||
// and encodes it by going back to Jacobian coordinates and montEncode all coordinates | |||
func (e *G2) DecodeCompressed(encoding []byte) error { | |||
if len(encoding) != G2CompressedSize { | |||
return errors.New("wrong encoded point size") | |||
} | |||
if encoding[0]&serializationCompressed == 0 { // Also test the length of the encoding to make sure it is 33bytes | |||
return errors.New("point isn't compressed") | |||
} | |||
// Unmarshal the points and check their caps | |||
if e.p == nil { | |||
e.p = &twistPoint{} | |||
} else { | |||
e.p.x.SetZero() | |||
e.p.y.SetZero() | |||
e.p.z.SetOne() | |||
e.p.t.SetOne() | |||
} | |||
// Removes the bits of the masking (This does a bitwise AND with `0001 1111`) | |||
// And thus removes the first 3 bits corresponding to the masking | |||
bin := make([]byte, G2CompressedSize) | |||
copy(bin, encoding) | |||
bin[0] &= serializationMask | |||
// Decode the point at infinity in the compressed form | |||
if encoding[0]&serializationInfinity != 0 { | |||
if encoding[0]&serializationBigY != 0 { | |||
return errors.New("high Y bit improperly set") | |||
} | |||
// Similar to `for i:=0; i<len(bin); i++ {}` | |||
for i := range bin { | |||
// Makes sense to check that all bytes of bin are 0x0 since we removed the masking above | |||
if bin[i] != 0 { | |||
return errors.New("invalid infinity encoding") | |||
} | |||
} | |||
e.p.SetInfinity() | |||
return nil | |||
} | |||
// Decompress the point P (P =/= ∞) | |||
var err error | |||
if err = e.p.x.x.Unmarshal(bin[1:]); err != nil { | |||
return err | |||
} | |||
if err = e.p.x.y.Unmarshal(bin[FqElementSize+1:]); err != nil { | |||
return err | |||
} | |||
// MontEncode our field elements for fast finite field arithmetic | |||
// Needs to be done since the z and t coordinates are also encoded (ie: created with newGFp) | |||
montEncode(&e.p.x.x, &e.p.x.x) | |||
montEncode(&e.p.x.y, &e.p.x.y) | |||
y, err := getYFromMontEncodedXG2(&e.p.x) | |||
if err != nil { | |||
return err | |||
} | |||
e.p.y = *y | |||
// The flag serializationBigY is set (so the point pt with the higher Y is encoded) | |||
// but the point e retrieved from the `getYFromX` is NOT the higher, then we inverse | |||
if !e.IsHigherY() { | |||
if encoding[0]&serializationBigY != 0 { | |||