├── go.mod ├── go.sum ├── gfp_decl.go ├── .github └── workflows │ ├── semgrep.yml │ └── ci-actions.yml ├── example_test.go ├── LICENSE ├── README.md ├── hash.go ├── gfp_arm64.s ├── mul_bmi2_amd64.h ├── gfp_amd64.s ├── gfp.go ├── mul_arm64.h ├── gfp2.go ├── constants.go ├── mul_amd64.h ├── gfp_generic.go ├── gfp_test.go ├── hash_test.go ├── twist.go ├── gfp12.go ├── bn256_test.go ├── curve.go ├── gfp6.go ├── optate.go └── bn256.go /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/cloudflare/bn256 2 | 3 | go 1.24.0 4 | 5 | require ( 6 | golang.org/x/crypto v0.45.0 7 | golang.org/x/sys v0.38.0 8 | ) 9 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= 2 | golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= 3 | golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= 4 | golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= 5 | -------------------------------------------------------------------------------- /gfp_decl.go: -------------------------------------------------------------------------------- 1 | // +build amd64,!generic arm64,!generic 2 | 3 | package bn256 4 | 5 | // This file contains forward declarations for the architecture-specific 6 | // assembly implementations of these functions, provided that they exist. 7 | 8 | import ( 9 | "golang.org/x/sys/cpu" 10 | ) 11 | 12 | var hasBMI2 = cpu.X86.HasBMI2 13 | 14 | //go:noescape 15 | func gfpNeg(c, a *gfP) 16 | 17 | //go:noescape 18 | func gfpAdd(c, a, b *gfP) 19 | 20 | //go:noescape 21 | func gfpSub(c, a, b *gfP) 22 | 23 | //go:noescape 24 | func gfpMul(c, a, b *gfP) 25 | -------------------------------------------------------------------------------- /.github/workflows/semgrep.yml: -------------------------------------------------------------------------------- 1 | on: 2 | pull_request: {} 3 | workflow_dispatch: {} 4 | push: 5 | branches: 6 | - master 7 | schedule: 8 | - cron: '0 0 * * *' 9 | permissions: 10 | contents: read 11 | name: Semgrep 12 | jobs: 13 | semgrep: 14 | name: semgrep/ci 15 | runs-on: ubuntu-latest 16 | if: github.repository == 'cloudflare/bn256' 17 | env: 18 | SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }} 19 | SEMGREP_URL: https://cloudflare.semgrep.dev 20 | SEMGREP_APP_URL: https://cloudflare.semgrep.dev 21 | SEMGREP_VERSION_CHECK_URL: https://cloudflare.semgrep.dev/api/check-version 22 | container: 23 | image: semgrep/semgrep 24 | steps: 25 | - uses: actions/checkout@v4 26 | - run: semgrep ci --verbose 27 | -------------------------------------------------------------------------------- /example_test.go: -------------------------------------------------------------------------------- 1 | package bn256 2 | 3 | import ( 4 | "crypto/rand" 5 | ) 6 | 7 | func ExamplePair() { 8 | // This implements the tripartite Diffie-Hellman algorithm from "A One 9 | // Round Protocol for Tripartite Diffie-Hellman", A. Joux. 10 | // http://www.springerlink.com/content/cddc57yyva0hburb/fulltext.pdf 11 | 12 | // Each of three parties, a, b and c, generate a private value. 13 | a, _ := rand.Int(rand.Reader, Order) 14 | b, _ := rand.Int(rand.Reader, Order) 15 | c, _ := rand.Int(rand.Reader, Order) 16 | 17 | // Then each party calculates g₁ and g₂ times their private value. 18 | pa := new(G1).ScalarBaseMult(a) 19 | qa := new(G2).ScalarBaseMult(a) 20 | 21 | pb := new(G1).ScalarBaseMult(b) 22 | qb := new(G2).ScalarBaseMult(b) 23 | 24 | pc := new(G1).ScalarBaseMult(c) 25 | qc := new(G2).ScalarBaseMult(c) 26 | 27 | // Now each party exchanges its public values with the other two and 28 | // all parties can calculate the shared key. 29 | k1 := Pair(pb, qc) 30 | k1.ScalarMult(k1, a) 31 | 32 | k2 := Pair(pc, qa) 33 | k2.ScalarMult(k2, b) 34 | 35 | k3 := Pair(pa, qb) 36 | k3.ScalarMult(k3, c) 37 | 38 | // k1, k2 and k3 will all be equal. 39 | } 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009 The Go Authors. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Google Inc. nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | bn256 2 | ----- 3 | 4 | Package bn256 implements a particular bilinear group. 5 | 6 | Bilinear groups are the basis of many of the new cryptographic protocols that 7 | have been proposed over the past decade. They consist of a triplet of groups 8 | (G₁, G₂ and GT) such that there exists a function e(g₁ˣ,g₂ʸ)=gTˣʸ (where gₓ is a 9 | generator of the respective group). That function is called a pairing function. 10 | 11 | This package specifically implements the Optimal Ate pairing over a 256-bit 12 | Barreto-Naehrig curve as described in 13 | http://cryptojedi.org/papers/dclxvi-20100714.pdf. Its output is compatible with 14 | the implementation described in that paper. 15 | 16 | This package previously claimed to operate at a 128-bit security level. However, 17 | recent improvements in attacks mean that is no longer true. See 18 | https://moderncrypto.org/mail-archive/curves/2016/000740.html. 19 | 20 | ### Benchmarks 21 | 22 | branch `master`: 23 | ``` 24 | BenchmarkG1-4 10000 154995 ns/op 25 | BenchmarkG2-4 3000 541503 ns/op 26 | BenchmarkGT-4 1000 1267811 ns/op 27 | BenchmarkPairing-4 1000 1630584 ns/op 28 | ``` 29 | 30 | branch `lattices`: 31 | ``` 32 | BenchmarkG1-4 20000 92198 ns/op 33 | BenchmarkG2-4 5000 340622 ns/op 34 | BenchmarkGT-4 2000 635061 ns/op 35 | BenchmarkPairing-4 1000 1629943 ns/op 36 | ``` 37 | 38 | official version: 39 | ``` 40 | BenchmarkG1-4 1000 2268491 ns/op 41 | BenchmarkG2-4 300 7227637 ns/op 42 | BenchmarkGT-4 100 15121359 ns/op 43 | BenchmarkPairing-4 50 20296164 ns/op 44 | ``` 45 | -------------------------------------------------------------------------------- /.github/workflows/ci-actions.yml: -------------------------------------------------------------------------------- 1 | name: Cloudflare/bn256 2 | on: 3 | push: 4 | branches: 5 | - master 6 | pull_request: 7 | branches: 8 | - master 9 | permissions: 10 | contents: read 11 | jobs: 12 | amd64_job: 13 | name: Go-${{matrix.GOVER}}/amd64 14 | runs-on: ubuntu-22.04 15 | strategy: 16 | matrix: 17 | GOVER: ['1.24', '1.23'] 18 | steps: 19 | - name: Checkout 20 | uses: actions/checkout@v4 21 | - name: Setup Go-${{ matrix.GOVER }} 22 | uses: actions/setup-go@v5 23 | with: 24 | go-version: ${{ matrix.GOVER }} 25 | - name: Building 26 | run: go build -v ./... 27 | - name: Testing 28 | run: go test -v -count=1 ./... 29 | arm64_job: 30 | name: Go-${{matrix.GOVER}}/arm64 31 | needs: [amd64_job] 32 | runs-on: ubuntu-24.04-arm 33 | strategy: 34 | matrix: 35 | GOVER: ['1.24', '1.23'] 36 | steps: 37 | - uses: actions/checkout@v4 38 | - name: Setup Go-${{ matrix.GOVER }} 39 | uses: actions/setup-go@v5 40 | with: 41 | go-version: ${{ matrix.GOVER }} 42 | - name: Building 43 | run: go build -v ./... 44 | - name: Testing 45 | run: go test -v -count=1 ./... 46 | osCompat: 47 | runs-on: ${{ matrix.os }} 48 | name: Running on ${{ matrix.os }} 49 | strategy: 50 | matrix: 51 | os: [macos-latest, windows-latest] 52 | steps: 53 | - name: Checkout 54 | uses: actions/checkout@v4 55 | - name: Setup Go 56 | uses: actions/setup-go@v5 57 | with: 58 | go-version: '1.24' 59 | - name: Building 60 | run: go build -v ./... 61 | - name: Testing 62 | run: go test -v -count=1 ./... 63 | -------------------------------------------------------------------------------- /hash.go: -------------------------------------------------------------------------------- 1 | package bn256 2 | 3 | // HashG1 implements a hashing function into the G1 group. 4 | // 5 | // dst represents domain separation tag, similar to salt, for the hash. 6 | func HashG1(msg, dst []byte) *G1 { 7 | return mapToCurve(hashToBase(msg, dst)) 8 | } 9 | 10 | func mapToCurve(t *gfP) *G1 { 11 | one := *newGFp(1) 12 | 13 | // calculate w = (s * t)/(1 + B + t^2) 14 | // we calculate w0 = s * t * (1 + B + t^2) and inverse of it, so that w = (st)^2/w0 15 | // and then later x3 = 1 + (1 + B + t^2)^4/w0^2 16 | w := &gfP{} 17 | 18 | // a = (1 + B + t^2) 19 | a := &gfP{} 20 | t2 := &gfP{} 21 | gfpMul(t2, t, t) 22 | gfpAdd(a, curveB, t2) 23 | gfpAdd(a, a, &one) 24 | 25 | st := &gfP{} 26 | gfpMul(st, s, t) 27 | 28 | w0 := &gfP{} 29 | gfpMul(w0, st, a) 30 | w0.Invert(w0) 31 | 32 | gfpMul(w, st, st) 33 | gfpMul(w, w, w0) 34 | 35 | e := sign0(t) 36 | cp := &curvePoint{z: one, t: one} 37 | 38 | // calculate x1 = ((-1 + s) / 2) - t * w 39 | tw := &gfP{} 40 | gfpMul(tw, t, w) 41 | x1 := &gfP{} 42 | gfpSub(x1, sMinus1Over2, tw) 43 | 44 | // check if y=x1^3+3 is a square 45 | y := &gfP{} 46 | y.Set(x1) 47 | gfpMul(y, x1, x1) 48 | gfpMul(y, y, x1) 49 | gfpAdd(y, y, curveB) 50 | if legendre(y) == 1 { 51 | cp.x = *x1 52 | y.Sqrt(y) 53 | if e != sign0(y) { 54 | gfpNeg(y, y) 55 | } 56 | cp.y = *y 57 | return &G1{cp} 58 | } 59 | 60 | // calculate x2 = -1 - x1 61 | x2 := newGFp(-1) 62 | gfpSub(x2, x2, x1) 63 | 64 | // check if y=x2^3+3 is a square 65 | y.Set(x2) 66 | gfpMul(y, x2, x2) 67 | gfpMul(y, y, x2) 68 | gfpAdd(y, y, curveB) 69 | if legendre(y) == 1 { 70 | cp.x = *x2 71 | y.Sqrt(y) 72 | if e != sign0(y) { 73 | gfpNeg(y, y) 74 | } 75 | cp.y = *y 76 | return &G1{cp} 77 | } 78 | 79 | // calculate x3 = 1 + (1/ww) = 1 + a^4 * w0^2 80 | x3 := &gfP{} 81 | gfpMul(x3, a, a) 82 | gfpMul(x3, x3, x3) 83 | gfpMul(x3, x3, w0) 84 | gfpMul(x3, x3, w0) 85 | gfpAdd(x3, x3, &one) 86 | 87 | y.Set(x3) 88 | gfpMul(y, x3, x3) 89 | gfpMul(y, y, x3) 90 | gfpAdd(y, y, curveB) 91 | 92 | cp.x = *x3 93 | y.Sqrt(y) 94 | if e != sign0(y) { 95 | gfpNeg(y, y) 96 | } 97 | cp.y = *y 98 | 99 | return &G1{cp} 100 | } 101 | -------------------------------------------------------------------------------- /gfp_arm64.s: -------------------------------------------------------------------------------- 1 | // +build arm64,!generic 2 | 3 | #define storeBlock(a0,a1,a2,a3, r) \ 4 | MOVD a0, 0+r \ 5 | MOVD a1, 8+r \ 6 | MOVD a2, 16+r \ 7 | MOVD a3, 24+r 8 | 9 | #define loadBlock(r, a0,a1,a2,a3) \ 10 | MOVD 0+r, a0 \ 11 | MOVD 8+r, a1 \ 12 | MOVD 16+r, a2 \ 13 | MOVD 24+r, a3 14 | 15 | #define loadModulus(p0,p1,p2,p3) \ 16 | MOVD ·p2+0(SB), p0 \ 17 | MOVD ·p2+8(SB), p1 \ 18 | MOVD ·p2+16(SB), p2 \ 19 | MOVD ·p2+24(SB), p3 20 | 21 | #include "mul_arm64.h" 22 | 23 | TEXT ·gfpNeg(SB),0,$0-16 24 | MOVD a+8(FP), R0 25 | loadBlock(0(R0), R1,R2,R3,R4) 26 | loadModulus(R5,R6,R7,R8) 27 | 28 | SUBS R1, R5, R1 29 | SBCS R2, R6, R2 30 | SBCS R3, R7, R3 31 | SBCS R4, R8, R4 32 | 33 | SUBS R5, R1, R5 34 | SBCS R6, R2, R6 35 | SBCS R7, R3, R7 36 | SBCS R8, R4, R8 37 | 38 | CSEL CS, R5, R1, R1 39 | CSEL CS, R6, R2, R2 40 | CSEL CS, R7, R3, R3 41 | CSEL CS, R8, R4, R4 42 | 43 | MOVD c+0(FP), R0 44 | storeBlock(R1,R2,R3,R4, 0(R0)) 45 | RET 46 | 47 | TEXT ·gfpAdd(SB),0,$0-24 48 | MOVD a+8(FP), R0 49 | loadBlock(0(R0), R1,R2,R3,R4) 50 | MOVD b+16(FP), R0 51 | loadBlock(0(R0), R5,R6,R7,R8) 52 | loadModulus(R9,R10,R11,R12) 53 | MOVD ZR, R0 54 | 55 | ADDS R5, R1 56 | ADCS R6, R2 57 | ADCS R7, R3 58 | ADCS R8, R4 59 | ADCS ZR, R0 60 | 61 | SUBS R9, R1, R5 62 | SBCS R10, R2, R6 63 | SBCS R11, R3, R7 64 | SBCS R12, R4, R8 65 | SBCS ZR, R0, R0 66 | 67 | CSEL CS, R5, R1, R1 68 | CSEL CS, R6, R2, R2 69 | CSEL CS, R7, R3, R3 70 | CSEL CS, R8, R4, R4 71 | 72 | MOVD c+0(FP), R0 73 | storeBlock(R1,R2,R3,R4, 0(R0)) 74 | RET 75 | 76 | TEXT ·gfpSub(SB),0,$0-24 77 | MOVD a+8(FP), R0 78 | loadBlock(0(R0), R1,R2,R3,R4) 79 | MOVD b+16(FP), R0 80 | loadBlock(0(R0), R5,R6,R7,R8) 81 | loadModulus(R9,R10,R11,R12) 82 | 83 | SUBS R5, R1 84 | SBCS R6, R2 85 | SBCS R7, R3 86 | SBCS R8, R4 87 | 88 | CSEL CS, ZR, R9, R9 89 | CSEL CS, ZR, R10, R10 90 | CSEL CS, ZR, R11, R11 91 | CSEL CS, ZR, R12, R12 92 | 93 | ADDS R9, R1 94 | ADCS R10, R2 95 | ADCS R11, R3 96 | ADCS R12, R4 97 | 98 | MOVD c+0(FP), R0 99 | storeBlock(R1,R2,R3,R4, 0(R0)) 100 | RET 101 | 102 | TEXT ·gfpMul(SB),0,$0-24 103 | MOVD a+8(FP), R0 104 | loadBlock(0(R0), R1,R2,R3,R4) 105 | MOVD b+16(FP), R0 106 | loadBlock(0(R0), R5,R6,R7,R8) 107 | 108 | mul(R9,R10,R11,R12,R13,R14,R15,R16) 109 | gfpReduce() 110 | 111 | MOVD c+0(FP), R0 112 | storeBlock(R1,R2,R3,R4, 0(R0)) 113 | RET 114 | -------------------------------------------------------------------------------- /mul_bmi2_amd64.h: -------------------------------------------------------------------------------- 1 | #define mulBMI2(a0,a1,a2,a3, rb) \ 2 | MOVQ a0, DX \ 3 | MOVQ $0, R13 \ 4 | MULXQ 0+rb, R8, R9 \ 5 | MULXQ 8+rb, AX, R10 \ 6 | ADDQ AX, R9 \ 7 | MULXQ 16+rb, AX, R11 \ 8 | ADCQ AX, R10 \ 9 | MULXQ 24+rb, AX, R12 \ 10 | ADCQ AX, R11 \ 11 | ADCQ $0, R12 \ 12 | ADCQ $0, R13 \ 13 | \ 14 | MOVQ a1, DX \ 15 | MOVQ $0, R14 \ 16 | MULXQ 0+rb, AX, BX \ 17 | ADDQ AX, R9 \ 18 | ADCQ BX, R10 \ 19 | MULXQ 16+rb, AX, BX \ 20 | ADCQ AX, R11 \ 21 | ADCQ BX, R12 \ 22 | ADCQ $0, R13 \ 23 | MULXQ 8+rb, AX, BX \ 24 | ADDQ AX, R10 \ 25 | ADCQ BX, R11 \ 26 | MULXQ 24+rb, AX, BX \ 27 | ADCQ AX, R12 \ 28 | ADCQ BX, R13 \ 29 | ADCQ $0, R14 \ 30 | \ 31 | MOVQ a2, DX \ 32 | MOVQ $0, CX \ 33 | MULXQ 0+rb, AX, BX \ 34 | ADDQ AX, R10 \ 35 | ADCQ BX, R11 \ 36 | MULXQ 16+rb, AX, BX \ 37 | ADCQ AX, R12 \ 38 | ADCQ BX, R13 \ 39 | ADCQ $0, R14 \ 40 | MULXQ 8+rb, AX, BX \ 41 | ADDQ AX, R11 \ 42 | ADCQ BX, R12 \ 43 | MULXQ 24+rb, AX, BX \ 44 | ADCQ AX, R13 \ 45 | ADCQ BX, R14 \ 46 | ADCQ $0, CX \ 47 | \ 48 | MOVQ a3, DX \ 49 | MULXQ 0+rb, AX, BX \ 50 | ADDQ AX, R11 \ 51 | ADCQ BX, R12 \ 52 | MULXQ 16+rb, AX, BX \ 53 | ADCQ AX, R13 \ 54 | ADCQ BX, R14 \ 55 | ADCQ $0, CX \ 56 | MULXQ 8+rb, AX, BX \ 57 | ADDQ AX, R12 \ 58 | ADCQ BX, R13 \ 59 | MULXQ 24+rb, AX, BX \ 60 | ADCQ AX, R14 \ 61 | ADCQ BX, CX 62 | 63 | #define gfpReduceBMI2() \ 64 | \ // m = (T * N') mod R, store m in R8:R9:R10:R11 65 | MOVQ ·np+0(SB), DX \ 66 | MULXQ 0(SP), R8, R9 \ 67 | MULXQ 8(SP), AX, R10 \ 68 | ADDQ AX, R9 \ 69 | MULXQ 16(SP), AX, R11 \ 70 | ADCQ AX, R10 \ 71 | MULXQ 24(SP), AX, BX \ 72 | ADCQ AX, R11 \ 73 | \ 74 | MOVQ ·np+8(SB), DX \ 75 | MULXQ 0(SP), AX, BX \ 76 | ADDQ AX, R9 \ 77 | ADCQ BX, R10 \ 78 | MULXQ 16(SP), AX, BX \ 79 | ADCQ AX, R11 \ 80 | MULXQ 8(SP), AX, BX \ 81 | ADDQ AX, R10 \ 82 | ADCQ BX, R11 \ 83 | \ 84 | MOVQ ·np+16(SB), DX \ 85 | MULXQ 0(SP), AX, BX \ 86 | ADDQ AX, R10 \ 87 | ADCQ BX, R11 \ 88 | MULXQ 8(SP), AX, BX \ 89 | ADDQ AX, R11 \ 90 | \ 91 | MOVQ ·np+24(SB), DX \ 92 | MULXQ 0(SP), AX, BX \ 93 | ADDQ AX, R11 \ 94 | \ 95 | storeBlock(R8,R9,R10,R11, 64(SP)) \ 96 | \ 97 | \ // m * N 98 | mulBMI2(·p2+0(SB),·p2+8(SB),·p2+16(SB),·p2+24(SB), 64(SP)) \ 99 | \ 100 | \ // Add the 512-bit intermediate to m*N 101 | MOVQ $0, AX \ 102 | ADDQ 0(SP), R8 \ 103 | ADCQ 8(SP), R9 \ 104 | ADCQ 16(SP), R10 \ 105 | ADCQ 24(SP), R11 \ 106 | ADCQ 32(SP), R12 \ 107 | ADCQ 40(SP), R13 \ 108 | ADCQ 48(SP), R14 \ 109 | ADCQ 56(SP), CX \ 110 | ADCQ $0, AX \ 111 | \ 112 | gfpCarry(R12,R13,R14,CX,AX, R8,R9,R10,R11,BX) 113 | -------------------------------------------------------------------------------- /gfp_amd64.s: -------------------------------------------------------------------------------- 1 | // +build amd64,!generic 2 | 3 | #define storeBlock(a0,a1,a2,a3, r) \ 4 | MOVQ a0, 0+r \ 5 | MOVQ a1, 8+r \ 6 | MOVQ a2, 16+r \ 7 | MOVQ a3, 24+r 8 | 9 | #define loadBlock(r, a0,a1,a2,a3) \ 10 | MOVQ 0+r, a0 \ 11 | MOVQ 8+r, a1 \ 12 | MOVQ 16+r, a2 \ 13 | MOVQ 24+r, a3 14 | 15 | #define gfpCarry(a0,a1,a2,a3,a4, b0,b1,b2,b3,b4) \ 16 | \ // b = a-p 17 | MOVQ a0, b0 \ 18 | MOVQ a1, b1 \ 19 | MOVQ a2, b2 \ 20 | MOVQ a3, b3 \ 21 | MOVQ a4, b4 \ 22 | \ 23 | SUBQ ·p2+0(SB), b0 \ 24 | SBBQ ·p2+8(SB), b1 \ 25 | SBBQ ·p2+16(SB), b2 \ 26 | SBBQ ·p2+24(SB), b3 \ 27 | SBBQ $0, b4 \ 28 | \ 29 | \ // if b is negative then return a 30 | \ // else return b 31 | CMOVQCC b0, a0 \ 32 | CMOVQCC b1, a1 \ 33 | CMOVQCC b2, a2 \ 34 | CMOVQCC b3, a3 35 | 36 | #include "mul_amd64.h" 37 | #include "mul_bmi2_amd64.h" 38 | 39 | TEXT ·gfpNeg(SB),0,$0-16 40 | MOVQ ·p2+0(SB), R8 41 | MOVQ ·p2+8(SB), R9 42 | MOVQ ·p2+16(SB), R10 43 | MOVQ ·p2+24(SB), R11 44 | 45 | MOVQ a+8(FP), DI 46 | SUBQ 0(DI), R8 47 | SBBQ 8(DI), R9 48 | SBBQ 16(DI), R10 49 | SBBQ 24(DI), R11 50 | 51 | MOVQ $0, AX 52 | gfpCarry(R8,R9,R10,R11,AX, R12,R13,R14,CX,BX) 53 | 54 | MOVQ c+0(FP), DI 55 | storeBlock(R8,R9,R10,R11, 0(DI)) 56 | RET 57 | 58 | TEXT ·gfpAdd(SB),0,$0-24 59 | MOVQ a+8(FP), DI 60 | MOVQ b+16(FP), SI 61 | 62 | loadBlock(0(DI), R8,R9,R10,R11) 63 | MOVQ $0, R12 64 | 65 | ADDQ 0(SI), R8 66 | ADCQ 8(SI), R9 67 | ADCQ 16(SI), R10 68 | ADCQ 24(SI), R11 69 | ADCQ $0, R12 70 | 71 | gfpCarry(R8,R9,R10,R11,R12, R13,R14,CX,AX,BX) 72 | 73 | MOVQ c+0(FP), DI 74 | storeBlock(R8,R9,R10,R11, 0(DI)) 75 | RET 76 | 77 | TEXT ·gfpSub(SB),0,$0-24 78 | MOVQ a+8(FP), DI 79 | MOVQ b+16(FP), SI 80 | 81 | loadBlock(0(DI), R8,R9,R10,R11) 82 | 83 | MOVQ ·p2+0(SB), R12 84 | MOVQ ·p2+8(SB), R13 85 | MOVQ ·p2+16(SB), R14 86 | MOVQ ·p2+24(SB), CX 87 | MOVQ $0, AX 88 | 89 | SUBQ 0(SI), R8 90 | SBBQ 8(SI), R9 91 | SBBQ 16(SI), R10 92 | SBBQ 24(SI), R11 93 | 94 | CMOVQCC AX, R12 95 | CMOVQCC AX, R13 96 | CMOVQCC AX, R14 97 | CMOVQCC AX, CX 98 | 99 | ADDQ R12, R8 100 | ADCQ R13, R9 101 | ADCQ R14, R10 102 | ADCQ CX, R11 103 | 104 | MOVQ c+0(FP), DI 105 | storeBlock(R8,R9,R10,R11, 0(DI)) 106 | RET 107 | 108 | TEXT ·gfpMul(SB),0,$160-24 109 | MOVQ a+8(FP), DI 110 | MOVQ b+16(FP), SI 111 | 112 | // Jump to a slightly different implementation if MULX isn't supported. 113 | CMPB ·hasBMI2(SB), $0 114 | JE nobmi2Mul 115 | 116 | mulBMI2(0(DI),8(DI),16(DI),24(DI), 0(SI)) 117 | storeBlock( R8, R9,R10,R11, 0(SP)) 118 | storeBlock(R12,R13,R14,CX, 32(SP)) 119 | gfpReduceBMI2() 120 | JMP end 121 | 122 | nobmi2Mul: 123 | mul(0(DI),8(DI),16(DI),24(DI), 0(SI), 0(SP)) 124 | gfpReduce(0(SP)) 125 | 126 | end: 127 | MOVQ c+0(FP), DI 128 | storeBlock(R12,R13,R14,CX, 0(DI)) 129 | RET 130 | -------------------------------------------------------------------------------- /gfp.go: -------------------------------------------------------------------------------- 1 | package bn256 2 | 3 | import ( 4 | "crypto/sha256" 5 | "encoding/binary" 6 | "fmt" 7 | "math/big" 8 | 9 | "golang.org/x/crypto/hkdf" 10 | ) 11 | 12 | type gfP [4]uint64 13 | 14 | func newGFp(x int64) (out *gfP) { 15 | if x >= 0 { 16 | out = &gfP{uint64(x)} 17 | } else { 18 | out = &gfP{uint64(-x)} 19 | gfpNeg(out, out) 20 | } 21 | 22 | montEncode(out, out) 23 | return out 24 | } 25 | 26 | // hashToBase implements hashing a message to an element of the field. 27 | // 28 | // L = ceil((256+128)/8)=48, ctr = 0, i = 1 29 | func hashToBase(msg, dst []byte) *gfP { 30 | var t [48]byte 31 | info := []byte{'H', '2', 'C', byte(0), byte(1)} 32 | r := hkdf.New(sha256.New, msg, dst, info) 33 | if _, err := r.Read(t[:]); err != nil { 34 | panic(err) 35 | } 36 | var x big.Int 37 | v := x.SetBytes(t[:]).Mod(&x, p).Bytes() 38 | v32 := [32]byte{} 39 | for i := len(v) - 1; i >= 0; i-- { 40 | v32[len(v)-1-i] = v[i] 41 | } 42 | u := &gfP{ 43 | binary.LittleEndian.Uint64(v32[0*8 : 1*8]), 44 | binary.LittleEndian.Uint64(v32[1*8 : 2*8]), 45 | binary.LittleEndian.Uint64(v32[2*8 : 3*8]), 46 | binary.LittleEndian.Uint64(v32[3*8 : 4*8]), 47 | } 48 | montEncode(u, u) 49 | return u 50 | } 51 | 52 | func (e *gfP) String() string { 53 | return fmt.Sprintf("%16.16x%16.16x%16.16x%16.16x", e[3], e[2], e[1], e[0]) 54 | } 55 | 56 | func (e *gfP) Set(f *gfP) { 57 | e[0] = f[0] 58 | e[1] = f[1] 59 | e[2] = f[2] 60 | e[3] = f[3] 61 | } 62 | 63 | func (e *gfP) exp(f *gfP, bits [4]uint64) { 64 | sum, power := &gfP{}, &gfP{} 65 | sum.Set(rN1) 66 | power.Set(f) 67 | 68 | for word := 0; word < 4; word++ { 69 | for bit := uint(0); bit < 64; bit++ { 70 | if (bits[word]>>bit)&1 == 1 { 71 | gfpMul(sum, sum, power) 72 | } 73 | gfpMul(power, power, power) 74 | } 75 | } 76 | 77 | gfpMul(sum, sum, r3) 78 | e.Set(sum) 79 | } 80 | 81 | func (e *gfP) Invert(f *gfP) { 82 | e.exp(f, pMinus2) 83 | } 84 | 85 | func (e *gfP) Sqrt(f *gfP) { 86 | // Since p = 4k+3, then e = f^(k+1) is a root of f. 87 | e.exp(f, pPlus1Over4) 88 | } 89 | 90 | func (e *gfP) Marshal(out []byte) { 91 | for w := uint(0); w < 4; w++ { 92 | for b := uint(0); b < 8; b++ { 93 | out[8*w+b] = byte(e[3-w] >> (56 - 8*b)) 94 | } 95 | } 96 | } 97 | 98 | func (e *gfP) Unmarshal(in []byte) { 99 | for w := uint(0); w < 4; w++ { 100 | e[3-w] = 0 101 | for b := uint(0); b < 8; b++ { 102 | e[3-w] += uint64(in[8*w+b]) << (56 - 8*b) 103 | } 104 | } 105 | } 106 | 107 | func montEncode(c, a *gfP) { gfpMul(c, a, r2) } 108 | func montDecode(c, a *gfP) { gfpMul(c, a, &gfP{1}) } 109 | 110 | func sign0(e *gfP) int { 111 | x := &gfP{} 112 | montDecode(x, e) 113 | for w := 3; w >= 0; w-- { 114 | if x[w] > pMinus1Over2[w] { 115 | return 1 116 | } else if x[w] < pMinus1Over2[w] { 117 | return -1 118 | } 119 | } 120 | return 1 121 | } 122 | 123 | func legendre(e *gfP) int { 124 | f := &gfP{} 125 | // Since p = 4k+3, then e^(2k+1) is the Legendre symbol of e. 126 | f.exp(e, pMinus1Over2) 127 | 128 | montDecode(f, f) 129 | 130 | if *f != [4]uint64{} { 131 | return 2*int(f[0]&1) - 1 132 | } 133 | 134 | return 0 135 | } 136 | -------------------------------------------------------------------------------- /mul_arm64.h: -------------------------------------------------------------------------------- 1 | // mul multiplies two 256-bit numbers in little-endian order. 2 | // The inputs are (R1,R2,R3,R4) times (R5,R6,R7,R8) 3 | // and the product is stored in (c0,c1,c2,c3,c4,c5,c6,c7). 4 | // Note that the input registers (R1,R2,R3) are overwritten. 5 | #define mul(c0,c1,c2,c3,c4,c5,c6,c7) \ 6 | MUL R1, R5, c0 \ 7 | UMULH R1, R5, c1 \ 8 | MUL R1, R6, R0 \ 9 | ADDS R0, c1 \ 10 | UMULH R1, R6, c2 \ 11 | MUL R1, R7, R0 \ 12 | ADCS R0, c2 \ 13 | UMULH R1, R7, c3 \ 14 | MUL R1, R8, R0 \ 15 | ADCS R0, c3 \ 16 | UMULH R1, R8, c4 \ 17 | ADCS ZR, c4 \ 18 | \ 19 | MUL R2, R5, R1 \ 20 | UMULH R2, R5, R26 \ 21 | MUL R2, R6, R0 \ 22 | ADDS R0, R26 \ 23 | UMULH R2, R6, c6 \ 24 | MUL R2, R7, R0 \ 25 | ADCS R0, c6 \ 26 | UMULH R2, R7, c7 \ 27 | MUL R2, R8, R0 \ 28 | ADCS R0, c7 \ 29 | UMULH R2, R8, c5 \ 30 | ADCS ZR, c5 \ 31 | ADDS R1, c1 \ 32 | ADCS R26, c2 \ 33 | ADCS c6, c3 \ 34 | ADCS c7, c4 \ 35 | ADCS ZR, c5 \ 36 | \ 37 | MUL R3, R5, R1 \ 38 | UMULH R3, R5, R26 \ 39 | MUL R3, R6, R0 \ 40 | ADDS R0, R26 \ 41 | UMULH R3, R6, R2 \ 42 | MUL R3, R7, R0 \ 43 | ADCS R0, R2 \ 44 | UMULH R3, R7, c7 \ 45 | MUL R3, R8, R0 \ 46 | ADCS R0, c7 \ 47 | UMULH R3, R8, c6 \ 48 | ADCS ZR, c6 \ 49 | ADDS R1, c2 \ 50 | ADCS R26, c3 \ 51 | ADCS R2, c4 \ 52 | ADCS c7, c5 \ 53 | ADCS ZR, c6 \ 54 | \ 55 | MUL R4, R5, R1 \ 56 | UMULH R4, R5, R26 \ 57 | MUL R4, R6, R0 \ 58 | ADDS R0, R26 \ 59 | UMULH R4, R6, R2 \ 60 | MUL R4, R7, R0 \ 61 | ADCS R0, R2 \ 62 | UMULH R4, R7, R3 \ 63 | MUL R4, R8, R0 \ 64 | ADCS R0, R3 \ 65 | UMULH R4, R8, c7 \ 66 | ADCS ZR, c7 \ 67 | ADDS R1, c3 \ 68 | ADCS R26, c4 \ 69 | ADCS R2, c5 \ 70 | ADCS R3, c6 \ 71 | ADCS ZR, c7 72 | 73 | #define gfpReduce() \ 74 | \ // m = (T * N') mod R, store m in R1:R2:R3:R4 75 | MOVD ·np+0(SB), R17 \ 76 | MOVD ·np+8(SB), R25 \ 77 | MOVD ·np+16(SB), R19 \ 78 | MOVD ·np+24(SB), R20 \ 79 | \ 80 | MUL R9, R17, R1 \ 81 | UMULH R9, R17, R2 \ 82 | MUL R9, R25, R0 \ 83 | ADDS R0, R2 \ 84 | UMULH R9, R25, R3 \ 85 | MUL R9, R19, R0 \ 86 | ADCS R0, R3 \ 87 | UMULH R9, R19, R4 \ 88 | MUL R9, R20, R0 \ 89 | ADCS R0, R4 \ 90 | \ 91 | MUL R10, R17, R21 \ 92 | UMULH R10, R17, R22 \ 93 | MUL R10, R25, R0 \ 94 | ADDS R0, R22 \ 95 | UMULH R10, R25, R23 \ 96 | MUL R10, R19, R0 \ 97 | ADCS R0, R23 \ 98 | ADDS R21, R2 \ 99 | ADCS R22, R3 \ 100 | ADCS R23, R4 \ 101 | \ 102 | MUL R11, R17, R21 \ 103 | UMULH R11, R17, R22 \ 104 | MUL R11, R25, R0 \ 105 | ADDS R0, R22 \ 106 | ADDS R21, R3 \ 107 | ADCS R22, R4 \ 108 | \ 109 | MUL R12, R17, R21 \ 110 | ADDS R21, R4 \ 111 | \ 112 | \ // m * N 113 | loadModulus(R5,R6,R7,R8) \ 114 | mul(R17,R25,R19,R20,R21,R22,R23,R24) \ 115 | \ 116 | \ // Add the 512-bit intermediate to m*N 117 | MOVD ZR, R0 \ 118 | ADDS R9, R17 \ 119 | ADCS R10, R25 \ 120 | ADCS R11, R19 \ 121 | ADCS R12, R20 \ 122 | ADCS R13, R21 \ 123 | ADCS R14, R22 \ 124 | ADCS R15, R23 \ 125 | ADCS R16, R24 \ 126 | ADCS ZR, R0 \ 127 | \ 128 | \ // Our output is R21:R22:R23:R24. Reduce mod p if necessary. 129 | SUBS R5, R21, R10 \ 130 | SBCS R6, R22, R11 \ 131 | SBCS R7, R23, R12 \ 132 | SBCS R8, R24, R13 \ 133 | SBCS $0, R0, R0 \ 134 | \ 135 | CSEL CS, R10, R21, R1 \ 136 | CSEL CS, R11, R22, R2 \ 137 | CSEL CS, R12, R23, R3 \ 138 | CSEL CS, R13, R24, R4 139 | -------------------------------------------------------------------------------- /gfp2.go: -------------------------------------------------------------------------------- 1 | package bn256 2 | 3 | // For details of the algorithms used, see "Multiplication and Squaring on 4 | // Pairing-Friendly Fields, Devegili et al. 5 | // http://eprint.iacr.org/2006/471.pdf. 6 | 7 | // gfP2 implements a field of size p² as a quadratic extension of the base field 8 | // where i²=-1. 9 | type gfP2 struct { 10 | x, y gfP // value is xi+y. 11 | } 12 | 13 | func gfP2Decode(in *gfP2) *gfP2 { 14 | out := &gfP2{} 15 | montDecode(&out.x, &in.x) 16 | montDecode(&out.y, &in.y) 17 | return out 18 | } 19 | 20 | func (e *gfP2) String() string { 21 | return "(" + e.x.String() + ", " + e.y.String() + ")" 22 | } 23 | 24 | func (e *gfP2) Set(a *gfP2) *gfP2 { 25 | e.x.Set(&a.x) 26 | e.y.Set(&a.y) 27 | return e 28 | } 29 | 30 | func (e *gfP2) SetZero() *gfP2 { 31 | e.x = gfP{0} 32 | e.y = gfP{0} 33 | return e 34 | } 35 | 36 | func (e *gfP2) SetOne() *gfP2 { 37 | e.x = gfP{0} 38 | e.y = *newGFp(1) 39 | return e 40 | } 41 | 42 | func (e *gfP2) IsZero() bool { 43 | zero := gfP{0} 44 | return e.x == zero && e.y == zero 45 | } 46 | 47 | func (e *gfP2) IsOne() bool { 48 | zero, one := gfP{0}, *newGFp(1) 49 | return e.x == zero && e.y == one 50 | } 51 | 52 | func (e *gfP2) Conjugate(a *gfP2) *gfP2 { 53 | e.y.Set(&a.y) 54 | gfpNeg(&e.x, &a.x) 55 | return e 56 | } 57 | 58 | func (e *gfP2) Neg(a *gfP2) *gfP2 { 59 | gfpNeg(&e.x, &a.x) 60 | gfpNeg(&e.y, &a.y) 61 | return e 62 | } 63 | 64 | func (e *gfP2) Add(a, b *gfP2) *gfP2 { 65 | gfpAdd(&e.x, &a.x, &b.x) 66 | gfpAdd(&e.y, &a.y, &b.y) 67 | return e 68 | } 69 | 70 | func (e *gfP2) Sub(a, b *gfP2) *gfP2 { 71 | gfpSub(&e.x, &a.x, &b.x) 72 | gfpSub(&e.y, &a.y, &b.y) 73 | return e 74 | } 75 | 76 | // See "Multiplication and Squaring in Pairing-Friendly Fields", 77 | // http://eprint.iacr.org/2006/471.pdf 78 | func (e *gfP2) Mul(a, b *gfP2) *gfP2 { 79 | tx, t := &gfP{}, &gfP{} 80 | gfpMul(tx, &a.x, &b.y) 81 | gfpMul(t, &b.x, &a.y) 82 | gfpAdd(tx, tx, t) 83 | 84 | ty := &gfP{} 85 | gfpMul(ty, &a.y, &b.y) 86 | gfpMul(t, &a.x, &b.x) 87 | gfpSub(ty, ty, t) 88 | 89 | e.x.Set(tx) 90 | e.y.Set(ty) 91 | return e 92 | } 93 | 94 | func (e *gfP2) MulScalar(a *gfP2, b *gfP) *gfP2 { 95 | gfpMul(&e.x, &a.x, b) 96 | gfpMul(&e.y, &a.y, b) 97 | return e 98 | } 99 | 100 | // MulXi sets e=ξa where ξ=i+3 and then returns e. 101 | func (e *gfP2) MulXi(a *gfP2) *gfP2 { 102 | // (xi+y)(i+3) = (3x+y)i+(3y-x) 103 | tx := &gfP{} 104 | gfpAdd(tx, &a.x, &a.x) 105 | gfpAdd(tx, tx, &a.x) 106 | gfpAdd(tx, tx, &a.y) 107 | 108 | ty := &gfP{} 109 | gfpAdd(ty, &a.y, &a.y) 110 | gfpAdd(ty, ty, &a.y) 111 | gfpSub(ty, ty, &a.x) 112 | 113 | e.x.Set(tx) 114 | e.y.Set(ty) 115 | return e 116 | } 117 | 118 | func (e *gfP2) Square(a *gfP2) *gfP2 { 119 | // Complex squaring algorithm: 120 | // (xi+y)² = (x+y)(y-x) + 2*i*x*y 121 | tx, ty := &gfP{}, &gfP{} 122 | gfpSub(tx, &a.y, &a.x) 123 | gfpAdd(ty, &a.x, &a.y) 124 | gfpMul(ty, tx, ty) 125 | 126 | gfpMul(tx, &a.x, &a.y) 127 | gfpAdd(tx, tx, tx) 128 | 129 | e.x.Set(tx) 130 | e.y.Set(ty) 131 | return e 132 | } 133 | 134 | func (e *gfP2) Invert(a *gfP2) *gfP2 { 135 | // See "Implementing cryptographic pairings", M. Scott, section 3.2. 136 | // ftp://136.206.11.249/pub/crypto/pairings.pdf 137 | t1, t2 := &gfP{}, &gfP{} 138 | gfpMul(t1, &a.x, &a.x) 139 | gfpMul(t2, &a.y, &a.y) 140 | gfpAdd(t1, t1, t2) 141 | 142 | inv := &gfP{} 143 | inv.Invert(t1) 144 | 145 | gfpNeg(t1, &a.x) 146 | 147 | gfpMul(&e.x, t1, inv) 148 | gfpMul(&e.y, &a.y, inv) 149 | return e 150 | } 151 | -------------------------------------------------------------------------------- /constants.go: -------------------------------------------------------------------------------- 1 | package bn256 2 | 3 | import ( 4 | "math/big" 5 | ) 6 | 7 | func bigFromBase10(s string) *big.Int { 8 | n, _ := new(big.Int).SetString(s, 10) 9 | return n 10 | } 11 | 12 | // u is the BN parameter that determines the prime: 1868033³. 13 | var u = bigFromBase10("6518589491078791937") 14 | 15 | // p is a prime over which we form a basic field: 36u⁴+36u³+24u²+6u+1. 16 | var p = bigFromBase10("65000549695646603732796438742359905742825358107623003571877145026864184071783") 17 | 18 | // Order is the number of elements in both G₁ and G₂: 36u⁴+36u³+18u²+6u+1. 19 | // order-1 = (2**5) * 3 * 5743 * 280941149 * 130979359433191 * 491513138693455212421542731357 * 6518589491078791937 20 | var Order = bigFromBase10("65000549695646603732796438742359905742570406053903786389881062969044166799969") 21 | 22 | // xiToPMinus1Over6 is ξ^((p-1)/6) where ξ = i+3. 23 | var xiToPMinus1Over6 = &gfP2{gfP{0x25af52988477cdb7, 0x3d81a455ddced86a, 0x227d012e872c2431, 0x179198d3ea65d05}, gfP{0x7407634dd9cca958, 0x36d5bd6c7afb8f26, 0xf4b1c32cebd880fa, 0x6aa7869306f455f}} 24 | 25 | // xiToPMinus1Over3 is ξ^((p-1)/3) where ξ = i+3. 26 | var xiToPMinus1Over3 = &gfP2{gfP{0x4f59e37c01832e57, 0xae6be39ac2bbbfe4, 0xe04ea1bb697512f8, 0x3097caa8fc40e10e}, gfP{0xf8606916d3816f2c, 0x1e5c0d7926de927e, 0xbc45f3946d81185e, 0x80752a25aa738091}} 27 | 28 | // xiToPMinus1Over2 is ξ^((p-1)/2) where ξ = i+3. 29 | var xiToPMinus1Over2 = &gfP2{gfP{0x19da71333653ee20, 0x7eaaf34fc6ed6019, 0xc4ba3a29a60cdd1d, 0x75281311bcc9df79}, gfP{0x18dbee03fb7708fa, 0x1e7601a602c843c7, 0x5dde0688cdb231cb, 0x86db5cf2c605a524}} 30 | 31 | // xiToPSquaredMinus1Over3 is ξ^((p²-1)/3) where ξ = i+3. 32 | var xiToPSquaredMinus1Over3 = &gfP{0x12d3cef5e1ada57d, 0xe2eca1463753babb, 0xca41e40ddccf750, 0x551337060397e04c} 33 | 34 | // xiTo2PSquaredMinus2Over3 is ξ^((2p²-2)/3) where ξ = i+3 (a cubic root of unity, mod p). 35 | var xiTo2PSquaredMinus2Over3 = &gfP{0x3642364f386c1db8, 0xe825f92d2acd661f, 0xf2aba7e846c19d14, 0x5a0bcea3dc52b7a0} 36 | 37 | // xiToPSquaredMinus1Over6 is ξ^((1p²-1)/6) where ξ = i+3 (a cubic root of -1, mod p). 38 | var xiToPSquaredMinus1Over6 = &gfP{0xe21a761d259c78af, 0x6358fa3f5e84f7e, 0xb7c444d01ac33f0d, 0x35a9333f6e50d058} 39 | 40 | // xiTo2PMinus2Over3 is ξ^((2p-2)/3) where ξ = i+3. 41 | var xiTo2PMinus2Over3 = &gfP2{gfP{0x51678e7469b3c52a, 0x4fb98f8b13319fc9, 0x29b2254db3f1df75, 0x1c044935a3d22fb2}, gfP{0x4d2ea218872f3d2c, 0x2fcb27fc4abe7b69, 0xd31d972f0e88ced9, 0x53adc04a00a73b15}} 42 | 43 | // p2 is p, represented as little-endian 64-bit words. 44 | var p2 = [4]uint64{0x185cac6c5e089667, 0xee5b88d120b5b59e, 0xaa6fecb86184dc21, 0x8fb501e34aa387f9} 45 | 46 | // np is the negative inverse of p, mod 2^256. 47 | var np = [4]uint64{0x2387f9007f17daa9, 0x734b3343ab8513c8, 0x2524282f48054c12, 0x38997ae661c3ef3c} 48 | 49 | // rN1 is R^-1 where R = 2^256 mod p. 50 | var rN1 = &gfP{0xcbb781e36236117d, 0xcc65f3bcec8c91b, 0x2eab68888ea1f515, 0x1fc5c0956f92f825} 51 | 52 | // r2 is R^2 where R = 2^256 mod p. 53 | var r2 = &gfP{0x9c21c3ff7e444f56, 0x409ed151b2efb0c2, 0xc6dc37b80fb1651, 0x7c36e0e62c2380b7} 54 | 55 | // r3 is R^3 where R = 2^256 mod p. 56 | var r3 = &gfP{0x2af2dfb9324a5bb8, 0x388f899054f538a4, 0xdf2ff66396b107a7, 0x24ebbbb3a2529292} 57 | 58 | // pPlus1Over4 is (p+1)/4. 59 | var pPlus1Over4 = [4]uint64{0x86172b1b1782259a, 0x7b96e234482d6d67, 0x6a9bfb2e18613708, 0x23ed4078d2a8e1fe} 60 | 61 | // pMinus2 is p-2. 62 | var pMinus2 = [4]uint64{0x185cac6c5e089665, 0xee5b88d120b5b59e, 0xaa6fecb86184dc21, 0x8fb501e34aa387f9} 63 | 64 | // pMinus1Over2 is (p-1)/2. 65 | var pMinus1Over2 = [4]uint64{0x0c2e56362f044b33, 0xf72dc468905adacf, 0xd537f65c30c26e10, 0x47da80f1a551c3fc} 66 | 67 | // s is the Montgomery encoding of the square root of -3. Then, s = sqrt(-3) * 2^256 mod p. 68 | var s = &gfP{0x236e675956be783b, 0x053957e6f379ab64, 0xe60789a768f4a5c4, 0x04f8979dd8bad754} 69 | 70 | // sMinus1Over2 is the Montgomery encoding of (s-1)/2. Then, sMinus1Over2 = ( (s-1) / 2) * 2^256 mod p. 71 | var sMinus1Over2 = &gfP{0x3642364f386c1db8, 0xe825f92d2acd661f, 0xf2aba7e846c19d14, 0x5a0bcea3dc52b7a0} 72 | -------------------------------------------------------------------------------- /mul_amd64.h: -------------------------------------------------------------------------------- 1 | #define mul(a0,a1,a2,a3, rb, stack) \ 2 | MOVQ a0, AX \ 3 | MULQ 0+rb \ 4 | MOVQ AX, R8 \ 5 | MOVQ DX, R9 \ 6 | MOVQ a0, AX \ 7 | MULQ 8+rb \ 8 | ADDQ AX, R9 \ 9 | ADCQ $0, DX \ 10 | MOVQ DX, R10 \ 11 | MOVQ a0, AX \ 12 | MULQ 16+rb \ 13 | ADDQ AX, R10 \ 14 | ADCQ $0, DX \ 15 | MOVQ DX, R11 \ 16 | MOVQ a0, AX \ 17 | MULQ 24+rb \ 18 | ADDQ AX, R11 \ 19 | ADCQ $0, DX \ 20 | MOVQ DX, R12 \ 21 | \ 22 | storeBlock(R8,R9,R10,R11, 0+stack) \ 23 | MOVQ R12, 32+stack \ 24 | \ 25 | MOVQ a1, AX \ 26 | MULQ 0+rb \ 27 | MOVQ AX, R8 \ 28 | MOVQ DX, R9 \ 29 | MOVQ a1, AX \ 30 | MULQ 8+rb \ 31 | ADDQ AX, R9 \ 32 | ADCQ $0, DX \ 33 | MOVQ DX, R10 \ 34 | MOVQ a1, AX \ 35 | MULQ 16+rb \ 36 | ADDQ AX, R10 \ 37 | ADCQ $0, DX \ 38 | MOVQ DX, R11 \ 39 | MOVQ a1, AX \ 40 | MULQ 24+rb \ 41 | ADDQ AX, R11 \ 42 | ADCQ $0, DX \ 43 | MOVQ DX, R12 \ 44 | \ 45 | ADDQ 8+stack, R8 \ 46 | ADCQ 16+stack, R9 \ 47 | ADCQ 24+stack, R10 \ 48 | ADCQ 32+stack, R11 \ 49 | ADCQ $0, R12 \ 50 | storeBlock(R8,R9,R10,R11, 8+stack) \ 51 | MOVQ R12, 40+stack \ 52 | \ 53 | MOVQ a2, AX \ 54 | MULQ 0+rb \ 55 | MOVQ AX, R8 \ 56 | MOVQ DX, R9 \ 57 | MOVQ a2, AX \ 58 | MULQ 8+rb \ 59 | ADDQ AX, R9 \ 60 | ADCQ $0, DX \ 61 | MOVQ DX, R10 \ 62 | MOVQ a2, AX \ 63 | MULQ 16+rb \ 64 | ADDQ AX, R10 \ 65 | ADCQ $0, DX \ 66 | MOVQ DX, R11 \ 67 | MOVQ a2, AX \ 68 | MULQ 24+rb \ 69 | ADDQ AX, R11 \ 70 | ADCQ $0, DX \ 71 | MOVQ DX, R12 \ 72 | \ 73 | ADDQ 16+stack, R8 \ 74 | ADCQ 24+stack, R9 \ 75 | ADCQ 32+stack, R10 \ 76 | ADCQ 40+stack, R11 \ 77 | ADCQ $0, R12 \ 78 | storeBlock(R8,R9,R10,R11, 16+stack) \ 79 | MOVQ R12, 48+stack \ 80 | \ 81 | MOVQ a3, AX \ 82 | MULQ 0+rb \ 83 | MOVQ AX, R8 \ 84 | MOVQ DX, R9 \ 85 | MOVQ a3, AX \ 86 | MULQ 8+rb \ 87 | ADDQ AX, R9 \ 88 | ADCQ $0, DX \ 89 | MOVQ DX, R10 \ 90 | MOVQ a3, AX \ 91 | MULQ 16+rb \ 92 | ADDQ AX, R10 \ 93 | ADCQ $0, DX \ 94 | MOVQ DX, R11 \ 95 | MOVQ a3, AX \ 96 | MULQ 24+rb \ 97 | ADDQ AX, R11 \ 98 | ADCQ $0, DX \ 99 | MOVQ DX, R12 \ 100 | \ 101 | ADDQ 24+stack, R8 \ 102 | ADCQ 32+stack, R9 \ 103 | ADCQ 40+stack, R10 \ 104 | ADCQ 48+stack, R11 \ 105 | ADCQ $0, R12 \ 106 | storeBlock(R8,R9,R10,R11, 24+stack) \ 107 | MOVQ R12, 56+stack 108 | 109 | #define gfpReduce(stack) \ 110 | \ // m = (T * N') mod R, store m in R8:R9:R10:R11 111 | MOVQ ·np+0(SB), AX \ 112 | MULQ 0+stack \ 113 | MOVQ AX, R8 \ 114 | MOVQ DX, R9 \ 115 | MOVQ ·np+0(SB), AX \ 116 | MULQ 8+stack \ 117 | ADDQ AX, R9 \ 118 | ADCQ $0, DX \ 119 | MOVQ DX, R10 \ 120 | MOVQ ·np+0(SB), AX \ 121 | MULQ 16+stack \ 122 | ADDQ AX, R10 \ 123 | ADCQ $0, DX \ 124 | MOVQ DX, R11 \ 125 | MOVQ ·np+0(SB), AX \ 126 | MULQ 24+stack \ 127 | ADDQ AX, R11 \ 128 | \ 129 | MOVQ ·np+8(SB), AX \ 130 | MULQ 0+stack \ 131 | MOVQ AX, R12 \ 132 | MOVQ DX, R13 \ 133 | MOVQ ·np+8(SB), AX \ 134 | MULQ 8+stack \ 135 | ADDQ AX, R13 \ 136 | ADCQ $0, DX \ 137 | MOVQ DX, R14 \ 138 | MOVQ ·np+8(SB), AX \ 139 | MULQ 16+stack \ 140 | ADDQ AX, R14 \ 141 | \ 142 | ADDQ R12, R9 \ 143 | ADCQ R13, R10 \ 144 | ADCQ R14, R11 \ 145 | \ 146 | MOVQ ·np+16(SB), AX \ 147 | MULQ 0+stack \ 148 | MOVQ AX, R12 \ 149 | MOVQ DX, R13 \ 150 | MOVQ ·np+16(SB), AX \ 151 | MULQ 8+stack \ 152 | ADDQ AX, R13 \ 153 | \ 154 | ADDQ R12, R10 \ 155 | ADCQ R13, R11 \ 156 | \ 157 | MOVQ ·np+24(SB), AX \ 158 | MULQ 0+stack \ 159 | ADDQ AX, R11 \ 160 | \ 161 | storeBlock(R8,R9,R10,R11, 64+stack) \ 162 | \ 163 | \ // m * N 164 | mul(·p2+0(SB),·p2+8(SB),·p2+16(SB),·p2+24(SB), 64+stack, 96+stack) \ 165 | \ 166 | \ // Add the 512-bit intermediate to m*N 167 | loadBlock(96+stack, R8,R9,R10,R11) \ 168 | loadBlock(128+stack, R12,R13,R14,CX) \ 169 | \ 170 | MOVQ $0, AX \ 171 | ADDQ 0+stack, R8 \ 172 | ADCQ 8+stack, R9 \ 173 | ADCQ 16+stack, R10 \ 174 | ADCQ 24+stack, R11 \ 175 | ADCQ 32+stack, R12 \ 176 | ADCQ 40+stack, R13 \ 177 | ADCQ 48+stack, R14 \ 178 | ADCQ 56+stack, CX \ 179 | ADCQ $0, AX \ 180 | \ 181 | gfpCarry(R12,R13,R14,CX,AX, R8,R9,R10,R11,BX) 182 | -------------------------------------------------------------------------------- /gfp_generic.go: -------------------------------------------------------------------------------- 1 | // +build !amd64,!arm64 generic 2 | 3 | package bn256 4 | 5 | func gfpCarry(a *gfP, head uint64) { 6 | b := &gfP{} 7 | 8 | var carry uint64 9 | for i, pi := range p2 { 10 | ai := a[i] 11 | bi := ai - pi - carry 12 | b[i] = bi 13 | carry = (pi&^ai | (pi|^ai)&bi) >> 63 14 | } 15 | carry = carry &^ head 16 | 17 | // If b is negative, then return a. 18 | // Else return b. 19 | carry = -carry 20 | ncarry := ^carry 21 | for i := 0; i < 4; i++ { 22 | a[i] = (a[i] & carry) | (b[i] & ncarry) 23 | } 24 | } 25 | 26 | func gfpNeg(c, a *gfP) { 27 | var carry uint64 28 | for i, pi := range p2 { 29 | ai := a[i] 30 | ci := pi - ai - carry 31 | c[i] = ci 32 | carry = (ai&^pi | (ai|^pi)&ci) >> 63 33 | } 34 | gfpCarry(c, 0) 35 | } 36 | 37 | func gfpAdd(c, a, b *gfP) { 38 | var carry uint64 39 | for i, ai := range a { 40 | bi := b[i] 41 | ci := ai + bi + carry 42 | c[i] = ci 43 | carry = (ai&bi | (ai|bi)&^ci) >> 63 44 | } 45 | gfpCarry(c, carry) 46 | } 47 | 48 | func gfpSub(c, a, b *gfP) { 49 | t := &gfP{} 50 | 51 | var carry uint64 52 | for i, pi := range p2 { 53 | bi := b[i] 54 | ti := pi - bi - carry 55 | t[i] = ti 56 | carry = (bi&^pi | (bi|^pi)&ti) >> 63 57 | } 58 | 59 | carry = 0 60 | for i, ai := range a { 61 | ti := t[i] 62 | ci := ai + ti + carry 63 | c[i] = ci 64 | carry = (ai&ti | (ai|ti)&^ci) >> 63 65 | } 66 | gfpCarry(c, carry) 67 | } 68 | 69 | func mul(a, b [4]uint64) [8]uint64 { 70 | const ( 71 | mask16 uint64 = 0x0000ffff 72 | mask32 uint64 = 0xffffffff 73 | ) 74 | 75 | var buff [32]uint64 76 | for i, ai := range a { 77 | a0, a1, a2, a3 := ai&mask16, (ai>>16)&mask16, (ai>>32)&mask16, ai>>48 78 | 79 | for j, bj := range b { 80 | b0, b2 := bj&mask32, bj>>32 81 | 82 | off := 4 * (i + j) 83 | buff[off+0] += a0 * b0 84 | buff[off+1] += a1 * b0 85 | buff[off+2] += a2*b0 + a0*b2 86 | buff[off+3] += a3*b0 + a1*b2 87 | buff[off+4] += a2 * b2 88 | buff[off+5] += a3 * b2 89 | } 90 | } 91 | 92 | for i := uint(1); i < 4; i++ { 93 | shift := 16 * i 94 | 95 | var head, carry uint64 96 | for j := uint(0); j < 8; j++ { 97 | block := 4 * j 98 | 99 | xi := buff[block] 100 | yi := (buff[block+i] << shift) + head 101 | zi := xi + yi + carry 102 | buff[block] = zi 103 | carry = (xi&yi | (xi|yi)&^zi) >> 63 104 | 105 | head = buff[block+i] >> (64 - shift) 106 | } 107 | } 108 | 109 | return [8]uint64{buff[0], buff[4], buff[8], buff[12], buff[16], buff[20], buff[24], buff[28]} 110 | } 111 | 112 | func halfMul(a, b [4]uint64) [4]uint64 { 113 | const ( 114 | mask16 uint64 = 0x0000ffff 115 | mask32 uint64 = 0xffffffff 116 | ) 117 | 118 | var buff [18]uint64 119 | for i, ai := range a { 120 | a0, a1, a2, a3 := ai&mask16, (ai>>16)&mask16, (ai>>32)&mask16, ai>>48 121 | 122 | for j, bj := range b { 123 | if i+j > 3 { 124 | break 125 | } 126 | b0, b2 := bj&mask32, bj>>32 127 | 128 | off := 4 * (i + j) 129 | buff[off+0] += a0 * b0 130 | buff[off+1] += a1 * b0 131 | buff[off+2] += a2*b0 + a0*b2 132 | buff[off+3] += a3*b0 + a1*b2 133 | buff[off+4] += a2 * b2 134 | buff[off+5] += a3 * b2 135 | } 136 | } 137 | 138 | for i := uint(1); i < 4; i++ { 139 | shift := 16 * i 140 | 141 | var head, carry uint64 142 | for j := uint(0); j < 4; j++ { 143 | block := 4 * j 144 | 145 | xi := buff[block] 146 | yi := (buff[block+i] << shift) + head 147 | zi := xi + yi + carry 148 | buff[block] = zi 149 | carry = (xi&yi | (xi|yi)&^zi) >> 63 150 | 151 | head = buff[block+i] >> (64 - shift) 152 | } 153 | } 154 | 155 | return [4]uint64{buff[0], buff[4], buff[8], buff[12]} 156 | } 157 | 158 | func gfpMul(c, a, b *gfP) { 159 | T := mul(*a, *b) 160 | m := halfMul([4]uint64{T[0], T[1], T[2], T[3]}, np) 161 | t := mul([4]uint64{m[0], m[1], m[2], m[3]}, p2) 162 | 163 | var carry uint64 164 | for i, Ti := range T { 165 | ti := t[i] 166 | zi := Ti + ti + carry 167 | T[i] = zi 168 | carry = (Ti&ti | (Ti|ti)&^zi) >> 63 169 | } 170 | 171 | *c = gfP{T[4], T[5], T[6], T[7]} 172 | gfpCarry(c, carry) 173 | } 174 | -------------------------------------------------------------------------------- /gfp_test.go: -------------------------------------------------------------------------------- 1 | package bn256 2 | 3 | import ( 4 | "crypto/rand" 5 | "encoding/binary" 6 | "io" 7 | "math/big" 8 | "testing" 9 | ) 10 | 11 | // randomGF returns a random integer between 0 and p-1. 12 | func randomGF(r io.Reader) *big.Int { 13 | k, err := rand.Int(r, p) 14 | if err != nil { 15 | panic(err) 16 | } 17 | return k 18 | } 19 | 20 | // toBigInt converts a field element into its reduced (mod p) 21 | // integer representation. 22 | func toBigInt(a *gfP) *big.Int { 23 | v := &gfP{} 24 | montDecode(v, a) 25 | c := new(big.Int) 26 | for i := len(v) - 1; i >= 0; i-- { 27 | c.Lsh(c, 64) 28 | c.Add(c, new(big.Int).SetUint64(v[i])) 29 | } 30 | return c 31 | } 32 | 33 | // togfP converts an integer into a field element (in 34 | // Montgomery representation). This function assumes the 35 | // input is between 0 and p-1; otherwise it panics. 36 | func togfP(k *big.Int) *gfP { 37 | if k.Cmp(p) >= 0 { 38 | panic("not in the range 0 to p-1") 39 | } 40 | v := k.Bytes() 41 | v32 := [32]byte{} 42 | for i := len(v) - 1; i >= 0; i-- { 43 | v32[len(v)-1-i] = v[i] 44 | } 45 | u := &gfP{ 46 | binary.LittleEndian.Uint64(v32[0*8 : 1*8]), 47 | binary.LittleEndian.Uint64(v32[1*8 : 2*8]), 48 | binary.LittleEndian.Uint64(v32[2*8 : 3*8]), 49 | binary.LittleEndian.Uint64(v32[3*8 : 4*8]), 50 | } 51 | montEncode(u, u) 52 | return u 53 | } 54 | 55 | func TestGFp(t *testing.T) { 56 | const testTimes = 1 << 8 57 | 58 | t.Run("add", func(t *testing.T) { 59 | c := &gfP{} 60 | bigC := new(big.Int) 61 | for i := 0; i < testTimes; i++ { 62 | bigA := randomGF(rand.Reader) 63 | bigB := randomGF(rand.Reader) 64 | want := bigC.Add(bigA, bigB).Mod(bigC, p) 65 | 66 | a := togfP(bigA) 67 | b := togfP(bigB) 68 | gfpAdd(c, a, b) 69 | got := toBigInt(c) 70 | 71 | if got.Cmp(want) != 0 { 72 | t.Errorf("got: %v want:%v", got, want) 73 | } 74 | } 75 | }) 76 | 77 | t.Run("sub", func(t *testing.T) { 78 | c := &gfP{} 79 | bigC := new(big.Int) 80 | for i := 0; i < testTimes; i++ { 81 | bigA := randomGF(rand.Reader) 82 | bigB := randomGF(rand.Reader) 83 | want := bigC.Sub(bigA, bigB).Mod(bigC, p) 84 | 85 | a := togfP(bigA) 86 | b := togfP(bigB) 87 | gfpSub(c, a, b) 88 | got := toBigInt(c) 89 | 90 | if got.Cmp(want) != 0 { 91 | t.Errorf("got: %v want:%v", got, want) 92 | } 93 | } 94 | }) 95 | 96 | t.Run("mul", func(t *testing.T) { 97 | c := &gfP{} 98 | bigC := new(big.Int) 99 | for i := 0; i < testTimes; i++ { 100 | bigA := randomGF(rand.Reader) 101 | bigB := randomGF(rand.Reader) 102 | want := bigC.Mul(bigA, bigB).Mod(bigC, p) 103 | 104 | a := togfP(bigA) 105 | b := togfP(bigB) 106 | gfpMul(c, a, b) 107 | got := toBigInt(c) 108 | 109 | if got.Cmp(want) != 0 { 110 | t.Errorf("got: %v want:%v", got, want) 111 | } 112 | } 113 | }) 114 | 115 | t.Run("neg", func(t *testing.T) { 116 | c := &gfP{} 117 | bigC := new(big.Int) 118 | for i := 0; i < testTimes; i++ { 119 | bigA := randomGF(rand.Reader) 120 | want := bigC.Neg(bigA).Mod(bigC, p) 121 | 122 | a := togfP(bigA) 123 | gfpNeg(c, a) 124 | got := toBigInt(c) 125 | 126 | if got.Cmp(want) != 0 { 127 | t.Errorf("got: %v want:%v", got, want) 128 | } 129 | } 130 | }) 131 | 132 | t.Run("inv", func(t *testing.T) { 133 | c := &gfP{} 134 | bigC := new(big.Int) 135 | for i := 0; i < testTimes; i++ { 136 | bigA := randomGF(rand.Reader) 137 | want := bigC.ModInverse(bigA, p) 138 | 139 | a := togfP(bigA) 140 | c.Invert(a) 141 | got := toBigInt(c) 142 | 143 | if got.Cmp(want) != 0 { 144 | t.Errorf("got: %v want:%v", got, want) 145 | } 146 | } 147 | }) 148 | 149 | t.Run("sqrt", func(t *testing.T) { 150 | c := &gfP{} 151 | bigC := new(big.Int) 152 | for i := 0; i < testTimes; i++ { 153 | bigA := randomGF(rand.Reader) 154 | bigA.Mul(bigA, bigA).Mod(bigA, p) 155 | want := bigC.ModSqrt(bigA, p) 156 | 157 | a := togfP(bigA) 158 | c.Sqrt(a) 159 | got := toBigInt(c) 160 | 161 | if got.Cmp(want) != 0 { 162 | t.Errorf("got: %v want:%v", got, want) 163 | } 164 | } 165 | }) 166 | } 167 | -------------------------------------------------------------------------------- /hash_test.go: -------------------------------------------------------------------------------- 1 | package bn256 2 | 3 | import ( 4 | "testing" 5 | 6 | "bytes" 7 | ) 8 | 9 | func TestKnownHashes(t *testing.T) { 10 | for i, mh := range marshaledHashes { 11 | g := HashG1([]byte{byte(i)}, nil) 12 | if !bytes.Equal(mh[:], g.Marshal()) { 13 | t.Fatal("hash doesn't match a known value") 14 | } 15 | } 16 | } 17 | 18 | var buf = make([]byte, 8192) 19 | 20 | func benchmarkSize(b *testing.B, size int) { 21 | b.SetBytes(int64(size)) 22 | for i := 0; i < b.N; i++ { 23 | HashG1(buf[:size], nil) 24 | } 25 | } 26 | 27 | func BenchmarkHashG1Size8bytes(b *testing.B) { 28 | b.ResetTimer() 29 | benchmarkSize(b, 8) 30 | } 31 | 32 | func BenchmarkHashG1Size1k(b *testing.B) { 33 | b.ResetTimer() 34 | benchmarkSize(b, 1024) 35 | } 36 | 37 | func BenchmarkHashG1Size8k(b *testing.B) { 38 | b.ResetTimer() 39 | benchmarkSize(b, 8192) 40 | } 41 | 42 | var marshaledHashes = [11][64]byte{ 43 | [64]byte{80, 233, 64, 52, 60, 233, 95, 49, 57, 115, 89, 101, 189, 182, 251, 43, 158, 186, 22, 10, 130, 128, 127, 143, 10, 158, 148, 102, 148, 86, 194, 111, 98, 232, 82, 178, 190, 193, 65, 1, 58, 126, 154, 37, 11, 185, 207, 250, 219, 202, 140, 196, 2, 35, 223, 87, 13, 60, 204, 201, 34, 231, 118, 206}, 44 | [64]byte{123, 250, 39, 222, 32, 210, 254, 221, 94, 5, 32, 6, 19, 120, 252, 162, 110, 53, 149, 185, 209, 83, 189, 194, 77, 40, 160, 168, 17, 143, 13, 121, 72, 31, 247, 190, 150, 8, 159, 57, 145, 45, 129, 145, 164, 29, 156, 159, 182, 177, 142, 145, 38, 236, 98, 84, 157, 8, 164, 38, 123, 73, 215, 23}, 45 | [64]byte{129, 78, 244, 19, 205, 198, 70, 100, 63, 152, 218, 52, 132, 20, 180, 241, 223, 109, 93, 80, 59, 6, 16, 183, 99, 5, 202, 77, 136, 165, 254, 32, 124, 242, 44, 52, 28, 76, 54, 116, 113, 243, 51, 101, 114, 70, 190, 124, 81, 194, 77, 8, 163, 135, 148, 175, 224, 248, 184, 44, 167, 124, 10, 30}, 46 | [64]byte{113, 140, 119, 103, 41, 163, 49, 69, 93, 208, 11, 126, 85, 100, 1, 11, 151, 207, 202, 144, 7, 154, 203, 84, 123, 255, 67, 107, 189, 188, 93, 14, 131, 167, 214, 27, 85, 82, 122, 220, 131, 237, 192, 206, 159, 132, 216, 254, 227, 52, 232, 216, 182, 154, 170, 46, 99, 78, 137, 79, 90, 30, 236, 16}, 47 | [64]byte{128, 205, 34, 132, 54, 241, 30, 185, 253, 248, 45, 227, 78, 202, 148, 137, 224, 86, 199, 253, 98, 156, 169, 132, 129, 141, 118, 247, 102, 200, 47, 231, 62, 4, 169, 180, 190, 184, 212, 40, 88, 118, 134, 129, 149, 108, 105, 153, 54, 153, 40, 159, 189, 245, 63, 172, 43, 49, 22, 246, 154, 57, 63, 57}, 48 | [64]byte{44, 243, 231, 191, 3, 107, 182, 73, 39, 43, 51, 20, 25, 235, 151, 112, 207, 24, 28, 96, 201, 60, 175, 210, 179, 42, 117, 101, 16, 196, 82, 238, 126, 198, 61, 68, 228, 96, 166, 130, 139, 167, 181, 195, 46, 10, 51, 83, 59, 165, 249, 111, 205, 113, 80, 43, 240, 194, 72, 240, 64, 235, 120, 34}, 49 | [64]byte{125, 159, 122, 73, 206, 48, 230, 111, 229, 18, 224, 100, 101, 149, 116, 190, 47, 116, 78, 156, 94, 87, 164, 157, 156, 211, 110, 229, 191, 250, 213, 83, 139, 111, 120, 241, 26, 131, 125, 200, 87, 166, 76, 136, 241, 37, 113, 44, 200, 158, 236, 122, 0, 33, 172, 198, 242, 255, 33, 101, 142, 245, 180, 243}, 50 | [64]byte{130, 99, 125, 203, 106, 197, 191, 151, 248, 98, 27, 76, 200, 122, 173, 139, 129, 31, 54, 51, 206, 49, 122, 51, 57, 88, 139, 191, 42, 22, 158, 125, 100, 87, 23, 89, 148, 160, 5, 224, 46, 35, 217, 254, 28, 247, 86, 227, 186, 200, 3, 206, 50, 134, 14, 193, 23, 58, 2, 161, 52, 1, 201, 136}, 51 | [64]byte{76, 28, 164, 59, 70, 75, 165, 57, 131, 109, 238, 103, 17, 89, 191, 194, 78, 248, 115, 8, 108, 206, 46, 235, 52, 219, 98, 231, 194, 252, 229, 98, 55, 45, 194, 177, 115, 176, 207, 167, 174, 12, 94, 199, 63, 175, 214, 137, 190, 168, 67, 247, 107, 64, 169, 74, 250, 174, 177, 141, 93, 207, 71, 147}, 52 | [64]byte{45, 115, 123, 118, 162, 144, 82, 134, 198, 17, 162, 200, 91, 168, 191, 115, 31, 66, 81, 201, 111, 250, 133, 16, 247, 62, 92, 251, 227, 234, 116, 183, 16, 117, 103, 177, 94, 201, 169, 155, 59, 218, 174, 242, 28, 66, 171, 113, 245, 247, 98, 236, 193, 26, 85, 62, 215, 101, 229, 214, 191, 153, 176, 168}, 53 | [64]byte{143, 123, 127, 149, 167, 27, 159, 25, 254, 211, 196, 88, 17, 185, 138, 237, 62, 140, 84, 177, 134, 58, 193, 141, 25, 152, 79, 6, 41, 39, 248, 117, 52, 208, 167, 215, 212, 60, 250, 228, 1, 232, 111, 254, 154, 18, 209, 55, 207, 200, 68, 60, 163, 106, 59, 27, 12, 72, 130, 141, 182, 103, 16, 80}, 54 | } 55 | -------------------------------------------------------------------------------- /twist.go: -------------------------------------------------------------------------------- 1 | package bn256 2 | 3 | import ( 4 | "math/big" 5 | ) 6 | 7 | // twistPoint implements the elliptic curve y²=x³+3/ξ over GF(p²). Points are 8 | // kept in Jacobian form and t=z² when valid. The group G₂ is the set of 9 | // n-torsion points of this curve over GF(p²) (where n = Order) 10 | type twistPoint struct { 11 | x, y, z, t gfP2 12 | } 13 | 14 | var twistB = &gfP2{ 15 | gfP{0x75046774386b8d71, 0x5bd0854a46d36cf8, 0x664327a1d41c8414, 0x96c9abb932eeb2f}, 16 | gfP{0xb94f760fb4c5ee14, 0xdae9f8f24c3b6eb4, 0x77a675d2e52f4fe4, 0x736f31b09116c66b}, 17 | } 18 | 19 | // twistGen is the generator of group G₂. 20 | var twistGen = &twistPoint{ 21 | gfP2{ 22 | gfP{0x402c4ab7139e1404, 0xce1c368a183d85a4, 0xd67cf9a6cb8d3983, 0x3cf246bbc2a9fbe8}, 23 | gfP{0x88f9f11da7cdc184, 0x18293f95d69509d3, 0xb5ce0c55a735d5a1, 0x15134189bfd45a0}, 24 | }, 25 | gfP2{ 26 | gfP{0xbfac7d731e9e87a2, 0xa50bb8007962e441, 0xafe910a4e8270556, 0x5075c5429d69159a}, 27 | gfP{0xc2e07c1463ea9e56, 0xee4442052072ebd2, 0x561a519486036937, 0x5bd9394cc0d2cce}, 28 | }, 29 | gfP2{*newGFp(0), *newGFp(1)}, 30 | gfP2{*newGFp(0), *newGFp(1)}, 31 | } 32 | 33 | func (c *twistPoint) String() string { 34 | c.MakeAffine() 35 | x, y := gfP2Decode(&c.x), gfP2Decode(&c.y) 36 | return "(" + x.String() + ", " + y.String() + ")" 37 | } 38 | 39 | func (c *twistPoint) Set(a *twistPoint) { 40 | c.x.Set(&a.x) 41 | c.y.Set(&a.y) 42 | c.z.Set(&a.z) 43 | c.t.Set(&a.t) 44 | } 45 | 46 | // IsOnCurve returns true iff c is on the curve. 47 | func (c *twistPoint) IsOnCurve() bool { 48 | c.MakeAffine() 49 | if c.IsInfinity() { 50 | return true 51 | } 52 | 53 | y2, x3 := &gfP2{}, &gfP2{} 54 | y2.Square(&c.y) 55 | x3.Square(&c.x).Mul(x3, &c.x).Add(x3, twistB) 56 | 57 | return *y2 == *x3 58 | } 59 | 60 | func (c *twistPoint) SetInfinity() { 61 | c.x.SetZero() 62 | c.y.SetOne() 63 | c.z.SetZero() 64 | c.t.SetZero() 65 | } 66 | 67 | func (c *twistPoint) IsInfinity() bool { 68 | return c.z.IsZero() 69 | } 70 | 71 | func (c *twistPoint) Add(a, b *twistPoint) { 72 | // For additional comments, see the same function in curve.go. 73 | 74 | if a.IsInfinity() { 75 | c.Set(b) 76 | return 77 | } 78 | if b.IsInfinity() { 79 | c.Set(a) 80 | return 81 | } 82 | 83 | // See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/addition/add-2007-bl.op3 84 | z12 := (&gfP2{}).Square(&a.z) 85 | z22 := (&gfP2{}).Square(&b.z) 86 | u1 := (&gfP2{}).Mul(&a.x, z22) 87 | u2 := (&gfP2{}).Mul(&b.x, z12) 88 | 89 | t := (&gfP2{}).Mul(&b.z, z22) 90 | s1 := (&gfP2{}).Mul(&a.y, t) 91 | 92 | t.Mul(&a.z, z12) 93 | s2 := (&gfP2{}).Mul(&b.y, t) 94 | 95 | h := (&gfP2{}).Sub(u2, u1) 96 | xEqual := h.IsZero() 97 | 98 | t.Add(h, h) 99 | i := (&gfP2{}).Square(t) 100 | j := (&gfP2{}).Mul(h, i) 101 | 102 | t.Sub(s2, s1) 103 | yEqual := t.IsZero() 104 | if xEqual && yEqual { 105 | c.Double(a) 106 | return 107 | } 108 | r := (&gfP2{}).Add(t, t) 109 | 110 | v := (&gfP2{}).Mul(u1, i) 111 | 112 | t4 := (&gfP2{}).Square(r) 113 | t.Add(v, v) 114 | t6 := (&gfP2{}).Sub(t4, j) 115 | c.x.Sub(t6, t) 116 | 117 | t.Sub(v, &c.x) // t7 118 | t4.Mul(s1, j) // t8 119 | t6.Add(t4, t4) // t9 120 | t4.Mul(r, t) // t10 121 | c.y.Sub(t4, t6) 122 | 123 | t.Add(&a.z, &b.z) // t11 124 | t4.Square(t) // t12 125 | t.Sub(t4, z12) // t13 126 | t4.Sub(t, z22) // t14 127 | c.z.Mul(t4, h) 128 | } 129 | 130 | func (c *twistPoint) Double(a *twistPoint) { 131 | // See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/doubling/dbl-2009-l.op3 132 | A := (&gfP2{}).Square(&a.x) 133 | B := (&gfP2{}).Square(&a.y) 134 | C := (&gfP2{}).Square(B) 135 | 136 | t := (&gfP2{}).Add(&a.x, B) 137 | t2 := (&gfP2{}).Square(t) 138 | t.Sub(t2, A) 139 | t2.Sub(t, C) 140 | d := (&gfP2{}).Add(t2, t2) 141 | t.Add(A, A) 142 | e := (&gfP2{}).Add(t, A) 143 | f := (&gfP2{}).Square(e) 144 | 145 | t.Add(d, d) 146 | c.x.Sub(f, t) 147 | 148 | c.z.Mul(&a.y, &a.z) 149 | c.z.Add(&c.z, &c.z) 150 | 151 | t.Add(C, C) 152 | t2.Add(t, t) 153 | t.Add(t2, t2) 154 | c.y.Sub(d, &c.x) 155 | t2.Mul(e, &c.y) 156 | c.y.Sub(t2, t) 157 | } 158 | 159 | func (c *twistPoint) Mul(a *twistPoint, scalar *big.Int) { 160 | sum, t := &twistPoint{}, &twistPoint{} 161 | 162 | for i := scalar.BitLen(); i >= 0; i-- { 163 | t.Double(sum) 164 | if scalar.Bit(i) != 0 { 165 | sum.Add(t, a) 166 | } else { 167 | sum.Set(t) 168 | } 169 | } 170 | 171 | c.Set(sum) 172 | } 173 | 174 | func (c *twistPoint) MakeAffine() { 175 | if c.z.IsOne() { 176 | return 177 | } else if c.z.IsZero() { 178 | c.x.SetZero() 179 | c.y.SetOne() 180 | c.t.SetZero() 181 | return 182 | } 183 | 184 | zInv := (&gfP2{}).Invert(&c.z) 185 | t := (&gfP2{}).Mul(&c.y, zInv) 186 | zInv2 := (&gfP2{}).Square(zInv) 187 | c.y.Mul(t, zInv2) 188 | t.Mul(&c.x, zInv2) 189 | c.x.Set(t) 190 | c.z.SetOne() 191 | c.t.SetOne() 192 | } 193 | 194 | func (c *twistPoint) Neg(a *twistPoint) { 195 | c.x.Set(&a.x) 196 | c.y.Neg(&a.y) 197 | c.z.Set(&a.z) 198 | c.t.SetZero() 199 | } 200 | -------------------------------------------------------------------------------- /gfp12.go: -------------------------------------------------------------------------------- 1 | package bn256 2 | 3 | // For details of the algorithms used, see "Multiplication and Squaring on 4 | // Pairing-Friendly Fields, Devegili et al. 5 | // http://eprint.iacr.org/2006/471.pdf. 6 | 7 | import ( 8 | "math/big" 9 | ) 10 | 11 | // gfP12 implements the field of size p¹² as a quadratic extension of gfP6 12 | // where ω²=τ. 13 | type gfP12 struct { 14 | x, y gfP6 // value is xω + y 15 | } 16 | 17 | var gfP12Gen *gfP12 = &gfP12{ 18 | x: gfP6{ 19 | x: gfP2{ 20 | x: gfP{0x62d608d6bb67a4fb, 0x9a66ec93f0c2032f, 0x5391628e924e1a34, 0x2162dbf7de801d0e}, 21 | y: gfP{0x3e0c1a72bf08eb4f, 0x4972ec05990a5ecc, 0xf7b9a407ead8007e, 0x3ca04c613572ce49}, 22 | }, 23 | y: gfP2{ 24 | x: gfP{0xace536a5607c910e, 0xda93774a941ddd40, 0x5de0e9853b7593ad, 0xe05bb926f513153}, 25 | y: gfP{0x3f4c99f8abaf1a22, 0x66d5f6121f86dc33, 0x8e0a82f68a50abba, 0x819927d1eebd0695}, 26 | }, 27 | z: gfP2{ 28 | x: gfP{0x7cdef49c5477faa, 0x40eb71ffedaa199d, 0xbc896661f17c9b8f, 0x3144462983c38c02}, 29 | y: gfP{0xcd09ee8dd8418013, 0xf8d050d05faa9b11, 0x589e90a555507ee1, 0x58e4ab25f9c49c15}, 30 | }, 31 | }, 32 | y: gfP6{ 33 | x: gfP2{ 34 | x: gfP{0x7e76809b142d020b, 0xd9949d1b2822e995, 0x3de93d974f84b076, 0x144523477028928d}, 35 | y: gfP{0x79952799f9ef4b0, 0x4102c47aa3df01c6, 0xfa82a633c53da2e1, 0x54c3f0392f9f7e0e}, 36 | }, 37 | y: gfP2{ 38 | x: gfP{0xd3432a335533272b, 0xa008fbbdc7d74f4a, 0x68e3c81eb7295ed9, 0x17fe34c21fdecef2}, 39 | y: gfP{0xfb0bc4c0ef6df55f, 0x8bdc585b70bc2120, 0x17d498d2cb720def, 0x2a368248319b899c}, 40 | }, 41 | z: gfP2{ 42 | x: gfP{0xf8487d81cb354c6c, 0x7421be69f1522caa, 0x6940c778b9fb2d54, 0x7da4b04e102bb621}, 43 | y: gfP{0x97b91989993e7be4, 0x8526545356eab684, 0xb050073022eb1892, 0x658b432ad09939c0}, 44 | }, 45 | }, 46 | } 47 | 48 | func (e *gfP12) String() string { 49 | return "(" + e.x.String() + "," + e.y.String() + ")" 50 | } 51 | 52 | func (e *gfP12) Set(a *gfP12) *gfP12 { 53 | e.x.Set(&a.x) 54 | e.y.Set(&a.y) 55 | return e 56 | } 57 | 58 | func (e *gfP12) SetZero() *gfP12 { 59 | e.x.SetZero() 60 | e.y.SetZero() 61 | return e 62 | } 63 | 64 | func (e *gfP12) SetOne() *gfP12 { 65 | e.x.SetZero() 66 | e.y.SetOne() 67 | return e 68 | } 69 | 70 | func (e *gfP12) IsZero() bool { 71 | return e.x.IsZero() && e.y.IsZero() 72 | } 73 | 74 | func (e *gfP12) IsOne() bool { 75 | return e.x.IsZero() && e.y.IsOne() 76 | } 77 | 78 | func (e *gfP12) Conjugate(a *gfP12) *gfP12 { 79 | e.x.Neg(&a.x) 80 | e.y.Set(&a.y) 81 | return e 82 | } 83 | 84 | func (e *gfP12) Neg(a *gfP12) *gfP12 { 85 | e.x.Neg(&a.x) 86 | e.y.Neg(&a.y) 87 | return e 88 | } 89 | 90 | // Frobenius computes (xω+y)^p = x^p ω·ξ^((p-1)/6) + y^p 91 | func (e *gfP12) Frobenius(a *gfP12) *gfP12 { 92 | e.x.Frobenius(&a.x) 93 | e.y.Frobenius(&a.y) 94 | e.x.MulScalar(&e.x, xiToPMinus1Over6) 95 | return e 96 | } 97 | 98 | // FrobeniusP2 computes (xω+y)^p² = x^p² ω·ξ^((p²-1)/6) + y^p² 99 | func (e *gfP12) FrobeniusP2(a *gfP12) *gfP12 { 100 | e.x.FrobeniusP2(&a.x) 101 | e.x.MulGFP(&e.x, xiToPSquaredMinus1Over6) 102 | e.y.FrobeniusP2(&a.y) 103 | return e 104 | } 105 | 106 | func (e *gfP12) FrobeniusP4(a *gfP12) *gfP12 { 107 | e.x.FrobeniusP4(&a.x) 108 | e.x.MulGFP(&e.x, xiToPSquaredMinus1Over3) 109 | e.y.FrobeniusP4(&a.y) 110 | return e 111 | } 112 | 113 | func (e *gfP12) Add(a, b *gfP12) *gfP12 { 114 | e.x.Add(&a.x, &b.x) 115 | e.y.Add(&a.y, &b.y) 116 | return e 117 | } 118 | 119 | func (e *gfP12) Sub(a, b *gfP12) *gfP12 { 120 | e.x.Sub(&a.x, &b.x) 121 | e.y.Sub(&a.y, &b.y) 122 | return e 123 | } 124 | 125 | func (e *gfP12) Mul(a, b *gfP12) *gfP12 { 126 | tx := (&gfP6{}).Mul(&a.x, &b.y) 127 | t := (&gfP6{}).Mul(&b.x, &a.y) 128 | tx.Add(tx, t) 129 | 130 | ty := (&gfP6{}).Mul(&a.y, &b.y) 131 | t.Mul(&a.x, &b.x).MulTau(t) 132 | 133 | e.x.Set(tx) 134 | e.y.Add(ty, t) 135 | return e 136 | } 137 | 138 | func (e *gfP12) MulScalar(a *gfP12, b *gfP6) *gfP12 { 139 | e.x.Mul(&a.x, b) 140 | e.y.Mul(&a.y, b) 141 | return e 142 | } 143 | 144 | func (c *gfP12) Exp(a *gfP12, power *big.Int) *gfP12 { 145 | sum := (&gfP12{}).SetOne() 146 | t := &gfP12{} 147 | 148 | for i := power.BitLen() - 1; i >= 0; i-- { 149 | t.Square(sum) 150 | if power.Bit(i) != 0 { 151 | sum.Mul(t, a) 152 | } else { 153 | sum.Set(t) 154 | } 155 | } 156 | 157 | c.Set(sum) 158 | return c 159 | } 160 | 161 | func (e *gfP12) Square(a *gfP12) *gfP12 { 162 | // Complex squaring algorithm 163 | v0 := (&gfP6{}).Mul(&a.x, &a.y) 164 | 165 | t := (&gfP6{}).MulTau(&a.x) 166 | t.Add(&a.y, t) 167 | ty := (&gfP6{}).Add(&a.x, &a.y) 168 | ty.Mul(ty, t).Sub(ty, v0) 169 | t.MulTau(v0) 170 | ty.Sub(ty, t) 171 | 172 | e.x.Add(v0, v0) 173 | e.y.Set(ty) 174 | return e 175 | } 176 | 177 | func (e *gfP12) Invert(a *gfP12) *gfP12 { 178 | // See "Implementing cryptographic pairings", M. Scott, section 3.2. 179 | // ftp://136.206.11.249/pub/crypto/pairings.pdf 180 | t1, t2 := &gfP6{}, &gfP6{} 181 | 182 | t1.Square(&a.x) 183 | t2.Square(&a.y) 184 | t1.MulTau(t1).Sub(t2, t1) 185 | t2.Invert(t1) 186 | 187 | e.x.Neg(&a.x) 188 | e.y.Set(&a.y) 189 | e.MulScalar(e, t2) 190 | return e 191 | } 192 | -------------------------------------------------------------------------------- /bn256_test.go: -------------------------------------------------------------------------------- 1 | package bn256 2 | 3 | import ( 4 | "testing" 5 | 6 | "bytes" 7 | "crypto/rand" 8 | ) 9 | 10 | func TestG1(t *testing.T) { 11 | k, Ga, err := RandomG1(rand.Reader) 12 | if err != nil { 13 | t.Fatal(err) 14 | } 15 | ma := Ga.Marshal() 16 | 17 | Gb := new(G1).ScalarBaseMult(k) 18 | mb := Gb.Marshal() 19 | 20 | if !bytes.Equal(ma, mb) { 21 | t.Fatal("bytes are different") 22 | } 23 | } 24 | 25 | func TestG1Marshal(t *testing.T) { 26 | _, Ga, err := RandomG1(rand.Reader) 27 | if err != nil { 28 | t.Fatal(err) 29 | } 30 | ma := Ga.Marshal() 31 | 32 | Gb := new(G1) 33 | _, err = Gb.Unmarshal(ma) 34 | if err != nil { 35 | t.Fatal(err) 36 | } 37 | mb := Gb.Marshal() 38 | 39 | if !bytes.Equal(ma, mb) { 40 | t.Fatal("bytes are different") 41 | } 42 | } 43 | 44 | func TestG2(t *testing.T) { 45 | k, Ga, err := RandomG2(rand.Reader) 46 | if err != nil { 47 | t.Fatal(err) 48 | } 49 | ma := Ga.Marshal() 50 | 51 | Gb := new(G2).ScalarBaseMult(k) 52 | mb := Gb.Marshal() 53 | 54 | if !bytes.Equal(ma, mb) { 55 | t.Fatal("bytes are different") 56 | } 57 | } 58 | 59 | func TestG2Marshal(t *testing.T) { 60 | _, Ga, err := RandomG2(rand.Reader) 61 | if err != nil { 62 | t.Fatal(err) 63 | } 64 | ma := Ga.Marshal() 65 | 66 | Gb := new(G2) 67 | _, err = Gb.Unmarshal(ma) 68 | if err != nil { 69 | t.Fatal(err) 70 | } 71 | mb := Gb.Marshal() 72 | 73 | if !bytes.Equal(ma, mb) { 74 | t.Fatal("bytes are different") 75 | } 76 | } 77 | 78 | func TestGT(t *testing.T) { 79 | k, Ga, err := RandomGT(rand.Reader) 80 | if err != nil { 81 | t.Fatal(err) 82 | } 83 | ma := Ga.Marshal() 84 | 85 | G := new(GT) 86 | _, err = G.Unmarshal((>{gfP12Gen}).Marshal()) 87 | if err != nil { 88 | t.Fatal("unmarshal not ok") 89 | } 90 | G.ScalarMult(G, k) 91 | mb := G.Marshal() 92 | 93 | if !bytes.Equal(ma, mb) { 94 | t.Fatal("bytes are different") 95 | } 96 | } 97 | 98 | func TestGTMarshal(t *testing.T) { 99 | _, Ga, err := RandomGT(rand.Reader) 100 | if err != nil { 101 | t.Fatal(err) 102 | } 103 | ma := Ga.Marshal() 104 | 105 | Gb := new(GT) 106 | _, err = Gb.Unmarshal(ma) 107 | if err != nil { 108 | t.Fatal(err) 109 | } 110 | mb := Gb.Marshal() 111 | 112 | if !bytes.Equal(ma, mb) { 113 | t.Fatal("bytes are different") 114 | } 115 | } 116 | 117 | func TestBilinearity(t *testing.T) { 118 | for i := 0; i < 2; i++ { 119 | a, p1, _ := RandomG1(rand.Reader) 120 | b, p2, _ := RandomG2(rand.Reader) 121 | e1 := Pair(p1, p2) 122 | 123 | e2 := Pair(&G1{curveGen}, &G2{twistGen}) 124 | e2.ScalarMult(e2, a) 125 | e2.ScalarMult(e2, b) 126 | 127 | if *e1.p != *e2.p { 128 | t.Fatalf("bad pairing result: %s", e1) 129 | } 130 | } 131 | } 132 | 133 | func TestTripartiteDiffieHellman(t *testing.T) { 134 | a, _ := rand.Int(rand.Reader, Order) 135 | b, _ := rand.Int(rand.Reader, Order) 136 | c, _ := rand.Int(rand.Reader, Order) 137 | 138 | pa, pb, pc := new(G1), new(G1), new(G1) 139 | qa, qb, qc := new(G2), new(G2), new(G2) 140 | 141 | pa.Unmarshal(new(G1).ScalarBaseMult(a).Marshal()) 142 | qa.Unmarshal(new(G2).ScalarBaseMult(a).Marshal()) 143 | pb.Unmarshal(new(G1).ScalarBaseMult(b).Marshal()) 144 | qb.Unmarshal(new(G2).ScalarBaseMult(b).Marshal()) 145 | pc.Unmarshal(new(G1).ScalarBaseMult(c).Marshal()) 146 | qc.Unmarshal(new(G2).ScalarBaseMult(c).Marshal()) 147 | 148 | k1 := Pair(pb, qc) 149 | k1.ScalarMult(k1, a) 150 | k1Bytes := k1.Marshal() 151 | 152 | k2 := Pair(pc, qa) 153 | k2.ScalarMult(k2, b) 154 | k2Bytes := k2.Marshal() 155 | 156 | k3 := Pair(pa, qb) 157 | k3.ScalarMult(k3, c) 158 | k3Bytes := k3.Marshal() 159 | 160 | if !bytes.Equal(k1Bytes, k2Bytes) || !bytes.Equal(k2Bytes, k3Bytes) { 161 | t.Errorf("keys didn't agree") 162 | } 163 | } 164 | 165 | func TestSelfAddG1(t *testing.T) { 166 | _, Ga, err := RandomG1(rand.Reader) 167 | if err != nil { 168 | t.Fatal(err) 169 | } 170 | 171 | Gb := &G1{curveGen} 172 | Gb.p.Double(Ga.p) 173 | mb := Gb.Marshal() 174 | 175 | Ga.Add(Ga, Ga) 176 | ma := Ga.Marshal() 177 | 178 | if !bytes.Equal(ma, mb) { 179 | t.Fatal("bytes are different") 180 | } 181 | } 182 | 183 | func TestSelfAddG2(t *testing.T) { 184 | _, Ga, err := RandomG2(rand.Reader) 185 | if err != nil { 186 | t.Fatal(err) 187 | } 188 | 189 | Gb := &G2{twistGen} 190 | Gb.p.Double(Ga.p) 191 | mb := Gb.Marshal() 192 | 193 | Ga.Add(Ga, Ga) 194 | ma := Ga.Marshal() 195 | 196 | if !bytes.Equal(ma, mb) { 197 | t.Fatal("bytes are different") 198 | } 199 | } 200 | 201 | func TestDirtyUnmarshal(t *testing.T) { 202 | _, Ga, err := RandomG2(rand.Reader) 203 | if err != nil { 204 | t.Fatal(err) 205 | } 206 | ma := Ga.Marshal() 207 | 208 | if _, err := Ga.Unmarshal(ma); err != nil { 209 | t.Fatal(err) 210 | } 211 | } 212 | 213 | func BenchmarkG1(b *testing.B) { 214 | x, _ := rand.Int(rand.Reader, Order) 215 | b.ResetTimer() 216 | 217 | for i := 0; i < b.N; i++ { 218 | new(G1).ScalarBaseMult(x) 219 | } 220 | } 221 | 222 | func BenchmarkG2(b *testing.B) { 223 | x, _ := rand.Int(rand.Reader, Order) 224 | b.ResetTimer() 225 | 226 | for i := 0; i < b.N; i++ { 227 | new(G2).ScalarBaseMult(x) 228 | } 229 | } 230 | 231 | func BenchmarkGT(b *testing.B) { 232 | x, _ := rand.Int(rand.Reader, Order) 233 | b.ResetTimer() 234 | 235 | for i := 0; i < b.N; i++ { 236 | new(GT).ScalarBaseMult(x) 237 | } 238 | } 239 | 240 | func BenchmarkPairing(b *testing.B) { 241 | for i := 0; i < b.N; i++ { 242 | Pair(&G1{curveGen}, &G2{twistGen}) 243 | } 244 | } 245 | -------------------------------------------------------------------------------- /curve.go: -------------------------------------------------------------------------------- 1 | package bn256 2 | 3 | import ( 4 | "math/big" 5 | ) 6 | 7 | // curvePoint implements the elliptic curve y²=x³+3. Points are kept in Jacobian 8 | // form and t=z² when valid. G₁ is the set of points of this curve on GF(p). 9 | type curvePoint struct { 10 | x, y, z, t gfP 11 | } 12 | 13 | var curveB = newGFp(3) 14 | 15 | // curveGen is the generator of G₁. 16 | var curveGen = &curvePoint{ 17 | x: *newGFp(1), 18 | y: *newGFp(-2), 19 | z: *newGFp(1), 20 | t: *newGFp(1), 21 | } 22 | 23 | func (c *curvePoint) String() string { 24 | c.MakeAffine() 25 | x, y := &gfP{}, &gfP{} 26 | montDecode(x, &c.x) 27 | montDecode(y, &c.y) 28 | return "(" + x.String() + ", " + y.String() + ")" 29 | } 30 | 31 | func (c *curvePoint) Set(a *curvePoint) { 32 | c.x.Set(&a.x) 33 | c.y.Set(&a.y) 34 | c.z.Set(&a.z) 35 | c.t.Set(&a.t) 36 | } 37 | 38 | // IsOnCurve returns true iff c is on the curve. 39 | func (c *curvePoint) IsOnCurve() bool { 40 | c.MakeAffine() 41 | if c.IsInfinity() { 42 | return true 43 | } 44 | 45 | y2, x3 := &gfP{}, &gfP{} 46 | gfpMul(y2, &c.y, &c.y) 47 | gfpMul(x3, &c.x, &c.x) 48 | gfpMul(x3, x3, &c.x) 49 | gfpAdd(x3, x3, curveB) 50 | 51 | return *y2 == *x3 52 | } 53 | 54 | func (c *curvePoint) SetInfinity() { 55 | c.x = gfP{0} 56 | c.y = *newGFp(1) 57 | c.z = gfP{0} 58 | c.t = gfP{0} 59 | } 60 | 61 | func (c *curvePoint) IsInfinity() bool { 62 | return c.z == gfP{0} 63 | } 64 | 65 | func (c *curvePoint) Add(a, b *curvePoint) { 66 | if a.IsInfinity() { 67 | c.Set(b) 68 | return 69 | } 70 | if b.IsInfinity() { 71 | c.Set(a) 72 | return 73 | } 74 | 75 | // See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/addition/add-2007-bl.op3 76 | 77 | // Normalize the points by replacing a = [x1:y1:z1] and b = [x2:y2:z2] 78 | // by [u1:s1:z1·z2] and [u2:s2:z1·z2] 79 | // where u1 = x1·z2², s1 = y1·z2³ and u1 = x2·z1², s2 = y2·z1³ 80 | z12, z22 := &gfP{}, &gfP{} 81 | gfpMul(z12, &a.z, &a.z) 82 | gfpMul(z22, &b.z, &b.z) 83 | 84 | u1, u2 := &gfP{}, &gfP{} 85 | gfpMul(u1, &a.x, z22) 86 | gfpMul(u2, &b.x, z12) 87 | 88 | t, s1 := &gfP{}, &gfP{} 89 | gfpMul(t, &b.z, z22) 90 | gfpMul(s1, &a.y, t) 91 | 92 | s2 := &gfP{} 93 | gfpMul(t, &a.z, z12) 94 | gfpMul(s2, &b.y, t) 95 | 96 | // Compute x = (2h)²(s²-u1-u2) 97 | // where s = (s2-s1)/(u2-u1) is the slope of the line through 98 | // (u1,s1) and (u2,s2). The extra factor 2h = 2(u2-u1) comes from the value of z below. 99 | // This is also: 100 | // 4(s2-s1)² - 4h²(u1+u2) = 4(s2-s1)² - 4h³ - 4h²(2u1) 101 | // = r² - j - 2v 102 | // with the notations below. 103 | h := &gfP{} 104 | gfpSub(h, u2, u1) 105 | xEqual := *h == gfP{0} 106 | 107 | gfpAdd(t, h, h) 108 | // i = 4h² 109 | i := &gfP{} 110 | gfpMul(i, t, t) 111 | // j = 4h³ 112 | j := &gfP{} 113 | gfpMul(j, h, i) 114 | 115 | gfpSub(t, s2, s1) 116 | yEqual := *t == gfP{0} 117 | if xEqual && yEqual { 118 | c.Double(a) 119 | return 120 | } 121 | r := &gfP{} 122 | gfpAdd(r, t, t) 123 | 124 | v := &gfP{} 125 | gfpMul(v, u1, i) 126 | 127 | // t4 = 4(s2-s1)² 128 | t4, t6 := &gfP{}, &gfP{} 129 | gfpMul(t4, r, r) 130 | gfpAdd(t, v, v) 131 | gfpSub(t6, t4, j) 132 | 133 | gfpSub(&c.x, t6, t) 134 | 135 | // Set y = -(2h)³(s1 + s*(x/4h²-u1)) 136 | // This is also 137 | // y = - 2·s1·j - (s2-s1)(2x - 2i·u1) = r(v-x) - 2·s1·j 138 | gfpSub(t, v, &c.x) // t7 139 | gfpMul(t4, s1, j) // t8 140 | gfpAdd(t6, t4, t4) // t9 141 | gfpMul(t4, r, t) // t10 142 | gfpSub(&c.y, t4, t6) 143 | 144 | // Set z = 2(u2-u1)·z1·z2 = 2h·z1·z2 145 | gfpAdd(t, &a.z, &b.z) // t11 146 | gfpMul(t4, t, t) // t12 147 | gfpSub(t, t4, z12) // t13 148 | gfpSub(t4, t, z22) // t14 149 | gfpMul(&c.z, t4, h) 150 | } 151 | 152 | func (c *curvePoint) Double(a *curvePoint) { 153 | // See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/doubling/dbl-2009-l.op3 154 | A, B, C := &gfP{}, &gfP{}, &gfP{} 155 | gfpMul(A, &a.x, &a.x) 156 | gfpMul(B, &a.y, &a.y) 157 | gfpMul(C, B, B) 158 | 159 | t, t2 := &gfP{}, &gfP{} 160 | gfpAdd(t, &a.x, B) 161 | gfpMul(t2, t, t) 162 | gfpSub(t, t2, A) 163 | gfpSub(t2, t, C) 164 | 165 | d, e, f := &gfP{}, &gfP{}, &gfP{} 166 | gfpAdd(d, t2, t2) 167 | gfpAdd(t, A, A) 168 | gfpAdd(e, t, A) 169 | gfpMul(f, e, e) 170 | 171 | gfpAdd(t, d, d) 172 | gfpSub(&c.x, f, t) 173 | 174 | gfpMul(&c.z, &a.y, &a.z) 175 | gfpAdd(&c.z, &c.z, &c.z) 176 | 177 | gfpAdd(t, C, C) 178 | gfpAdd(t2, t, t) 179 | gfpAdd(t, t2, t2) 180 | gfpSub(&c.y, d, &c.x) 181 | gfpMul(t2, e, &c.y) 182 | gfpSub(&c.y, t2, t) 183 | } 184 | 185 | func (c *curvePoint) Mul(a *curvePoint, scalar *big.Int) { 186 | sum, t := &curvePoint{}, &curvePoint{} 187 | sum.SetInfinity() 188 | 189 | for i := scalar.BitLen(); i >= 0; i-- { 190 | t.Double(sum) 191 | if scalar.Bit(i) != 0 { 192 | sum.Add(t, a) 193 | } else { 194 | sum.Set(t) 195 | } 196 | } 197 | 198 | c.Set(sum) 199 | } 200 | 201 | func (c *curvePoint) MakeAffine() { 202 | if c.z == *newGFp(1) { 203 | return 204 | } else if c.z == *newGFp(0) { 205 | c.x = gfP{0} 206 | c.y = *newGFp(1) 207 | c.t = gfP{0} 208 | return 209 | } 210 | 211 | zInv := &gfP{} 212 | zInv.Invert(&c.z) 213 | 214 | t, zInv2 := &gfP{}, &gfP{} 215 | gfpMul(t, &c.y, zInv) 216 | gfpMul(zInv2, zInv, zInv) 217 | 218 | gfpMul(&c.x, &c.x, zInv2) 219 | gfpMul(&c.y, t, zInv2) 220 | 221 | c.z = *newGFp(1) 222 | c.t = *newGFp(1) 223 | } 224 | 225 | func (c *curvePoint) Neg(a *curvePoint) { 226 | c.x.Set(&a.x) 227 | gfpNeg(&c.y, &a.y) 228 | c.z.Set(&a.z) 229 | c.t = gfP{0} 230 | } 231 | -------------------------------------------------------------------------------- /gfp6.go: -------------------------------------------------------------------------------- 1 | package bn256 2 | 3 | // For details of the algorithms used, see "Multiplication and Squaring on 4 | // Pairing-Friendly Fields, Devegili et al. 5 | // http://eprint.iacr.org/2006/471.pdf. 6 | 7 | // gfP6 implements the field of size p⁶ as a cubic extension of gfP2 where τ³=ξ 8 | // and ξ=i+3. 9 | type gfP6 struct { 10 | x, y, z gfP2 // value is xτ² + yτ + z 11 | } 12 | 13 | func (e *gfP6) String() string { 14 | return "(" + e.x.String() + ", " + e.y.String() + ", " + e.z.String() + ")" 15 | } 16 | 17 | func (e *gfP6) Set(a *gfP6) *gfP6 { 18 | e.x.Set(&a.x) 19 | e.y.Set(&a.y) 20 | e.z.Set(&a.z) 21 | return e 22 | } 23 | 24 | func (e *gfP6) SetZero() *gfP6 { 25 | e.x.SetZero() 26 | e.y.SetZero() 27 | e.z.SetZero() 28 | return e 29 | } 30 | 31 | func (e *gfP6) SetOne() *gfP6 { 32 | e.x.SetZero() 33 | e.y.SetZero() 34 | e.z.SetOne() 35 | return e 36 | } 37 | 38 | func (e *gfP6) IsZero() bool { 39 | return e.x.IsZero() && e.y.IsZero() && e.z.IsZero() 40 | } 41 | 42 | func (e *gfP6) IsOne() bool { 43 | return e.x.IsZero() && e.y.IsZero() && e.z.IsOne() 44 | } 45 | 46 | func (e *gfP6) Neg(a *gfP6) *gfP6 { 47 | e.x.Neg(&a.x) 48 | e.y.Neg(&a.y) 49 | e.z.Neg(&a.z) 50 | return e 51 | } 52 | 53 | func (e *gfP6) Frobenius(a *gfP6) *gfP6 { 54 | e.x.Conjugate(&a.x) 55 | e.y.Conjugate(&a.y) 56 | e.z.Conjugate(&a.z) 57 | 58 | e.x.Mul(&e.x, xiTo2PMinus2Over3) 59 | e.y.Mul(&e.y, xiToPMinus1Over3) 60 | return e 61 | } 62 | 63 | // FrobeniusP2 computes (xτ²+yτ+z)^(p²) = xτ^(2p²) + yτ^(p²) + z 64 | func (e *gfP6) FrobeniusP2(a *gfP6) *gfP6 { 65 | // τ^(2p²) = τ²τ^(2p²-2) = τ²ξ^((2p²-2)/3) 66 | e.x.MulScalar(&a.x, xiTo2PSquaredMinus2Over3) 67 | // τ^(p²) = ττ^(p²-1) = τξ^((p²-1)/3) 68 | e.y.MulScalar(&a.y, xiToPSquaredMinus1Over3) 69 | e.z.Set(&a.z) 70 | return e 71 | } 72 | 73 | func (e *gfP6) FrobeniusP4(a *gfP6) *gfP6 { 74 | e.x.MulScalar(&a.x, xiToPSquaredMinus1Over3) 75 | e.y.MulScalar(&a.y, xiTo2PSquaredMinus2Over3) 76 | e.z.Set(&a.z) 77 | return e 78 | } 79 | 80 | func (e *gfP6) Add(a, b *gfP6) *gfP6 { 81 | e.x.Add(&a.x, &b.x) 82 | e.y.Add(&a.y, &b.y) 83 | e.z.Add(&a.z, &b.z) 84 | return e 85 | } 86 | 87 | func (e *gfP6) Sub(a, b *gfP6) *gfP6 { 88 | e.x.Sub(&a.x, &b.x) 89 | e.y.Sub(&a.y, &b.y) 90 | e.z.Sub(&a.z, &b.z) 91 | return e 92 | } 93 | 94 | func (e *gfP6) Mul(a, b *gfP6) *gfP6 { 95 | // "Multiplication and Squaring on Pairing-Friendly Fields" 96 | // Section 4, Karatsuba method. 97 | // http://eprint.iacr.org/2006/471.pdf 98 | v0 := (&gfP2{}).Mul(&a.z, &b.z) 99 | v1 := (&gfP2{}).Mul(&a.y, &b.y) 100 | v2 := (&gfP2{}).Mul(&a.x, &b.x) 101 | 102 | t0 := (&gfP2{}).Add(&a.x, &a.y) 103 | t1 := (&gfP2{}).Add(&b.x, &b.y) 104 | tz := (&gfP2{}).Mul(t0, t1) 105 | tz.Sub(tz, v1).Sub(tz, v2).MulXi(tz).Add(tz, v0) 106 | 107 | t0.Add(&a.y, &a.z) 108 | t1.Add(&b.y, &b.z) 109 | ty := (&gfP2{}).Mul(t0, t1) 110 | t0.MulXi(v2) 111 | ty.Sub(ty, v0).Sub(ty, v1).Add(ty, t0) 112 | 113 | t0.Add(&a.x, &a.z) 114 | t1.Add(&b.x, &b.z) 115 | tx := (&gfP2{}).Mul(t0, t1) 116 | tx.Sub(tx, v0).Add(tx, v1).Sub(tx, v2) 117 | 118 | e.x.Set(tx) 119 | e.y.Set(ty) 120 | e.z.Set(tz) 121 | return e 122 | } 123 | 124 | func (e *gfP6) MulScalar(a *gfP6, b *gfP2) *gfP6 { 125 | e.x.Mul(&a.x, b) 126 | e.y.Mul(&a.y, b) 127 | e.z.Mul(&a.z, b) 128 | return e 129 | } 130 | 131 | func (e *gfP6) MulGFP(a *gfP6, b *gfP) *gfP6 { 132 | e.x.MulScalar(&a.x, b) 133 | e.y.MulScalar(&a.y, b) 134 | e.z.MulScalar(&a.z, b) 135 | return e 136 | } 137 | 138 | // MulTau computes τ·(aτ²+bτ+c) = bτ²+cτ+aξ 139 | func (e *gfP6) MulTau(a *gfP6) *gfP6 { 140 | tz := (&gfP2{}).MulXi(&a.x) 141 | ty := (&gfP2{}).Set(&a.y) 142 | 143 | e.y.Set(&a.z) 144 | e.x.Set(ty) 145 | e.z.Set(tz) 146 | return e 147 | } 148 | 149 | func (e *gfP6) Square(a *gfP6) *gfP6 { 150 | v0 := (&gfP2{}).Square(&a.z) 151 | v1 := (&gfP2{}).Square(&a.y) 152 | v2 := (&gfP2{}).Square(&a.x) 153 | 154 | c0 := (&gfP2{}).Add(&a.x, &a.y) 155 | c0.Square(c0).Sub(c0, v1).Sub(c0, v2).MulXi(c0).Add(c0, v0) 156 | 157 | c1 := (&gfP2{}).Add(&a.y, &a.z) 158 | c1.Square(c1).Sub(c1, v0).Sub(c1, v1) 159 | xiV2 := (&gfP2{}).MulXi(v2) 160 | c1.Add(c1, xiV2) 161 | 162 | c2 := (&gfP2{}).Add(&a.x, &a.z) 163 | c2.Square(c2).Sub(c2, v0).Add(c2, v1).Sub(c2, v2) 164 | 165 | e.x.Set(c2) 166 | e.y.Set(c1) 167 | e.z.Set(c0) 168 | return e 169 | } 170 | 171 | func (e *gfP6) Invert(a *gfP6) *gfP6 { 172 | // See "Implementing cryptographic pairings", M. Scott, section 3.2. 173 | // ftp://136.206.11.249/pub/crypto/pairings.pdf 174 | 175 | // Here we can give a short explanation of how it works: let j be a cubic root of 176 | // unity in GF(p²) so that 1+j+j²=0. 177 | // Then (xτ² + yτ + z)(xj²τ² + yjτ + z)(xjτ² + yj²τ + z) 178 | // = (xτ² + yτ + z)(Cτ²+Bτ+A) 179 | // = (x³ξ²+y³ξ+z³-3ξxyz) = F is an element of the base field (the norm). 180 | // 181 | // On the other hand (xj²τ² + yjτ + z)(xjτ² + yj²τ + z) 182 | // = τ²(y²-ξxz) + τ(ξx²-yz) + (z²-ξxy) 183 | // 184 | // So that's why A = (z²-ξxy), B = (ξx²-yz), C = (y²-ξxz) 185 | t1 := (&gfP2{}).Mul(&a.x, &a.y) 186 | t1.MulXi(t1) 187 | 188 | A := (&gfP2{}).Square(&a.z) 189 | A.Sub(A, t1) 190 | 191 | B := (&gfP2{}).Square(&a.x) 192 | B.MulXi(B) 193 | t1.Mul(&a.y, &a.z) 194 | B.Sub(B, t1) 195 | 196 | C := (&gfP2{}).Square(&a.y) 197 | t1.Mul(&a.x, &a.z) 198 | C.Sub(C, t1) 199 | 200 | F := (&gfP2{}).Mul(C, &a.y) 201 | F.MulXi(F) 202 | t1.Mul(A, &a.z) 203 | F.Add(F, t1) 204 | t1.Mul(B, &a.x).MulXi(t1) 205 | F.Add(F, t1) 206 | 207 | F.Invert(F) 208 | 209 | e.x.Mul(C, F) 210 | e.y.Mul(B, F) 211 | e.z.Mul(A, F) 212 | return e 213 | } 214 | -------------------------------------------------------------------------------- /optate.go: -------------------------------------------------------------------------------- 1 | package bn256 2 | 3 | func lineFunctionAdd(r, p *twistPoint, q *curvePoint, r2 *gfP2) (a, b, c *gfP2, rOut *twistPoint) { 4 | // See the mixed addition algorithm from "Faster Computation of the 5 | // Tate Pairing", http://arxiv.org/pdf/0904.0854v3.pdf 6 | B := (&gfP2{}).Mul(&p.x, &r.t) 7 | 8 | D := (&gfP2{}).Add(&p.y, &r.z) 9 | D.Square(D).Sub(D, r2).Sub(D, &r.t).Mul(D, &r.t) 10 | 11 | H := (&gfP2{}).Sub(B, &r.x) 12 | I := (&gfP2{}).Square(H) 13 | 14 | E := (&gfP2{}).Add(I, I) 15 | E.Add(E, E) 16 | 17 | J := (&gfP2{}).Mul(H, E) 18 | 19 | L1 := (&gfP2{}).Sub(D, &r.y) 20 | L1.Sub(L1, &r.y) 21 | 22 | V := (&gfP2{}).Mul(&r.x, E) 23 | 24 | rOut = &twistPoint{} 25 | rOut.x.Square(L1).Sub(&rOut.x, J).Sub(&rOut.x, V).Sub(&rOut.x, V) 26 | 27 | rOut.z.Add(&r.z, H).Square(&rOut.z).Sub(&rOut.z, &r.t).Sub(&rOut.z, I) 28 | 29 | t := (&gfP2{}).Sub(V, &rOut.x) 30 | t.Mul(t, L1) 31 | t2 := (&gfP2{}).Mul(&r.y, J) 32 | t2.Add(t2, t2) 33 | rOut.y.Sub(t, t2) 34 | 35 | rOut.t.Square(&rOut.z) 36 | 37 | t.Add(&p.y, &rOut.z).Square(t).Sub(t, r2).Sub(t, &rOut.t) 38 | 39 | t2.Mul(L1, &p.x) 40 | t2.Add(t2, t2) 41 | a = (&gfP2{}).Sub(t2, t) 42 | 43 | c = (&gfP2{}).MulScalar(&rOut.z, &q.y) 44 | c.Add(c, c) 45 | 46 | b = (&gfP2{}).Neg(L1) 47 | b.MulScalar(b, &q.x).Add(b, b) 48 | 49 | return 50 | } 51 | 52 | func lineFunctionDouble(r *twistPoint, q *curvePoint) (a, b, c *gfP2, rOut *twistPoint) { 53 | // See the doubling algorithm for a=0 from "Faster Computation of the 54 | // Tate Pairing", http://arxiv.org/pdf/0904.0854v3.pdf 55 | A := (&gfP2{}).Square(&r.x) 56 | B := (&gfP2{}).Square(&r.y) 57 | C := (&gfP2{}).Square(B) 58 | 59 | D := (&gfP2{}).Add(&r.x, B) 60 | D.Square(D).Sub(D, A).Sub(D, C).Add(D, D) 61 | 62 | E := (&gfP2{}).Add(A, A) 63 | E.Add(E, A) 64 | 65 | G := (&gfP2{}).Square(E) 66 | 67 | rOut = &twistPoint{} 68 | rOut.x.Sub(G, D).Sub(&rOut.x, D) 69 | 70 | rOut.z.Add(&r.y, &r.z).Square(&rOut.z).Sub(&rOut.z, B).Sub(&rOut.z, &r.t) 71 | 72 | rOut.y.Sub(D, &rOut.x).Mul(&rOut.y, E) 73 | t := (&gfP2{}).Add(C, C) 74 | t.Add(t, t).Add(t, t) 75 | rOut.y.Sub(&rOut.y, t) 76 | 77 | rOut.t.Square(&rOut.z) 78 | 79 | t.Mul(E, &r.t).Add(t, t) 80 | b = (&gfP2{}).Neg(t) 81 | b.MulScalar(b, &q.x) 82 | 83 | a = (&gfP2{}).Add(&r.x, E) 84 | a.Square(a).Sub(a, A).Sub(a, G) 85 | t.Add(B, B).Add(t, t) 86 | a.Sub(a, t) 87 | 88 | c = (&gfP2{}).Mul(&rOut.z, &r.t) 89 | c.Add(c, c).MulScalar(c, &q.y) 90 | 91 | return 92 | } 93 | 94 | func mulLine(ret *gfP12, a, b, c *gfP2) { 95 | a2 := &gfP6{} 96 | a2.y.Set(a) 97 | a2.z.Set(b) 98 | a2.Mul(a2, &ret.x) 99 | t3 := (&gfP6{}).MulScalar(&ret.y, c) 100 | 101 | t := (&gfP2{}).Add(b, c) 102 | t2 := &gfP6{} 103 | t2.y.Set(a) 104 | t2.z.Set(t) 105 | ret.x.Add(&ret.x, &ret.y) 106 | 107 | ret.y.Set(t3) 108 | 109 | ret.x.Mul(&ret.x, t2).Sub(&ret.x, a2).Sub(&ret.x, &ret.y) 110 | a2.MulTau(a2) 111 | ret.y.Add(&ret.y, a2) 112 | } 113 | 114 | // sixuPlus2NAF is 6u+2 in non-adjacent form. 115 | var sixuPlus2NAF = []int8{0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, -1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, -1, 0, 1, 0, 0, 0, 1, 0, -1, 0, 0, 0, -1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, -1, 0, -1, 0, 0, 0, 0, 1, 0, 0, 0, 1} 116 | 117 | // miller implements the Miller loop for calculating the Optimal Ate pairing. 118 | // See algorithm 1 from http://cryptojedi.org/papers/dclxvi-20100714.pdf 119 | func miller(q *twistPoint, p *curvePoint) *gfP12 { 120 | ret := (&gfP12{}).SetOne() 121 | 122 | aAffine := &twistPoint{} 123 | aAffine.Set(q) 124 | aAffine.MakeAffine() 125 | 126 | bAffine := &curvePoint{} 127 | bAffine.Set(p) 128 | bAffine.MakeAffine() 129 | 130 | minusA := &twistPoint{} 131 | minusA.Neg(aAffine) 132 | 133 | r := &twistPoint{} 134 | r.Set(aAffine) 135 | 136 | r2 := (&gfP2{}).Square(&aAffine.y) 137 | 138 | for i := len(sixuPlus2NAF) - 1; i > 0; i-- { 139 | a, b, c, newR := lineFunctionDouble(r, bAffine) 140 | if i != len(sixuPlus2NAF)-1 { 141 | ret.Square(ret) 142 | } 143 | 144 | mulLine(ret, a, b, c) 145 | r = newR 146 | 147 | switch sixuPlus2NAF[i-1] { 148 | case 1: 149 | a, b, c, newR = lineFunctionAdd(r, aAffine, bAffine, r2) 150 | case -1: 151 | a, b, c, newR = lineFunctionAdd(r, minusA, bAffine, r2) 152 | default: 153 | continue 154 | } 155 | 156 | mulLine(ret, a, b, c) 157 | r = newR 158 | } 159 | 160 | // In order to calculate Q1 we have to convert q from the sextic twist 161 | // to the full GF(p^12) group, apply the Frobenius there, and convert 162 | // back. 163 | // 164 | // The twist isomorphism is (x', y') -> (xω², yω³). If we consider just 165 | // x for a moment, then after applying the Frobenius, we have x̄ω^(2p) 166 | // where x̄ is the conjugate of x. If we are going to apply the inverse 167 | // isomorphism we need a value with a single coefficient of ω² so we 168 | // rewrite this as x̄ω^(2p-2)ω². ξ⁶ = ω and, due to the construction of 169 | // p, 2p-2 is a multiple of six. Therefore we can rewrite as 170 | // x̄ξ^((p-1)/3)ω² and applying the inverse isomorphism eliminates the 171 | // ω². 172 | // 173 | // A similar argument can be made for the y value. 174 | 175 | q1 := &twistPoint{} 176 | q1.x.Conjugate(&aAffine.x).Mul(&q1.x, xiToPMinus1Over3) 177 | q1.y.Conjugate(&aAffine.y).Mul(&q1.y, xiToPMinus1Over2) 178 | q1.z.SetOne() 179 | q1.t.SetOne() 180 | 181 | // For Q2 we are applying the p² Frobenius. The two conjugations cancel 182 | // out and we are left only with the factors from the isomorphism. In 183 | // the case of x, we end up with a pure number which is why 184 | // xiToPSquaredMinus1Over3 is ∈ GF(p). With y we get a factor of -1. We 185 | // ignore this to end up with -Q2. 186 | 187 | minusQ2 := &twistPoint{} 188 | minusQ2.x.MulScalar(&aAffine.x, xiToPSquaredMinus1Over3) 189 | minusQ2.y.Set(&aAffine.y) 190 | minusQ2.z.SetOne() 191 | minusQ2.t.SetOne() 192 | 193 | r2.Square(&q1.y) 194 | a, b, c, newR := lineFunctionAdd(r, q1, bAffine, r2) 195 | mulLine(ret, a, b, c) 196 | r = newR 197 | 198 | r2.Square(&minusQ2.y) 199 | a, b, c, _ = lineFunctionAdd(r, minusQ2, bAffine, r2) 200 | mulLine(ret, a, b, c) 201 | 202 | return ret 203 | } 204 | 205 | // finalExponentiation computes the (p¹²-1)/Order-th power of an element of 206 | // GF(p¹²) to obtain an element of GT (steps 13-15 of algorithm 1 from 207 | // http://cryptojedi.org/papers/dclxvi-20100714.pdf) 208 | func finalExponentiation(in *gfP12) *gfP12 { 209 | t1 := &gfP12{} 210 | 211 | // This is the p^6-Frobenius 212 | t1.x.Neg(&in.x) 213 | t1.y.Set(&in.y) 214 | 215 | inv := &gfP12{} 216 | inv.Invert(in) 217 | t1.Mul(t1, inv) 218 | 219 | t2 := (&gfP12{}).FrobeniusP2(t1) 220 | t1.Mul(t1, t2) 221 | 222 | fp := (&gfP12{}).Frobenius(t1) 223 | fp2 := (&gfP12{}).FrobeniusP2(t1) 224 | fp3 := (&gfP12{}).Frobenius(fp2) 225 | 226 | fu := (&gfP12{}).Exp(t1, u) 227 | fu2 := (&gfP12{}).Exp(fu, u) 228 | fu3 := (&gfP12{}).Exp(fu2, u) 229 | 230 | y3 := (&gfP12{}).Frobenius(fu) 231 | fu2p := (&gfP12{}).Frobenius(fu2) 232 | fu3p := (&gfP12{}).Frobenius(fu3) 233 | y2 := (&gfP12{}).FrobeniusP2(fu2) 234 | 235 | y0 := &gfP12{} 236 | y0.Mul(fp, fp2).Mul(y0, fp3) 237 | 238 | y1 := (&gfP12{}).Conjugate(t1) 239 | y5 := (&gfP12{}).Conjugate(fu2) 240 | y3.Conjugate(y3) 241 | y4 := (&gfP12{}).Mul(fu, fu2p) 242 | y4.Conjugate(y4) 243 | 244 | y6 := (&gfP12{}).Mul(fu3, fu3p) 245 | y6.Conjugate(y6) 246 | 247 | t0 := (&gfP12{}).Square(y6) 248 | t0.Mul(t0, y4).Mul(t0, y5) 249 | t1.Mul(y3, y5).Mul(t1, t0) 250 | t0.Mul(t0, y2) 251 | t1.Square(t1).Mul(t1, t0).Square(t1) 252 | t0.Mul(t1, y1) 253 | t1.Mul(t1, y0) 254 | t0.Square(t0).Mul(t0, t1) 255 | 256 | return t0 257 | } 258 | 259 | func optimalAte(a *twistPoint, b *curvePoint) *gfP12 { 260 | e := miller(a, b) 261 | ret := finalExponentiation(e) 262 | 263 | if a.IsInfinity() || b.IsInfinity() { 264 | ret.SetOne() 265 | } 266 | return ret 267 | } 268 | -------------------------------------------------------------------------------- /bn256.go: -------------------------------------------------------------------------------- 1 | // Package bn256 implements a particular bilinear group. 2 | // 3 | // Bilinear groups are the basis of many of the new cryptographic protocols that 4 | // have been proposed over the past decade. They consist of a triplet of groups 5 | // (G₁, G₂ and GT) such that there exists a function e(g₁ˣ,g₂ʸ)=gTˣʸ (where gₓ 6 | // is a generator of the respective group). That function is called a pairing 7 | // function. 8 | // 9 | // This package specifically implements the Optimal Ate pairing over a 256-bit 10 | // Barreto-Naehrig curve as described in 11 | // http://cryptojedi.org/papers/dclxvi-20100714.pdf. Its output is compatible 12 | // with the implementation described in that paper. 13 | // 14 | // This package previously claimed to operate at a 128-bit security level. 15 | // However, recent improvements in attacks mean that is no longer true. See 16 | // https://moderncrypto.org/mail-archive/curves/2016/000740.html. 17 | package bn256 18 | 19 | import ( 20 | "crypto/rand" 21 | "errors" 22 | "io" 23 | "math/big" 24 | ) 25 | 26 | func randomK(r io.Reader) (k *big.Int, err error) { 27 | for { 28 | k, err = rand.Int(r, Order) 29 | if err != nil || k.Sign() > 0 { 30 | return 31 | } 32 | } 33 | 34 | return 35 | } 36 | 37 | // G1 is an abstract cyclic group. The zero value is suitable for use as the 38 | // output of an operation, but cannot be used as an input. 39 | type G1 struct { 40 | p *curvePoint 41 | } 42 | 43 | // RandomG1 returns x and g₁ˣ where x is a random, non-zero number read from r. 44 | func RandomG1(r io.Reader) (*big.Int, *G1, error) { 45 | k, err := randomK(r) 46 | if err != nil { 47 | return nil, nil, err 48 | } 49 | 50 | return k, new(G1).ScalarBaseMult(k), nil 51 | } 52 | 53 | func (g *G1) String() string { 54 | return "bn256.G1" + g.p.String() 55 | } 56 | 57 | // ScalarBaseMult sets e to g*k where g is the generator of the group and then 58 | // returns e. 59 | func (e *G1) ScalarBaseMult(k *big.Int) *G1 { 60 | if e.p == nil { 61 | e.p = &curvePoint{} 62 | } 63 | e.p.Mul(curveGen, k) 64 | return e 65 | } 66 | 67 | // ScalarMult sets e to a*k and then returns e. 68 | func (e *G1) ScalarMult(a *G1, k *big.Int) *G1 { 69 | if e.p == nil { 70 | e.p = &curvePoint{} 71 | } 72 | e.p.Mul(a.p, k) 73 | return e 74 | } 75 | 76 | // Add sets e to a+b and then returns e. 77 | func (e *G1) Add(a, b *G1) *G1 { 78 | if e.p == nil { 79 | e.p = &curvePoint{} 80 | } 81 | e.p.Add(a.p, b.p) 82 | return e 83 | } 84 | 85 | // Neg sets e to -a and then returns e. 86 | func (e *G1) Neg(a *G1) *G1 { 87 | if e.p == nil { 88 | e.p = &curvePoint{} 89 | } 90 | e.p.Neg(a.p) 91 | return e 92 | } 93 | 94 | // Set sets e to a and then returns e. 95 | func (e *G1) Set(a *G1) *G1 { 96 | if e.p == nil { 97 | e.p = &curvePoint{} 98 | } 99 | e.p.Set(a.p) 100 | return e 101 | } 102 | 103 | // Marshal converts e to a byte slice. 104 | func (e *G1) Marshal() []byte { 105 | // Each value is a 256-bit number. 106 | const numBytes = 256 / 8 107 | 108 | if e.p == nil { 109 | e.p = &curvePoint{} 110 | } 111 | 112 | e.p.MakeAffine() 113 | ret := make([]byte, numBytes*2) 114 | if e.p.IsInfinity() { 115 | return ret 116 | } 117 | temp := &gfP{} 118 | 119 | montDecode(temp, &e.p.x) 120 | temp.Marshal(ret) 121 | montDecode(temp, &e.p.y) 122 | temp.Marshal(ret[numBytes:]) 123 | 124 | return ret 125 | } 126 | 127 | // Unmarshal sets e to the result of converting the output of Marshal back into 128 | // a group element and then returns e. 129 | func (e *G1) Unmarshal(m []byte) ([]byte, error) { 130 | // Each value is a 256-bit number. 131 | const numBytes = 256 / 8 132 | 133 | if len(m) < 2*numBytes { 134 | return nil, errors.New("bn256: not enough data") 135 | } 136 | 137 | if e.p == nil { 138 | e.p = &curvePoint{} 139 | } else { 140 | e.p.x, e.p.y = gfP{0}, gfP{0} 141 | } 142 | 143 | e.p.x.Unmarshal(m) 144 | e.p.y.Unmarshal(m[numBytes:]) 145 | montEncode(&e.p.x, &e.p.x) 146 | montEncode(&e.p.y, &e.p.y) 147 | 148 | zero := gfP{0} 149 | if e.p.x == zero && e.p.y == zero { 150 | // This is the point at infinity. 151 | e.p.y = *newGFp(1) 152 | e.p.z = gfP{0} 153 | e.p.t = gfP{0} 154 | } else { 155 | e.p.z = *newGFp(1) 156 | e.p.t = *newGFp(1) 157 | 158 | if !e.p.IsOnCurve() { 159 | return nil, errors.New("bn256: malformed point") 160 | } 161 | } 162 | 163 | return m[2*numBytes:], nil 164 | } 165 | 166 | // G2 is an abstract cyclic group. The zero value is suitable for use as the 167 | // output of an operation, but cannot be used as an input. 168 | type G2 struct { 169 | p *twistPoint 170 | } 171 | 172 | // RandomG2 returns x and g₂ˣ where x is a random, non-zero number read from r. 173 | func RandomG2(r io.Reader) (*big.Int, *G2, error) { 174 | k, err := randomK(r) 175 | if err != nil { 176 | return nil, nil, err 177 | } 178 | 179 | return k, new(G2).ScalarBaseMult(k), nil 180 | } 181 | 182 | func (e *G2) String() string { 183 | return "bn256.G2" + e.p.String() 184 | } 185 | 186 | // ScalarBaseMult sets e to g*k where g is the generator of the group and then 187 | // returns out. 188 | func (e *G2) ScalarBaseMult(k *big.Int) *G2 { 189 | if e.p == nil { 190 | e.p = &twistPoint{} 191 | } 192 | e.p.Mul(twistGen, k) 193 | return e 194 | } 195 | 196 | // ScalarMult sets e to a*k and then returns e. 197 | func (e *G2) ScalarMult(a *G2, k *big.Int) *G2 { 198 | if e.p == nil { 199 | e.p = &twistPoint{} 200 | } 201 | e.p.Mul(a.p, k) 202 | return e 203 | } 204 | 205 | // Add sets e to a+b and then returns e. 206 | func (e *G2) Add(a, b *G2) *G2 { 207 | if e.p == nil { 208 | e.p = &twistPoint{} 209 | } 210 | e.p.Add(a.p, b.p) 211 | return e 212 | } 213 | 214 | // Neg sets e to -a and then returns e. 215 | func (e *G2) Neg(a *G2) *G2 { 216 | if e.p == nil { 217 | e.p = &twistPoint{} 218 | } 219 | e.p.Neg(a.p) 220 | return e 221 | } 222 | 223 | // Set sets e to a and then returns e. 224 | func (e *G2) Set(a *G2) *G2 { 225 | if e.p == nil { 226 | e.p = &twistPoint{} 227 | } 228 | e.p.Set(a.p) 229 | return e 230 | } 231 | 232 | // Marshal converts e into a byte slice. 233 | func (e *G2) Marshal() []byte { 234 | // Each value is a 256-bit number. 235 | const numBytes = 256 / 8 236 | 237 | if e.p == nil { 238 | e.p = &twistPoint{} 239 | } 240 | 241 | e.p.MakeAffine() 242 | if e.p.IsInfinity() { 243 | return make([]byte, 1) 244 | } 245 | 246 | ret := make([]byte, 1+numBytes*4) 247 | ret[0] = 0x01 248 | temp := &gfP{} 249 | 250 | montDecode(temp, &e.p.x.x) 251 | temp.Marshal(ret[1:]) 252 | montDecode(temp, &e.p.x.y) 253 | temp.Marshal(ret[1+numBytes:]) 254 | montDecode(temp, &e.p.y.x) 255 | temp.Marshal(ret[1+2*numBytes:]) 256 | montDecode(temp, &e.p.y.y) 257 | temp.Marshal(ret[1+3*numBytes:]) 258 | 259 | return ret 260 | } 261 | 262 | // Unmarshal sets e to the result of converting the output of Marshal back into 263 | // a group element and then returns e. 264 | func (e *G2) Unmarshal(m []byte) ([]byte, error) { 265 | // Each value is a 256-bit number. 266 | const numBytes = 256 / 8 267 | 268 | if e.p == nil { 269 | e.p = &twistPoint{} 270 | } 271 | 272 | if len(m) > 0 && m[0] == 0x00 { 273 | e.p.SetInfinity() 274 | return m[1:], nil 275 | } else if len(m) > 0 && m[0] != 0x01 { 276 | return nil, errors.New("bn256: malformed point") 277 | } else if len(m) < 1+4*numBytes { 278 | return nil, errors.New("bn256: not enough data") 279 | } 280 | 281 | e.p.x.x.Unmarshal(m[1:]) 282 | e.p.x.y.Unmarshal(m[1+numBytes:]) 283 | e.p.y.x.Unmarshal(m[1+2*numBytes:]) 284 | e.p.y.y.Unmarshal(m[1+3*numBytes:]) 285 | montEncode(&e.p.x.x, &e.p.x.x) 286 | montEncode(&e.p.x.y, &e.p.x.y) 287 | montEncode(&e.p.y.x, &e.p.y.x) 288 | montEncode(&e.p.y.y, &e.p.y.y) 289 | 290 | if e.p.x.IsZero() && e.p.y.IsZero() { 291 | // This is the point at infinity. 292 | e.p.y.SetOne() 293 | e.p.z.SetZero() 294 | e.p.t.SetZero() 295 | } else { 296 | e.p.z.SetOne() 297 | e.p.t.SetOne() 298 | 299 | if !e.p.IsOnCurve() { 300 | return nil, errors.New("bn256: malformed point") 301 | } 302 | } 303 | 304 | return m[1+4*numBytes:], nil 305 | } 306 | 307 | // GT is an abstract cyclic group. The zero value is suitable for use as the 308 | // output of an operation, but cannot be used as an input. 309 | type GT struct { 310 | p *gfP12 311 | } 312 | 313 | // RandomGT returns x and e(g₁, g₂)ˣ where x is a random, non-zero number read 314 | // from r. 315 | func RandomGT(r io.Reader) (*big.Int, *GT, error) { 316 | k, err := randomK(r) 317 | if err != nil { 318 | return nil, nil, err 319 | } 320 | 321 | return k, new(GT).ScalarBaseMult(k), nil 322 | } 323 | 324 | // Pair calculates an Optimal Ate pairing. 325 | func Pair(g1 *G1, g2 *G2) *GT { 326 | return >{optimalAte(g2.p, g1.p)} 327 | } 328 | 329 | // Miller applies Miller's algorithm, which is a bilinear function from the 330 | // source groups to F_p^12. Miller(g1, g2).Finalize() is equivalent to Pair(g1, 331 | // g2). 332 | func Miller(g1 *G1, g2 *G2) *GT { 333 | return >{miller(g2.p, g1.p)} 334 | } 335 | 336 | func (g *GT) String() string { 337 | return "bn256.GT" + g.p.String() 338 | } 339 | 340 | // ScalarBaseMult sets e to g*k where g is the generator of the group and then 341 | // returns out. 342 | func (e *GT) ScalarBaseMult(k *big.Int) *GT { 343 | if e.p == nil { 344 | e.p = &gfP12{} 345 | } 346 | e.p.Exp(gfP12Gen, k) 347 | return e 348 | } 349 | 350 | // ScalarMult sets e to a*k and then returns e. 351 | func (e *GT) ScalarMult(a *GT, k *big.Int) *GT { 352 | if e.p == nil { 353 | e.p = &gfP12{} 354 | } 355 | e.p.Exp(a.p, k) 356 | return e 357 | } 358 | 359 | // Add sets e to a+b and then returns e. 360 | func (e *GT) Add(a, b *GT) *GT { 361 | if e.p == nil { 362 | e.p = &gfP12{} 363 | } 364 | e.p.Mul(a.p, b.p) 365 | return e 366 | } 367 | 368 | // Neg sets e to -a and then returns e. 369 | func (e *GT) Neg(a *GT) *GT { 370 | if e.p == nil { 371 | e.p = &gfP12{} 372 | } 373 | e.p.Conjugate(a.p) 374 | return e 375 | } 376 | 377 | // Set sets e to a and then returns e. 378 | func (e *GT) Set(a *GT) *GT { 379 | if e.p == nil { 380 | e.p = &gfP12{} 381 | } 382 | e.p.Set(a.p) 383 | return e 384 | } 385 | 386 | // Finalize is a linear function from F_p^12 to GT. 387 | func (e *GT) Finalize() *GT { 388 | ret := finalExponentiation(e.p) 389 | e.p.Set(ret) 390 | return e 391 | } 392 | 393 | // Marshal converts e into a byte slice. 394 | func (e *GT) Marshal() []byte { 395 | // Each value is a 256-bit number. 396 | const numBytes = 256 / 8 397 | 398 | if e.p == nil { 399 | e.p = &gfP12{} 400 | e.p.SetOne() 401 | } 402 | 403 | ret := make([]byte, numBytes*12) 404 | temp := &gfP{} 405 | 406 | montDecode(temp, &e.p.x.x.x) 407 | temp.Marshal(ret) 408 | montDecode(temp, &e.p.x.x.y) 409 | temp.Marshal(ret[numBytes:]) 410 | montDecode(temp, &e.p.x.y.x) 411 | temp.Marshal(ret[2*numBytes:]) 412 | montDecode(temp, &e.p.x.y.y) 413 | temp.Marshal(ret[3*numBytes:]) 414 | montDecode(temp, &e.p.x.z.x) 415 | temp.Marshal(ret[4*numBytes:]) 416 | montDecode(temp, &e.p.x.z.y) 417 | temp.Marshal(ret[5*numBytes:]) 418 | montDecode(temp, &e.p.y.x.x) 419 | temp.Marshal(ret[6*numBytes:]) 420 | montDecode(temp, &e.p.y.x.y) 421 | temp.Marshal(ret[7*numBytes:]) 422 | montDecode(temp, &e.p.y.y.x) 423 | temp.Marshal(ret[8*numBytes:]) 424 | montDecode(temp, &e.p.y.y.y) 425 | temp.Marshal(ret[9*numBytes:]) 426 | montDecode(temp, &e.p.y.z.x) 427 | temp.Marshal(ret[10*numBytes:]) 428 | montDecode(temp, &e.p.y.z.y) 429 | temp.Marshal(ret[11*numBytes:]) 430 | 431 | return ret 432 | } 433 | 434 | // Unmarshal sets e to the result of converting the output of Marshal back into 435 | // a group element and then returns e. 436 | func (e *GT) Unmarshal(m []byte) ([]byte, error) { 437 | // Each value is a 256-bit number. 438 | const numBytes = 256 / 8 439 | 440 | if len(m) < 12*numBytes { 441 | return nil, errors.New("bn256: not enough data") 442 | } 443 | 444 | if e.p == nil { 445 | e.p = &gfP12{} 446 | } 447 | 448 | e.p.x.x.x.Unmarshal(m) 449 | e.p.x.x.y.Unmarshal(m[numBytes:]) 450 | e.p.x.y.x.Unmarshal(m[2*numBytes:]) 451 | e.p.x.y.y.Unmarshal(m[3*numBytes:]) 452 | e.p.x.z.x.Unmarshal(m[4*numBytes:]) 453 | e.p.x.z.y.Unmarshal(m[5*numBytes:]) 454 | e.p.y.x.x.Unmarshal(m[6*numBytes:]) 455 | e.p.y.x.y.Unmarshal(m[7*numBytes:]) 456 | e.p.y.y.x.Unmarshal(m[8*numBytes:]) 457 | e.p.y.y.y.Unmarshal(m[9*numBytes:]) 458 | e.p.y.z.x.Unmarshal(m[10*numBytes:]) 459 | e.p.y.z.y.Unmarshal(m[11*numBytes:]) 460 | montEncode(&e.p.x.x.x, &e.p.x.x.x) 461 | montEncode(&e.p.x.x.y, &e.p.x.x.y) 462 | montEncode(&e.p.x.y.x, &e.p.x.y.x) 463 | montEncode(&e.p.x.y.y, &e.p.x.y.y) 464 | montEncode(&e.p.x.z.x, &e.p.x.z.x) 465 | montEncode(&e.p.x.z.y, &e.p.x.z.y) 466 | montEncode(&e.p.y.x.x, &e.p.y.x.x) 467 | montEncode(&e.p.y.x.y, &e.p.y.x.y) 468 | montEncode(&e.p.y.y.x, &e.p.y.y.x) 469 | montEncode(&e.p.y.y.y, &e.p.y.y.y) 470 | montEncode(&e.p.y.z.x, &e.p.y.z.x) 471 | montEncode(&e.p.y.z.y, &e.p.y.z.y) 472 | 473 | return m[12*numBytes:], nil 474 | } 475 | --------------------------------------------------------------------------------