crypto/bls12381: remove vendored library

This commit is contained in:
Marius van der Wijden 2024-04-08 09:55:55 +02:00
parent 1eab649970
commit 8c2bb6c383
37 changed files with 1 additions and 24101 deletions

View file

@ -1,241 +0,0 @@
// +build amd64,!generic
package bls12381
import (
"golang.org/x/sys/cpu"
)
func init() {
if !cpu.X86.HasADX || !cpu.X86.HasBMI2 {
mul = mulNoADX
wmul = wmulNoADX
fromWide = montRedNoADX
mulFR = mulNoADXFR
wmulFR = wmulNoADXFR
wfp2Mul = wfp2MulGeneric
wfp2Square = wfp2SquareGeneric
}
}
var mul func(c, a, b *fe) = mulADX
var wmul func(c *wfe, a, b *fe) = wmulADX
var fromWide func(c *fe, w *wfe) = montRedADX
var wfp2Mul func(c *wfe2, a, b *fe2) = wfp2MulADX
var wfp2Square func(c *wfe2, b *fe2) = wfp2SquareADX
func square(c, a *fe) {
mul(c, a, a)
}
func neg(c, a *fe) {
if a.isZero() {
c.set(a)
} else {
_neg(c, a)
}
}
//go:noescape
func add(c, a, b *fe)
//go:noescape
func addAssign(a, b *fe)
//go:noescape
func ladd(c, a, b *fe)
//go:noescape
func laddAssign(a, b *fe)
//go:noescape
func double(c, a *fe)
//go:noescape
func doubleAssign(a *fe)
//go:noescape
func ldouble(c, a *fe)
//go:noescape
func ldoubleAssign(a *fe)
//go:noescape
func sub(c, a, b *fe)
//go:noescape
func subAssign(a, b *fe)
//go:noescape
func lsubAssign(a, b *fe)
//go:noescape
func _neg(c, a *fe)
//go:noescape
func mulNoADX(c, a, b *fe)
//go:noescape
func mulADX(c, a, b *fe)
//go:noescape
func wmulNoADX(c *wfe, a, b *fe)
//go:noescape
func wmulADX(c *wfe, a, b *fe)
//go:noescape
func montRedNoADX(a *fe, w *wfe)
//go:noescape
func montRedADX(a *fe, w *wfe)
//go:noescape
func lwadd(c, a, b *wfe)
//go:noescape
func lwaddAssign(a, b *wfe)
//go:noescape
func wadd(c, a, b *wfe)
//go:noescape
func lwdouble(c, a *wfe)
//go:noescape
func wdouble(c, a *wfe)
//go:noescape
func lwsub(c, a, b *wfe)
//go:noescape
func lwsubAssign(a, b *wfe)
//go:noescape
func wsub(c, a, b *wfe)
//go:noescape
func fp2Add(c, a, b *fe2)
//go:noescape
func fp2AddAssign(a, b *fe2)
//go:noescape
func fp2Ladd(c, a, b *fe2)
//go:noescape
func fp2LaddAssign(a, b *fe2)
//go:noescape
func fp2DoubleAssign(a *fe2)
//go:noescape
func fp2Double(c, a *fe2)
//go:noescape
func fp2Sub(c, a, b *fe2)
//go:noescape
func fp2SubAssign(a, b *fe2)
//go:noescape
func mulByNonResidue(c, a *fe2)
//go:noescape
func mulByNonResidueAssign(a *fe2)
//go:noescape
func wfp2Add(c, a, b *wfe2)
//go:noescape
func wfp2AddAssign(a, b *wfe2)
//go:noescape
func wfp2Ladd(c, a, b *wfe2)
//go:noescape
func wfp2LaddAssign(a, b *wfe2)
//go:noescape
func wfp2AddMixed(c, a, b *wfe2)
//go:noescape
func wfp2AddMixedAssign(a, b *wfe2)
//go:noescape
func wfp2Sub(c, a, b *wfe2)
//go:noescape
func wfp2SubAssign(a, b *wfe2)
//go:noescape
func wfp2SubMixed(c, a, b *wfe2)
//go:noescape
func wfp2SubMixedAssign(a, b *wfe2)
//go:noescape
func wfp2Double(c, a *wfe2)
//go:noescape
func wfp2DoubleAssign(a *wfe2)
//go:noescape
func wfp2MulByNonResidue(c, a *wfe2)
//go:noescape
func wfp2MulByNonResidueAssign(a *wfe2)
//go:noescape
func wfp2SquareADX(c *wfe2, a *fe2)
//go:noescape
func wfp2MulADX(c *wfe2, a, b *fe2)
var mulFR func(c, a, b *Fr) = mulADXFR
var wmulFR func(c *wideFr, a, b *Fr) = wmulADXFR
func squareFR(c, a *Fr) {
mulFR(c, a, a)
}
func negFR(c, a *Fr) {
if a.IsZero() {
c.Set(a)
} else {
_negFR(c, a)
}
}
//go:noescape
func addFR(c, a, b *Fr)
//go:noescape
func laddAssignFR(a, b *Fr)
//go:noescape
func doubleFR(c, a *Fr)
//go:noescape
func subFR(c, a, b *Fr)
//go:noescape
func lsubAssignFR(a, b *Fr)
//go:noescape
func _negFR(c, a *Fr)
//go:noescape
func mulNoADXFR(c, a, b *Fr)
//go:noescape
func mulADXFR(c, a, b *Fr)
//go:noescape
func wmulADXFR(c *wideFr, a, b *Fr)
//go:noescape
func wmulNoADXFR(c *wideFr, a, b *Fr)
//go:noescape
func waddFR(a, b *wideFr)

View file

@ -1,62 +0,0 @@
// +build !amd64 generic
// Copyright 2020 ConsenSys Software Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Code generated by goff (v0.3.5) DO NOT EDIT
package bls12381
import (
"math/bits"
)
// madd0 hi = a*b + c (discards lo bits)
func madd0(a, b, c uint64) (hi uint64) {
var carry, lo uint64
hi, lo = bits.Mul64(a, b)
_, carry = bits.Add64(lo, c, 0)
hi, _ = bits.Add64(hi, 0, carry)
return
}
// madd1 hi, lo = a*b + c
func madd1(a, b, c uint64) (hi uint64, lo uint64) {
var carry uint64
hi, lo = bits.Mul64(a, b)
lo, carry = bits.Add64(lo, c, 0)
hi, _ = bits.Add64(hi, 0, carry)
return
}
// madd2 hi, lo = a*b + c + d
func madd2(a, b, c, d uint64) (hi uint64, lo uint64) {
var carry uint64
hi, lo = bits.Mul64(a, b)
c, carry = bits.Add64(c, d, 0)
hi, _ = bits.Add64(hi, 0, carry)
lo, carry = bits.Add64(lo, c, 0)
hi, _ = bits.Add64(hi, 0, carry)
return
}
func madd3(a, b, c, d, e uint64) (hi uint64, lo uint64) {
var carry uint64
hi, lo = bits.Mul64(a, b)
c, carry = bits.Add64(c, d, 0)
hi, _ = bits.Add64(hi, 0, carry)
lo, carry = bits.Add64(lo, c, 0)
hi, _ = bits.Add64(hi, e, carry)
return
}

File diff suppressed because it is too large Load diff

View file

@ -1,25 +0,0 @@
// Copyright 2020 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
//go:build amd64 && blsadx
// +build amd64,blsadx
package bls12381
// enableADX is true if the ADX/BMI2 instruction set was requested for the BLS
// implementation. The system may still fall back to plain ASM if the necessary
// instructions are unavailable on the CPU.
const enableADX = true

View file

@ -1,25 +0,0 @@
// Copyright 2020 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
//go:build amd64 && blsasm
// +build amd64,blsasm
package bls12381
// enableADX is true if the ADX/BMI2 instruction set was requested for the BLS
// implementation. The system may still fall back to plain ASM if the necessary
// instructions are unavailable on the CPU.
const enableADX = false

View file

@ -1,309 +0,0 @@
package bls12381
const fpNumberOfLimbs = 6
const fpByteSize = 48
const fpBitSize = 381
const sixWordBitSize = 384
// Base Field
// p = 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab
// r = 2 ^ 384
// modulus = p
var modulus = fe{0xb9feffffffffaaab, 0x1eabfffeb153ffff, 0x6730d2a0f6b0f624, 0x64774b84f38512bf, 0x4b1ba7b6434bacd7, 0x1a0111ea397fe69a}
// -p^(-1) mod 2^64
var inp uint64 = 0x89f3fffcfffcfffd
// r1 = r mod p
var r1 = &fe{0x760900000002fffd, 0xebf4000bc40c0002, 0x5f48985753c758ba, 0x77ce585370525745, 0x5c071a97a256ec6d, 0x15f65ec3fa80e493}
// one = mod p
var one = r1
// zero = 0
var zero = &fe{}
// r2 = r^2 mod p
var r2 = &fe{
0xf4df1f341c341746, 0x0a76e6a609d104f1, 0x8de5476c4c95b6d5, 0x67eb88a9939d83c0, 0x9a793e85b519952d, 0x11988fe592cae3aa,
}
// negativeOne = -r mod p
var negativeOne = &fe{
0x43f5fffffffcaaae, 0x32b7fff2ed47fffd, 0x07e83a49a2e99d69, 0xeca8f3318332bb7a, 0xef148d1ea0f4c069, 0x040ab3263eff0206,
}
// negativeOne2 = -1 + 0 * u
var negativeOne2 = &fe2{
fe{0x43f5fffffffcaaae, 0x32b7fff2ed47fffd, 0x07e83a49a2e99d69, 0xeca8f3318332bb7a, 0xef148d1ea0f4c069, 0x040ab3263eff0206},
fe{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000},
}
// twoInv = 2^(-1)
var twoInv = &fe{0x1804000000015554, 0x855000053ab00001, 0x633cb57c253c276f, 0x6e22d1ec31ebb502, 0xd3916126f2d14ca2, 0x17fbb8571a006596}
// pMinus3Over4 = (p - 3) / 4
var pMinus3Over4 = bigFromHex("0x680447a8e5ff9a692c6e9ed90d2eb35d91dd2e13ce144afd9cc34a83dac3d8907aaffffac54ffffee7fbfffffffeaaa")
// pPlus1Over4 = (p + 1) / 4
var pPlus1Over4 = bigFromHex("0x680447a8e5ff9a692c6e9ed90d2eb35d91dd2e13ce144afd9cc34a83dac3d8907aaffffac54ffffee7fbfffffffeaab")
// pMinus1Over2 = (p - 1) / 2
var pMinus1Over2 = bigFromHex("0xd0088f51cbff34d258dd3db21a5d66bb23ba5c279c2895fb39869507b587b120f55ffff58a9ffffdcff7fffffffd555")
// nonResidue1 = -1
var nonResidue1 = &fe{0x43f5fffffffcaaae, 0x32b7fff2ed47fffd, 0x07e83a49a2e99d69, 0xeca8f3318332bb7a, 0xef148d1ea0f4c069, 0x040ab3263eff0206}
// nonResidue2 = (1 + 1 * u)
var nonResidue2 = &fe2{
fe{0x760900000002fffd, 0xebf4000bc40c0002, 0x5f48985753c758ba, 0x77ce585370525745, 0x5c071a97a256ec6d, 0x15f65ec3fa80e493},
fe{0x760900000002fffd, 0xebf4000bc40c0002, 0x5f48985753c758ba, 0x77ce585370525745, 0x5c071a97a256ec6d, 0x15f65ec3fa80e493},
}
// Scalar Field
// q = 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001
// Size of six words
// qr = 2 ^ 256
var qBig = bigFromHex("0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001")
var q = Fr{0xffffffff00000001, 0x53bda402fffe5bfe, 0x3339d80809a1d805, 0x73eda753299d7d48}
// var qmodulus = Fr{0xffffffff00000001, 0x53bda402fffe5bfe, 0x3339d80809a1d805, 0x73eda753299d7d48}
// -q^(-1) mod 2^64
var qinp uint64 = 0xfffffffeffffffff
// supress warning: qinp is used in assembly code
var _ = qinp
// qr1 = qr mod q
var qr1 = &Fr{0x00000001fffffffe, 0x5884b7fa00034802, 0x998c4fefecbc4ff5, 0x1824b159acc5056f}
// qr2 = qr^2 mod q
var qr2 = &Fr{0xc999e990f3f29c6d, 0x2b6cedcb87925c23, 0x05d314967254398f, 0x0748d9d99f59ff11}
// Curve Constants
// b coefficient for G1
var b = &fe{0xaa270000000cfff3, 0x53cc0032fc34000a, 0x478fe97a6b0a807f, 0xb1d37ebee6ba24d7, 0x8ec9733bbf78ab2f, 0x09d645513d83de7e}
// b coefficient for G2
var b2 = &fe2{
fe{0xaa270000000cfff3, 0x53cc0032fc34000a, 0x478fe97a6b0a807f, 0xb1d37ebee6ba24d7, 0x8ec9733bbf78ab2f, 0x09d645513d83de7e},
fe{0xaa270000000cfff3, 0x53cc0032fc34000a, 0x478fe97a6b0a807f, 0xb1d37ebee6ba24d7, 0x8ec9733bbf78ab2f, 0x09d645513d83de7e},
}
// G1 cofactor
var cofactorG1 = bigFromHex("0x396c8c005555e1568c00aaab0000aaab")
// G2 cofactor
var cofactorG2 = bigFromHex("5d543a95414e7f1091d50792876a202cd91de4547085abaa68a205b2e5a7ddfa628f1cb4d9e82ef21537e293a6691ae1616ec6e786f0c70cf1c38e31c7238e5")
// Efficient G1 cofactor
var cofactorEFFG1 = bigFromHex("0xd201000000010001")
// Efficient G2 cofactor
var cofactorEFFG2 = bigFromHex("0x0bc69f08f2ee75b3584c6a0ea91b352888e2a8e9145ad7689986ff031508ffe1329c2f178731db956d82bf015d1212b02ec0ec69d7477c1ae954cbc06689f6a359894c0adebbf6b4e8020005aaa95551")
// G1 generator
var g1One = PointG1{
fe{0x5cb38790fd530c16, 0x7817fc679976fff5, 0x154f95c7143ba1c1, 0xf0ae6acdf3d0e747, 0xedce6ecc21dbf440, 0x120177419e0bfb75},
fe{0xbaac93d50ce72271, 0x8c22631a7918fd8e, 0xdd595f13570725ce, 0x51ac582950405194, 0x0e1c8c3fad0059c0, 0x0bbc3efc5008a26a},
fe{0x760900000002fffd, 0xebf4000bc40c0002, 0x5f48985753c758ba, 0x77ce585370525745, 0x5c071a97a256ec6d, 0x15f65ec3fa80e493},
}
var G1One = g1One
// G2 generator
var g2One = PointG2{
fe2{
fe{0xf5f28fa202940a10, 0xb3f5fb2687b4961a, 0xa1a893b53e2ae580, 0x9894999d1a3caee9, 0x6f67b7631863366b, 0x058191924350bcd7},
fe{0xa5a9c0759e23f606, 0xaaa0c59dbccd60c3, 0x3bb17e18e2867806, 0x1b1ab6cc8541b367, 0xc2b6ed0ef2158547, 0x11922a097360edf3},
},
fe2{
fe{0x4c730af860494c4a, 0x597cfa1f5e369c5a, 0xe7e6856caa0a635a, 0xbbefb5e96e0d495f, 0x07d3a975f0ef25a2, 0x083fd8e7e80dae5},
fe{0xadc0fc92df64b05d, 0x18aa270a2b1461dc, 0x86adac6a3be4eba0, 0x79495c4ec93da33a, 0xe7175850a43ccaed, 0xb2bc2a163de1bf2},
},
fe2{
fe{0x760900000002fffd, 0xebf4000bc40c0002, 0x5f48985753c758ba, 0x77ce585370525745, 0x5c071a97a256ec6d, 0x15f65ec3fa80e493},
fe{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000},
},
}
var G2One = g2One
// Psi values for faster cofactor clearing
// psix = 1 / (nr ^ (p - 1)/3)
var psix = fe2{
fe{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000},
fe{0x890dc9e4867545c3, 0x2af322533285a5d5, 0x50880866309b7e2c, 0xa20d1b8c7e881024, 0x14e4f04fe2db9068, 0x14e56d3f1564853a},
}
// psiy = 1 / (nr ^ (p - 1)/2)
var psiy = fe2{
fe{0x3e2f585da55c9ad1, 0x4294213d86c18183, 0x382844c88b623732, 0x92ad2afd19103e18, 0x1d794e4fac7cf0b9, 0x0bd592fc7d825ec8},
fe{0x7bcfa7a25aa30fda, 0xdc17dec12a927e7c, 0x2f088dd86b4ebef1, 0xd1ca2087da74d4a7, 0x2da2596696cebc1d, 0x0e2b7eedbbfd87d2},
}
// Frobenius Coeffs
// z = -1
var frobeniusCoeffs2 = [2]fe{
// z ^ (( p ^ 0 - 1) / 2)
{0x760900000002fffd, 0xebf4000bc40c0002, 0x5f48985753c758ba, 0x77ce585370525745, 0x5c071a97a256ec6d, 0x15f65ec3fa80e493},
// z ^ (( p ^ 1 - 1) / 2)
{0x43f5fffffffcaaae, 0x32b7fff2ed47fffd, 0x07e83a49a2e99d69, 0xeca8f3318332bb7a, 0xef148d1ea0f4c069, 0x040ab3263eff0206},
}
// z = u + 1
var frobeniusCoeffs61 = [6]fe2{
// z ^ (( p ^ 0 - 1) / 3)
{
{0x760900000002fffd, 0xebf4000bc40c0002, 0x5f48985753c758ba, 0x77ce585370525745, 0x5c071a97a256ec6d, 0x15f65ec3fa80e493},
{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000},
},
// z ^ (( p ^ 1 - 1) / 3)
{
{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000},
{0xcd03c9e48671f071, 0x5dab22461fcda5d2, 0x587042afd3851b95, 0x8eb60ebe01bacb9e, 0x03f97d6e83d050d2, 0x18f0206554638741},
},
// z ^ (( p ^ 2 - 1) / 3)
{
{0x30f1361b798a64e8, 0xf3b8ddab7ece5a2a, 0x16a8ca3ac61577f7, 0xc26a2ff874fd029b, 0x3636b76660701c6e, 0x051ba4ab241b6160},
{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000},
},
// z ^ (( p ^ 3 - 1) / 3)
{
{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000},
{0x760900000002fffd, 0xebf4000bc40c0002, 0x5f48985753c758ba, 0x77ce585370525745, 0x5c071a97a256ec6d, 0x15f65ec3fa80e493},
},
// z ^ (( p ^ 4 - 1) / 3)
{
{0xcd03c9e48671f071, 0x5dab22461fcda5d2, 0x587042afd3851b95, 0x8eb60ebe01bacb9e, 0x03f97d6e83d050d2, 0x18f0206554638741},
{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000},
},
// z ^ (( p ^ 5 - 1) / 3)
{
{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000},
{0x30f1361b798a64e8, 0xf3b8ddab7ece5a2a, 0x16a8ca3ac61577f7, 0xc26a2ff874fd029b, 0x3636b76660701c6e, 0x051ba4ab241b6160},
},
}
// z = u + 1
var frobeniusCoeffs62 = [6]fe2{
// z ^ (( 2 * p ^ 0 - 2) / 3)
{
{0x760900000002fffd, 0xebf4000bc40c0002, 0x5f48985753c758ba, 0x77ce585370525745, 0x5c071a97a256ec6d, 0x15f65ec3fa80e493},
{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000},
},
// z ^ (( 2 * p ^ 1 - 2) / 3)
{
{0x890dc9e4867545c3, 0x2af322533285a5d5, 0x50880866309b7e2c, 0xa20d1b8c7e881024, 0x14e4f04fe2db9068, 0x14e56d3f1564853a},
{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000},
},
// z ^ (( 2 * p ^ 2 - 2) / 3)
{
{0xcd03c9e48671f071, 0x5dab22461fcda5d2, 0x587042afd3851b95, 0x8eb60ebe01bacb9e, 0x03f97d6e83d050d2, 0x18f0206554638741},
{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000},
},
// z ^ (( 2 * p ^ 3 - 2) / 3)
{
{0x43f5fffffffcaaae, 0x32b7fff2ed47fffd, 0x07e83a49a2e99d69, 0xeca8f3318332bb7a, 0xef148d1ea0f4c069, 0x040ab3263eff0206},
{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000},
},
// z ^ (( 2 * p ^ 4 - 2) / 3)
{
{0x30f1361b798a64e8, 0xf3b8ddab7ece5a2a, 0x16a8ca3ac61577f7, 0xc26a2ff874fd029b, 0x3636b76660701c6e, 0x051ba4ab241b6160},
{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000},
},
// z ^ (( 2 * p ^ 5 - 2) / 3)
{
{0xecfb361b798dba3a, 0xc100ddb891865a2c, 0x0ec08ff1232bda8e, 0xd5c13cc6f1ca4721, 0x47222a47bf7b5c04, 0x0110f184e51c5f59},
{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000},
},
}
var frobeniusCoeffs12 = [12]fe2{
// z = u + 1
// z ^ ((p ^ 0 - 1) / 6)
{
{0x760900000002fffd, 0xebf4000bc40c0002, 0x5f48985753c758ba, 0x77ce585370525745, 0x5c071a97a256ec6d, 0x15f65ec3fa80e493},
{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000},
},
// z ^ ((p ^ 1 - 1) / 6)
{
{0x07089552b319d465, 0xc6695f92b50a8313, 0x97e83cccd117228f, 0xa35baecab2dc29ee, 0x1ce393ea5daace4d, 0x08f2220fb0fb66eb},
{0xb2f66aad4ce5d646, 0x5842a06bfc497cec, 0xcf4895d42599d394, 0xc11b9cba40a8e8d0, 0x2e3813cbe5a0de89, 0x110eefda88847faf},
},
// z ^ ((p ^ 2 - 1) / 6)
{
{0xecfb361b798dba3a, 0xc100ddb891865a2c, 0x0ec08ff1232bda8e, 0xd5c13cc6f1ca4721, 0x47222a47bf7b5c04, 0x0110f184e51c5f59},
{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000},
},
// z ^ ((p ^ 3 - 1) / 6)
{
{0x3e2f585da55c9ad1, 0x4294213d86c18183, 0x382844c88b623732, 0x92ad2afd19103e18, 0x1d794e4fac7cf0b9, 0x0bd592fc7d825ec8},
{0x7bcfa7a25aa30fda, 0xdc17dec12a927e7c, 0x2f088dd86b4ebef1, 0xd1ca2087da74d4a7, 0x2da2596696cebc1d, 0x0e2b7eedbbfd87d2},
},
// z ^ ((p ^ 4 - 1) / 6)
{
{0x30f1361b798a64e8, 0xf3b8ddab7ece5a2a, 0x16a8ca3ac61577f7, 0xc26a2ff874fd029b, 0x3636b76660701c6e, 0x051ba4ab241b6160},
{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000},
},
// z ^ ((p ^ 5 - 1) / 6)
{
{0x3726c30af242c66c, 0x7c2ac1aad1b6fe70, 0xa04007fbba4b14a2, 0xef517c3266341429, 0x0095ba654ed2226b, 0x02e370eccc86f7dd},
{0x82d83cf50dbce43f, 0xa2813e53df9d018f, 0xc6f0caa53c65e181, 0x7525cf528d50fe95, 0x4a85ed50f4798a6b, 0x171da0fd6cf8eebd},
},
// z ^ ((p ^ 6 - 1) / 6)
{
{0x43f5fffffffcaaae, 0x32b7fff2ed47fffd, 0x07e83a49a2e99d69, 0xeca8f3318332bb7a, 0xef148d1ea0f4c069, 0x040ab3263eff0206},
{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000},
},
// z ^ ((p ^ 7 - 1) / 6)
{
{0xb2f66aad4ce5d646, 0x5842a06bfc497cec, 0xcf4895d42599d394, 0xc11b9cba40a8e8d0, 0x2e3813cbe5a0de89, 0x110eefda88847faf},
{0x07089552b319d465, 0xc6695f92b50a8313, 0x97e83cccd117228f, 0xa35baecab2dc29ee, 0x1ce393ea5daace4d, 0x08f2220fb0fb66eb},
},
// z ^ ((p ^ 8 - 1) / 6)
{
{0xcd03c9e48671f071, 0x5dab22461fcda5d2, 0x587042afd3851b95, 0x8eb60ebe01bacb9e, 0x03f97d6e83d050d2, 0x18f0206554638741},
{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000},
},
// z ^ ((p ^ 9 - 1) / 6)
{
{0x7bcfa7a25aa30fda, 0xdc17dec12a927e7c, 0x2f088dd86b4ebef1, 0xd1ca2087da74d4a7, 0x2da2596696cebc1d, 0x0e2b7eedbbfd87d2},
{0x3e2f585da55c9ad1, 0x4294213d86c18183, 0x382844c88b623732, 0x92ad2afd19103e18, 0x1d794e4fac7cf0b9, 0x0bd592fc7d825ec8},
},
// z ^ ((p ^ 10 - 1) / 6)
{
{0x890dc9e4867545c3, 0x2af322533285a5d5, 0x50880866309b7e2c, 0xa20d1b8c7e881024, 0x14e4f04fe2db9068, 0x14e56d3f1564853a},
{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000},
},
// z ^ ((p ^ 11 - 1) / 6)
{
{0x82d83cf50dbce43f, 0xa2813e53df9d018f, 0xc6f0caa53c65e181, 0x7525cf528d50fe95, 0x4a85ed50f4798a6b, 0x171da0fd6cf8eebd},
{0x3726c30af242c66c, 0x7c2ac1aad1b6fe70, 0xa04007fbba4b14a2, 0xef517c3266341429, 0x0095ba654ed2226b, 0x02e370eccc86f7dd},
},
}
// x
// var x = bigFromHex("0xd201000000010000")
var x uint64 = 0xd201000000010000
// square root
var sqrtMinus1 = &fe2{*new(fe).zero(), *new(fe).one()}
var sqrtSqrtMinus1 = &fe2{
fe{0x3e2f585da55c9ad1, 0x4294213d86c18183, 0x382844c88b623732, 0x92ad2afd19103e18, 0x1d794e4fac7cf0b9, 0x0bd592fc7d825ec8},
fe{0x7bcfa7a25aa30fda, 0xdc17dec12a927e7c, 0x2f088dd86b4ebef1, 0xd1ca2087da74d4a7, 0x2da2596696cebc1d, 0x0e2b7eedbbfd87d2},
}
var sqrtMinusSqrtMinus1 = &fe2{
fe{0x7bcfa7a25aa30fda, 0xdc17dec12a927e7c, 0x2f088dd86b4ebef1, 0xd1ca2087da74d4a7, 0x2da2596696cebc1d, 0x0e2b7eedbbfd87d2},
fe{0x7bcfa7a25aa30fda, 0xdc17dec12a927e7c, 0x2f088dd86b4ebef1, 0xd1ca2087da74d4a7, 0x2da2596696cebc1d, 0x0e2b7eedbbfd87d2},
}

View file

@ -1,67 +0,0 @@
package bls12381
import (
"crypto/rand"
"encoding/hex"
"errors"
"flag"
"math/big"
"os"
"testing"
)
var fuz int
func TestMain(m *testing.M) {
_fuz := flag.Int("fuzz", 10, "# of iterations")
flag.Parse()
fuz = *_fuz
os.Exit(m.Run())
}
func randScalar(max *big.Int) *big.Int {
a, err := rand.Int(rand.Reader, max)
if err != nil {
panic(errors.New(""))
}
return a
}
func fromHex(size int, hexStrs ...string) []byte {
var out []byte
if size > 0 {
out = make([]byte, size*len(hexStrs))
}
for i := 0; i < len(hexStrs); i++ {
hexStr := hexStrs[i]
if hexStr[:2] == "0x" {
hexStr = hexStr[2:]
}
if len(hexStr)%2 == 1 {
hexStr = "0" + hexStr
}
bytes, err := hex.DecodeString(hexStr)
if err != nil {
return nil
}
if size <= 0 {
out = append(out, bytes...)
} else {
if len(bytes) > size {
return nil
}
offset := i*size + (size - len(bytes))
copy(out[offset:], bytes)
}
}
return out
}
func padBytes(in []byte, size int) []byte {
out := make([]byte, size)
if len(in) > size {
panic("bad input for padding")
}
copy(out[size-len(in):], in)
return out
}

View file

@ -1,404 +0,0 @@
package bls12381
import (
"crypto/rand"
"encoding/hex"
"fmt"
"io"
"math/big"
)
// fe is base field element representation
type fe /*** ***/ [fpNumberOfLimbs]uint64
// fe2 is element representation of 'fp2' which is quadratic extention of base field 'fp'
// Representation follows c[0] + c[1] * u encoding order.
type fe2 /** ***/ [2]fe
// fe6 is element representation of 'fp6' field which is cubic extention of 'fp2'
// Representation follows c[0] + c[1] * v + c[2] * v^2 encoding order.
type fe6 /** ***/ [3]fe2
// fe12 is element representation of 'fp12' field which is quadratic extention of 'fp6'
// Representation follows c[0] + c[1] * w encoding order.
type fe12 /** ***/ [2]fe6
type wfe /*** ***/ [fpNumberOfLimbs * 2]uint64
type wfe2 /** ***/ [2]wfe
type wfe6 /** ***/ [3]wfe2
func (fe *fe) setBytes(in []byte) *fe {
l := len(in)
if l >= fpByteSize {
l = fpByteSize
}
padded := make([]byte, fpByteSize)
copy(padded[fpByteSize-l:], in[:])
var a int
for i := 0; i < fpNumberOfLimbs; i++ {
a = fpByteSize - i*8
fe[i] = uint64(padded[a-1]) | uint64(padded[a-2])<<8 |
uint64(padded[a-3])<<16 | uint64(padded[a-4])<<24 |
uint64(padded[a-5])<<32 | uint64(padded[a-6])<<40 |
uint64(padded[a-7])<<48 | uint64(padded[a-8])<<56
}
return fe
}
func (fe *fe) setBig(a *big.Int) *fe {
return fe.setBytes(a.Bytes())
}
func (fe *fe) setString(s string) (*fe, error) {
if s[:2] == "0x" {
s = s[2:]
}
bytes, err := hex.DecodeString(s)
if err != nil {
return nil, err
}
return fe.setBytes(bytes), nil
}
func (fe *fe) set(fe2 *fe) *fe {
fe[0] = fe2[0]
fe[1] = fe2[1]
fe[2] = fe2[2]
fe[3] = fe2[3]
fe[4] = fe2[4]
fe[5] = fe2[5]
return fe
}
func (fe *fe) bytes() []byte {
out := make([]byte, fpByteSize)
var a int
for i := 0; i < fpNumberOfLimbs; i++ {
a = fpByteSize - i*8
out[a-1] = byte(fe[i])
out[a-2] = byte(fe[i] >> 8)
out[a-3] = byte(fe[i] >> 16)
out[a-4] = byte(fe[i] >> 24)
out[a-5] = byte(fe[i] >> 32)
out[a-6] = byte(fe[i] >> 40)
out[a-7] = byte(fe[i] >> 48)
out[a-8] = byte(fe[i] >> 56)
}
return out
}
func (fe *fe) big() *big.Int {
return new(big.Int).SetBytes(fe.bytes())
}
func (fe *fe) string() (s string) {
for i := fpNumberOfLimbs - 1; i >= 0; i-- {
s = fmt.Sprintf("%s%16.16x", s, fe[i])
}
return "0x" + s
}
func (fe *fe) zero() *fe {
fe[0] = 0
fe[1] = 0
fe[2] = 0
fe[3] = 0
fe[4] = 0
fe[5] = 0
return fe
}
func (fe *fe) one() *fe {
return fe.set(r1)
}
func (fe *fe) rand(r io.Reader) (*fe, error) {
bi, err := rand.Int(r, modulus.big())
if err != nil {
return nil, err
}
return fe.setBig(bi), nil
}
func (fe *fe) isValid() bool {
return fe.cmp(&modulus) == -1
}
func (fe *fe) isOdd() bool {
var mask uint64 = 1
return fe[0]&mask != 0
}
func (fe *fe) isEven() bool {
var mask uint64 = 1
return fe[0]&mask == 0
}
func (fe *fe) isZero() bool {
return (fe[5] | fe[4] | fe[3] | fe[2] | fe[1] | fe[0]) == 0
}
func (fe *fe) isOne() bool {
return fe.equal(r1)
}
func (fe *fe) cmp(fe2 *fe) int {
for i := fpNumberOfLimbs - 1; i >= 0; i-- {
if fe[i] > fe2[i] {
return 1
} else if fe[i] < fe2[i] {
return -1
}
}
return 0
}
func (fe *fe) equal(fe2 *fe) bool {
return fe2[0] == fe[0] && fe2[1] == fe[1] && fe2[2] == fe[2] && fe2[3] == fe[3] && fe2[4] == fe[4] && fe2[5] == fe[5]
}
func (e *fe) signBE() bool {
negZ, z := new(fe), new(fe)
fromMont(z, e)
neg(negZ, z)
return negZ.cmp(z) > -1
}
func (e *fe) sign() bool {
r := new(fe)
fromMont(r, e)
return r[0]&1 == 0
}
func (e *fe) div2(u uint64) {
e[0] = e[0]>>1 | e[1]<<63
e[1] = e[1]>>1 | e[2]<<63
e[2] = e[2]>>1 | e[3]<<63
e[3] = e[3]>>1 | e[4]<<63
e[4] = e[4]>>1 | e[5]<<63
e[5] = e[5]>>1 | u<<63
}
func (e *fe) mul2() uint64 {
u := e[5] >> 63
e[5] = e[5]<<1 | e[4]>>63
e[4] = e[4]<<1 | e[3]>>63
e[3] = e[3]<<1 | e[2]>>63
e[2] = e[2]<<1 | e[1]>>63
e[1] = e[1]<<1 | e[0]>>63
e[0] = e[0] << 1
return u
}
func (e *fe2) zero() *fe2 {
e[0].zero()
e[1].zero()
return e
}
func (e *fe2) one() *fe2 {
e[0].one()
e[1].zero()
return e
}
func (e *fe2) set(e2 *fe2) *fe2 {
e[0].set(&e2[0])
e[1].set(&e2[1])
return e
}
func (e *fe2) fromMont(a *fe2) {
fromMont(&e[0], &a[0])
fromMont(&e[1], &a[1])
}
func (e *fe2) fromWide(w *wfe2) {
fromWide(&e[0], &w[0])
fromWide(&e[1], &w[1])
}
func (e *fe2) rand(r io.Reader) (*fe2, error) {
a0, err := new(fe).rand(r)
if err != nil {
return nil, err
}
e[0].set(a0)
a1, err := new(fe).rand(r)
if err != nil {
return nil, err
}
e[1].set(a1)
return e, nil
}
func (e *fe2) isOne() bool {
return e[0].isOne() && e[1].isZero()
}
func (e *fe2) isZero() bool {
return e[0].isZero() && e[1].isZero()
}
func (e *fe2) equal(e2 *fe2) bool {
return e[0].equal(&e2[0]) && e[1].equal(&e2[1])
}
func (e *fe2) signBE() bool {
if !e[1].isZero() {
return e[1].signBE()
}
return e[0].signBE()
}
func (e *fe2) sign() bool {
r := new(fe)
if !e[0].isZero() {
fromMont(r, &e[0])
return r[0]&1 == 0
}
fromMont(r, &e[1])
return r[0]&1 == 0
}
func (e *fe6) zero() *fe6 {
e[0].zero()
e[1].zero()
e[2].zero()
return e
}
func (e *fe6) one() *fe6 {
e[0].one()
e[1].zero()
e[2].zero()
return e
}
func (e *fe6) set(e2 *fe6) *fe6 {
e[0].set(&e2[0])
e[1].set(&e2[1])
e[2].set(&e2[2])
return e
}
func (e *fe6) fromMont(a *fe6) {
e[0].fromMont(&a[0])
e[1].fromMont(&a[1])
e[2].fromMont(&a[2])
}
func (e *fe6) fromWide(w *wfe6) {
e[0].fromWide(&w[0])
e[1].fromWide(&w[1])
e[2].fromWide(&w[2])
}
func (e *fe6) rand(r io.Reader) (*fe6, error) {
a0, err := new(fe2).rand(r)
if err != nil {
return nil, err
}
e[0].set(a0)
a1, err := new(fe2).rand(r)
if err != nil {
return nil, err
}
e[1].set(a1)
a2, err := new(fe2).rand(r)
if err != nil {
return nil, err
}
e[2].set(a2)
return e, nil
}
func (e *fe6) isOne() bool {
return e[0].isOne() && e[1].isZero() && e[2].isZero()
}
func (e *fe6) isZero() bool {
return e[0].isZero() && e[1].isZero() && e[2].isZero()
}
func (e *fe6) equal(e2 *fe6) bool {
return e[0].equal(&e2[0]) && e[1].equal(&e2[1]) && e[2].equal(&e2[2])
}
func (e *fe12) zero() *fe12 {
e[0].zero()
e[1].zero()
return e
}
func (e *fe12) one() *fe12 {
e[0].one()
e[1].zero()
return e
}
func (e *fe12) set(e2 *fe12) *fe12 {
e[0].set(&e2[0])
e[1].set(&e2[1])
return e
}
func (e *fe12) fromMont(a *fe12) {
e[0].fromMont(&a[0])
e[1].fromMont(&a[1])
}
func (e *fe12) rand(r io.Reader) (*fe12, error) {
a0, err := new(fe6).rand(r)
if err != nil {
return nil, err
}
e[0].set(a0)
a1, err := new(fe6).rand(r)
if err != nil {
return nil, err
}
e[1].set(a1)
return e, nil
}
func (e *fe12) isOne() bool {
return e[0].isOne() && e[1].isZero()
}
func (e *fe12) isZero() bool {
return e[0].isZero() && e[1].isZero()
}
func (e *fe12) equal(e2 *fe12) bool {
return e[0].equal(&e2[0]) && e[1].equal(&e2[1])
}
func (fe *wfe) set(fe2 *wfe) *wfe {
fe[0] = fe2[0]
fe[1] = fe2[1]
fe[2] = fe2[2]
fe[3] = fe2[3]
fe[4] = fe2[4]
fe[5] = fe2[5]
fe[6] = fe2[6]
fe[7] = fe2[7]
fe[8] = fe2[8]
fe[9] = fe2[9]
fe[10] = fe2[10]
fe[11] = fe2[11]
return fe
}
func (fe *wfe2) set(fe2 *wfe2) *wfe2 {
fe[0].set(&fe2[0])
fe[1].set(&fe2[1])
return fe
}
func (fe *wfe6) set(fe2 *wfe6) *wfe6 {
fe[0].set(&fe2[0])
fe[1].set(&fe2[1])
fe[2].set(&fe2[2])
return fe
}

View file

@ -1,249 +0,0 @@
package bls12381
import (
"bytes"
"crypto/rand"
"math/big"
"testing"
)
func TestFieldElementValidation(t *testing.T) {
// fe
zero := new(fe).zero()
if !zero.isValid() {
t.Fatal("zero must be valid")
}
one := new(fe).one()
if !one.isValid() {
t.Fatal("one must be valid")
}
if modulus.isValid() {
t.Fatal("modulus must be invalid")
}
n := modulus.big()
n.Add(n, big.NewInt(1))
if new(fe).setBig(n).isValid() {
t.Fatal("number greater than modulus must be invalid")
}
}
func TestFieldElementEquality(t *testing.T) {
// fe
zero := new(fe).zero()
if !zero.equal(zero) {
t.Fatal("0 == 0")
}
one := new(fe).one()
if !one.equal(one) {
t.Fatal("1 == 1")
}
a, _ := new(fe).rand(rand.Reader)
if !a.equal(a) {
t.Fatal("a == a")
}
b := new(fe)
add(b, a, one)
if a.equal(b) {
t.Fatal("a != a + 1")
}
// fe2
zero2 := new(fe2).zero()
if !zero2.equal(zero2) {
t.Fatal("0 == 0")
}
one2 := new(fe2).one()
if !one2.equal(one2) {
t.Fatal("1 == 1")
}
a2, _ := new(fe2).rand(rand.Reader)
if !a2.equal(a2) {
t.Fatal("a == a")
}
b2 := new(fe2)
fp2Add(b2, a2, one2)
if a2.equal(b2) {
t.Fatal("a != a + 1")
}
// fe6
zero6 := new(fe6).zero()
if !zero6.equal(zero6) {
t.Fatal("0 == 0")
}
one6 := new(fe6).one()
if !one6.equal(one6) {
t.Fatal("1 == 1")
}
a6, _ := new(fe6).rand(rand.Reader)
if !a6.equal(a6) {
t.Fatal("a == a")
}
b6 := new(fe6)
fp6Add(b6, a6, one6)
if a6.equal(b6) {
t.Fatal("a != a + 1")
}
// fe12
zero12 := new(fe12).zero()
if !zero12.equal(zero12) {
t.Fatal("0 == 0")
}
one12 := new(fe12).one()
if !one12.equal(one12) {
t.Fatal("1 == 1")
}
a12, _ := new(fe12).rand(rand.Reader)
if !a12.equal(a12) {
t.Fatal("a == a")
}
b12 := new(fe12)
fp12Add(b12, a12, one12)
if a12.equal(b12) {
t.Fatal("a != a + 1")
}
}
func TestFieldElementHelpers(t *testing.T) {
// fe
zero := new(fe).zero()
if !zero.isZero() {
t.Fatal("'zero' is not zero")
}
one := new(fe).one()
if !one.isOne() {
t.Fatal("'one' is not one")
}
odd := new(fe).setBig(big.NewInt(1))
if !odd.isOdd() {
t.Fatal("1 must be odd")
}
if odd.isEven() {
t.Fatal("1 must not be even")
}
even := new(fe).setBig(big.NewInt(2))
if !even.isEven() {
t.Fatal("2 must be even")
}
if even.isOdd() {
t.Fatal("2 must not be odd")
}
// fe2
zero2 := new(fe2).zero()
if !zero2.isZero() {
t.Fatal("'zero' is not zero, 2")
}
one2 := new(fe2).one()
if !one2.isOne() {
t.Fatal("'one' is not one, 2")
}
// fe6
zero6 := new(fe6).zero()
if !zero6.isZero() {
t.Fatal("'zero' is not zero, 6")
}
one6 := new(fe6).one()
if !one6.isOne() {
t.Fatal("'one' is not one, 6")
}
// fe12
zero12 := new(fe12).zero()
if !zero12.isZero() {
t.Fatal("'zero' is not zero, 12")
}
one12 := new(fe12).one()
if !one12.isOne() {
t.Fatal("'one' is not one, 12")
}
}
func TestFieldElementSerialization(t *testing.T) {
t.Run("zero", func(t *testing.T) {
in := make([]byte, fpByteSize)
fe := new(fe).setBytes(in)
if !fe.isZero() {
t.Fatal("serialization failed")
}
if !bytes.Equal(in, fe.bytes()) {
t.Fatal("serialization failed")
}
})
t.Run("bytes", func(t *testing.T) {
for i := 0; i < fuz; i++ {
a, _ := new(fe).rand(rand.Reader)
b := new(fe).setBytes(a.bytes())
if !a.equal(b) {
t.Fatal("serialization failed")
}
}
})
t.Run("big", func(t *testing.T) {
for i := 0; i < fuz; i++ {
a, _ := new(fe).rand(rand.Reader)
b := new(fe).setBig(a.big())
if !a.equal(b) {
t.Fatal("encoding or decoding failed")
}
}
})
t.Run("string", func(t *testing.T) {
for i := 0; i < fuz; i++ {
a, _ := new(fe).rand(rand.Reader)
b, err := new(fe).setString(a.string())
if err != nil {
t.Fatal(err)
}
if !a.equal(b) {
t.Fatal("encoding or decoding failed")
}
}
})
}
func TestFieldElementByteInputs(t *testing.T) {
zero := new(fe).zero()
in := make([]byte, 0)
a := new(fe).setBytes(in)
if !a.equal(zero) {
t.Fatal("serialization failed")
}
in = make([]byte, fpByteSize)
a = new(fe).setBytes(in)
if !a.equal(zero) {
t.Fatal("serialization failed")
}
in = make([]byte, fpByteSize+200)
a = new(fe).setBytes(in)
if !a.equal(zero) {
t.Fatal("serialization failed")
}
in = make([]byte, fpByteSize+1)
in[fpByteSize-1] = 1
normalOne := &fe{1, 0, 0, 0, 0, 0}
a = new(fe).setBytes(in)
if !a.equal(normalOne) {
t.Fatal("serialization failed")
}
}
func TestFieldElementCopy(t *testing.T) {
a, _ := new(fe).rand(rand.Reader)
b := new(fe).set(a)
if !a.equal(b) {
t.Fatal("copy failed")
}
a2, _ := new(fe2).rand(rand.Reader)
b2 := new(fe2).set(a2)
if !a2.equal(b2) {
t.Fatal("copy failed")
}
a6, _ := new(fe6).rand(rand.Reader)
b6 := new(fe6).set(a6)
if !a6.equal(b6) {
t.Fatal("copy failed")
}
a12, _ := new(fe12).rand(rand.Reader)
b12 := new(fe12).set(a12)
if !a12.equal(b12) {
t.Fatal("copy failed2")
}
}

View file

@ -1,372 +0,0 @@
package bls12381
import (
"errors"
"math/big"
)
func fromBytes(in []byte) (*fe, error) {
fe := &fe{}
if len(in) != fpByteSize {
return nil, errors.New("input string must be equal 48 bytes")
}
fe.setBytes(in)
if !fe.isValid() {
return nil, errors.New("must be less than modulus")
}
toMont(fe, fe)
return fe, nil
}
func from64Bytes(in []byte) (*fe, error) {
if len(in) != 32*2 {
return nil, errors.New("input string must be equal 64 bytes")
}
a0 := make([]byte, fpByteSize)
copy(a0[fpByteSize-32:fpByteSize], in[:32])
a1 := make([]byte, fpByteSize)
copy(a1[fpByteSize-32:fpByteSize], in[32:])
e0, err := fromBytes(a0)
if err != nil {
return nil, err
}
e1, err := fromBytes(a1)
if err != nil {
return nil, err
}
// F = 2 ^ 256 * R
F := fe{
0x75b3cd7c5ce820f,
0x3ec6ba621c3edb0b,
0x168a13d82bff6bce,
0x87663c4bf8c449d2,
0x15f34c83ddc8d830,
0xf9628b49caa2e85,
}
mul(e0, e0, &F)
add(e1, e1, e0)
return e1, nil
}
func fromBig(in *big.Int) (*fe, error) {
fe := new(fe).setBig(in)
if !fe.isValid() {
return nil, errors.New("invalid input string")
}
toMont(fe, fe)
return fe, nil
}
func fromString(in string) (*fe, error) {
fe, err := new(fe).setString(in)
if err != nil {
return nil, err
}
if !fe.isValid() {
return nil, errors.New("invalid input string")
}
toMont(fe, fe)
return fe, nil
}
func toBytes(e *fe) []byte {
e2 := new(fe)
fromMont(e2, e)
return e2.bytes()
}
func toBig(e *fe) *big.Int {
e2 := new(fe)
fromMont(e2, e)
return e2.big()
}
func toString(e *fe) (s string) {
e2 := new(fe)
fromMont(e2, e)
return e2.string()
}
func toMont(c, a *fe) {
mul(c, a, r2)
}
func fromMont(c, a *fe) {
mul(c, a, &fe{1})
}
func wfp2MulGeneric(c *wfe2, a, b *fe2) {
wt0, wt1 := new(wfe), new(wfe)
t0, t1 := new(fe), new(fe)
wmul(wt0, &a[0], &b[0])
wmul(wt1, &a[1], &b[1])
wsub(&c[0], wt0, wt1)
lwaddAssign(wt0, wt1)
ladd(t0, &a[0], &a[1])
ladd(t1, &b[0], &b[1])
wmul(wt1, t0, t1)
lwsub(&c[1], wt1, wt0)
}
func wfp2SquareGeneric(c *wfe2, a *fe2) {
t0, t1, t2 := new(fe), new(fe), new(fe)
ladd(t0, &a[0], &a[1])
sub(t1, &a[0], &a[1])
ldouble(t2, &a[0])
wmul(&c[0], t1, t0)
wmul(&c[1], t2, &a[1])
}
func exp(c, a *fe, e *big.Int) {
z := new(fe).set(r1)
for i := e.BitLen(); i >= 0; i-- {
mul(z, z, z)
if e.Bit(i) == 1 {
mul(z, z, a)
}
}
c.set(z)
}
func inverse(inv, e *fe) {
if e.isZero() {
inv.zero()
return
}
u := new(fe).set(&modulus)
v := new(fe).set(e)
s := &fe{1}
r := &fe{0}
var k int
var z uint64
var found = false
// Phase 1
for i := 0; i < sixWordBitSize*2; i++ {
if v.isZero() {
found = true
break
}
if u.isEven() {
u.div2(0)
s.mul2()
} else if v.isEven() {
v.div2(0)
z += r.mul2()
} else if u.cmp(v) == 1 {
lsubAssign(u, v)
u.div2(0)
laddAssign(r, s)
s.mul2()
} else {
lsubAssign(v, u)
v.div2(0)
laddAssign(s, r)
z += r.mul2()
}
k += 1
}
if !found {
inv.zero()
return
}
if k < fpBitSize || k > fpBitSize+sixWordBitSize {
inv.zero()
return
}
if r.cmp(&modulus) != -1 || z > 0 {
lsubAssign(r, &modulus)
}
u.set(&modulus)
lsubAssign(u, r)
// Phase 2
for i := k; i < 2*sixWordBitSize; i++ {
double(u, u)
}
inv.set(u)
}
func inverseBatch(in []fe) {
n, N, setFirst := 0, len(in), false
for i := 0; i < len(in); i++ {
if !in[i].isZero() {
n++
}
}
if n == 0 {
return
}
tA := make([]fe, n)
tB := make([]fe, n)
for i, j := 0, 0; i < N; i++ {
if !in[i].isZero() {
if !setFirst {
setFirst = true
tA[j].set(&in[i])
} else {
mul(&tA[j], &in[i], &tA[j-1])
}
j = j + 1
}
}
inverse(&tB[n-1], &tA[n-1])
for i, j := N-1, n-1; j != 0; i-- {
if !in[i].isZero() {
mul(&tB[j-1], &tB[j], &in[i])
j = j - 1
}
}
for i, j := 0, 0; i < N; i++ {
if !in[i].isZero() {
if setFirst {
setFirst = false
in[i].set(&tB[j])
} else {
mul(&in[i], &tA[j-1], &tB[j])
}
j = j + 1
}
}
}
func rsqrt(c, a *fe) bool {
t0, t1 := new(fe), new(fe)
sqrtAddchain(t0, a)
mul(t1, t0, a)
square(t1, t1)
ret := t1.equal(a)
c.set(t0)
return ret
}
func sqrt(c, a *fe) bool {
u, v := new(fe).set(a), new(fe)
// a ^ (p - 3) / 4
sqrtAddchain(c, a)
// a ^ (p + 1) / 4
mul(c, c, u)
square(v, c)
return u.equal(v)
}
func _sqrt(c, a *fe) bool {
u, v := new(fe).set(a), new(fe)
exp(c, a, pPlus1Over4)
square(v, c)
return u.equal(v)
}
func sqrtAddchain(c, a *fe) {
chain := func(c *fe, n int, a *fe) {
for i := 0; i < n; i++ {
square(c, c)
}
mul(c, c, a)
}
t := make([]fe, 16)
t[13].set(a)
square(&t[0], &t[13])
mul(&t[8], &t[0], &t[13])
square(&t[4], &t[0])
mul(&t[1], &t[8], &t[0])
mul(&t[6], &t[4], &t[8])
mul(&t[9], &t[1], &t[4])
mul(&t[12], &t[6], &t[4])
mul(&t[3], &t[9], &t[4])
mul(&t[7], &t[12], &t[4])
mul(&t[15], &t[3], &t[4])
mul(&t[10], &t[7], &t[4])
mul(&t[2], &t[15], &t[4])
mul(&t[11], &t[10], &t[4])
square(&t[0], &t[3])
mul(&t[14], &t[11], &t[4])
mul(&t[5], &t[0], &t[8])
mul(&t[4], &t[0], &t[1])
chain(&t[0], 12, &t[15])
chain(&t[0], 7, &t[7])
chain(&t[0], 4, &t[1])
chain(&t[0], 6, &t[6])
chain(&t[0], 7, &t[11])
chain(&t[0], 5, &t[4])
chain(&t[0], 2, &t[8])
chain(&t[0], 6, &t[3])
chain(&t[0], 6, &t[3])
chain(&t[0], 6, &t[9])
chain(&t[0], 3, &t[8])
chain(&t[0], 7, &t[3])
chain(&t[0], 4, &t[3])
chain(&t[0], 6, &t[7])
chain(&t[0], 6, &t[14])
chain(&t[0], 3, &t[13])
chain(&t[0], 8, &t[3])
chain(&t[0], 7, &t[11])
chain(&t[0], 5, &t[12])
chain(&t[0], 6, &t[3])
chain(&t[0], 6, &t[5])
chain(&t[0], 4, &t[9])
chain(&t[0], 8, &t[5])
chain(&t[0], 4, &t[3])
chain(&t[0], 7, &t[11])
chain(&t[0], 9, &t[10])
chain(&t[0], 2, &t[8])
chain(&t[0], 5, &t[6])
chain(&t[0], 7, &t[1])
chain(&t[0], 7, &t[9])
chain(&t[0], 6, &t[11])
chain(&t[0], 5, &t[5])
chain(&t[0], 5, &t[10])
chain(&t[0], 5, &t[10])
chain(&t[0], 8, &t[3])
chain(&t[0], 7, &t[2])
chain(&t[0], 9, &t[7])
chain(&t[0], 5, &t[3])
chain(&t[0], 3, &t[8])
chain(&t[0], 8, &t[7])
chain(&t[0], 3, &t[8])
chain(&t[0], 7, &t[9])
chain(&t[0], 9, &t[7])
chain(&t[0], 6, &t[2])
chain(&t[0], 6, &t[4])
chain(&t[0], 5, &t[4])
chain(&t[0], 5, &t[4])
chain(&t[0], 4, &t[3])
chain(&t[0], 3, &t[8])
chain(&t[0], 8, &t[2])
chain(&t[0], 7, &t[4])
chain(&t[0], 5, &t[4])
chain(&t[0], 5, &t[4])
chain(&t[0], 4, &t[7])
chain(&t[0], 4, &t[6])
chain(&t[0], 7, &t[4])
chain(&t[0], 5, &t[5])
chain(&t[0], 5, &t[4])
chain(&t[0], 5, &t[4])
chain(&t[0], 5, &t[4])
chain(&t[0], 5, &t[4])
chain(&t[0], 5, &t[4])
chain(&t[0], 5, &t[4])
chain(&t[0], 4, &t[3])
chain(&t[0], 6, &t[2])
chain(&t[0], 4, &t[1])
square(c, &t[0])
}
func isQuadraticNonResidue(a *fe) bool {
if a.isZero() {
return true
}
return !sqrt(new(fe), a)
}

View file

@ -1,303 +0,0 @@
package bls12381
import (
"errors"
"math/big"
)
type fp12 struct {
fp12temp
fp6 *fp6
}
type fp12temp struct {
t2 [7]*fe2
t6 [4]*fe6
wt2 [3]*wfe2
wt6 [3]*wfe6
}
func newFp12Temp() fp12temp {
t2 := [7]*fe2{}
t6 := [4]*fe6{}
for i := 0; i < len(t2); i++ {
t2[i] = &fe2{}
}
for i := 0; i < len(t6); i++ {
t6[i] = &fe6{}
}
wt2 := [3]*wfe2{}
for i := 0; i < len(wt2); i++ {
wt2[i] = &wfe2{}
}
wt6 := [3]*wfe6{}
for i := 0; i < len(wt6); i++ {
wt6[i] = &wfe6{}
}
return fp12temp{t2, t6, wt2, wt6}
}
func newFp12(fp6 *fp6) *fp12 {
t := newFp12Temp()
if fp6 == nil {
return &fp12{t, newFp6(nil)}
}
return &fp12{t, fp6}
}
func (e *fp12) fp2() *fp2 {
return e.fp6.fp2
}
func (e *fp12) fromBytes(in []byte) (*fe12, error) {
if len(in) != 576 {
return nil, errors.New("input string length must be equal to 576 bytes")
}
fp6 := e.fp6
c1, err := fp6.fromBytes(in[:6*fpByteSize])
if err != nil {
return nil, err
}
c0, err := fp6.fromBytes(in[6*fpByteSize:])
if err != nil {
return nil, err
}
return &fe12{*c0, *c1}, nil
}
func (e *fp12) toBytes(a *fe12) []byte {
fp6 := e.fp6
out := make([]byte, 12*fpByteSize)
copy(out[:6*fpByteSize], fp6.toBytes(&a[1]))
copy(out[6*fpByteSize:], fp6.toBytes(&a[0]))
return out
}
func (e *fp12) new() *fe12 {
return new(fe12)
}
func (e *fp12) zero() *fe12 {
return new(fe12)
}
func (e *fp12) one() *fe12 {
return new(fe12).one()
}
func fp12Add(c, a, b *fe12) {
fp6Add(&c[0], &a[0], &b[0])
fp6Add(&c[1], &a[1], &b[1])
}
func fp12Double(c, a *fe12) {
fp6Double(&c[0], &a[0])
fp6Double(&c[1], &a[1])
}
func fp12Sub(c, a, b *fe12) {
fp6Sub(&c[0], &a[0], &b[0])
fp6Sub(&c[1], &a[1], &b[1])
}
func fp12Neg(c, a *fe12) {
fp6Neg(&c[0], &a[0])
fp6Neg(&c[1], &a[1])
}
func fp12Conjugate(c, a *fe12) {
c[0].set(&a[0])
fp6Neg(&c[1], &a[1])
}
func (e *fp12) mul(c, a, b *fe12) {
wt, t := e.wt6, e.t6
e.fp6.wmul(wt[1], &a[0], &b[0])
e.fp6.wmul(wt[2], &a[1], &b[1])
fp6Add(t[0], &a[0], &a[1])
fp6Add(t[3], &b[0], &b[1])
e.fp6.wmul(wt[0], t[0], t[3])
wfp6SubAssign(wt[0], wt[1])
wfp6SubAssign(wt[0], wt[2])
c[1].fromWide(wt[0])
e.fp6.wmulByNonResidueAssign(wt[2])
wfp6AddAssign(wt[1], wt[2])
c[0].fromWide(wt[1])
}
func (e *fp12) mulAssign(a, b *fe12) {
wt, t := e.wt6, e.t6
e.fp6.wmul(wt[1], &a[0], &b[0])
e.fp6.wmul(wt[2], &a[1], &b[1])
fp6Add(t[0], &a[0], &a[1])
fp6Add(t[3], &b[0], &b[1])
e.fp6.wmul(wt[0], t[0], t[3])
wfp6SubAssign(wt[0], wt[1])
wfp6SubAssign(wt[0], wt[2])
a[1].fromWide(wt[0])
e.fp6.wmulByNonResidueAssign(wt[2])
wfp6AddAssign(wt[1], wt[2])
a[0].fromWide(wt[1])
}
func (e *fp12) mul014(a *fe12, b0, b1, b4 *fe2) {
wt, t := e.wt6, e.t6
e.fp6.wmul01(wt[0], &a[0], b0, b1)
e.fp6.wmul1(wt[1], &a[1], b4)
fp2LaddAssign(b1, b4)
fp6Ladd(t[2], &a[1], &a[0])
e.fp6.wmul01(wt[2], t[2], b0, b1)
wfp6SubAssign(wt[2], wt[0])
wfp6SubAssign(wt[2], wt[1])
a[1].fromWide(wt[2])
e.fp6.wmulByNonResidueAssign(wt[1])
wfp6AddAssign(wt[0], wt[1])
a[0].fromWide(wt[0])
}
func (e *fp12) square(c, a *fe12) {
t := e.t6
// Multiplication and Squaring on Pairing-Friendly Fields
// Complex squaring algorithm
// https://eprint.iacr.org/2006/471
fp6Add(t[0], &a[0], &a[1])
e.fp6.mul(t[2], &a[0], &a[1])
e.fp6.mulByNonResidue(t[1], &a[1])
fp6AddAssign(t[1], &a[0])
e.fp6.mulByNonResidue(t[3], t[2])
e.fp6.mul(t[0], t[0], t[1])
fp6SubAssign(t[0], t[2])
fp6Sub(&c[0], t[0], t[3])
fp6Double(&c[1], t[2])
}
func (e *fp12) squareAssign(a *fe12) {
t := e.t6
// Multiplication and Squaring on Pairing-Friendly Fields
// Complex squaring algorithm
// https://eprint.iacr.org/2006/471
fp6Add(t[0], &a[0], &a[1])
e.fp6.mul(t[2], &a[0], &a[1])
e.fp6.mulByNonResidue(t[1], &a[1])
fp6AddAssign(t[1], &a[0])
e.fp6.mulByNonResidue(t[3], t[2])
e.fp6.mul(t[0], t[0], t[1])
fp6SubAssign(t[0], t[2])
fp6Sub(&a[0], t[0], t[3])
fp6Double(&a[1], t[2])
}
func (e *fp12) inverse(c, a *fe12) {
// Guide to Pairing Based Cryptography
// Algorithm 5.16
t := e.t6
e.fp6.square(t[0], &a[0]) // a0^2
e.fp6.square(t[1], &a[1]) // a1^2
e.fp6.mulByNonResidue(t[1], t[1]) // βa1^2
fp6SubAssign(t[0], t[1]) // v = (a0^2 - a1^2)
e.fp6.inverse(t[1], t[0]) // v = v^-1
e.fp6.mul(&c[0], &a[0], t[1]) // c0 = a0v
e.fp6.mulAssign(t[1], &a[1]) //
fp6Neg(&c[1], t[1]) // c1 = -a1v
}
func (e *fp12) exp(c, a *fe12, s *big.Int) {
z := e.one()
for i := s.BitLen() - 1; i >= 0; i-- {
e.square(z, z)
if s.Bit(i) == 1 {
e.mul(z, z, a)
}
}
c.set(z)
}
func (e *fp12) cyclotomicExp(c, a *fe12, s *big.Int) {
z := e.one()
for i := s.BitLen() - 1; i >= 0; i-- {
e.cyclotomicSquare(z)
if s.Bit(i) == 1 {
e.mul(z, z, a)
}
}
c.set(z)
}
func (e *fp12) cyclotomicSquare(a *fe12) {
t := e.t2
// Guide to Pairing Based Cryptography
// 5.5.4 Airthmetic in Cyclotomic Groups
e.fp4Square(t[3], t[4], &a[0][0], &a[1][1])
fp2Sub(t[2], t[3], &a[0][0])
fp2DoubleAssign(t[2])
fp2Add(&a[0][0], t[2], t[3])
fp2Add(t[2], t[4], &a[1][1])
fp2DoubleAssign(t[2])
fp2Add(&a[1][1], t[2], t[4])
e.fp4Square(t[3], t[4], &a[1][0], &a[0][2])
e.fp4Square(t[5], t[6], &a[0][1], &a[1][2])
fp2Sub(t[2], t[3], &a[0][1])
fp2DoubleAssign(t[2])
fp2Add(&a[0][1], t[2], t[3])
fp2Add(t[2], t[4], &a[1][2])
fp2DoubleAssign(t[2])
fp2Add(&a[1][2], t[2], t[4])
mulByNonResidue(t[3], t[6])
fp2Add(t[2], t[3], &a[1][0])
fp2DoubleAssign(t[2])
fp2Add(&a[1][0], t[2], t[3])
fp2Sub(t[2], t[5], &a[0][2])
fp2DoubleAssign(t[2])
fp2Add(&a[0][2], t[2], t[5])
}
func (e *fp12) fp4Square(c0, c1, a0, a1 *fe2) {
wt, t := e.wt2, e.t2
// Multiplication and Squaring on Pairing-Friendly Fields
// Karatsuba squaring algorithm
// https://eprint.iacr.org/2006/471
wfp2Square(wt[0], a0)
wfp2Square(wt[1], a1)
wfp2MulByNonResidue(wt[2], wt[1])
wfp2AddAssign(wt[2], wt[0])
c0.fromWide(wt[2])
fp2Add(t[0], a0, a1)
wfp2Square(wt[2], t[0])
wfp2SubAssign(wt[2], wt[0])
wfp2SubAssign(wt[2], wt[1])
c1.fromWide(wt[2])
}
func (e *fp12) frobeniusMap1(a *fe12) {
fp6, fp2 := e.fp6, e.fp6.fp2
fp6.frobeniusMap1(&a[0])
fp6.frobeniusMap1(&a[1])
fp2.mulAssign(&a[1][0], &frobeniusCoeffs12[1])
fp2.mulAssign(&a[1][1], &frobeniusCoeffs12[1])
fp2.mulAssign(&a[1][2], &frobeniusCoeffs12[1])
}
func (e *fp12) frobeniusMap2(a *fe12) {
fp6, fp2 := e.fp6, e.fp6.fp2
fp6.frobeniusMap2(&a[0])
fp6.frobeniusMap2(&a[1])
fp2.mulAssign(&a[1][0], &frobeniusCoeffs12[2])
fp2.mulAssign(&a[1][1], &frobeniusCoeffs12[2])
fp2.mulAssign(&a[1][2], &frobeniusCoeffs12[2])
}
func (e *fp12) frobeniusMap3(a *fe12) {
fp6, fp2 := e.fp6, e.fp6.fp2
fp6.frobeniusMap3(&a[0])
fp6.frobeniusMap3(&a[1])
fp2.mulAssign(&a[1][0], &frobeniusCoeffs12[3])
fp2.mulAssign(&a[1][1], &frobeniusCoeffs12[3])
fp2.mulAssign(&a[1][2], &frobeniusCoeffs12[3])
}

View file

@ -1,306 +0,0 @@
package bls12381
import (
"errors"
"math/big"
)
type fp2Temp struct {
t [3]*fe
w *wfe2
}
type fp2 struct {
fp2Temp
}
func newFp2Temp() fp2Temp {
t := [3]*fe{}
for i := 0; i < len(t); i++ {
t[i] = &fe{}
}
return fp2Temp{t, &wfe2{}}
}
func newFp2() *fp2 {
t := newFp2Temp()
return &fp2{t}
}
func (e *fp2) fromBytes(in []byte) (*fe2, error) {
if len(in) != 2*fpByteSize {
return nil, errors.New("input string must be equal to 96 bytes")
}
c1, err := fromBytes(in[:fpByteSize])
if err != nil {
return nil, err
}
c0, err := fromBytes(in[fpByteSize:])
if err != nil {
return nil, err
}
return &fe2{*c0, *c1}, nil
}
func (e *fp2) toBytes(a *fe2) []byte {
out := make([]byte, 2*fpByteSize)
copy(out[:fpByteSize], toBytes(&a[1]))
copy(out[fpByteSize:], toBytes(&a[0]))
return out
}
func (e *fp2) new() *fe2 {
return new(fe2).zero()
}
func (e *fp2) zero() *fe2 {
return new(fe2).zero()
}
func (e *fp2) one() *fe2 {
return new(fe2).one()
}
func fp2Neg(c, a *fe2) {
neg(&c[0], &a[0])
neg(&c[1], &a[1])
}
func fp2Conjugate(c, a *fe2) {
c[0].set(&a[0])
neg(&c[1], &a[1])
}
func (e *fp2) mul(c, a, b *fe2) {
wfp2Mul(e.w, b, a)
c.fromWide(e.w)
}
func (e *fp2) mulAssign(a, b *fe2) {
wfp2Mul(e.w, b, a)
a.fromWide(e.w)
}
func (e *fp2) square(c, a *fe2) {
t := e.t
// Guide to Pairing Based Cryptography
// Algorithm 5.16
ladd(t[0], &a[0], &a[1]) // (a0 + a1)
sub(t[1], &a[0], &a[1]) // (a0 - a1)
ldouble(t[2], &a[0]) // 2a0
mul(&c[0], t[0], t[1]) // c0 = (a0 + a1)(a0 - a1)
mul(&c[1], t[2], &a[1]) // c1 = 2a0a1
}
func (e *fp2) squareAssign(a *fe2) {
t := e.t
ladd(t[0], &a[0], &a[1])
sub(t[1], &a[0], &a[1])
ldouble(t[2], &a[0])
mul(&a[0], t[0], t[1])
mul(&a[1], t[2], &a[1])
}
func (e *fp2) mul0(c, a *fe2, b *fe) {
mul(&c[0], &a[0], b)
mul(&c[1], &a[1], b)
}
func (e *fp2) mul0Assign(a *fe2, b *fe) {
mul(&a[0], &a[0], b)
mul(&a[1], &a[1], b)
}
func (e *fp2) mulByB(c, a *fe2) {
t := e.t
// c0 = 4a0 - 4a1
// c1 = 4a0 + 4a1
double(t[0], &a[0])
doubleAssign(t[0])
double(t[1], &a[1])
doubleAssign(t[1])
sub(&c[0], t[0], t[1])
add(&c[1], t[0], t[1])
}
func (e *fp2) inverse(c, a *fe2) {
t := e.t
// Guide to Pairing Based Cryptography
// Algorithm 5.16
square(t[0], &a[0]) // a0^2
square(t[1], &a[1]) // a1^2
addAssign(t[0], t[1]) // a0^2 + a1^2
inverse(t[0], t[0]) // (a0^2 + a1^2)^-1
mul(&c[0], &a[0], t[0]) // c0 = a0(a0^2 + a1^2)^-1
mul(t[0], t[0], &a[1]) // a1(a0^2 + a1^2)^-1
neg(&c[1], t[0]) // c1 = a1(a0^2 + a1^2)^-1
}
func (e *fp2) inverseBatch(in []fe2) {
n, N, setFirst := 0, len(in), false
for i := 0; i < len(in); i++ {
if !in[i].isZero() {
n++
}
}
if n == 0 {
return
}
tA := make([]fe2, n)
tB := make([]fe2, n)
// a, ab, abc, abcd, ...
for i, j := 0, 0; i < N; i++ {
if !in[i].isZero() {
if !setFirst {
setFirst = true
tA[j].set(&in[i])
} else {
e.mul(&tA[j], &in[i], &tA[j-1])
}
j = j + 1
}
}
// (abcd...)^-1
e.inverse(&tB[n-1], &tA[n-1])
// a^-1, ab^-1, abc^-1, abcd^-1, ...
for i, j := N-1, n-1; j != 0; i-- {
if !in[i].isZero() {
e.mul(&tB[j-1], &tB[j], &in[i])
j = j - 1
}
}
// a^-1, b^-1, c^-1, d^-1
for i, j := 0, 0; i < N; i++ {
if !in[i].isZero() {
if setFirst {
setFirst = false
in[i].set(&tB[j])
} else {
e.mul(&in[i], &tA[j-1], &tB[j])
}
j = j + 1
}
}
}
func (e *fp2) exp(c, a *fe2, s *big.Int) {
z := e.one()
for i := s.BitLen() - 1; i >= 0; i-- {
e.square(z, z)
if s.Bit(i) == 1 {
e.mul(z, z, a)
}
}
c.set(z)
}
func (e *fp2) frobeniusMap1(a *fe2) {
fp2Conjugate(a, a)
}
func (e *fp2) frobeniusMap(a *fe2, power int) {
if power&1 == 1 {
fp2Conjugate(a, a)
}
}
func (e *fp2) sqrt(c, a *fe2) bool {
u, x0, a1, alpha := &fe2{}, &fe2{}, &fe2{}, &fe2{}
u.set(a)
e.exp(a1, a, pMinus3Over4)
e.square(alpha, a1)
e.mul(alpha, alpha, a)
e.mul(x0, a1, a)
if alpha.equal(negativeOne2) {
neg(&c[0], &x0[1])
c[1].set(&x0[0])
return true
}
fp2Add(alpha, alpha, e.one())
e.exp(alpha, alpha, pMinus1Over2)
e.mul(c, alpha, x0)
e.square(alpha, c)
return alpha.equal(u)
}
func (e *fp2) isQuadraticNonResidue(a *fe2) bool {
c0, c1 := new(fe), new(fe)
square(c0, &a[0])
square(c1, &a[1])
add(c1, c1, c0)
return isQuadraticNonResidue(c1)
}
// faster square root algorith is adapted from blst library
// https://github.com/supranational/blst/blob/master/src/sqrt.c
func (e *fp2) sqrtBLST(out, inp *fe2) bool {
aa, bb := new(fe), new(fe)
ret := new(fe2)
square(aa, &inp[0])
square(bb, &inp[1])
add(aa, aa, bb)
sqrt(aa, aa)
sub(bb, &inp[0], aa)
add(aa, &inp[0], aa)
if aa.isZero() {
aa.set(bb)
}
mul(aa, aa, twoInv)
rsqrt(&ret[0], aa)
ret[1].set(&inp[1])
mul(&ret[1], &ret[1], twoInv)
mul(&ret[1], &ret[1], &ret[0])
mul(&ret[0], &ret[0], aa)
return e.sqrtAlignBLST(out, ret, ret, inp)
}
func (e *fp2) sqrtAlignBLST(out, ret, sqrt, inp *fe2) bool {
t0, t1 := new(fe2), new(fe2)
coeff := e.one()
e.square(t0, sqrt)
//
fp2Sub(t1, t0, inp)
isSqrt := t1.isZero()
//
fp2Add(t1, t0, inp)
flag := t1.isZero()
if flag {
coeff.set(sqrtMinus1)
}
isSqrt = flag || isSqrt
//
sub(&t1[0], &t0[0], &inp[1])
add(&t1[1], &t0[1], &inp[0])
flag = t1.isZero()
if flag {
coeff.set(sqrtSqrtMinus1)
}
isSqrt = flag || isSqrt
//
add(&t1[0], &t0[0], &inp[1])
sub(&t1[1], &t0[1], &inp[0])
flag = t1.isZero()
if flag {
coeff.set(sqrtMinusSqrtMinus1)
}
isSqrt = flag || isSqrt
e.mul(out, coeff, ret)
return isSqrt
}

File diff suppressed because it is too large Load diff

View file

@ -1,516 +0,0 @@
package bls12381
import (
"errors"
"math/big"
)
type fp6Temp struct {
t [5]*fe2
wt [6]*wfe2
}
type fp6 struct {
fp2 *fp2
fp6Temp
}
func newFp6Temp() fp6Temp {
t := [5]*fe2{}
for i := 0; i < len(t); i++ {
t[i] = &fe2{}
}
wt := [6]*wfe2{}
for i := 0; i < len(wt); i++ {
wt[i] = &wfe2{}
}
return fp6Temp{t, wt}
}
func newFp6(f *fp2) *fp6 {
t := newFp6Temp()
if f == nil {
return &fp6{newFp2(), t}
}
return &fp6{f, t}
}
func (e *fp6) fromBytes(b []byte) (*fe6, error) {
if len(b) != 288 {
return nil, errors.New("input string length must be equal to 288 bytes")
}
fp2 := e.fp2
u2, err := fp2.fromBytes(b[:2*fpByteSize])
if err != nil {
return nil, err
}
u1, err := fp2.fromBytes(b[2*fpByteSize : 4*fpByteSize])
if err != nil {
return nil, err
}
u0, err := fp2.fromBytes(b[4*fpByteSize:])
if err != nil {
return nil, err
}
return &fe6{*u0, *u1, *u2}, nil
}
func (e *fp6) toBytes(a *fe6) []byte {
fp2 := e.fp2
out := make([]byte, 6*fpByteSize)
copy(out[:2*fpByteSize], fp2.toBytes(&a[2]))
copy(out[2*fpByteSize:4*fpByteSize], fp2.toBytes(&a[1]))
copy(out[4*fpByteSize:], fp2.toBytes(&a[0]))
return out
}
func (e *fp6) new() *fe6 {
return new(fe6)
}
func (e *fp6) zero() *fe6 {
return new(fe6)
}
func (e *fp6) one() *fe6 {
return new(fe6).one()
}
func fp6Ladd(c, a, b *fe6) {
fp2Ladd(&c[0], &a[0], &b[0])
fp2Ladd(&c[1], &a[1], &b[1])
fp2Ladd(&c[2], &a[2], &b[2])
}
func wfp6SubAssign(a, b *wfe6) {
wfp2SubAssign(&a[0], &b[0])
wfp2SubAssign(&a[1], &b[1])
wfp2SubAssign(&a[2], &b[2])
}
func wfp6AddAssign(a, b *wfe6) {
wfp2AddAssign(&a[0], &b[0])
wfp2AddAssign(&a[1], &b[1])
wfp2AddAssign(&a[2], &b[2])
}
func fp6Add(c, a, b *fe6) {
fp2Add(&c[0], &a[0], &b[0])
fp2Add(&c[1], &a[1], &b[1])
fp2Add(&c[2], &a[2], &b[2])
}
func fp6AddAssign(a, b *fe6) {
fp2AddAssign(&a[0], &b[0])
fp2AddAssign(&a[1], &b[1])
fp2AddAssign(&a[2], &b[2])
}
func fp6Double(c, a *fe6) {
fp2Double(&c[0], &a[0])
fp2Double(&c[1], &a[1])
fp2Double(&c[2], &a[2])
}
func fp6DoubleAssign(a *fe6) {
fp2DoubleAssign(&a[0])
fp2DoubleAssign(&a[1])
fp2DoubleAssign(&a[2])
}
func fp6Sub(c, a, b *fe6) {
fp2Sub(&c[0], &a[0], &b[0])
fp2Sub(&c[1], &a[1], &b[1])
fp2Sub(&c[2], &a[2], &b[2])
}
func fp6SubAssign(a, b *fe6) {
fp2SubAssign(&a[0], &b[0])
fp2SubAssign(&a[1], &b[1])
fp2SubAssign(&a[2], &b[2])
}
func fp6Neg(c, a *fe6) {
fp2Neg(&c[0], &a[0])
fp2Neg(&c[1], &a[1])
fp2Neg(&c[2], &a[2])
}
func (e *fp6) wmul01(c *wfe6, a *fe6, b0, b1 *fe2) {
wt, t := e.wt, e.t
wfp2Mul(wt[0], &a[0], b0) // v0 = b0a0
wfp2Mul(wt[1], &a[1], b1) // v1 = a1b1
fp2Ladd(t[2], &a[1], &a[2]) // a1 + a2
wfp2Mul(wt[2], t[2], b1) // b1(a1 + a2)
wfp2SubAssign(wt[2], wt[1]) // b1(a1 + a2) - v1
wfp2MulByNonResidueAssign(wt[2])
fp2Ladd(t[3], &a[0], &a[2]) // a0 + a2
wfp2Mul(wt[3], t[3], b0) // b0(a0 + a2)
wfp2SubAssign(wt[3], wt[0])
wfp2Add(&c[2], wt[3], wt[1])
fp2Ladd(t[0], b0, b1) // (b0 + b1)
fp2Ladd(t[1], &a[0], &a[1]) // (a0 + a1)
wfp2Mul(wt[4], t[0], t[1]) // (a0 + a1)(b0 + b1)
wfp2SubAssign(wt[4], wt[0])
wfp2Sub(&c[1], wt[4], wt[1])
wfp2Add(&c[0], wt[2], wt[0])
}
func (e *fp6) wmul1(c *wfe6, a *fe6, b1 *fe2) {
wt := e.wt
wfp2Mul(wt[0], &a[2], b1)
wfp2Mul(&c[2], &a[1], b1)
wfp2Mul(&c[1], &a[0], b1)
wfp2MulByNonResidue(&c[0], wt[0])
}
func (e *fp6) wmul(c *wfe6, a, b *fe6) {
wt, t := e.wt, e.t
// Faster Explicit Formulas for Computing Pairings over Ordinary Curves
// AKLGL
// https://eprint.iacr.org/2010/526.pdf
// Algorithm 3
// 1. T0 = a0b0,T1 = a1b1, T2 = a2b2
wfp2Mul(wt[0], &a[0], &b[0])
wfp2Mul(wt[1], &a[1], &b[1])
wfp2Mul(wt[2], &a[2], &b[2])
// 2. t0 = a1 + a2, t1 = b1 + b2
fp2Ladd(t[0], &a[1], &a[2])
fp2Ladd(t[1], &b[1], &b[2])
// 3. T3 = t0 * t1
wfp2Mul(wt[3], t[0], t[1])
// 4. T4 = T1 + T2
wfp2Add(wt[4], wt[1], wt[2])
// 5,6. T3 = T3 - T4
wfp2SubMixedAssign(wt[3], wt[4])
// 7. T4 = β * T3
wfp2MulByNonResidue(wt[4], wt[3])
// 8. T5 = T4 + T0
wfp2Add(wt[5], wt[4], wt[0])
// 9. t0 = a0 + a1, t1 = b0 + b1
fp2Ladd(t[0], &a[0], &a[1])
fp2Ladd(t[1], &b[0], &b[1])
// 10. T3 = t0 * t1
wfp2Mul(wt[3], t[0], t[1])
// 11. T4 = T0 + T1
wfp2Add(wt[4], wt[0], wt[1])
// 12,13. T3 = T3 - T4
wfp2SubMixedAssign(wt[3], wt[4])
// 14,15. T4 = β * T2
wfp2MulByNonResidue(wt[4], wt[2])
// 17. t0 = a0 + a2, t1 = b0 + b2
fp2Ladd(t[0], &a[0], &a[2])
fp2Ladd(t[1], &b[0], &b[2])
// 16. T6 = T3 + T4
wfp2Add(&c[1], wt[3], wt[4])
// 18. T3 = t0 * t1
wfp2Mul(wt[3], t[0], t[1])
// 19. T4 = T0 + T2
wfp2Add(wt[4], wt[0], wt[2])
// 20,21. T3 = T3 - T4
wfp2SubMixedAssign(wt[3], wt[4])
// 22,23. T7 = T3 + T1
wfp2AddMixed(&c[2], wt[3], wt[1])
// c = T5, T6, T7
c[0].set(wt[5])
}
func (e *fp6) mul(c *fe6, a, b *fe6) {
wt, t := e.wt, e.t
// 1. T0 = a0b0,T1 = a1b1, T2 = a2b2
wfp2Mul(wt[0], &a[0], &b[0])
wfp2Mul(wt[1], &a[1], &b[1])
wfp2Mul(wt[2], &a[2], &b[2])
// 2. t0 = a1 + a2, t1 = b1 + b2
fp2Ladd(t[0], &a[1], &a[2])
fp2Ladd(t[1], &b[1], &b[2])
// 3. T3 = t0 * t1
wfp2Mul(wt[3], t[0], t[1])
// 4. T4 = T1 + T2
wfp2Add(wt[4], wt[1], wt[2])
// 5,6. T3 = T3 - T4
wfp2SubMixedAssign(wt[3], wt[4])
// 7. T4 = β * T3
wfp2MulByNonResidue(wt[4], wt[3])
// 8. T5 = T4 + T0
wfp2Add(wt[5], wt[4], wt[0])
// 9. t0 = a0 + a1, t1 = b0 + b1
fp2Ladd(t[0], &a[0], &a[1])
fp2Ladd(t[1], &b[0], &b[1])
// 10. T3 = t0 * t1
wfp2Mul(wt[3], t[0], t[1])
// 11. T4 = T0 + T1
wfp2Add(wt[4], wt[0], wt[1])
// 12,13. T3 = T3 - T4
wfp2SubMixed(wt[3], wt[3], wt[4])
// 14,15. T4 = β * T2
wfp2MulByNonResidue(wt[4], wt[2])
// 17. t0 = a0 + a2, t1 = b0 + b2
fp2Ladd(t[0], &a[0], &a[2])
fp2Ladd(t[1], &b[0], &b[2])
// 16. T6 = T3 + T4
wfp2Add(wt[3], wt[3], wt[4])
c[1].fromWide(wt[3])
// 18. T3 = t0 * t1
wfp2Mul(wt[3], t[0], t[1])
// 19. T4 = T0 + T2
wfp2Add(wt[4], wt[0], wt[2])
// 20,21. T3 = T3 - T4
wfp2SubMixed(wt[3], wt[3], wt[4])
// 22,23. T7 = T3 + T1
wfp2AddMixed(wt[3], wt[3], wt[1])
c[2].fromWide(wt[3])
// c = T5, T6, T7
c[0].fromWide(wt[5])
}
func (e *fp6) mulAssign(a, b *fe6) {
wt, t := e.wt, e.t
// Faster Explicit Formulas for Computing Pairings over Ordinary Curves
// AKLGL
// https://eprint.iacr.org/2010/526.pdf
// Algorithm 3
// 1. T0 = a0b0,T1 = a1b1, T2 = a2b2
wfp2Mul(wt[0], &a[0], &b[0])
wfp2Mul(wt[1], &a[1], &b[1])
wfp2Mul(wt[2], &a[2], &b[2])
// 2. t0 = a1 + a2, t1 = b1 + b2
fp2Ladd(t[0], &a[1], &a[2])
fp2Ladd(t[1], &b[1], &b[2])
// 3. T3 = t0 * t1
wfp2Mul(wt[3], t[0], t[1])
// 4. T4 = T1 + T2
wfp2Add(wt[4], wt[1], wt[2])
// 5,6. T3 = T3 - T4
wfp2SubMixed(wt[3], wt[3], wt[4])
// 7. T4 = β * T3
wfp2MulByNonResidue(wt[4], wt[3])
// 8. T5 = T4 + T0
wfp2Add(wt[5], wt[4], wt[0])
// 9. t0 = a0 + a1, t1 = b0 + b1
fp2Ladd(t[0], &a[0], &a[1])
fp2Ladd(t[1], &b[0], &b[1])
// 10. T3 = t0 * t1
wfp2Mul(wt[3], t[0], t[1])
// 11. T4 = T0 + T1
wfp2Add(wt[4], wt[0], wt[1])
// 12,13. T3 = T3 - T4
wfp2SubMixed(wt[3], wt[3], wt[4])
// 14,15. T4 = β * T2
wfp2MulByNonResidue(wt[4], wt[2])
// 17. t0 = a0 + a2, t1 = b0 + b2
fp2Ladd(t[0], &a[0], &a[2])
fp2Ladd(t[1], &b[0], &b[2])
// 16. T6 = T3 + T4
wfp2Add(wt[3], wt[3], wt[4])
a[1].fromWide(wt[3])
// 18. T3 = t0 * t1
wfp2Mul(wt[3], t[0], t[1])
// 19. T4 = T0 + T2
wfp2Add(wt[4], wt[0], wt[2])
// 20,21. T3 = T3 - T4
wfp2SubMixed(wt[3], wt[3], wt[4])
// 22,23. T7 = T3 + T1
wfp2AddMixed(wt[3], wt[3], wt[1])
a[2].fromWide(wt[3])
// a = T5, T6, T7
a[0].fromWide(wt[5])
}
func (e *fp6) square(c, a *fe6) {
wt, t := e.wt, e.t
wfp2Square(wt[0], &a[0])
wfp2Mul(wt[1], &a[0], &a[1])
wfp2DoubleAssign(wt[1])
fp2Sub(t[2], &a[0], &a[1])
fp2AddAssign(t[2], &a[2])
wfp2Square(wt[2], t[2])
wfp2Mul(wt[3], &a[1], &a[2])
wfp2DoubleAssign(wt[3])
wfp2Square(wt[4], &a[2])
wfp2MulByNonResidue(wt[5], wt[3])
wfp2AddAssign(wt[5], wt[0])
c[0].fromWide(wt[5])
wfp2MulByNonResidue(wt[5], wt[4])
wfp2AddAssign(wt[5], wt[1])
c[1].fromWide(wt[5])
wfp2AddAssign(wt[1], wt[2])
wfp2AddAssign(wt[1], wt[3])
wfp2AddAssign(wt[0], wt[4])
wfp2SubAssign(wt[1], wt[0])
c[2].fromWide(wt[1])
}
func (e *fp6) wsquare(c *wfe6, a *fe6) {
wt, t := e.wt, e.t
wfp2Square(wt[0], &a[0])
wfp2Mul(wt[1], &a[0], &a[1])
wfp2DoubleAssign(wt[1])
fp2Sub(t[2], &a[0], &a[1])
fp2AddAssign(t[2], &a[2])
wfp2Square(wt[2], t[2])
wfp2Mul(wt[3], &a[1], &a[2])
wfp2DoubleAssign(wt[3])
wfp2Square(wt[4], &a[2])
wfp2MulByNonResidue(wt[5], wt[3])
wfp2Add(&c[0], wt[5], wt[0])
wfp2MulByNonResidue(wt[5], wt[4])
wfp2Add(&c[1], wt[1], wt[5])
wfp2AddAssign(wt[1], wt[2])
wfp2AddAssign(wt[1], wt[3])
wfp2AddAssign(wt[0], wt[4])
wfp2Sub(&c[2], wt[1], wt[0])
}
func (e *fp6) mulByNonResidue(c, a *fe6) {
t := e.t
t[0].set(&a[0])
mulByNonResidue(&c[0], &a[2])
c[2].set(&a[1])
c[1].set(t[0])
}
func (e *fp6) wmulByNonResidue(c, a *wfe6) {
t := e.wt
t[0].set(&a[0])
wfp2MulByNonResidue(&c[0], &a[2])
c[2].set(&a[1])
c[1].set(t[0])
}
func (e *fp6) wmulByNonResidueAssign(a *wfe6) {
t := e.wt
t[0].set(&a[0])
wfp2MulByNonResidue(&a[0], &a[2])
a[2].set(&a[1])
a[1].set(t[0])
}
func (e *fp6) mulByBaseField(c, a *fe6, b *fe2) {
fp2 := e.fp2
fp2.mul(&c[0], &a[0], b)
fp2.mul(&c[1], &a[1], b)
fp2.mul(&c[2], &a[2], b)
}
func (e *fp6) exp(c, a *fe6, s *big.Int) {
z := e.one()
for i := s.BitLen() - 1; i >= 0; i-- {
e.square(z, z)
if s.Bit(i) == 1 {
e.mul(z, z, a)
}
}
c.set(z)
}
func (e *fp6) inverse(c, a *fe6) {
fp2, t := e.fp2, e.t
fp2.square(t[0], &a[0])
fp2.mul(t[1], &a[1], &a[2])
mulByNonResidueAssign(t[1])
fp2SubAssign(t[0], t[1]) // A = v0 - βv5
fp2.square(t[1], &a[1]) // v1 = a1^2
fp2.mul(t[2], &a[0], &a[2]) // v4 = a0a2
fp2SubAssign(t[1], t[2]) // C = v1 - v4
fp2.square(t[2], &a[2]) // v2 = a2^2
mulByNonResidueAssign(t[2]) // βv2
fp2.mul(t[3], &a[0], &a[1]) // v3 = a0a1
fp2SubAssign(t[2], t[3]) // B = βv2 - v3
fp2.mul(t[3], &a[2], t[2]) // B * a2
fp2.mul(t[4], &a[1], t[1]) // C * a1
fp2AddAssign(t[3], t[4]) // Ca1 + Ba2
mulByNonResidueAssign(t[3]) // β(Ca1 + Ba2)
fp2.mul(t[4], &a[0], t[0]) // Aa0
fp2AddAssign(t[3], t[4]) // v6 = Aa0 + β(Ca1 + Ba2)
fp2.inverse(t[3], t[3]) // F = v6^-1
fp2.mul(&c[0], t[0], t[3]) // c0 = AF
fp2.mul(&c[1], t[2], t[3]) // c1 = BF
fp2.mul(&c[2], t[1], t[3]) // c2 = CF
}
func (e *fp6) frobeniusMap(a *fe6, power int) {
fp2 := e.fp2
fp2.frobeniusMap(&a[0], power)
fp2.frobeniusMap(&a[1], power)
fp2.frobeniusMap(&a[2], power)
fp2.mulAssign(&a[1], &frobeniusCoeffs61[power%6])
fp2.mulAssign(&a[2], &frobeniusCoeffs62[power%6])
}
func (e *fp6) frobeniusMap1(a *fe6) {
fp2 := e.fp2
fp2.frobeniusMap1(&a[0])
fp2.frobeniusMap1(&a[1])
fp2.frobeniusMap1(&a[2])
fp2.mulAssign(&a[1], &frobeniusCoeffs61[1])
fp2.mulAssign(&a[2], &frobeniusCoeffs62[1])
}
func (e *fp6) frobeniusMap2(a *fe6) {
e.fp2.mulAssign(&a[1], &frobeniusCoeffs61[2])
e.fp2.mulAssign(&a[2], &frobeniusCoeffs62[2])
}
func (e *fp6) frobeniusMap3(a *fe6) {
t := e.t
e.fp2.frobeniusMap1(&a[0])
e.fp2.frobeniusMap1(&a[1])
e.fp2.frobeniusMap1(&a[2])
neg(&t[0][0], &a[1][1])
a[1][1].set(&a[1][0])
a[1][0].set(&t[0][0])
fp2Neg(&a[2], &a[2])
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,455 +0,0 @@
package bls12381
import (
"crypto/rand"
"io"
"math/big"
"math/bits"
)
const frByteSize = 32
const frBitSize = 255
const frNumberOfLimbs = 4
const fourWordBitSize = 256
type Fr [4]uint64
type wideFr [8]uint64
func NewFr() *Fr {
return &Fr{}
}
func (e *Fr) Rand(r io.Reader) (*Fr, error) {
bi, err := rand.Int(r, qBig)
if err != nil {
return nil, err
}
_ = e.fromBig(bi)
return e, nil
}
func (e *Fr) Set(e2 *Fr) *Fr {
e[0] = e2[0]
e[1] = e2[1]
e[2] = e2[2]
e[3] = e2[3]
return e
}
func (e *Fr) Zero() *Fr {
e[0] = 0
e[1] = 0
e[2] = 0
e[3] = 0
return e
}
func (e *Fr) One() *Fr {
e.Set(&Fr{1})
return e
}
func (e *Fr) RedOne() *Fr {
e.Set(qr1)
return e
}
func (e *Fr) FromBytes(in []byte) *Fr {
e.fromBytes(in)
return e
}
func (e *Fr) RedFromBytes(in []byte) *Fr {
e.fromBytes(in)
e.toMont()
return e
}
func (e *Fr) fromBytes(in []byte) *Fr {
u := new(big.Int).SetBytes(in)
_ = e.fromBig(u)
return e
}
func (e *Fr) fromBig(in *big.Int) *Fr {
e.Zero()
_in := new(big.Int).Set(in)
zero := new(big.Int)
c0 := _in.Cmp(zero)
c1 := _in.Cmp(qBig)
if c0 == -1 || c1 == 1 {
_in.Mod(_in, qBig)
}
words := _in.Bits() // a little-endian Word slice
if bits.UintSize == 64 { // in the 64-bit architecture
for i := 0; i < len(words); i++ {
e[i] = uint64(words[i])
}
} else { // in the 32-bit architecture
for i := 0; i < len(e); i++ {
j := i * 2
if j+1 < len(words) {
e[i] = uint64(words[j+1])<<32 | uint64(words[j])
} else if j < len(words) {
e[i] = uint64(words[j])
} else {
e[i] = uint64(0)
}
}
}
return e
}
func (e *Fr) setUint64(n uint64) *Fr {
e.Zero()
e[0] = n
return e
}
func (e *Fr) ToBytes() []byte {
return NewFr().Set(e).bytes()
}
func (e *Fr) RedToBytes() []byte {
out := NewFr().Set(e)
out.fromMont()
return out.bytes()
}
func (e *Fr) ToBig() *big.Int {
return new(big.Int).SetBytes(e.ToBytes())
}
func (e *Fr) RedToBig() *big.Int {
return new(big.Int).SetBytes(e.RedToBytes())
}
func (e *Fr) bytes() []byte {
out := make([]byte, frByteSize)
var a int
for i := 0; i < frNumberOfLimbs; i++ {
a = frByteSize - i*8
out[a-1] = byte(e[i])
out[a-2] = byte(e[i] >> 8)
out[a-3] = byte(e[i] >> 16)
out[a-4] = byte(e[i] >> 24)
out[a-5] = byte(e[i] >> 32)
out[a-6] = byte(e[i] >> 40)
out[a-7] = byte(e[i] >> 48)
out[a-8] = byte(e[i] >> 56)
}
return out
}
func (e *Fr) IsZero() bool {
return (e[3] | e[2] | e[1] | e[0]) == 0
}
func (e *Fr) IsOne() bool {
return e.Equal(&Fr{1})
}
func (e *Fr) IsRedOne() bool {
return e.Equal(qr1)
}
func (e *Fr) Equal(e2 *Fr) bool {
return e2[0] == e[0] && e2[1] == e[1] && e2[2] == e[2] && e2[3] == e[3]
}
func (e *Fr) Cmp(e1 *Fr) int {
for i := frNumberOfLimbs - 1; i >= 0; i-- {
if e[i] > e1[i] {
return 1
} else if e[i] < e1[i] {
return -1
}
}
return 0
}
func (e *Fr) sliceUint64(from int) uint64 {
if from < 64 {
return e[0]>>from | e[1]<<(64-from)
} else if from < 128 {
return e[1]>>(from-64) | e[2]<<(128-from)
} else if from < 192 {
return e[2]>>(from-128) | e[3]<<(192-from)
}
return e[3] >> (from - 192)
}
func (e *Fr) div2() {
e[0] = e[0]>>1 | e[1]<<63
e[1] = e[1]>>1 | e[2]<<63
e[2] = e[2]>>1 | e[3]<<63
e[3] = e[3] >> 1
}
func (e *Fr) mul2() uint64 {
c := e[3] >> 63
e[3] = e[3]<<1 | e[2]>>63
e[2] = e[2]<<1 | e[1]>>63
e[1] = e[1]<<1 | e[0]>>63
e[0] = e[0] << 1
return c
}
func (e *Fr) isEven() bool {
var mask uint64 = 1
return e[0]&mask == 0
}
func (e *Fr) Bit(at int) bool {
if at < 64 {
return (e[0]>>at)&1 == 1
} else if at < 128 {
return (e[1]>>(at-64))&1 == 1
} else if at < 192 {
return (e[2]>>(at-128))&1 == 1
} else if at < 256 {
return (e[3]>>(at-192))&1 == 1
}
return false
}
func (e *Fr) toMont() {
e.RedMul(e, qr2)
}
func (e *Fr) fromMont() {
e.RedMul(e, &Fr{1})
}
func (e *Fr) FromRed() {
e.fromMont()
}
func (e *Fr) ToRed() {
e.toMont()
}
func (e *Fr) Add(a, b *Fr) {
addFR(e, a, b)
}
func (e *Fr) Double(a *Fr) {
doubleFR(e, a)
}
func (e *Fr) Sub(a, b *Fr) {
subFR(e, a, b)
}
func (e *Fr) Neg(a *Fr) {
negFR(e, a)
}
func (e *Fr) Mul(a, b *Fr) {
e.RedMul(a, b)
e.toMont()
}
func (e *Fr) RedMul(a, b *Fr) {
mulFR(e, a, b)
}
func (e *Fr) Square(a *Fr) {
e.RedSquare(a)
e.toMont()
}
func (e *Fr) RedSquare(a *Fr) {
squareFR(e, a)
}
func (e *Fr) RedExp(a *Fr, ee *big.Int) {
z := new(Fr).RedOne()
for i := ee.BitLen(); i >= 0; i-- {
z.RedSquare(z)
if ee.Bit(i) == 1 {
z.RedMul(z, a)
}
}
e.Set(z)
}
func (e *Fr) Exp(a *Fr, ee *big.Int) {
e.Set(a).toMont()
e.RedExp(e, ee)
e.fromMont()
}
func RedInverseBatchFr(in []Fr) {
inverseBatchFr(in, func(a, b *Fr) { a.RedInverse(b) })
}
func InverseBatchFr(in []Fr) {
inverseBatchFr(in, func(a, b *Fr) { a.Inverse(b) })
}
func inverseBatchFr(in []Fr, invFn func(out *Fr, in *Fr)) {
n, N, setFirst := 0, len(in), false
for i := 0; i < len(in); i++ {
if !in[i].IsZero() {
n++
}
}
if n == 0 {
return
}
tA := make([]Fr, n)
tB := make([]Fr, n)
for i, j := 0, 0; i < N; i++ {
if !in[i].IsZero() {
if !setFirst {
setFirst = true
tA[j].Set(&in[i])
} else {
tA[j].Mul(&in[i], &tA[j-1])
}
j = j + 1
}
}
invFn(&tB[n-1], &tA[n-1])
for i, j := N-1, n-1; j != 0; i-- {
if !in[i].IsZero() {
tB[j-1].Mul(&tB[j], &in[i])
j = j - 1
}
}
for i, j := 0, 0; i < N; i++ {
if !in[i].IsZero() {
if setFirst {
setFirst = false
in[i].Set(&tB[j])
} else {
in[i].Mul(&tA[j-1], &tB[j])
}
j = j + 1
}
}
}
func (e *Fr) Inverse(a *Fr) {
e.Set(a).toMont()
e.RedInverse(e)
e.fromMont()
}
func (e *Fr) RedInverse(ei *Fr) {
if ei.IsZero() {
e.Zero()
return
}
u := new(Fr).Set(&q)
v := new(Fr).Set(ei)
s := &Fr{1}
r := &Fr{0}
var k int
var z uint64
var found = false
// Phase 1
for i := 0; i < fourWordBitSize*2; i++ {
if v.IsZero() {
found = true
break
}
if u.isEven() {
u.div2()
s.mul2()
} else if v.isEven() {
v.div2()
z += r.mul2()
} else if u.Cmp(v) == 1 {
lsubAssignFR(u, v)
u.div2()
laddAssignFR(r, s)
s.mul2()
} else {
lsubAssignFR(v, u)
v.div2()
laddAssignFR(s, r)
z += r.mul2()
}
k += 1
}
if !found {
e.Zero()
return
}
if k < frBitSize || k > frBitSize+fourWordBitSize {
e.Zero()
return
}
if r.Cmp(&q) != -1 || z > 0 {
lsubAssignFR(r, &q)
}
u.Set(&q)
lsubAssignFR(u, r)
// Phase 2
for i := k; i < 2*fourWordBitSize; i++ {
doubleFR(u, u)
}
e.Set(u)
}
func (ew *wideFr) mul(a, b *Fr) {
wmulFR(ew, a, b)
}
func (ew *wideFr) add(a *wideFr) {
waddFR(ew, a)
}
func (ew *wideFr) round() *Fr {
ew.add(halfR)
return ew.high()
}
func (ew *wideFr) high() *Fr {
e := new(Fr)
e[0] = ew[4]
e[1] = ew[5]
e[2] = ew[6]
e[3] = ew[7]
return e
}
func (ew *wideFr) low() *Fr {
e := new(Fr)
e[0] = ew[0]
e[1] = ew[1]
e[2] = ew[2]
e[3] = ew[3]
return e
}
func (e *wideFr) bytes() []byte {
out := make([]byte, frByteSize*2)
var a int
for i := 0; i < frNumberOfLimbs*2; i++ {
a = frByteSize*2 - i*8
out[a-1] = byte(e[i])
out[a-2] = byte(e[i] >> 8)
out[a-3] = byte(e[i] >> 16)
out[a-4] = byte(e[i] >> 24)
out[a-5] = byte(e[i] >> 32)
out[a-6] = byte(e[i] >> 40)
out[a-7] = byte(e[i] >> 48)
out[a-8] = byte(e[i] >> 56)
}
return out
}

File diff suppressed because it is too large Load diff

View file

@ -1,383 +0,0 @@
// +build !amd64 generic
// Copyright 2020 ConsenSys Software Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Code generated by goff (v0.3.5) DO NOT EDIT
// /!\ WARNING /!\
// this code has not been audited and is provided as-is. In particular,
// there is no security guarantees such as constant time implementation
// or side-channel attack resistance
// /!\ WARNING /!\
package bls12381
import "math/bits"
func addFR(z, x, y *Fr) {
var carry uint64
z[0], carry = bits.Add64(x[0], y[0], 0)
z[1], carry = bits.Add64(x[1], y[1], carry)
z[2], carry = bits.Add64(x[2], y[2], carry)
z[3], _ = bits.Add64(x[3], y[3], carry)
// if z > q --> z -= q
// note: this is NOT constant time
if !(z[3] < 8353516859464449352 || (z[3] == 8353516859464449352 && (z[2] < 3691218898639771653 || (z[2] == 3691218898639771653 && (z[1] < 6034159408538082302 || (z[1] == 6034159408538082302 && (z[0] < 18446744069414584321))))))) {
var b uint64
z[0], b = bits.Sub64(z[0], 18446744069414584321, 0)
z[1], b = bits.Sub64(z[1], 6034159408538082302, b)
z[2], b = bits.Sub64(z[2], 3691218898639771653, b)
z[3], _ = bits.Sub64(z[3], 8353516859464449352, b)
}
}
func laddAssignFR(z, y *Fr) {
var carry uint64
z[0], carry = bits.Add64(z[0], y[0], 0)
z[1], carry = bits.Add64(z[1], y[1], carry)
z[2], carry = bits.Add64(z[2], y[2], carry)
z[3], _ = bits.Add64(z[3], y[3], carry)
}
func doubleFR(z, x *Fr) {
var carry uint64
z[0], carry = bits.Add64(x[0], x[0], 0)
z[1], carry = bits.Add64(x[1], x[1], carry)
z[2], carry = bits.Add64(x[2], x[2], carry)
z[3], _ = bits.Add64(x[3], x[3], carry)
// if z > q --> z -= q
// note: this is NOT constant time
if !(z[3] < 8353516859464449352 || (z[3] == 8353516859464449352 && (z[2] < 3691218898639771653 || (z[2] == 3691218898639771653 && (z[1] < 6034159408538082302 || (z[1] == 6034159408538082302 && (z[0] < 18446744069414584321))))))) {
var b uint64
z[0], b = bits.Sub64(z[0], 18446744069414584321, 0)
z[1], b = bits.Sub64(z[1], 6034159408538082302, b)
z[2], b = bits.Sub64(z[2], 3691218898639771653, b)
z[3], _ = bits.Sub64(z[3], 8353516859464449352, b)
}
}
func subFR(z, x, y *Fr) {
var b uint64
z[0], b = bits.Sub64(x[0], y[0], 0)
z[1], b = bits.Sub64(x[1], y[1], b)
z[2], b = bits.Sub64(x[2], y[2], b)
z[3], b = bits.Sub64(x[3], y[3], b)
if b != 0 {
var c uint64
z[0], c = bits.Add64(z[0], 18446744069414584321, 0)
z[1], c = bits.Add64(z[1], 6034159408538082302, c)
z[2], c = bits.Add64(z[2], 3691218898639771653, c)
z[3], _ = bits.Add64(z[3], 8353516859464449352, c)
}
}
func lsubAssignFR(z, y *Fr) {
var b uint64
z[0], b = bits.Sub64(z[0], y[0], 0)
z[1], b = bits.Sub64(z[1], y[1], b)
z[2], b = bits.Sub64(z[2], y[2], b)
z[3], b = bits.Sub64(z[3], y[3], b)
}
func negFR(z, x *Fr) {
if x.IsZero() {
z.Zero()
return
}
var borrow uint64
z[0], borrow = bits.Sub64(18446744069414584321, x[0], 0)
z[1], borrow = bits.Sub64(6034159408538082302, x[1], borrow)
z[2], borrow = bits.Sub64(3691218898639771653, x[2], borrow)
z[3], _ = bits.Sub64(8353516859464449352, x[3], borrow)
}
func mulFR(z, x, y *Fr) {
var t [4]uint64
var c [3]uint64
{
// round 0
v := x[0]
c[1], c[0] = bits.Mul64(v, y[0])
m := c[0] * 18446744069414584319
c[2] = madd0(m, 18446744069414584321, c[0])
c[1], c[0] = madd1(v, y[1], c[1])
c[2], t[0] = madd2(m, 6034159408538082302, c[2], c[0])
c[1], c[0] = madd1(v, y[2], c[1])
c[2], t[1] = madd2(m, 3691218898639771653, c[2], c[0])
c[1], c[0] = madd1(v, y[3], c[1])
t[3], t[2] = madd3(m, 8353516859464449352, c[0], c[2], c[1])
}
{
// round 1
v := x[1]
c[1], c[0] = madd1(v, y[0], t[0])
m := c[0] * 18446744069414584319
c[2] = madd0(m, 18446744069414584321, c[0])
c[1], c[0] = madd2(v, y[1], c[1], t[1])
c[2], t[0] = madd2(m, 6034159408538082302, c[2], c[0])
c[1], c[0] = madd2(v, y[2], c[1], t[2])
c[2], t[1] = madd2(m, 3691218898639771653, c[2], c[0])
c[1], c[0] = madd2(v, y[3], c[1], t[3])
t[3], t[2] = madd3(m, 8353516859464449352, c[0], c[2], c[1])
}
{
// round 2
v := x[2]
c[1], c[0] = madd1(v, y[0], t[0])
m := c[0] * 18446744069414584319
c[2] = madd0(m, 18446744069414584321, c[0])
c[1], c[0] = madd2(v, y[1], c[1], t[1])
c[2], t[0] = madd2(m, 6034159408538082302, c[2], c[0])
c[1], c[0] = madd2(v, y[2], c[1], t[2])
c[2], t[1] = madd2(m, 3691218898639771653, c[2], c[0])
c[1], c[0] = madd2(v, y[3], c[1], t[3])
t[3], t[2] = madd3(m, 8353516859464449352, c[0], c[2], c[1])
}
{
// round 3
v := x[3]
c[1], c[0] = madd1(v, y[0], t[0])
m := c[0] * 18446744069414584319
c[2] = madd0(m, 18446744069414584321, c[0])
c[1], c[0] = madd2(v, y[1], c[1], t[1])
c[2], z[0] = madd2(m, 6034159408538082302, c[2], c[0])
c[1], c[0] = madd2(v, y[2], c[1], t[2])
c[2], z[1] = madd2(m, 3691218898639771653, c[2], c[0])
c[1], c[0] = madd2(v, y[3], c[1], t[3])
z[3], z[2] = madd3(m, 8353516859464449352, c[0], c[2], c[1])
}
// if z > q --> z -= q
// note: this is NOT constant time
if !(z[3] < 8353516859464449352 || (z[3] == 8353516859464449352 && (z[2] < 3691218898639771653 || (z[2] == 3691218898639771653 && (z[1] < 6034159408538082302 || (z[1] == 6034159408538082302 && (z[0] < 18446744069414584321))))))) {
var b uint64
z[0], b = bits.Sub64(z[0], 18446744069414584321, 0)
z[1], b = bits.Sub64(z[1], 6034159408538082302, b)
z[2], b = bits.Sub64(z[2], 3691218898639771653, b)
z[3], _ = bits.Sub64(z[3], 8353516859464449352, b)
}
}
func squareFR(z, x *Fr) {
var t [4]uint64
var c [3]uint64
{
// round 0
v := x[0]
c[1], c[0] = bits.Mul64(v, x[0])
m := c[0] * 18446744069414584319
c[2] = madd0(m, 18446744069414584321, c[0])
c[1], c[0] = madd1(v, x[1], c[1])
c[2], t[0] = madd2(m, 6034159408538082302, c[2], c[0])
c[1], c[0] = madd1(v, x[2], c[1])
c[2], t[1] = madd2(m, 3691218898639771653, c[2], c[0])
c[1], c[0] = madd1(v, x[3], c[1])
t[3], t[2] = madd3(m, 8353516859464449352, c[0], c[2], c[1])
}
{
// round 1
v := x[1]
c[1], c[0] = madd1(v, x[0], t[0])
m := c[0] * 18446744069414584319
c[2] = madd0(m, 18446744069414584321, c[0])
c[1], c[0] = madd2(v, x[1], c[1], t[1])
c[2], t[0] = madd2(m, 6034159408538082302, c[2], c[0])
c[1], c[0] = madd2(v, x[2], c[1], t[2])
c[2], t[1] = madd2(m, 3691218898639771653, c[2], c[0])
c[1], c[0] = madd2(v, x[3], c[1], t[3])
t[3], t[2] = madd3(m, 8353516859464449352, c[0], c[2], c[1])
}
{
// round 2
v := x[2]
c[1], c[0] = madd1(v, x[0], t[0])
m := c[0] * 18446744069414584319
c[2] = madd0(m, 18446744069414584321, c[0])
c[1], c[0] = madd2(v, x[1], c[1], t[1])
c[2], t[0] = madd2(m, 6034159408538082302, c[2], c[0])
c[1], c[0] = madd2(v, x[2], c[1], t[2])
c[2], t[1] = madd2(m, 3691218898639771653, c[2], c[0])
c[1], c[0] = madd2(v, x[3], c[1], t[3])
t[3], t[2] = madd3(m, 8353516859464449352, c[0], c[2], c[1])
}
{
// round 3
v := x[3]
c[1], c[0] = madd1(v, x[0], t[0])
m := c[0] * 18446744069414584319
c[2] = madd0(m, 18446744069414584321, c[0])
c[1], c[0] = madd2(v, x[1], c[1], t[1])
c[2], z[0] = madd2(m, 6034159408538082302, c[2], c[0])
c[1], c[0] = madd2(v, x[2], c[1], t[2])
c[2], z[1] = madd2(m, 3691218898639771653, c[2], c[0])
c[1], c[0] = madd2(v, x[3], c[1], t[3])
z[3], z[2] = madd3(m, 8353516859464449352, c[0], c[2], c[1])
}
// if z > q --> z -= q
// note: this is NOT constant time
if !(z[3] < 8353516859464449352 || (z[3] == 8353516859464449352 && (z[2] < 3691218898639771653 || (z[2] == 3691218898639771653 && (z[1] < 6034159408538082302 || (z[1] == 6034159408538082302 && (z[0] < 18446744069414584321))))))) {
var b uint64
z[0], b = bits.Sub64(z[0], 18446744069414584321, 0)
z[1], b = bits.Sub64(z[1], 6034159408538082302, b)
z[2], b = bits.Sub64(z[2], 3691218898639771653, b)
z[3], _ = bits.Sub64(z[3], 8353516859464449352, b)
}
}
func waddFR(z, y *wideFr) {
var carry uint64
z[0], carry = bits.Add64(z[0], y[0], 0)
z[1], carry = bits.Add64(z[1], y[1], carry)
z[2], carry = bits.Add64(z[2], y[2], carry)
z[3], carry = bits.Add64(z[3], y[3], carry)
z[4], carry = bits.Add64(z[4], y[4], carry)
z[5], carry = bits.Add64(z[5], y[5], carry)
z[6], carry = bits.Add64(z[6], y[6], carry)
z[7], _ = bits.Add64(z[7], y[7], carry)
}
// We applied custom multiplication since goff does generate multiplication code nested with reduction
func wmulFR(w *wideFr, a, b *Fr) {
// Handbook of Applied Cryptography
// Hankerson, Menezes, Vanstone
// 14.12 Algorithm Multiple-precision multiplication
var w0, w1, w2, w3, w4, w5, w6, w7 uint64
var a0 = a[0]
var a1 = a[1]
var a2 = a[2]
var a3 = a[3]
var b0 = b[0]
var b1 = b[1]
var b2 = b[2]
var b3 = b[3]
var u, v, c, t uint64
// i = 0, j = 0
c, w0 = bits.Mul64(a0, b0)
// i = 0, j = 1
u, v = bits.Mul64(a1, b0)
w1 = v + c
c = u + (v&c|(v|c)&^w1)>>63
// i = 0, j = 2
u, v = bits.Mul64(a2, b0)
w2 = v + c
c = u + (v&c|(v|c)&^w2)>>63
// i = 0, j = 3
u, v = bits.Mul64(a3, b0)
w3 = v + c
w4 = u + (v&c|(v|c)&^w3)>>63
// i = 1, j = 0
c, v = bits.Mul64(a0, b1)
t = v + w1
c += (v&w1 | (v|w1)&^t) >> 63
w1 = t
// i = 1, j = 1
u, v = bits.Mul64(a1, b1)
t = v + w2
u += (v&w2 | (v|w2)&^t) >> 63
w2 = t + c
c = u + (t&c|(t|c)&^w2)>>63
// i = 1, j = 2
u, v = bits.Mul64(a2, b1)
t = v + w3
u += (v&w3 | (v|w3)&^t) >> 63
w3 = t + c
c = u + (t&c|(t|c)&^w3)>>63
// i = 1, j = 3
u, v = bits.Mul64(a3, b1)
t = v + w4
u += (v&w4 | (v|w4)&^t) >> 63
w4 = t + c
w5 = u + (t&c|(t|c)&^w4)>>63
// i = 2, j = 0
c, v = bits.Mul64(a0, b2)
t = v + w2
c += (v&w2 | (v|w2)&^t) >> 63
w2 = t
// i = 2, j = 1
u, v = bits.Mul64(a1, b2)
t = v + w3
u += (v&w3 | (v|w3)&^t) >> 63
w3 = t + c
c = u + (t&c|(t|c)&^w3)>>63
// i = 2, j = 2
u, v = bits.Mul64(a2, b2)
t = v + w4
u += (v&w4 | (v|w4)&^t) >> 63
w4 = t + c
c = u + (t&c|(t|c)&^w4)>>63
// i = 2, j = 3
u, v = bits.Mul64(a3, b2)
t = v + w5
u += (v&w5 | (v|w5)&^t) >> 63
w5 = t + c
w6 = u + (t&c|(t|c)&^w5)>>63
// i = 3, j = 0
c, v = bits.Mul64(a0, b3)
t = v + w3
c += (v&w3 | (v|w3)&^t) >> 63
w3 = t
// i = 3, j = 1
u, v = bits.Mul64(a1, b3)
t = v + w4
u += (v&w4 | (v|w4)&^t) >> 63
w4 = t + c
c = u + (t&c|(t|c)&^w4)>>63
// i = 3, j = 2
u, v = bits.Mul64(a2, b3)
t = v + w5
u += (v&w5 | (v|w5)&^t) >> 63
w5 = t + c
c = u + (t&c|(t|c)&^w5)>>63
// i = 3, j = 3
u, v = bits.Mul64(a3, b3)
t = v + w6
u += (v&w6 | (v|w6)&^t) >> 63
w6 = t + c
w7 = u + (t&c|(t|c)&^w6)>>63
w[0] = w0
w[1] = w1
w[2] = w2
w[3] = w3
w[4] = w4
w[5] = w5
w[6] = w6
w[7] = w7
}

View file

@ -1,417 +0,0 @@
package bls12381
import (
"bytes"
"crypto/rand"
"math/big"
"testing"
)
func TestScalarField(t *testing.T) {
r := new(Fr).Set(qr1)
r.fromMont()
if r[0] != 1 && r[1] != 0 && r[2] != 0 && r[3] != 0 {
t.Fatal("bad r value")
}
r.Set(qr2)
r.fromMont()
r.fromMont()
if r[0] != 1 && r[1] != 0 && r[2] != 0 && r[3] != 0 {
t.Fatal("bad r2 value")
}
r = &Fr{1}
r.toMont()
if !r.Equal(qr1) {
t.Fatal("mont transformaition failed")
}
}
func TestFrSerialization(t *testing.T) {
in := make([]byte, frByteSize)
e := new(Fr).FromBytes(in)
if !e.IsZero() {
t.Fatal("serialization failed, from bytes zero")
}
if !bytes.Equal(in, e.ToBytes()) {
t.Fatal("serialization failed, to bytes zero")
}
e = new(Fr).RedFromBytes(in)
if !e.IsZero() {
t.Fatal("serialization failed, from bytes zero, reduced")
}
if !bytes.Equal(in, e.RedToBytes()) {
t.Fatal("serialization failed, to bytes zero, reduced")
}
a, err := new(Fr).Rand(rand.Reader)
if err != nil {
t.Fatal(err)
}
b := new(Fr)
b.fromBytes(a.bytes())
if !a.Equal(b) {
t.Fatal("serialization failed, set bytes")
}
b = new(Fr).FromBytes(a.ToBytes())
if !a.Equal(b) {
t.Fatal("serialization failed, from/to bytes")
}
b = new(Fr).RedFromBytes(a.RedToBytes())
if !a.Equal(b) {
t.Fatal("serialization failed, from/to bytes, reduced")
}
}
func TestFrSliceUint(t *testing.T) {
s, err := new(Fr).Rand(rand.Reader)
if err != nil {
t.Fatal(err)
}
sBig := s.ToBig()
for offset := 0; offset < 260; offset++ {
a0 := new(big.Int).Rsh(sBig, uint(offset)).Uint64()
a1 := s.sliceUint64(offset)
if a0 != a1 {
t.Fatal("uint slice failed", offset)
}
}
}
func TestFrBitTest(t *testing.T) {
s, err := new(Fr).Rand(rand.Reader)
if err != nil {
t.Fatal(err)
}
sBig := s.ToBig()
for i := 0; i < 260; i++ {
a0 := sBig.Bit(i) == 1
a1 := s.Bit(i)
if a0 != a1 {
t.Fatal("bit test failed", i)
}
}
}
func TestFrBitShift(t *testing.T) {
a, _ := new(Fr).Rand(rand.Reader)
b := new(Fr).Set(a)
b.mul2()
b.div2()
if !b.Equal(a) {
t.Fatal("mul2 div2 failed")
}
a, _ = new(Fr).Rand(rand.Reader)
a[0] = a[0] & 0xfffffffffffffffe
b.Set(a)
b.div2()
b.mul2()
if !b.Equal(a) {
t.Fatal("mul2 div2 failed")
}
}
func TestFrAdditionCrossAgainstBigInt(t *testing.T) {
for i := 0; i < fuz; i++ {
a, _ := new(Fr).Rand(rand.Reader)
b, _ := new(Fr).Rand(rand.Reader)
c := new(Fr)
bigA := a.ToBig()
bigB := b.ToBig()
bigC := new(big.Int)
c.Add(a, b)
out1 := c.ToBytes()
out2 := padBytes(bigC.Add(bigA, bigB).Mod(bigC, qBig).Bytes(), frByteSize)
if !bytes.Equal(out1, out2) {
t.Fatal("cross test against big.Int is failed, add")
}
c.Double(a)
out1 = c.ToBytes()
out2 = padBytes(bigC.Add(bigA, bigA).Mod(bigC, qBig).Bytes(), frByteSize)
if !bytes.Equal(out1, out2) {
t.Fatal("cross test against big.Int is failed, double")
}
c.Sub(a, b)
out1 = c.ToBytes()
out2 = padBytes(bigC.Sub(bigA, bigB).Mod(bigC, qBig).Bytes(), frByteSize)
if !bytes.Equal(out1, out2) {
t.Fatal("cross test against big.Int is failed, sub")
}
c.Neg(a)
out1 = c.ToBytes()
out2 = padBytes(bigC.Neg(bigA).Mod(bigC, qBig).Bytes(), frByteSize)
if !bytes.Equal(out1, out2) {
t.Fatal("cross test against big.Int is failed, neg")
}
}
}
func TestFrAdditionProperties(t *testing.T) {
for i := 0; i < fuz; i++ {
zero := new(Fr)
a, _ := new(Fr).Rand(rand.Reader)
b, _ := new(Fr).Rand(rand.Reader)
c1, c2 := new(Fr), new(Fr)
c1.Add(a, zero)
if !c1.Equal(a) {
t.Fatal("a + 0 == a")
}
c1.Sub(a, zero)
if !c1.Equal(a) {
t.Fatal("a - 0 == a")
}
c1.Double(zero)
if !c1.Equal(zero) {
t.Fatal("2 * 0 == 0")
}
c1.Neg(zero)
if !c1.Equal(zero) {
t.Fatal("-0 == 0")
}
c1.Sub(zero, a)
c2.Neg(a)
if !c1.Equal(c2) {
t.Fatal("0-a == -a")
}
c1.Double(a)
c2.Add(a, a)
if !c1.Equal(c2) {
t.Fatal("2 * a == a + a")
}
c1.Add(a, b)
c2.Add(b, a)
if !c1.Equal(c2) {
t.Fatal("a + b = b + a")
}
c1.Sub(a, b)
c2.Sub(b, a)
c2.Neg(c2)
if !c1.Equal(c2) {
t.Fatal("a - b = - ( b - a )")
}
c0, _ := new(Fr).Rand(rand.Reader)
c1.Add(a, b)
c1.Add(c1, c0)
c2.Add(a, c0)
c2.Add(c2, b)
if !c1.Equal(c2) {
t.Fatal("(a + b) + c == (a + c ) + b")
}
c1.Sub(a, b)
c1.Sub(c1, c0)
c2.Sub(a, c0)
c2.Sub(c2, b)
if !c1.Equal(c2) {
t.Fatal("(a - b) - c == (a - c ) -b")
}
}
}
func TestFrMultiplicationCrossAgainstBigInt(t *testing.T) {
for i := 0; i < fuz; i++ {
a, _ := new(Fr).Rand(rand.Reader)
b, _ := new(Fr).Rand(rand.Reader)
c := new(Fr)
bigA := a.ToBig()
bigB := b.ToBig()
bigC := new(big.Int)
c.Mul(a, b)
out1 := c.ToBytes()
out2 := padBytes(bigC.Mul(bigA, bigB).Mod(bigC, qBig).Bytes(), frByteSize)
if !bytes.Equal(out1, out2) {
t.Fatal("cross test against big.Int is failed")
}
}
}
func TestFrMultiplicationCrossAgainstBigIntReduced(t *testing.T) {
for i := 0; i < fuz; i++ {
a, _ := new(Fr).Rand(rand.Reader)
b, _ := new(Fr).Rand(rand.Reader)
c := new(Fr)
bigA := a.RedToBig()
bigB := b.RedToBig()
bigC := new(big.Int)
c.RedMul(a, b)
out1 := c.RedToBytes()
out2 := padBytes(bigC.Mul(bigA, bigB).Mod(bigC, qBig).Bytes(), frByteSize)
if !bytes.Equal(out1, out2) {
t.Fatal("cross test against big.Int is failed, reduced")
}
}
}
func TestFrMultiplicationProperties(t *testing.T) {
for i := 0; i < fuz; i++ {
a, _ := new(Fr).Rand(rand.Reader)
b, _ := new(Fr).Rand(rand.Reader)
zero, one := new(Fr).Zero(), new(Fr).One()
c1, c2 := new(Fr), new(Fr)
c1.Mul(a, zero)
if !c1.Equal(zero) {
t.Fatal("a * 0 == 0")
}
c1.Mul(a, one)
if !c1.Equal(a) {
t.Fatal("a * 1 == a")
}
c1.Mul(a, b)
c2.Mul(b, a)
if !c1.Equal(c2) {
t.Fatal("a * b == b * a")
}
c0, _ := new(Fr).Rand(rand.Reader)
c1.Mul(a, b)
c1.Mul(c1, c0)
c2.Mul(c0, b)
c2.Mul(c2, a)
if !c1.Equal(c2) {
t.Fatal("(a * b) * c == (a * c) * b")
}
a.Square(zero)
if !a.Equal(zero) {
t.Fatal("0^2 == 0")
}
a.Square(one)
if !a.Equal(one) {
t.Fatal("1^2 == 1")
}
_, _ = a.Rand(rand.Reader)
c1.Square(a)
c2.Mul(a, a)
if !c1.Equal(c1) {
t.Fatal("a^2 == a*a")
}
}
}
func TestFrMultiplicationPropertiesReduced(t *testing.T) {
for i := 0; i < fuz; i++ {
a, _ := new(Fr).Rand(rand.Reader)
b, _ := new(Fr).Rand(rand.Reader)
zero, one := new(Fr).Zero(), new(Fr).RedOne()
c1, c2 := new(Fr), new(Fr)
c1.RedMul(a, zero)
if !c1.Equal(zero) {
t.Fatal("a * 0 == 0")
}
c1.RedMul(a, one)
if !c1.Equal(a) {
t.Fatal("a * 1 == a")
}
c1.RedMul(a, b)
c2.RedMul(b, a)
if !c1.Equal(c2) {
t.Fatal("a * b == b * a")
}
c0, _ := new(Fr).Rand(rand.Reader)
c1.RedMul(a, b)
c1.RedMul(c1, c0)
c2.RedMul(c0, b)
c2.RedMul(c2, a)
if !c1.Equal(c2) {
t.Fatal("(a * b) * c == (a * c) * b")
}
a.RedSquare(zero)
if !a.Equal(zero) {
t.Fatal("0^2 == 0")
}
a.RedSquare(one)
if !a.Equal(one) {
t.Fatal("1^2 == 1")
}
_, _ = a.Rand(rand.Reader)
c1.RedSquare(a)
c2.RedMul(a, a)
if !c1.Equal(c1) {
t.Fatal("a^2 == a*a")
}
}
}
func TestFrExponentiation(t *testing.T) {
for i := 0; i < fuz; i++ {
a, _ := new(Fr).Rand(rand.Reader)
u := new(Fr)
u.Exp(a, big.NewInt(0))
if !u.IsOne() {
t.Fatal("a^0 == 1")
}
u.Exp(a, big.NewInt(1))
if !u.Equal(a) {
t.Fatal("a^1 == a")
}
v := new(Fr)
u.Mul(a, a)
u.Mul(u, u)
u.Mul(u, u)
v.Exp(a, big.NewInt(8))
if !u.Equal(v) {
t.Fatal("((a^2)^2)^2 == a^8")
}
u.Exp(a, qBig)
if !u.Equal(a) {
t.Fatal("a^p == a")
}
qMinus1 := new(big.Int).Sub(qBig, big.NewInt(1))
u.Exp(a, qMinus1)
if !u.IsOne() {
t.Fatal("a^(p-1) == 1")
}
}
}
func TestFrInversion(t *testing.T) {
for i := 0; i < fuz; i++ {
u := new(Fr)
zero, one := new(Fr).Zero(), new(Fr).One()
u.Inverse(zero)
if !u.Equal(zero) {
t.Fatal("(0^-1) == 0)")
}
u.Inverse(one)
if !u.IsOne() {
t.Fatal("(1^-1) == 1)")
}
a, _ := new(Fr).Rand(rand.Reader)
u.Inverse(a)
u.Mul(u, a)
if !u.IsOne() {
t.Fatal("a * a^-1 == 1")
}
v := new(Fr)
z := new(big.Int)
u.Exp(a, z.Sub(qBig, big.NewInt(2)))
v.Inverse(a)
if !v.Equal(u) {
t.Fatal("a^(p-2) == a^-1")
}
}
}
func TestFnBatchInversion(t *testing.T) {
for i := 0; i < fuz; i++ {
zero, one := new(Fr).Zero(), new(Fr).One()
a, _ := new(Fr).Rand(rand.Reader)
u := new(Fr)
z := new(big.Int)
u.Exp(a, z.Sub(qBig, big.NewInt(2)))
var arr []Fr
arr = append(arr, *zero, *one, *a)
InverseBatchFr(arr)
if !arr[0].Equal(zero) {
t.Fatal("(0^-1) == 0)")
}
if !arr[1].IsOne() {
t.Fatal("(1^-1) == 1)")
}
if !arr[2].Equal(u) {
t.Fatal("a^(p-2) == a^-1")
}
}
}

View file

@ -1,846 +0,0 @@
package bls12381
import (
"errors"
"math"
"math/big"
)
// PointG1 is type for point in G1 and used for both Affine and Jacobian point representation.
// A point is accounted as in affine form if z is equal to one.
type PointG1 [3]fe
var wnafMulWindowG1 uint = 5
func (p *PointG1) Set(p2 *PointG1) *PointG1 {
p[0].set(&p2[0])
p[1].set(&p2[1])
p[2].set(&p2[2])
return p
}
func (p *PointG1) Zero() *PointG1 {
p[0].zero()
p[1].one()
p[2].zero()
return p
}
// IsAffine checks a G1 point whether it is in affine form.
func (p *PointG1) IsAffine() bool {
return p[2].isOne()
}
type tempG1 struct {
t [9]*fe
}
// G1 is struct for G1 group.
type G1 struct {
tempG1
}
// NewG1 constructs a new G1 instance.
func NewG1() *G1 {
t := newTempG1()
return &G1{t}
}
func newTempG1() tempG1 {
t := [9]*fe{}
for i := 0; i < 9; i++ {
t[i] = &fe{}
}
return tempG1{t}
}
// Q returns group order in big.Int.
func (g *G1) Q() *big.Int {
return new(big.Int).Set(qBig)
}
// FromUncompressed expects byte slice at least 96 bytes and given bytes returns a new point in G1.
// Serialization rules are in line with zcash library. See below for details.
// https://github.com/zcash/librustzcash/blob/master/pairing/src/bls12_381/README.md#serialization
// https://docs.rs/bls12_381/0.1.1/bls12_381/notes/serialization/index.html
func (g *G1) FromUncompressed(uncompressed []byte) (*PointG1, error) {
if len(uncompressed) != 2*fpByteSize {
return nil, errors.New("input string length must be equal to 96 bytes")
}
var in [2 * fpByteSize]byte
copy(in[:], uncompressed[:2*fpByteSize])
if in[0]&(1<<7) != 0 {
return nil, errors.New("compression flag must be zero")
}
if in[0]&(1<<5) != 0 {
return nil, errors.New("sort flag must be zero")
}
if in[0]&(1<<6) != 0 {
for i, v := range in {
if (i == 0 && v != 0x40) || (i != 0 && v != 0x00) {
return nil, errors.New("input string must be zero when infinity flag is set")
}
}
return g.Zero(), nil
}
in[0] &= 0x1f
x, err := fromBytes(in[:fpByteSize])
if err != nil {
return nil, err
}
y, err := fromBytes(in[fpByteSize:])
if err != nil {
return nil, err
}
z := new(fe).one()
p := &PointG1{*x, *y, *z}
if !g.IsOnCurve(p) {
return nil, errors.New("point is not on curve")
}
if !g.InCorrectSubgroup(p) {
return nil, errors.New("point is not on correct subgroup")
}
return p, nil
}
// ToUncompressed given a G1 point returns bytes in uncompressed (x, y) form of the point.
// Serialization rules are in line with zcash library. See below for details.
// https://github.com/zcash/librustzcash/blob/master/pairing/src/bls12_381/README.md#serialization
// https://docs.rs/bls12_381/0.1.1/bls12_381/notes/serialization/index.html
func (g *G1) ToUncompressed(p *PointG1) []byte {
out := make([]byte, 2*fpByteSize)
if g.IsZero(p) {
out[0] |= 1 << 6
return out
}
g.Affine(p)
copy(out[:fpByteSize], toBytes(&p[0]))
copy(out[fpByteSize:], toBytes(&p[1]))
return out
}
// FromCompressed expects byte slice at least 48 bytes and given bytes returns a new point in G1.
// Serialization rules are in line with zcash library. See below for details.
// https://github.com/zcash/librustzcash/blob/master/pairing/src/bls12_381/README.md#serialization
// https://docs.rs/bls12_381/0.1.1/bls12_381/notes/serialization/index.html
func (g *G1) FromCompressed(compressed []byte) (*PointG1, error) {
if len(compressed) != fpByteSize {
return nil, errors.New("input string length must be equal to 48 bytes")
}
var in [fpByteSize]byte
copy(in[:], compressed[:])
if in[0]&(1<<7) == 0 {
return nil, errors.New("compression flag must be set")
}
if in[0]&(1<<6) != 0 {
// in[0] == (1 << 6) + (1 << 7)
for i, v := range in {
if (i == 0 && v != 0xc0) || (i != 0 && v != 0x00) {
return nil, errors.New("input string must be zero when infinity flag is set")
}
}
return g.Zero(), nil
}
a := in[0]&(1<<5) != 0
in[0] &= 0x1f
x, err := fromBytes(in[:])
if err != nil {
return nil, err
}
// solve curve equation
y := &fe{}
square(y, x)
mul(y, y, x)
add(y, y, b)
if ok := sqrt(y, y); !ok {
return nil, errors.New("point is not on curve")
}
if y.signBE() == a {
neg(y, y)
}
z := new(fe).one()
p := &PointG1{*x, *y, *z}
if !g.InCorrectSubgroup(p) {
return nil, errors.New("point is not on correct subgroup")
}
return p, nil
}
// ToCompressed given a G1 point returns bytes in compressed form of the point.
// Serialization rules are in line with zcash library. See below for details.
// https://github.com/zcash/librustzcash/blob/master/pairing/src/bls12_381/README.md#serialization
// https://docs.rs/bls12_381/0.1.1/bls12_381/notes/serialization/index.html
func (g *G1) ToCompressed(p *PointG1) []byte {
out := make([]byte, fpByteSize)
g.Affine(p)
if g.IsZero(p) {
out[0] |= 1 << 6
} else {
copy(out[:], toBytes(&p[0]))
if !p[1].signBE() {
out[0] |= 1 << 5
}
}
out[0] |= 1 << 7
return out
}
func (g *G1) fromBytesUnchecked(in []byte) (*PointG1, error) {
p0, err := fromBytes(in[:fpByteSize])
if err != nil {
return nil, err
}
p1, err := fromBytes(in[fpByteSize:])
if err != nil {
return nil, err
}
p2 := new(fe).one()
return &PointG1{*p0, *p1, *p2}, nil
}
// FromBytes constructs a new point given uncompressed byte input.
// Input string is expected to be equal to 96 bytes and concatenation of x and y cooridanates.
// (0, 0) is considered as infinity.
func (g *G1) FromBytes(in []byte) (*PointG1, error) {
if len(in) != 2*fpByteSize {
return nil, errors.New("input string length must be equal to 96 bytes")
}
p0, err := fromBytes(in[:fpByteSize])
if err != nil {
return nil, err
}
p1, err := fromBytes(in[fpByteSize:])
if err != nil {
return nil, err
}
// check if given input points to infinity
if p0.isZero() && p1.isZero() {
return g.Zero(), nil
}
p2 := new(fe).one()
p := &PointG1{*p0, *p1, *p2}
if !g.IsOnCurve(p) {
return nil, errors.New("point is not on curve")
}
return p, nil
}
// ToBytes serializes a point into bytes in uncompressed form.
// ToBytes returns (0, 0) if point is infinity.
func (g *G1) ToBytes(p *PointG1) []byte {
out := make([]byte, 2*fpByteSize)
if g.IsZero(p) {
return out
}
g.Affine(p)
copy(out[:fpByteSize], toBytes(&p[0]))
copy(out[fpByteSize:], toBytes(&p[1]))
return out
}
// New creates a new G1 Point which is equal to zero in other words point at infinity.
func (g *G1) New() *PointG1 {
return g.Zero()
}
// Zero returns a new G1 Point which is equal to point at infinity.
func (g *G1) Zero() *PointG1 {
return new(PointG1).Zero()
}
// One returns a new G1 Point which is equal to generator point.
func (g *G1) One() *PointG1 {
p := &PointG1{}
return p.Set(&g1One)
}
// IsZero returns true if given point is equal to zero.
func (g *G1) IsZero(p *PointG1) bool {
return p[2].isZero()
}
// Equal checks if given two G1 point is equal in their affine form.
func (g *G1) Equal(p1, p2 *PointG1) bool {
if g.IsZero(p1) {
return g.IsZero(p2)
}
if g.IsZero(p2) {
return g.IsZero(p1)
}
t := g.t
square(t[0], &p1[2])
square(t[1], &p2[2])
mul(t[2], t[0], &p2[0])
mul(t[3], t[1], &p1[0])
mul(t[0], t[0], &p1[2])
mul(t[1], t[1], &p2[2])
mul(t[1], t[1], &p1[1])
mul(t[0], t[0], &p2[1])
return t[0].equal(t[1]) && t[2].equal(t[3])
}
// InCorrectSubgroup checks whether given point is in correct subgroup.
func (g *G1) InCorrectSubgroup(p *PointG1) bool {
// Faster Subgroup Checks for BLS12-381
// S. Bowe
// https://eprint.iacr.org/2019/814.pdf
mulZ := func(p *PointG1) {
// z = [(x^2 1)/3]
z := &Fr{0x0000000055555555, 0x396c8c005555e156}
e := z.toWNAF(wnafMulWindowG1)
g.wnafMul(p, p, e)
}
// [(x^2 1)/3](2σ(P) P σ^2(P)) σ^2(P) ?= O
t0 := g.New().Set(p)
g.glvEndomorphism(t0, t0)
t1 := g.New().Set(t0) // σ(P)
g.glvEndomorphism(t0, t0) // σ^2(P)
g.Double(t1, t1) // 2σ(P)
g.Sub(t1, t1, p) // 2σ(P) P
g.Sub(t1, t1, t0) // 2σ(P) P σ^2(P)
mulZ(t1) // [(x^2 1)/3](2σ(P) P σ^2(P))
g.Sub(t1, t1, t0) // [(x^2 1)/3](2σ(P) P σ^2(P)) σ^2(P)
return g.IsZero(t1)
}
// IsOnCurve checks a G1 point is on curve.
func (g *G1) IsOnCurve(p *PointG1) bool {
if g.IsZero(p) {
return true
}
t := g.t
square(t[0], &p[1]) // y^2
square(t[1], &p[0]) // x^2
mul(t[1], t[1], &p[0]) // x^3
if p.IsAffine() {
addAssign(t[1], b) // x^2 + b
return t[0].equal(t[1]) // y^2 ?= x^3 + b
}
square(t[2], &p[2]) // z^2
square(t[3], t[2]) // z^4
mul(t[2], t[2], t[3]) // z^6
mul(t[2], b, t[2]) // b * z^6
add(t[1], t[1], t[2]) // x^3 + b * z^6
return t[0].equal(t[1]) // y^2 ?= x^3 + b * z^6
}
// IsAffine checks a G1 point whether it is in affine form.
func (g *G1) IsAffine(p *PointG1) bool {
return p[2].isOne()
}
// Affine returns the affine representation of the given point
func (g *G1) Affine(p *PointG1) *PointG1 {
return g.affine(p, p)
}
func (g *G1) affine(r, p *PointG1) *PointG1 {
if g.IsZero(p) {
return r.Zero()
}
if !g.IsAffine(p) {
t := g.t
inverse(t[0], &p[2]) // z^-1
square(t[1], t[0]) // z^-2
mul(&r[0], &p[0], t[1]) // x = x * z^-2
mul(t[0], t[0], t[1]) // z^-3
mul(&r[1], &p[1], t[0]) // y = y * z^-3
r[2].one() // z = 1
} else {
r.Set(p)
}
return r
}
// AffineBatch given multiple of points returns affine representations
func (g *G1) AffineBatch(p []*PointG1) {
inverses := make([]fe, len(p))
for i := 0; i < len(p); i++ {
inverses[i].set(&p[i][2])
}
inverseBatch(inverses)
t := g.t
for i := 0; i < len(p); i++ {
if !g.IsAffine(p[i]) && !g.IsZero(p[i]) {
square(t[1], &inverses[i])
mul(&p[i][0], &p[i][0], t[1])
mul(t[0], &inverses[i], t[1])
mul(&p[i][1], &p[i][1], t[0])
p[i][2].one()
}
}
}
// Add adds two G1 points p1, p2 and assigns the result to point at first argument.
func (g *G1) Add(r, p1, p2 *PointG1) *PointG1 {
// http://www.hyperelliptic.org/EFD/gp/auto-shortw-jacobian-0.html#addition-add-2007-bl
if g.IsZero(p1) {
return r.Set(p2)
}
if g.IsZero(p2) {
return r.Set(p1)
}
if g.IsAffine(p2) {
return g.AddMixed(r, p1, p2)
}
t := g.t
square(t[7], &p1[2]) // z1z1
mul(t[1], &p2[0], t[7]) // u2 = x2 * z1z1
mul(t[2], &p1[2], t[7]) // z1z1 * z1
mul(t[0], &p2[1], t[2]) // s2 = y2 * z1z1 * z1
square(t[8], &p2[2]) // z2z2
mul(t[3], &p1[0], t[8]) // u1 = x1 * z2z2
mul(t[4], &p2[2], t[8]) // z2z2 * z2
mul(t[2], &p1[1], t[4]) // s1 = y1 * z2z2 * z2
if t[1].equal(t[3]) {
if t[0].equal(t[2]) {
return g.Double(r, p1)
} else {
return r.Zero()
}
}
subAssign(t[1], t[3]) // h = u2 - u1
double(t[4], t[1]) // 2h
square(t[4], t[4]) // i = 2h^2
mul(t[5], t[1], t[4]) // j = h*i
subAssign(t[0], t[2]) // s2 - s1
doubleAssign(t[0]) // r = 2*(s2 - s1)
square(t[6], t[0]) // r^2
subAssign(t[6], t[5]) // r^2 - j
mul(t[3], t[3], t[4]) // v = u1 * i
double(t[4], t[3]) // 2*v
sub(&r[0], t[6], t[4]) // x3 = r^2 - j - 2*v
sub(t[4], t[3], &r[0]) // v - x3
mul(t[6], t[2], t[5]) // s1 * j
doubleAssign(t[6]) // 2 * s1 * j
mul(t[0], t[0], t[4]) // r * (v - x3)
sub(&r[1], t[0], t[6]) // y3 = r * (v - x3) - (2 * s1 * j)
add(t[0], &p1[2], &p2[2]) // z1 + z2
square(t[0], t[0]) // (z1 + z2)^2
subAssign(t[0], t[7]) // (z1 + z2)^2 - z1z1
subAssign(t[0], t[8]) // (z1 + z2)^2 - z1z1 - z2z2
mul(&r[2], t[0], t[1]) // z3 = ((z1 + z2)^2 - z1z1 - z2z2) * h
return r
}
// Add adds two G1 points p1, p2 and assigns the result to point at first argument.
// Expects the second point p2 in affine form.
func (g *G1) AddMixed(r, p1, p2 *PointG1) *PointG1 {
// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-madd-2007-bl
if g.IsZero(p1) {
return r.Set(p2)
}
if g.IsZero(p2) {
return r.Set(p1)
}
t := g.t
square(t[7], &p1[2]) // z1z1
mul(t[1], &p2[0], t[7]) // u2 = x2 * z1z1
mul(t[2], &p1[2], t[7]) // z1z1 * z1
mul(t[0], &p2[1], t[2]) // s2 = y2 * z1z1 * z1
if p1[0].equal(t[1]) && p1[1].equal(t[0]) {
return g.Double(r, p1)
}
sub(t[1], t[1], &p1[0]) // h = u2 - x1
square(t[2], t[1]) // hh
double(t[4], t[2])
doubleAssign(t[4]) // 4hh
mul(t[5], t[1], t[4]) // j = h*i
subAssign(t[0], &p1[1]) // s2 - y1
doubleAssign(t[0]) // r = 2*(s2 - y1)
square(t[6], t[0]) // r^2
subAssign(t[6], t[5]) // r^2 - j
mul(t[3], &p1[0], t[4]) // v = x1 * i
double(t[4], t[3]) // 2*v
sub(&r[0], t[6], t[4]) // x3 = r^2 - j - 2*v
sub(t[4], t[3], &r[0]) // v - x3
mul(t[6], &p1[1], t[5]) // y1 * j
doubleAssign(t[6]) // 2 * y1 * j
mul(t[0], t[0], t[4]) // r * (v - x3)
sub(&r[1], t[0], t[6]) // y3 = r * (v - x3) - (2 * y1 * j)
add(t[0], &p1[2], t[1]) // z1 + h
square(t[0], t[0]) // (z1 + h)^2
subAssign(t[0], t[7]) // (z1 + h)^2 - z1z1
sub(&r[2], t[0], t[2]) // z3 = (z1 + z2)^2 - z1z1 - hh
return r
}
// Double doubles a G1 point p and assigns the result to the point at first argument.
func (g *G1) Double(r, p *PointG1) *PointG1 {
// http://www.hyperelliptic.org/EFD/gp/auto-shortw-jacobian-0.html#doubling-dbl-2009-l
if g.IsZero(p) {
return r.Zero()
}
t := g.t
square(t[0], &p[0]) // a = x^2
square(t[1], &p[1]) // b = y^2
square(t[2], t[1]) // c = b^2
add(t[1], &p[0], t[1]) // b + x1
square(t[1], t[1]) // (b + x1)^2
subAssign(t[1], t[0]) // (b + x1)^2 - a
subAssign(t[1], t[2]) // (b + x1)^2 - a - c
doubleAssign(t[1]) // d = 2((b+x1)^2 - a - c)
double(t[3], t[0]) // 2a
addAssign(t[0], t[3]) // e = 3a
square(t[4], t[0]) // f = e^2
double(t[3], t[1]) // 2d
sub(&r[0], t[4], t[3]) // x3 = f - 2d
subAssign(t[1], &r[0]) // d-x3
doubleAssign(t[2]) //
doubleAssign(t[2]) //
doubleAssign(t[2]) // 8c
mul(t[0], t[0], t[1]) // e * (d - x3)
sub(t[1], t[0], t[2]) // x3 = e * (d - x3) - 8c
mul(t[0], &p[1], &p[2]) // y1 * z1
r[1].set(t[1]) //
double(&r[2], t[0]) // z3 = 2(y1 * z1)
return r
}
// Neg negates a G1 point p and assigns the result to the point at first argument.
func (g *G1) Neg(r, p *PointG1) *PointG1 {
r[0].set(&p[0])
r[2].set(&p[2])
neg(&r[1], &p[1])
return r
}
// Sub subtracts two G1 points p1, p2 and assigns the result to point at first argument.
func (g *G1) Sub(c, a, b *PointG1) *PointG1 {
d := &PointG1{}
g.Neg(d, b)
g.Add(c, a, d)
return c
}
// MulScalar multiplies a point by given scalar value and assigns the result to point at first argument.
func (g *G1) MulScalar(r, p *PointG1, e *Fr) *PointG1 {
return g.glvMulFr(r, p, e)
}
// MulScalar multiplies a point by given scalar value in big.Int and assigns the result to point at first argument.
func (g *G1) MulScalarBig(r, p *PointG1, e *big.Int) *PointG1 {
return g.glvMulBig(r, p, e)
}
func (g *G1) mulScalar(c, p *PointG1, e *Fr) *PointG1 {
q, n := &PointG1{}, &PointG1{}
n.Set(p)
for i := 0; i < frBitSize; i++ {
if e.Bit(i) {
g.Add(q, q, n)
}
g.Double(n, n)
}
return c.Set(q)
}
func (g *G1) mulScalarBig(c, p *PointG1, e *big.Int) *PointG1 {
q, n := &PointG1{}, &PointG1{}
n.Set(p)
for i := 0; i < frBitSize; i++ {
if e.Bit(i) == 1 {
g.Add(q, q, n)
}
g.Double(n, n)
}
return c.Set(q)
}
func (g *G1) wnafMulFr(r, p *PointG1, e *Fr) *PointG1 {
wnaf := e.toWNAF(wnafMulWindowG1)
return g.wnafMul(r, p, wnaf)
}
func (g *G1) wnafMulBig(r, p *PointG1, e *big.Int) *PointG1 {
wnaf := bigToWNAF(e, wnafMulWindowG1)
return g.wnafMul(r, p, wnaf)
}
func (g *G1) wnafMul(c, p *PointG1, wnaf nafNumber) *PointG1 {
l := (1 << (wnafMulWindowG1 - 1))
twoP, acc := g.New(), new(PointG1).Set(p)
g.Double(twoP, p)
g.Affine(twoP)
// table = {p, 3p, 5p, ..., -p, -3p, -5p}
table := make([]*PointG1, l*2)
table[0], table[l] = g.New(), g.New()
table[0].Set(p)
g.Neg(table[l], table[0])
for i := 1; i < l; i++ {
g.AddMixed(acc, acc, twoP)
table[i], table[i+l] = g.New(), g.New()
table[i].Set(acc)
g.Neg(table[i+l], table[i])
}
q := g.Zero()
for i := len(wnaf) - 1; i >= 0; i-- {
if wnaf[i] > 0 {
g.Add(q, q, table[wnaf[i]>>1])
} else if wnaf[i] < 0 {
g.Add(q, q, table[((-wnaf[i])>>1)+l])
}
if i != 0 {
g.Double(q, q)
}
}
return c.Set(q)
}
func (g *G1) glvMulFr(r, p *PointG1, e *Fr) *PointG1 {
return g.glvMul(r, p, new(glvVectorFr).new(e))
}
func (g *G1) glvMulBig(r, p *PointG1, e *big.Int) *PointG1 {
return g.glvMul(r, p, new(glvVectorBig).new(e))
}
func (g *G1) glvMul(r, p0 *PointG1, v glvVector) *PointG1 {
w := glvMulWindowG1
l := 1 << (w - 1)
// prepare tables
// tableK1 = {P, 3P, 5P, ...}
// tableK2 = {λP, 3λP, 5λP, ...}
tableK1, tableK2 := make([]*PointG1, l), make([]*PointG1, l)
double := g.New()
g.Double(double, p0)
g.affine(double, double)
tableK1[0] = new(PointG1)
tableK1[0].Set(p0)
for i := 1; i < l; i++ {
tableK1[i] = new(PointG1)
g.AddMixed(tableK1[i], tableK1[i-1], double)
}
g.AffineBatch(tableK1)
for i := 0; i < l; i++ {
tableK2[i] = new(PointG1)
g.glvEndomorphism(tableK2[i], tableK1[i])
}
// recode small scalars
naf1, naf2 := v.wnaf(w)
lenNAF1, lenNAF2 := len(naf1), len(naf2)
lenNAF := lenNAF1
if lenNAF2 > lenNAF {
lenNAF = lenNAF2
}
acc, p1 := g.New(), g.New()
// function for naf addition
add := func(table []*PointG1, naf int) {
if naf != 0 {
nafAbs := naf
if nafAbs < 0 {
nafAbs = -nafAbs
}
p1.Set(table[nafAbs>>1])
if naf < 0 {
g.Neg(p1, p1)
}
g.AddMixed(acc, acc, p1)
}
}
// sliding
for i := lenNAF - 1; i >= 0; i-- {
if i < lenNAF1 {
add(tableK1, naf1[i])
}
if i < lenNAF2 {
add(tableK2, naf2[i])
}
if i != 0 {
g.Double(acc, acc)
}
}
return r.Set(acc)
}
// MultiExpBig calculates multi exponentiation. Scalar values are received as big.Int type.
// Given pairs of G1 point and scalar values `(P_0, e_0), (P_1, e_1), ... (P_n, e_n)`,
// calculates `r = e_0 * P_0 + e_1 * P_1 + ... + e_n * P_n`.
// Length of points and scalars are expected to be equal, otherwise an error is returned.
// Result is assigned to point at first argument.
func (g *G1) MultiExpBig(r *PointG1, points []*PointG1, scalars []*big.Int) (*PointG1, error) {
if len(points) != len(scalars) {
return nil, errors.New("point and scalar vectors should be in same length")
}
c := 3
if len(scalars) >= 32 {
c = int(math.Ceil(math.Log(float64(len(scalars)))))
}
bucketSize := (1 << c) - 1
windows := make([]PointG1, 255/c+1)
bucket := make([]PointG1, bucketSize)
for j := 0; j < len(windows); j++ {
for i := 0; i < bucketSize; i++ {
bucket[i].Zero()
}
for i := 0; i < len(scalars); i++ {
index := bucketSize & int(new(big.Int).Rsh(scalars[i], uint(c*j)).Int64())
if index != 0 {
g.Add(&bucket[index-1], &bucket[index-1], points[i])
}
}
acc, sum := g.New(), g.New()
for i := bucketSize - 1; i >= 0; i-- {
g.Add(sum, sum, &bucket[i])
g.Add(acc, acc, sum)
}
windows[j].Set(acc)
}
acc := g.New()
for i := len(windows) - 1; i >= 0; i-- {
for j := 0; j < c; j++ {
g.Double(acc, acc)
}
g.Add(acc, acc, &windows[i])
}
return r.Set(acc), nil
}
// MultiExp calculates multi exponentiation. Given pairs of G1 point and scalar values `(P_0, e_0), (P_1, e_1), ... (P_n, e_n)`,
// calculates `r = e_0 * P_0 + e_1 * P_1 + ... + e_n * P_n`. Length of points and scalars are expected to be equal,
// otherwise an error is returned. Result is assigned to point at first argument.
func (g *G1) MultiExp(r *PointG1, points []*PointG1, scalars []*Fr) (*PointG1, error) {
if len(points) != len(scalars) {
return nil, errors.New("point and scalar vectors should be in same length")
}
g.AffineBatch(points)
c := 3
if len(scalars) >= 32 {
c = int(math.Ceil(math.Log(float64(len(scalars)))))
}
bucketSize := (1 << c) - 1
windows := make([]*PointG1, 255/c+1)
bucket := make([]PointG1, bucketSize)
for j := 0; j < len(windows); j++ {
for i := 0; i < bucketSize; i++ {
bucket[i].Zero()
}
for i := 0; i < len(scalars); i++ {
index := bucketSize & int(scalars[i].sliceUint64(c*j))
if index != 0 {
g.AddMixed(&bucket[index-1], &bucket[index-1], points[i])
}
}
acc, sum := g.New(), g.New()
for i := bucketSize - 1; i >= 0; i-- {
g.Add(sum, sum, &bucket[i])
g.Add(acc, acc, sum)
}
windows[j] = g.New().Set(acc)
}
g.AffineBatch(windows)
acc := g.New()
for i := len(windows) - 1; i >= 0; i-- {
for j := 0; j < c; j++ {
g.Double(acc, acc)
}
g.AddMixed(acc, acc, windows[i])
}
return r.Set(acc), nil
}
func (g *G1) ClearCofactor(p *PointG1) *PointG1 {
chain := func(p0 *PointG1, n int, p1 *PointG1) {
for i := 0; i < n; i++ {
g.Double(p0, p0)
}
g.Add(p0, p0, p1)
}
t := g.New().Set(p)
chain(p, 1, t)
chain(p, 2, t)
chain(p, 3, t)
chain(p, 9, t)
chain(p, 32, t)
chain(p, 16, t)
return p
}
// MapToCurve given a byte slice returns a valid G1 point.
// This mapping function implements the Simplified Shallue-van de Woestijne-Ulas method.
// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06
// Input byte slice should be a valid field element, otherwise an error is returned.
func (g *G1) MapToCurve(in []byte) (*PointG1, error) {
u, err := fromBytes(in)
if err != nil {
return nil, err
}
x, y := swuMapG1(u)
isogenyMapG1(x, y)
one := new(fe).one()
p := &PointG1{*x, *y, *one}
g.ClearCofactor(p)
return g.Affine(p), nil
}
// EncodeToCurve given a message and domain seperator tag returns the hash result
// which is a valid curve point.
// Implementation follows BLS12381G1_XMD:SHA-256_SSWU_NU_ suite at
// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06
func (g *G1) EncodeToCurve(msg, domain []byte) (*PointG1, error) {
hashRes, err := hashToFpXMDSHA256(msg, domain, 1)
if err != nil {
return nil, err
}
u := hashRes[0]
x, y := swuMapG1(u)
isogenyMapG1(x, y)
one := new(fe).one()
p := &PointG1{*x, *y, *one}
g.ClearCofactor(p)
return g.Affine(p), nil
}
// HashToCurve given a message and domain seperator tag returns the hash result
// which is a valid curve point.
// Implementation follows BLS12381G1_XMD:SHA-256_SSWU_RO_ suite at
// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06
func (g *G1) HashToCurve(msg, domain []byte) (*PointG1, error) {
hashRes, err := hashToFpXMDSHA256(msg, domain, 2)
if err != nil {
return nil, err
}
u0, u1 := hashRes[0], hashRes[1]
x0, y0 := swuMapG1(u0)
x1, y1 := swuMapG1(u1)
one := new(fe).one()
p0, p1 := &PointG1{*x0, *y0, *one}, &PointG1{*x1, *y1, *one}
g.Add(p0, p0, p1)
g.Affine(p0)
isogenyMapG1(&p0[0], &p0[1])
g.ClearCofactor(p0)
return g.Affine(p0), nil
}

View file

@ -1,726 +0,0 @@
package bls12381
import (
"bytes"
"crypto/rand"
"fmt"
"io/ioutil"
"math/big"
"testing"
)
func (g *G1) one() *PointG1 {
return g.New().Set(&g1One)
}
func (g *G1) rand() *PointG1 {
p := &PointG1{}
z, _ := new(fe).rand(rand.Reader)
z6, bz6 := new(fe), new(fe)
square(z6, z)
square(z6, z6)
mul(z6, z6, z)
mul(z6, z6, z)
mul(bz6, z6, b)
for {
x, _ := new(fe).rand(rand.Reader)
y := new(fe)
square(y, x)
mul(y, y, x)
add(y, y, bz6)
if sqrt(y, y) {
p.Set(&PointG1{*x, *y, *z})
break
}
}
if !g.IsOnCurve(p) {
panic("rand point must be on curve")
}
if g.InCorrectSubgroup(p) {
panic("rand point must be out of correct subgroup")
}
return p
}
func (g *G1) randCorrect() *PointG1 {
p := g.ClearCofactor(g.rand())
if !g.InCorrectSubgroup(p) {
panic("must be in correct subgroup")
}
return p
}
func (g *G1) randAffine() *PointG1 {
return g.Affine(g.randCorrect())
}
func (g *G1) new() *PointG1 {
return g.Zero()
}
func TestG1Serialization(t *testing.T) {
var err error
g := NewG1()
zero := g.Zero()
b0 := g.ToUncompressed(zero)
p0, err := g.FromUncompressed(b0)
if err != nil {
t.Fatal(err)
}
if !g.IsZero(p0) {
t.Fatal("infinity serialization failed")
}
b0 = g.ToCompressed(zero)
p0, err = g.FromCompressed(b0)
if err != nil {
t.Fatal(err)
}
if !g.IsZero(p0) {
t.Fatal("infinity serialization failed")
}
b0 = g.ToBytes(zero)
p0, err = g.FromBytes(b0)
if err != nil {
t.Fatal(err)
}
if !g.IsZero(p0) {
t.Fatal("infinity serialization failed")
}
for i := 0; i < fuz; i++ {
a := g.randAffine()
uncompressed := g.ToUncompressed(a)
b, err := g.FromUncompressed(uncompressed)
if err != nil {
t.Fatal(err)
}
if !g.Equal(a, b) {
t.Fatal("serialization failed")
}
compressed := g.ToCompressed(b)
a, err = g.FromCompressed(compressed)
if err != nil {
t.Fatal(err)
}
if !g.Equal(a, b) {
t.Fatal("serialization failed")
}
}
for i := 0; i < fuz; i++ {
a := g.randAffine()
uncompressed := g.ToBytes(a)
b, err := g.FromBytes(uncompressed)
if err != nil {
t.Fatal(err)
}
if !g.Equal(a, b) {
t.Fatal("serialization failed")
}
}
}
func TestG1IsOnCurve(t *testing.T) {
g := NewG1()
zero := g.Zero()
if !g.IsOnCurve(zero) {
t.Fatal("zero must be on curve")
}
one := new(fe).one()
p := &PointG1{*one, *one, *one}
if g.IsOnCurve(p) {
t.Fatal("(1, 1) is not on curve")
}
}
func TestG1BatchAffine(t *testing.T) {
n := 20
g := NewG1()
points0 := make([]*PointG1, n)
points1 := make([]*PointG1, n)
for i := 0; i < n; i++ {
points0[i] = g.rand()
points1[i] = g.New().Set(points0[i])
if g.IsAffine(points0[i]) {
t.Fatal("expect non affine point")
}
}
g.AffineBatch(points0)
for i := 0; i < n; i++ {
if !g.Equal(points0[i], points1[i]) {
t.Fatal("batch affine failed")
}
}
}
func TestG1AdditiveProperties(t *testing.T) {
g := NewG1()
t0, t1 := g.New(), g.New()
zero := g.Zero()
for i := 0; i < fuz; i++ {
a, b := g.rand(), g.rand()
g.Add(t0, a, zero)
if !g.Equal(t0, a) {
t.Fatal("a + 0 == a")
}
g.Add(t0, zero, zero)
if !g.Equal(t0, zero) {
t.Fatal("0 + 0 == 0")
}
g.Sub(t0, a, zero)
if !g.Equal(t0, a) {
t.Fatal("a - 0 == a")
}
g.Sub(t0, zero, zero)
if !g.Equal(t0, zero) {
t.Fatal("0 - 0 == 0")
}
g.Neg(t0, zero)
if !g.Equal(t0, zero) {
t.Fatal("- 0 == 0")
}
g.Sub(t0, zero, a)
g.Neg(t0, t0)
if !g.Equal(t0, a) {
t.Fatal(" - (0 - a) == a")
}
g.Double(t0, zero)
if !g.Equal(t0, zero) {
t.Fatal("2 * 0 == 0")
}
g.Double(t0, a)
g.Sub(t0, t0, a)
if !g.Equal(t0, a) || !g.IsOnCurve(t0) {
t.Fatal(" (2 * a) - a == a")
}
g.Add(t0, a, b)
g.Add(t1, b, a)
if !g.Equal(t0, t1) {
t.Fatal("a + b == b + a")
}
g.Sub(t0, a, b)
g.Sub(t1, b, a)
g.Neg(t1, t1)
if !g.Equal(t0, t1) {
t.Fatal("a - b == - ( b - a )")
}
c := g.rand()
g.Add(t0, a, b)
g.Add(t0, t0, c)
g.Add(t1, a, c)
g.Add(t1, t1, b)
if !g.Equal(t0, t1) {
t.Fatal("(a + b) + c == (a + c ) + b")
}
g.Sub(t0, a, b)
g.Sub(t0, t0, c)
g.Sub(t1, a, c)
g.Sub(t1, t1, b)
if !g.Equal(t0, t1) {
t.Fatal("(a - b) - c == (a - c) -b")
}
}
}
func TestG1MixedAdd(t *testing.T) {
g := NewG1()
for i := 0; i < fuz; i++ {
a, b := g.rand(), g.rand()
if g.IsAffine(a) || g.IsAffine(b) {
t.Fatal("expect non affine points")
}
bAffine := g.New().Set(b)
g.Affine(bAffine)
r0, r1 := g.New(), g.New()
g.Add(r0, a, b)
g.AddMixed(r1, a, bAffine)
if !g.Equal(r0, r1) {
t.Fatal("mixed addition failed")
}
aAffine := g.New().Set(a)
g.Affine(aAffine)
g.AddMixed(r0, a, aAffine)
g.Double(r1, a)
if !g.Equal(r0, r1) {
t.Fatal("mixed addition must double where points are equal")
}
}
}
func TestG1MultiplicationCross(t *testing.T) {
g := NewG1()
for i := 0; i < fuz; i++ {
a := g.randCorrect()
s, _ := new(Fr).Rand(rand.Reader)
sBig := s.ToBig()
res0, res1, res2, res3, res4 := g.New(), g.New(), g.New(), g.New(), g.New()
g.mulScalar(res0, a, s)
g.glvMulFr(res1, a, s)
g.glvMulBig(res2, a, sBig)
g.wnafMulFr(res3, a, s)
g.wnafMulBig(res4, a, sBig)
if !g.Equal(res0, res1) {
t.Fatal("cross multiplication failed (glv, fr)", i)
}
if !g.Equal(res0, res2) {
t.Fatal("cross multiplication failed (glv, big)", i)
}
if !g.Equal(res0, res3) {
t.Fatal("cross multiplication failed (wnaf, fr)", i)
}
if !g.Equal(res0, res4) {
t.Fatal("cross multiplication failed (wnaf, big)", i)
}
}
}
func TestG1MultiplicativeProperties(t *testing.T) {
g := NewG1()
t0, t1 := g.New(), g.New()
zero := g.Zero()
for i := 0; i < fuz; i++ {
a := g.randCorrect()
s1, _ := new(Fr).Rand(rand.Reader)
s2, _ := new(Fr).Rand(rand.Reader)
s3, _ := new(Fr).Rand(rand.Reader)
sone := &Fr{1}
g.MulScalar(t0, zero, s1)
if !g.Equal(t0, zero) {
t.Fatal(" 0 ^ s == 0")
}
g.MulScalar(t0, a, sone)
if !g.Equal(t0, a) {
t.Fatal(" a ^ 1 == a")
}
g.MulScalar(t0, zero, s1)
if !g.Equal(t0, zero) {
t.Fatal(" 0 ^ s == a")
}
g.MulScalar(t0, a, s1)
g.MulScalar(t0, t0, s2)
s3.Mul(s1, s2)
g.MulScalar(t1, a, s3)
if !g.Equal(t0, t1) {
t.Fatal(" (a ^ s1) ^ s2 == a ^ (s1 * s2)")
}
g.MulScalar(t0, a, s1)
g.MulScalar(t1, a, s2)
g.Add(t0, t0, t1)
s3.Add(s1, s2)
g.MulScalar(t1, a, s3)
if !g.Equal(t0, t1) {
t.Fatal(" (a ^ s1) + (a ^ s2) == a ^ (s1 + s2)")
}
}
}
func TestZKCryptoVectorsG1UncompressedValid(t *testing.T) {
data, err := ioutil.ReadFile("tests/g1_uncompressed_valid_test_vectors.dat")
if err != nil {
panic(err)
}
g := NewG1()
p1 := g.Zero()
for i := 0; i < 1000; i++ {
vector := data[i*2*fpByteSize : (i+1)*2*fpByteSize]
p2, err := g.FromUncompressed(vector)
if err != nil {
t.Fatal("decoing fails", err, i)
}
uncompressed := g.ToUncompressed(p2)
if !bytes.Equal(vector, uncompressed) || !g.Equal(p1, p2) {
t.Fatal("serialization failed")
}
g.Add(p1, p1, &g1One)
}
}
func TestZKCryptoVectorsG1CompressedValid(t *testing.T) {
data, err := ioutil.ReadFile("tests/g1_compressed_valid_test_vectors.dat")
if err != nil {
panic(err)
}
g := NewG1()
p1 := g.Zero()
for i := 0; i < 1000; i++ {
vector := data[i*fpByteSize : (i+1)*fpByteSize]
p2, err := g.FromCompressed(vector)
if err != nil {
t.Fatal("decoing fails", err, i)
}
compressed := g.ToCompressed(p2)
if !bytes.Equal(vector, compressed) || !g.Equal(p1, p2) {
t.Fatal("serialization failed")
}
g.Add(p1, p1, &g1One)
}
}
func TestG1MultiExpExpected(t *testing.T) {
g := NewG1()
one := g.one()
var scalars [2]*Fr
var bases [2]*PointG1
scalars[0] = &Fr{2}
scalars[1] = &Fr{3}
bases[0], bases[1] = new(PointG1).Set(one), new(PointG1).Set(one)
expected, result := g.New(), g.New()
g.mulScalar(expected, one, &Fr{5})
_, _ = g.MultiExp(result, bases[:], scalars[:])
if !g.Equal(expected, result) {
t.Fatal("multi-exponentiation failed")
}
}
func TestG1MultiExpBigExpected(t *testing.T) {
g := NewG1()
one := g.one()
var scalars [2]*big.Int
var bases [2]*PointG1
scalars[0] = big.NewInt(2)
scalars[1] = big.NewInt(3)
bases[0], bases[1] = new(PointG1).Set(one), new(PointG1).Set(one)
expected, result := g.New(), g.New()
g.mulScalarBig(expected, one, big.NewInt(5))
_, _ = g.MultiExpBig(result, bases[:], scalars[:])
if !g.Equal(expected, result) {
t.Fatal("multi-exponentiation failed")
}
}
func TestG1MultiExpBig(t *testing.T) {
g := NewG1()
for n := 1; n < 1024+1; n = n * 2 {
bases := make([]*PointG1, n)
scalars := make([]*big.Int, n)
var err error
for i := 0; i < n; i++ {
scalars[i], err = rand.Int(rand.Reader, qBig)
if err != nil {
t.Fatal(err)
}
bases[i] = g.randAffine()
}
expected, tmp := g.New(), g.New()
for i := 0; i < n; i++ {
g.mulScalarBig(tmp, bases[i], scalars[i])
g.Add(expected, expected, tmp)
}
result := g.New()
_, _ = g.MultiExpBig(result, bases, scalars)
if !g.Equal(expected, result) {
t.Fatal("multi-exponentiation failed")
}
}
}
func TestG1MultiExp(t *testing.T) {
g := NewG1()
for n := 1; n < 1024+1; n = n * 2 {
bases := make([]*PointG1, n)
scalars := make([]*Fr, n)
var err error
for i := 0; i < n; i++ {
scalars[i], err = new(Fr).Rand(rand.Reader)
if err != nil {
t.Fatal(err)
}
bases[i] = g.randAffine()
}
expected, tmp := g.New(), g.New()
for i := 0; i < n; i++ {
g.mulScalar(tmp, bases[i], scalars[i])
g.Add(expected, expected, tmp)
}
result := g.New()
_, _ = g.MultiExp(result, bases, scalars)
if !g.Equal(expected, result) {
t.Fatal("multi-exponentiation failed")
}
}
}
func TestG1ClearCofactor(t *testing.T) {
g := NewG1()
for i := 0; i < fuz; i++ {
p0 := g.rand()
if g.InCorrectSubgroup(p0) {
t.Fatal("rand point should be out of correct subgroup")
}
g.ClearCofactor(p0)
if !g.InCorrectSubgroup(p0) {
t.Fatal("cofactor clearing is failed")
}
}
}
func TestG1MapToCurve(t *testing.T) {
for i, v := range []struct {
u []byte
expected []byte
}{
{
u: make([]byte, fpByteSize),
expected: fromHex(-1,
"11a9a0372b8f332d5c30de9ad14e50372a73fa4c45d5f2fa5097f2d6fb93bcac592f2e1711ac43db0519870c7d0ea415",
"092c0f994164a0719f51c24ba3788de240ff926b55f58c445116e8bc6a47cd63392fd4e8e22bdf9feaa96ee773222133",
),
},
{
u: fromHex(-1, "07fdf49ea58e96015d61f6b5c9d1c8f277146a533ae7fbca2a8ef4c41055cd961fbc6e26979b5554e4b4f22330c0e16d"),
expected: fromHex(-1,
"1223effdbb2d38152495a864d78eee14cb0992d89a241707abb03819a91a6d2fd65854ab9a69e9aacb0cbebfd490732c",
"0f925d61e0b235ecd945cbf0309291878df0d06e5d80d6b84aa4ff3e00633b26f9a7cb3523ef737d90e6d71e8b98b2d5",
),
},
{
u: fromHex(-1, "1275ab3adbf824a169ed4b1fd669b49cf406d822f7fe90d6b2f8c601b5348436f89761bb1ad89a6fb1137cd91810e5d2"),
expected: fromHex(-1,
"179d3fd0b4fb1da43aad06cea1fb3f828806ddb1b1fa9424b1e3944dfdbab6e763c42636404017da03099af0dcca0fd6",
"0d037cb1c6d495c0f5f22b061d23f1be3d7fe64d3c6820cfcd99b6b36fa69f7b4c1f4addba2ae7aa46fb25901ab483e4",
),
},
{
u: fromHex(-1, "0e93d11d30de6d84b8578827856f5c05feef36083eef0b7b263e35ecb9b56e86299614a042e57d467fa20948e8564909"),
expected: fromHex(-1,
"15aa66c77eded1209db694e8b1ba49daf8b686733afaa7b68c683d0b01788dfb0617a2e2d04c0856db4981921d3004af",
"0952bb2f61739dd1d201dd0a79d74cda3285403d47655ee886afe860593a8a4e51c5b77a22d2133e3a4280eaaaa8b788",
),
},
{
u: fromHex(-1, "015a41481155d17074d20be6d8ec4d46632a51521cd9c916e265bd9b47343b3689979b50708c8546cbc2916b86cb1a3a"),
expected: fromHex(-1,
"06328ce5106e837935e8da84bd9af473422e62492930aa5f460369baad9545defa468d9399854c23a75495d2a80487ee",
"094bfdfe3e552447433b5a00967498a3f1314b86ce7a7164c8a8f4131f99333b30a574607e301d5f774172c627fd0bca",
),
},
} {
g := NewG1()
p0, err := g.MapToCurve(v.u)
if err != nil {
t.Fatal("map to curve fails", i, err)
}
if !bytes.Equal(g.ToBytes(p0), v.expected) {
t.Fatal("map to curve fails", i)
}
}
}
func TestG1EncodeToCurve(t *testing.T) {
domain := []byte("BLS12381G1_XMD:SHA-256_SSWU_NU_TESTGEN")
for i, v := range []struct {
msg []byte
expected []byte
}{
{
msg: []byte(""),
expected: fromHex(-1,
"1223effdbb2d38152495a864d78eee14cb0992d89a241707abb03819a91a6d2fd65854ab9a69e9aacb0cbebfd490732c",
"0f925d61e0b235ecd945cbf0309291878df0d06e5d80d6b84aa4ff3e00633b26f9a7cb3523ef737d90e6d71e8b98b2d5",
),
},
{
msg: []byte("abc"),
expected: fromHex(-1,
"179d3fd0b4fb1da43aad06cea1fb3f828806ddb1b1fa9424b1e3944dfdbab6e763c42636404017da03099af0dcca0fd6",
"0d037cb1c6d495c0f5f22b061d23f1be3d7fe64d3c6820cfcd99b6b36fa69f7b4c1f4addba2ae7aa46fb25901ab483e4",
),
},
{
msg: []byte("abcdef0123456789"),
expected: fromHex(-1,
"15aa66c77eded1209db694e8b1ba49daf8b686733afaa7b68c683d0b01788dfb0617a2e2d04c0856db4981921d3004af",
"0952bb2f61739dd1d201dd0a79d74cda3285403d47655ee886afe860593a8a4e51c5b77a22d2133e3a4280eaaaa8b788",
),
},
{
msg: []byte("a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"),
expected: fromHex(-1,
"06328ce5106e837935e8da84bd9af473422e62492930aa5f460369baad9545defa468d9399854c23a75495d2a80487ee",
"094bfdfe3e552447433b5a00967498a3f1314b86ce7a7164c8a8f4131f99333b30a574607e301d5f774172c627fd0bca",
),
},
} {
g := NewG1()
p0, err := g.EncodeToCurve(v.msg, domain)
if err != nil {
t.Fatal("encode to point fails", i, err)
}
if !bytes.Equal(g.ToBytes(p0), v.expected) {
t.Fatal("encode to point fails", i)
}
}
}
func TestG1HashToCurve(t *testing.T) {
domain := []byte("BLS12381G1_XMD:SHA-256_SSWU_RO_TESTGEN")
for i, v := range []struct {
msg []byte
expected []byte
}{
{
msg: []byte(""),
expected: fromHex(-1,
"0576730ab036cbac1d95b38dca905586f28d0a59048db4e8778782d89bff856ddef89277ead5a21e2975c4a6e3d8c79e",
"1273e568bebf1864393c517f999b87c1eaa1b8432f95aea8160cd981b5b05d8cd4a7cf00103b6ef87f728e4b547dd7ae",
),
},
{
msg: []byte("abc"),
expected: fromHex(-1,
"061daf0cc00d8912dac1d4cf5a7c32fca97f8b3bf3f805121888e5eb89f77f9a9f406569027ac6d0e61b1229f42c43d6",
"0de1601e5ba02cb637c1d35266f5700acee9850796dc88e860d022d7b9e7e3dce5950952e97861e5bb16d215c87f030d",
),
},
{
msg: []byte("abcdef0123456789"),
expected: fromHex(-1,
"0fb3455436843e76079c7cf3dfef75e5a104dfe257a29a850c145568d500ad31ccfe79be9ae0ea31a722548070cf98cd",
"177989f7e2c751658df1b26943ee829d3ebcf131d8f805571712f3a7527ee5334ecff8a97fc2a50cea86f5e6212e9a57",
),
},
{
msg: []byte("a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"),
expected: fromHex(-1,
"0514af2137c1ae1d78d5cb97ee606ea142824c199f0f25ac463a0c78200de57640d34686521d3e9cf6b3721834f8a038",
"047a85d6898416a0899e26219bca7c4f0fa682717199de196b02b95eaf9fb55456ac3b810e78571a1b7f5692b7c58ab6",
),
},
} {
g := NewG1()
p0, err := g.HashToCurve(v.msg, domain)
if err != nil {
t.Fatal("hash to point fails", i, err)
}
if !bytes.Equal(g.ToBytes(p0), v.expected) {
t.Fatal("hash to point fails", i)
}
}
}
func BenchmarkG1Add(t *testing.B) {
g := NewG1()
a, b, c := g.rand(), g.rand(), PointG1{}
t.ResetTimer()
for i := 0; i < t.N; i++ {
g.Add(&c, a, b)
}
}
func BenchmarkG1MulWNAF(t *testing.B) {
g := NewG1()
p := new(PointG1).Set(&g1One)
s, _ := new(Fr).Rand(rand.Reader)
sBig := s.ToBig()
res := new(PointG1)
t.Run("Naive", func(t *testing.B) {
t.ResetTimer()
for i := 0; i < t.N; i++ {
g.mulScalar(res, p, s)
}
})
for i := 1; i < 8; i++ {
wnafMulWindowG1 = uint(i)
t.Run(fmt.Sprintf("Fr, window: %d", i), func(t *testing.B) {
t.ResetTimer()
for i := 0; i < t.N; i++ {
g.wnafMulFr(res, p, s)
}
})
t.Run(fmt.Sprintf("Big, window: %d", i), func(t *testing.B) {
t.ResetTimer()
for i := 0; i < t.N; i++ {
g.wnafMulBig(res, p, sBig)
}
})
}
}
func BenchmarkG1MulGLV(t *testing.B) {
g := NewG1()
p := new(PointG1).Set(&g1One)
s, _ := new(Fr).Rand(rand.Reader)
sBig := s.ToBig()
res := new(PointG1)
t.Run("Naive", func(t *testing.B) {
t.ResetTimer()
for i := 0; i < t.N; i++ {
g.mulScalar(res, p, s)
}
})
for i := 1; i < 8; i++ {
glvMulWindowG1 = uint(i)
t.Run(fmt.Sprintf("Fr, window: %d", i), func(t *testing.B) {
t.ResetTimer()
for i := 0; i < t.N; i++ {
g.glvMulFr(res, p, s)
}
})
t.Run(fmt.Sprintf("Big, window: %d", i), func(t *testing.B) {
t.ResetTimer()
for i := 0; i < t.N; i++ {
g.glvMulBig(res, p, sBig)
}
})
}
}
func BenchmarkG1MultiExp(t *testing.B) {
g := NewG1()
v := func(n int) ([]*PointG1, []*Fr) {
bases := make([]*PointG1, n)
scalars := make([]*Fr, n)
var err error
for i := 0; i < n; i++ {
scalars[i], err = new(Fr).Rand(rand.Reader)
if err != nil {
t.Fatal(err)
}
bases[i] = g.randAffine()
}
return bases, scalars
}
for _, i := range []int{2, 10, 100, 1000} {
t.Run(fmt.Sprint(i), func(t *testing.B) {
bases, scalars := v(i)
result := g.New()
t.ResetTimer()
for i := 0; i < t.N; i++ {
_, _ = g.MultiExp(result, bases, scalars)
}
})
}
}
func BenchmarkG1ClearCofactor(t *testing.B) {
g := NewG1()
a := g.rand()
t.ResetTimer()
for i := 0; i < t.N; i++ {
g.ClearCofactor(a)
}
}
func BenchmarkG1SubgroupCheck(t *testing.B) {
g := NewG1()
a := g.rand()
t.ResetTimer()
for i := 0; i < t.N; i++ {
g.InCorrectSubgroup(a)
}
}
func BenchmarkG1MapToCurve(t *testing.B) {
a := fromHex(fpByteSize, "0x1234")
g := NewG1()
t.ResetTimer()
for i := 0; i < t.N; i++ {
_, err := g.MapToCurve(a)
if err != nil {
t.Fatal(err)
}
}
}

View file

@ -1,887 +0,0 @@
package bls12381
import (
"errors"
"math"
"math/big"
)
// PointG2 is type for point in G2 and used for both affine and Jacobian representation.
// A point is accounted as in affine form if z is equal to one.
type PointG2 [3]fe2
// Set copies values of one point to another.
func (p *PointG2) Set(p2 *PointG2) *PointG2 {
p[0].set(&p2[0])
p[1].set(&p2[1])
p[2].set(&p2[2])
return p
}
func (p *PointG2) Zero() *PointG2 {
p[0].zero()
p[1].one()
p[2].zero()
return p
}
// IsAffine checks a G1 point whether it is in affine form.
func (p *PointG2) IsAffine() bool {
return p[2].isOne()
}
type tempG2 struct {
t [9]*fe2
}
// G2 is struct for G2 group.
type G2 struct {
f *fp2
tempG2
}
// NewG2 constructs a new G2 instance.
func NewG2() *G2 {
return newG2(nil)
}
func newG2(f *fp2) *G2 {
if f == nil {
f = newFp2()
}
t := newTempG2()
return &G2{f, t}
}
func newTempG2() tempG2 {
t := [9]*fe2{}
for i := 0; i < 9; i++ {
t[i] = &fe2{}
}
return tempG2{t}
}
// Q returns group order in big.Int.
func (g *G2) Q() *big.Int {
return new(big.Int).Set(qBig)
}
// FromUncompressed expects byte slice at least 192 bytes and given bytes returns a new point in G2.
// Serialization rules are in line with zcash library. See below for details.
// https://github.com/zcash/librustzcash/blob/master/pairing/src/bls12_381/README.md#serialization
// https://docs.rs/bls12_381/0.1.1/bls12_381/notes/serialization/index.html
func (g *G2) FromUncompressed(uncompressed []byte) (*PointG2, error) {
if len(uncompressed) != 4*fpByteSize {
return nil, errors.New("input string length must be equal to 192 bytes")
}
var in [4 * fpByteSize]byte
copy(in[:], uncompressed[:4*fpByteSize])
if in[0]&(1<<7) != 0 {
return nil, errors.New("compression flag must be zero")
}
if in[0]&(1<<5) != 0 {
return nil, errors.New("sort flag must be zero")
}
if in[0]&(1<<6) != 0 {
for i, v := range in {
if (i == 0 && v != 0x40) || (i != 0 && v != 0x00) {
return nil, errors.New("input string must be zero when infinity flag is set")
}
}
return g.Zero(), nil
}
in[0] &= 0x1f
x, err := g.f.fromBytes(in[:2*fpByteSize])
if err != nil {
return nil, err
}
y, err := g.f.fromBytes(in[2*fpByteSize:])
if err != nil {
return nil, err
}
z := new(fe2).one()
p := &PointG2{*x, *y, *z}
if !g.IsOnCurve(p) {
return nil, errors.New("point is not on curve")
}
if !g.InCorrectSubgroup(p) {
return nil, errors.New("point is not on correct subgroup")
}
return p, nil
}
// ToUncompressed given a G2 point returns bytes in uncompressed (x, y) form of the point.
// Serialization rules are in line with zcash library. See below for details.
// https://github.com/zcash/librustzcash/blob/master/pairing/src/bls12_381/README.md#serialization
// https://docs.rs/bls12_381/0.1.1/bls12_381/notes/serialization/index.html
func (g *G2) ToUncompressed(p *PointG2) []byte {
out := make([]byte, 4*fpByteSize)
g.Affine(p)
if g.IsZero(p) {
out[0] |= 1 << 6
return out
}
copy(out[:2*fpByteSize], g.f.toBytes(&p[0]))
copy(out[2*fpByteSize:], g.f.toBytes(&p[1]))
return out
}
// FromCompressed expects byte slice at least 96 bytes and given bytes returns a new point in G2.
// Serialization rules are in line with zcash library. See below for details.
// https://github.com/zcash/librustzcash/blob/master/pairing/src/bls12_381/README.md#serialization
// https://docs.rs/bls12_381/0.1.1/bls12_381/notes/serialization/index.html
func (g *G2) FromCompressed(compressed []byte) (*PointG2, error) {
if len(compressed) != 2*fpByteSize {
return nil, errors.New("input string length must be equal to 96 bytes")
}
var in [2 * fpByteSize]byte
copy(in[:], compressed[:])
if in[0]&(1<<7) == 0 {
return nil, errors.New("compression flag must be set")
}
if in[0]&(1<<6) != 0 {
// in[0] == (1 << 6) + (1 << 7)
for i, v := range in {
if (i == 0 && v != 0xc0) || (i != 0 && v != 0x00) {
return nil, errors.New("input string must be zero when infinity flag is set")
}
}
return g.Zero(), nil
}
a := in[0]&(1<<5) != 0
in[0] &= 0x1f
x, err := g.f.fromBytes(in[:])
if err != nil {
return nil, err
}
// solve curve equation
y := &fe2{}
g.f.square(y, x)
g.f.mul(y, y, x)
fp2Add(y, y, b2)
if ok := g.f.sqrt(y, y); !ok {
return nil, errors.New("point is not on curve")
}
if y.signBE() == a {
fp2Neg(y, y)
}
z := new(fe2).one()
p := &PointG2{*x, *y, *z}
if !g.InCorrectSubgroup(p) {
return nil, errors.New("point is not on correct subgroup")
}
return p, nil
}
// ToCompressed given a G2 point returns bytes in compressed form of the point.
// Serialization rules are in line with zcash library. See below for details.
// https://github.com/zcash/librustzcash/blob/master/pairing/src/bls12_381/README.md#serialization
// https://docs.rs/bls12_381/0.1.1/bls12_381/notes/serialization/index.html
func (g *G2) ToCompressed(p *PointG2) []byte {
out := make([]byte, 2*fpByteSize)
g.Affine(p)
if g.IsZero(p) {
out[0] |= 1 << 6
} else {
copy(out[:], g.f.toBytes(&p[0]))
if !p[1].signBE() {
out[0] |= 1 << 5
}
}
out[0] |= 1 << 7
return out
}
func (g *G2) fromBytesUnchecked(in []byte) (*PointG2, error) {
p0, err := g.f.fromBytes(in[:2*fpByteSize])
if err != nil {
return nil, err
}
p1, err := g.f.fromBytes(in[2*fpByteSize:])
if err != nil {
return nil, err
}
p2 := new(fe2).one()
return &PointG2{*p0, *p1, *p2}, nil
}
// FromBytes constructs a new point given uncompressed byte input.
// Input string expected to be 192 bytes and concatenation of x and y values
// Point (0, 0) is considered as infinity.
func (g *G2) FromBytes(in []byte) (*PointG2, error) {
if len(in) != 4*fpByteSize {
return nil, errors.New("input string length must be equal to 192 bytes")
}
p0, err := g.f.fromBytes(in[:2*fpByteSize])
if err != nil {
return nil, err
}
p1, err := g.f.fromBytes(in[2*fpByteSize:])
if err != nil {
return nil, err
}
// check if given input points to infinity
if p0.isZero() && p1.isZero() {
return g.Zero(), nil
}
p2 := new(fe2).one()
p := &PointG2{*p0, *p1, *p2}
if !g.IsOnCurve(p) {
return nil, errors.New("point is not on curve")
}
return p, nil
}
// ToBytes serializes a point into bytes in uncompressed form,
// returns (0, 0) if point is infinity.
func (g *G2) ToBytes(p *PointG2) []byte {
out := make([]byte, 4*fpByteSize)
if g.IsZero(p) {
return out
}
g.Affine(p)
copy(out[:2*fpByteSize], g.f.toBytes(&p[0]))
copy(out[2*fpByteSize:], g.f.toBytes(&p[1]))
return out
}
// New creates a new G2 Point which is equal to zero in other words point at infinity.
func (g *G2) New() *PointG2 {
return new(PointG2).Zero()
}
// Zero returns a new G2 Point which is equal to point at infinity.
func (g *G2) Zero() *PointG2 {
return new(PointG2).Zero()
}
// One returns a new G2 Point which is equal to generator point.
func (g *G2) One() *PointG2 {
p := &PointG2{}
return p.Set(&g2One)
}
// IsZero returns true if given point is equal to zero.
func (g *G2) IsZero(p *PointG2) bool {
return p[2].isZero()
}
// Equal checks if given two G2 point is equal in their affine form.
func (g *G2) Equal(p1, p2 *PointG2) bool {
if g.IsZero(p1) {
return g.IsZero(p2)
}
if g.IsZero(p2) {
return g.IsZero(p1)
}
t := g.t
g.f.square(t[0], &p1[2])
g.f.square(t[1], &p2[2])
g.f.mul(t[2], t[0], &p2[0])
g.f.mul(t[3], t[1], &p1[0])
g.f.mulAssign(t[0], &p1[2])
g.f.mulAssign(t[1], &p2[2])
g.f.mulAssign(t[1], &p1[1])
g.f.mulAssign(t[0], &p2[1])
return t[0].equal(t[1]) && t[2].equal(t[3])
}
// IsOnCurve checks a G2 point is on curve.
func (g *G2) IsOnCurve(p *PointG2) bool {
if g.IsZero(p) {
return true
}
t := g.t
g.f.square(t[0], &p[1]) // y^2
g.f.square(t[1], &p[0]) // x^2
g.f.mul(t[1], t[1], &p[0]) // x^3
if p.IsAffine() {
fp2Add(t[1], t[1], b2) // x^2 + b
return t[0].equal(t[1]) // y^2 ?= x^3 + b
}
g.f.square(t[2], &p[2]) // z^2
g.f.square(t[3], t[2]) // z^4
g.f.mulAssign(t[2], t[3]) // z^6
g.f.mulAssign(t[2], b2) // b*z^6
fp2AddAssign(t[1], t[2]) // x^3 + b * z^6
return t[0].equal(t[1]) // y^2 ?= x^3 + b * z^6
}
// IsAffine checks a G2 point whether it is in affine form.
func (g *G2) IsAffine(p *PointG2) bool {
return p[2].isOne()
}
// Affine calculates affine form of given G2 point.
func (g *G2) Affine(p *PointG2) *PointG2 {
return g.affine(p, p)
}
func (g *G2) affine(r, p *PointG2) *PointG2 {
if g.IsZero(p) {
return r.Zero()
}
if !g.IsAffine(p) {
t := g.t
g.f.inverse(t[0], &p[2]) // z^-1
g.f.square(t[1], t[0]) // z^-2
g.f.mulAssign(&r[0], t[1]) // x = x * z^-2
g.f.mulAssign(t[0], t[1]) // z^-3
g.f.mulAssign(&r[1], t[0]) // y = y * z^-3
r[2].one() // z = 1
} else {
r.Set(p)
}
return r
}
// AffineBatch given multiple of points returns affine representations
func (g *G2) AffineBatch(p []*PointG2) {
inverses := make([]fe2, len(p))
for i := 0; i < len(p); i++ {
inverses[i].set(&p[i][2])
}
g.f.inverseBatch(inverses)
t := g.t
for i := 0; i < len(p); i++ {
if !g.IsAffine(p[i]) && !g.IsZero(p[i]) {
g.f.square(t[1], &inverses[i])
g.f.mulAssign(&p[i][0], t[1])
g.f.mul(t[0], &inverses[i], t[1])
g.f.mulAssign(&p[i][1], t[0])
p[i][2].one()
}
}
}
// Add adds two G2 points p1, p2 and assigns the result to point at first argument.
func (g *G2) Add(r, p1, p2 *PointG2) *PointG2 {
// http://www.hyperelliptic.org/EFD/gp/auto-shortw-jacobian-0.html#addition-add-2007-bl
if g.IsZero(p1) {
return r.Set(p2)
}
if g.IsZero(p2) {
return r.Set(p1)
}
if g.IsAffine(p2) {
return g.AddMixed(r, p1, p2)
}
t := g.t
g.f.square(t[7], &p1[2]) // z1z1
g.f.mul(t[1], &p2[0], t[7]) // u2 = x2 * z1z1
g.f.mul(t[2], &p1[2], t[7]) // z1z1 * z1
g.f.mul(t[0], &p2[1], t[2]) // s2 = y2 * z1z1 * z1
g.f.square(t[8], &p2[2]) // z2z2
g.f.mul(t[3], &p1[0], t[8]) // u1 = x1 * z2z2
g.f.mul(t[4], &p2[2], t[8]) // z2z2 * z2
g.f.mul(t[2], &p1[1], t[4]) // s1 = y1 * z2z2 * z2
if t[1].equal(t[3]) {
if t[0].equal(t[2]) {
return g.Double(r, p1)
} else {
return r.Zero()
}
}
fp2SubAssign(t[1], t[3]) // h = u2 - u1
fp2Double(t[4], t[1]) // 2h
g.f.squareAssign(t[4]) // i = 2h^2
g.f.mul(t[5], t[1], t[4]) // j = h*i
fp2SubAssign(t[0], t[2]) // s2 - s1
fp2DoubleAssign(t[0]) // r = 2*(s2 - s1)
g.f.square(t[6], t[0]) // r^2
fp2SubAssign(t[6], t[5]) // r^2 - j
g.f.mulAssign(t[3], t[4]) // v = u1 * i
fp2Double(t[4], t[3]) // 2*v
fp2Sub(&r[0], t[6], t[4]) // x3 = r^2 - j - 2*v
fp2Sub(t[4], t[3], &r[0]) // v - x3
g.f.mul(t[6], t[2], t[5]) // s1 * j
fp2DoubleAssign(t[6]) // 2 * s1 * j
g.f.mulAssign(t[0], t[4]) // r * (v - x3)
fp2Sub(&r[1], t[0], t[6]) // y3 = r * (v - x3) - (2 * s1 * j)
fp2Add(t[0], &p1[2], &p2[2]) // z1 + z2
g.f.squareAssign(t[0]) // (z1 + z2)^2
fp2SubAssign(t[0], t[7]) // (z1 + z2)^2 - z1z1
fp2SubAssign(t[0], t[8]) // (z1 + z2)^2 - z1z1 - z2z2
g.f.mul(&r[2], t[0], t[1]) // z3 = ((z1 + z2)^2 - z1z1 - z2z2) * h
return r
}
// Add adds two G1 points p1, p2 and assigns the result to point at first argument.
// Expects the second point p2 in affine form.
func (g *G2) AddMixed(r, p1, p2 *PointG2) *PointG2 {
// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-madd-2007-bl
if g.IsZero(p1) {
return r.Set(p2)
}
if g.IsZero(p2) {
return r.Set(p1)
}
t := g.t
g.f.square(t[7], &p1[2]) // z1z1
g.f.mul(t[1], &p2[0], t[7]) // u2 = x2 * z1z1
g.f.mul(t[2], &p1[2], t[7]) // z1z1 * z1
g.f.mul(t[0], &p2[1], t[2]) // s2 = y2 * z1z1 * z1
if p1[0].equal(t[1]) && p1[1].equal(t[0]) {
return g.Double(r, p1)
}
fp2SubAssign(t[1], &p1[0]) // h = u2 - x1
g.f.square(t[2], t[1]) // hh
fp2Double(t[4], t[2])
fp2DoubleAssign(t[4]) // 4hh
g.f.mul(t[5], t[1], t[4]) // j = h*i
fp2SubAssign(t[0], &p1[1]) // s2 - y1
fp2DoubleAssign(t[0]) // r = 2*(s2 - y1)
g.f.square(t[6], t[0]) // r^2
fp2SubAssign(t[6], t[5]) // r^2 - j
g.f.mul(t[3], &p1[0], t[4]) // v = x1 * i
fp2Double(t[4], t[3]) // 2*v
fp2Sub(&r[0], t[6], t[4]) // x3 = r^2 - j - 2*v
fp2Sub(t[4], t[3], &r[0]) // v - x3
g.f.mul(t[6], &p1[1], t[5]) // y1 * j
fp2DoubleAssign(t[6]) // 2 * y1 * j
g.f.mulAssign(t[0], t[4]) // r * (v - x3)
fp2Sub(&r[1], t[0], t[6]) // y3 = r * (v - x3) - (2 * y1 * j)
fp2Add(t[0], &p1[2], t[1]) // z1 + h
g.f.squareAssign(t[0]) // (z1 + h)^2
fp2SubAssign(t[0], t[7]) // (z1 + h)^2 - z1z1
fp2Sub(&r[2], t[0], t[2]) // z3 = (z1 + z2)^2 - z1z1 - hh
return r
}
// Double doubles a G2 point p and assigns the result to the point at first argument.
func (g *G2) Double(r, p *PointG2) *PointG2 {
// http://www.hyperelliptic.org/EFD/gp/auto-shortw-jacobian-0.html#doubling-dbl-2009-l
if g.IsZero(p) {
return r.Set(p)
}
t := g.t
g.f.square(t[0], &p[0]) // a = x^2
g.f.square(t[1], &p[1]) // b = y^2
g.f.square(t[2], t[1]) // c = b^2
fp2AddAssign(t[1], &p[0]) // b + x1
g.f.squareAssign(t[1]) // (b + x1)^2
fp2SubAssign(t[1], t[0]) // (b + x1)^2 - a
fp2SubAssign(t[1], t[2]) // (b + x1)^2 - a - c
fp2DoubleAssign(t[1]) // d = 2((b+x1)^2 - a - c)
fp2Double(t[3], t[0]) // 2a
fp2AddAssign(t[0], t[3]) // e = 3a
g.f.square(t[4], t[0]) // f = e^2
fp2Double(t[3], t[1]) // 2d
fp2Sub(&r[0], t[4], t[3]) // x3 = f - 2d
fp2SubAssign(t[1], &r[0]) // d-x3
fp2DoubleAssign(t[2]) //
fp2DoubleAssign(t[2]) //
fp2DoubleAssign(t[2]) // 8c
g.f.mulAssign(t[0], t[1]) // e * (d - x3)
fp2Sub(t[1], t[0], t[2]) // x3 = e * (d - x3) - 8c
g.f.mul(t[0], &p[1], &p[2]) // y1 * z1
r[1].set(t[1]) //
fp2Double(&r[2], t[0]) // z3 = 2(y1 * z1)
return r
}
// Neg negates a G2 point p and assigns the result to the point at first argument.
func (g *G2) Neg(r, p *PointG2) *PointG2 {
r[0].set(&p[0])
fp2Neg(&r[1], &p[1])
r[2].set(&p[2])
return r
}
// Sub subtracts two G2 points p1, p2 and assigns the result to point at first argument.
func (g *G2) Sub(c, a, b *PointG2) *PointG2 {
d := &PointG2{}
g.Neg(d, b)
g.Add(c, a, d)
return c
}
// MulScalar multiplies a point by given scalar value and assigns the result to point at first argument.
func (g *G2) MulScalar(r, p *PointG2, e *Fr) *PointG2 {
return g.glvMulFr(r, p, e)
}
// MulScalarBig multiplies a point by given scalar value in big.Int and assigns the result to point at first argument.
func (g *G2) MulScalarBig(r, p *PointG2, e *big.Int) *PointG2 {
return g.glvMulBig(r, p, e)
}
func (g *G2) mulScalar(c, p *PointG2, e *Fr) *PointG2 {
q, n := &PointG2{}, &PointG2{}
n.Set(p)
for i := 0; i < frBitSize; i++ {
if e.Bit(i) {
g.Add(q, q, n)
}
g.Double(n, n)
}
return c.Set(q)
}
func (g *G2) mulScalarBig(c, p *PointG2, e *big.Int) *PointG2 {
q, n := &PointG2{}, &PointG2{}
n.Set(p)
l := e.BitLen()
for i := 0; i < l; i++ {
if e.Bit(i) == 1 {
g.Add(q, q, n)
}
g.Double(n, n)
}
return c.Set(q)
}
func (g *G2) wnafMulFr(r, p *PointG2, e *Fr) *PointG2 {
wnaf := e.toWNAF(wnafMulWindowG2)
return g.wnafMul(r, p, wnaf)
}
func (g *G2) wnafMulBig(r, p *PointG2, e *big.Int) *PointG2 {
wnaf := bigToWNAF(e, wnafMulWindowG2)
return g.wnafMul(r, p, wnaf)
}
func (g *G2) wnafMul(c, p *PointG2, wnaf nafNumber) *PointG2 {
l := (1 << (wnafMulWindowG2 - 1))
twoP, acc := g.New(), new(PointG2).Set(p)
g.Double(twoP, p)
g.Affine(twoP)
// table = {p, 3p, 5p, ..., -p, -3p, -5p}
table := make([]*PointG2, l*2)
table[0], table[l] = g.New(), g.New()
table[0].Set(p)
g.Neg(table[l], table[0])
for i := 1; i < l; i++ {
g.AddMixed(acc, acc, twoP)
table[i], table[i+l] = g.New(), g.New()
table[i].Set(acc)
g.Neg(table[i+l], table[i])
}
q := g.Zero()
for i := len(wnaf) - 1; i >= 0; i-- {
if wnaf[i] > 0 {
g.Add(q, q, table[wnaf[i]>>1])
} else if wnaf[i] < 0 {
g.Add(q, q, table[((-wnaf[i])>>1)+l])
}
if i != 0 {
g.Double(q, q)
}
}
return c.Set(q)
}
func (g *G2) glvMulFr(r, p *PointG2, e *Fr) *PointG2 {
return g.glvMul(r, p, new(glvVectorFr).new(e))
}
func (g *G2) glvMulBig(r, p *PointG2, e *big.Int) *PointG2 {
return g.glvMul(r, p, new(glvVectorBig).new(e))
}
func (g *G2) glvMul(r, p0 *PointG2, v glvVector) *PointG2 {
w := glvMulWindowG2
l := 1 << (w - 1)
// prepare tables
// tableK1 = {P, 3P, 5P, ...}
// tableK2 = {λP, 3λP, 5λP, ...}
tableK1, tableK2 := make([]*PointG2, l), make([]*PointG2, l)
double := g.New()
g.Double(double, p0)
g.affine(double, double)
tableK1[0] = new(PointG2)
tableK1[0].Set(p0)
for i := 1; i < l; i++ {
tableK1[i] = new(PointG2)
g.AddMixed(tableK1[i], tableK1[i-1], double)
}
g.AffineBatch(tableK1)
for i := 0; i < l; i++ {
tableK2[i] = new(PointG2)
g.glvEndomorphism(tableK2[i], tableK1[i])
}
// recode small scalars
naf1, naf2 := v.wnaf(w)
lenNAF1, lenNAF2 := len(naf1), len(naf2)
lenNAF := lenNAF1
if lenNAF2 > lenNAF {
lenNAF = lenNAF2
}
acc, p1 := g.New(), g.New()
// function for naf addition
add := func(table []*PointG2, naf int) {
if naf != 0 {
nafAbs := naf
if nafAbs < 0 {
nafAbs = -nafAbs
}
p1.Set(table[nafAbs>>1])
if naf < 0 {
g.Neg(p1, p1)
}
g.AddMixed(acc, acc, p1)
}
}
// sliding
for i := lenNAF - 1; i >= 0; i-- {
if i < lenNAF1 {
add(tableK1, naf1[i])
}
if i < lenNAF2 {
add(tableK2, naf2[i])
}
if i != 0 {
g.Double(acc, acc)
}
}
return r.Set(acc)
}
// MultiExpBig calculates multi exponentiation. Scalar values are received as big.Int type.
// Given pairs of G2 point and scalar values `(P_0, e_0), (P_1, e_1), ... (P_n, e_n)`,
// calculates `r = e_0 * P_0 + e_1 * P_1 + ... + e_n * P_n`.
// Length of points and scalars are expected to be equal, otherwise an error is returned.
// Result is assigned to point at first argument.
func (g *G2) MultiExpBig(r *PointG2, points []*PointG2, scalars []*big.Int) (*PointG2, error) {
if len(points) != len(scalars) {
return nil, errors.New("point and scalar vectors should be in same length")
}
c := 3
if len(scalars) >= 32 {
c = int(math.Ceil(math.Log(float64(len(scalars)))))
}
bucketSize := (1 << c) - 1
windows := make([]PointG2, 255/c+1)
bucket := make([]PointG2, bucketSize)
for j := 0; j < len(windows); j++ {
for i := 0; i < bucketSize; i++ {
bucket[i].Zero()
}
for i := 0; i < len(scalars); i++ {
index := bucketSize & int(new(big.Int).Rsh(scalars[i], uint(c*j)).Int64())
if index != 0 {
g.Add(&bucket[index-1], &bucket[index-1], points[i])
}
}
acc, sum := g.New(), g.New()
for i := bucketSize - 1; i >= 0; i-- {
g.Add(sum, sum, &bucket[i])
g.Add(acc, acc, sum)
}
windows[j].Set(acc)
}
acc := g.New()
for i := len(windows) - 1; i >= 0; i-- {
for j := 0; j < c; j++ {
g.Double(acc, acc)
}
g.Add(acc, acc, &windows[i])
}
return r.Set(acc), nil
}
// MultiExp calculates multi exponentiation. Given pairs of G2 point and scalar values `(P_0, e_0), (P_1, e_1), ... (P_n, e_n)`,
// calculates `r = e_0 * P_0 + e_1 * P_1 + ... + e_n * P_n`. Length of points and scalars are expected to be equal,
// otherwise an error is returned. Result is assigned to point at first argument.
func (g *G2) MultiExp(r *PointG2, points []*PointG2, scalars []*Fr) (*PointG2, error) {
if len(points) != len(scalars) {
return nil, errors.New("point and scalar vectors should be in same length")
}
g.AffineBatch(points)
c := 3
if len(scalars) >= 32 {
c = int(math.Ceil(math.Log(float64(len(scalars)))))
}
bucketSize := (1 << c) - 1
windows := make([]*PointG2, 255/c+1)
bucket := make([]PointG2, bucketSize)
for j := 0; j < len(windows); j++ {
for i := 0; i < bucketSize; i++ {
bucket[i].Zero()
}
for i := 0; i < len(scalars); i++ {
index := bucketSize & int(scalars[i].sliceUint64(c*j))
if index != 0 {
g.AddMixed(&bucket[index-1], &bucket[index-1], points[i])
}
}
acc, sum := g.New(), g.New()
for i := bucketSize - 1; i >= 0; i-- {
g.Add(sum, sum, &bucket[i])
g.Add(acc, acc, sum)
}
windows[j] = g.New().Set(acc)
}
g.AffineBatch(windows)
acc := g.New()
for i := len(windows) - 1; i >= 0; i-- {
for j := 0; j < c; j++ {
g.Double(acc, acc)
}
g.AddMixed(acc, acc, windows[i])
}
return r.Set(acc), nil
}
// InCorrectSubgroup checks whether given point is in correct subgroup.
func (g *G2) InCorrectSubgroup(p *PointG2) bool {
// Faster Subgroup Checks for BLS12-381
// S. Bowe
// https://eprint.iacr.org/2019/814.pdf
// [z]ψ^3(P) ψ^2(P) + P = O
t0, t1 := g.New().Set(p), g.New()
g.psi(t0)
g.psi(t0)
g.Neg(t1, t0) // - ψ^2(P)
g.psi(t0) // ψ^3(P)
g.mulX(t0) // - x ψ^3(P)
g.Neg(t0, t0)
g.Add(t0, t0, t1)
g.Add(t0, t0, p)
return g.IsZero(t0)
}
// ClearCofactor maps given a G2 point to correct subgroup
func (g *G2) ClearCofactor(p *PointG2) *PointG2 {
// Efficient hash maps to G2 on BLS curves
// A. Budroni, F. Pintore
// https://eprint.iacr.org/2017/419.pdf
// [h(ψ)]P = [x^2 x 1]P + [x 1]ψ(P) + ψ^2(2P)
t0, t1, t2, t3 := g.New().Set(p), g.New().Set(p), g.New().Set(p), g.New()
g.Double(t0, t0)
g.psi(t0)
g.psi(t0) // P2 = ψ^2(2P)
g.psi(t2) // P1 = ψ(P)
g.mulX(t1) // -xP0
g.Sub(t3, t1, t2) // -xP0 - P1
g.mulX(t3) // (x^2)P0 + xP1
g.Sub(t1, t1, p) // (-x-1)P0
g.Add(t3, t3, t1) // (x^2-x-1)P0 + xP1
g.Sub(t3, t3, t2) // (x^2-x-1)P0 + (x-1)P1
g.Add(t3, t3, t0) // (x^2-x-1)P0 + (x-1)P1 + P2
return p.Set(t3)
}
func (g *G2) psi(p *PointG2) {
fp2Conjugate(&p[0], &p[0])
fp2Conjugate(&p[1], &p[1])
fp2Conjugate(&p[2], &p[2])
g.f.mul(&p[0], &p[0], &psix)
g.f.mul(&p[1], &p[1], &psiy)
}
func (g *G2) mulX(p *PointG2) {
chain := func(p0 *PointG2, n int, p1 *PointG2) {
g.Add(p0, p0, p1)
for i := 0; i < n; i++ {
g.Double(p0, p0)
}
}
t := g.New().Set(p)
g.Double(p, t)
chain(p, 2, t)
chain(p, 3, t)
chain(p, 9, t)
chain(p, 32, t)
chain(p, 16, t)
}
// MapToCurve given a byte slice returns a valid G2 point.
// This mapping function implements the Simplified Shallue-van de Woestijne-Ulas method.
// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-05#section-6.6.2
// Input byte slice should be a valid field element, otherwise an error is returned.
func (g *G2) MapToCurve(in []byte) (*PointG2, error) {
fp2 := g.f
u, err := fp2.fromBytes(in)
if err != nil {
return nil, err
}
x, y := swuMapG2(fp2, u)
isogenyMapG2(fp2, x, y)
z := new(fe2).one()
q := &PointG2{*x, *y, *z}
g.ClearCofactor(q)
return g.Affine(q), nil
}
// EncodeToCurve given a message and domain seperator tag returns the hash result
// which is a valid curve point.
// Implementation follows BLS12381G1_XMD:SHA-256_SSWU_NU_ suite at
// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06
func (g *G2) EncodeToCurve(msg, domain []byte) (*PointG2, error) {
hashRes, err := hashToFpXMDSHA256(msg, domain, 2)
if err != nil {
return nil, err
}
fp2 := g.f
u := &fe2{*hashRes[0], *hashRes[1]}
x, y := swuMapG2(fp2, u)
isogenyMapG2(fp2, x, y)
z := new(fe2).one()
q := &PointG2{*x, *y, *z}
g.ClearCofactor(q)
return g.Affine(q), nil
}
// HashToCurve given a message and domain seperator tag returns the hash result
// which is a valid curve point.
// Implementation follows BLS12381G1_XMD:SHA-256_SSWU_RO_ suite at
// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06
func (g *G2) HashToCurve(msg, domain []byte) (*PointG2, error) {
hashRes, err := hashToFpXMDSHA256(msg, domain, 4)
if err != nil {
return nil, err
}
fp2 := g.f
u0, u1 := &fe2{*hashRes[0], *hashRes[1]}, &fe2{*hashRes[2], *hashRes[3]}
x0, y0 := swuMapG2(fp2, u0)
x1, y1 := swuMapG2(fp2, u1)
z0 := new(fe2).one()
z1 := new(fe2).one()
p0, p1 := &PointG2{*x0, *y0, *z0}, &PointG2{*x1, *y1, *z1}
g.Add(p0, p0, p1)
g.Affine(p0)
isogenyMapG2(fp2, &p0[0], &p0[1])
g.ClearCofactor(p0)
return g.Affine(p0), nil
}

View file

@ -1,764 +0,0 @@
package bls12381
import (
"bytes"
"crypto/rand"
"fmt"
"io/ioutil"
"math/big"
"testing"
)
func (g *G2) one() *PointG2 {
return g.New().Set(&g2One)
}
func (g *G2) rand() *PointG2 {
p := &PointG2{}
z, _ := new(fe2).rand(rand.Reader)
z6, bz6 := new(fe2), new(fe2)
g.f.square(z6, z)
g.f.square(z6, z6)
g.f.mul(z6, z6, z)
g.f.mul(z6, z6, z)
g.f.mul(bz6, z6, b2)
for {
x, _ := new(fe2).rand(rand.Reader)
y := new(fe2)
g.f.square(y, x)
g.f.mul(y, y, x)
fp2Add(y, y, bz6)
if g.f.sqrt(y, y) {
p.Set(&PointG2{*x, *y, *z})
break
}
}
if !g.IsOnCurve(p) {
panic("rand point must be on curve")
}
if g.InCorrectSubgroup(p) {
panic("rand point must be out of correct subgroup")
}
return p
}
func (g *G2) randCorrect() *PointG2 {
p := g.ClearCofactor(g.rand())
if !g.InCorrectSubgroup(p) {
panic("must be in correct subgroup")
}
return p
}
func (g *G2) randAffine() *PointG2 {
return g.Affine(g.randCorrect())
}
func (g *G2) new() *PointG2 {
return g.Zero()
}
func TestG2Serialization(t *testing.T) {
var err error
g2 := NewG2()
zero := g2.Zero()
b0 := g2.ToUncompressed(zero)
p0, err := g2.FromUncompressed(b0)
if err != nil {
t.Fatal(err)
}
if !g2.IsZero(p0) {
t.Fatal("infinity serialization failed")
}
b0 = g2.ToCompressed(zero)
p0, err = g2.FromCompressed(b0)
if err != nil {
t.Fatal(err)
}
if !g2.IsZero(p0) {
t.Fatal("infinity serialization failed")
}
b0 = g2.ToBytes(zero)
p0, err = g2.FromBytes(b0)
if err != nil {
t.Fatal(err)
}
if !g2.IsZero(p0) {
t.Fatal("infinity serialization failed")
}
for i := 0; i < fuz; i++ {
a := g2.randAffine()
uncompressed := g2.ToUncompressed(a)
b, err := g2.FromUncompressed(uncompressed)
if err != nil {
t.Fatal(err)
}
if !g2.Equal(a, b) {
t.Fatal("serialization failed")
}
compressed := g2.ToCompressed(b)
a, err = g2.FromCompressed(compressed)
if err != nil {
t.Fatal(err)
}
if !g2.Equal(a, b) {
t.Fatal("serialization failed")
}
}
for i := 0; i < fuz; i++ {
a := g2.rand()
uncompressed := g2.ToBytes(a)
b, err := g2.FromBytes(uncompressed)
if err != nil {
t.Fatal(err)
}
if !g2.Equal(a, b) {
t.Fatal("serialization failed")
}
}
}
func TestG2IsOnCurve(t *testing.T) {
g := NewG2()
zero := g.Zero()
if !g.IsOnCurve(zero) {
t.Fatal("zero must be on curve")
}
one := new(fe2).one()
p := &PointG2{*one, *one, *one}
if g.IsOnCurve(p) {
t.Fatal("(1, 1) is not on curve")
}
}
func TestG2BatchAffine(t *testing.T) {
n := 20
g := NewG2()
points0 := make([]*PointG2, n)
points1 := make([]*PointG2, n)
for i := 0; i < n; i++ {
points0[i] = g.rand()
points1[i] = g.New().Set(points0[i])
if g.IsAffine(points0[i]) {
t.Fatal("expect non affine point")
}
}
g.AffineBatch(points0)
for i := 0; i < n; i++ {
if !g.Equal(points0[i], points1[i]) {
t.Fatal("batch affine failed")
}
}
}
func TestG2AdditiveProperties(t *testing.T) {
g := NewG2()
t0, t1 := g.New(), g.New()
zero := g.Zero()
for i := 0; i < fuz; i++ {
a, b := g.rand(), g.rand()
_, _, _ = b, t1, zero
g.Add(t0, a, zero)
if !g.Equal(t0, a) {
t.Fatal("a + 0 == a")
}
g.Add(t0, zero, zero)
if !g.Equal(t0, zero) {
t.Fatal("0 + 0 == 0")
}
g.Sub(t0, a, zero)
if !g.Equal(t0, a) {
t.Fatal("a - 0 == a")
}
g.Sub(t0, zero, zero)
if !g.Equal(t0, zero) {
t.Fatal("0 - 0 == 0")
}
g.Neg(t0, zero)
if !g.Equal(t0, zero) {
t.Fatal("- 0 == 0")
}
g.Sub(t0, zero, a)
g.Neg(t0, t0)
if !g.Equal(t0, a) {
t.Fatal(" - (0 - a) == a")
}
g.Double(t0, zero)
if !g.Equal(t0, zero) {
t.Fatal("2 * 0 == 0")
}
g.Double(t0, a)
g.Sub(t0, t0, a)
if !g.Equal(t0, a) || !g.IsOnCurve(t0) {
t.Fatal(" (2 * a) - a == a")
}
g.Add(t0, a, b)
g.Add(t1, b, a)
if !g.Equal(t0, t1) {
t.Fatal("a + b == b + a")
}
g.Sub(t0, a, b)
g.Sub(t1, b, a)
g.Neg(t1, t1)
if !g.Equal(t0, t1) {
t.Fatal("a - b == - ( b - a )")
}
c := g.rand()
g.Add(t0, a, b)
g.Add(t0, t0, c)
g.Add(t1, a, c)
g.Add(t1, t1, b)
if !g.Equal(t0, t1) {
t.Fatal("(a + b) + c == (a + c ) + b")
}
g.Sub(t0, a, b)
g.Sub(t0, t0, c)
g.Sub(t1, a, c)
g.Sub(t1, t1, b)
if !g.Equal(t0, t1) {
t.Fatal("(a - b) - c == (a - c) -b")
}
}
}
func TestG2MixedAdd(t *testing.T) {
g := NewG2()
for i := 0; i < fuz; i++ {
a, b := g.rand(), g.rand()
if g.IsAffine(a) || g.IsAffine(b) {
t.Fatal("expect non affine points")
}
bAffine := g.New().Set(b)
g.Affine(bAffine)
r0, r1 := g.New(), g.New()
g.Add(r0, a, b)
g.AddMixed(r1, a, bAffine)
if !g.Equal(r0, r1) {
t.Fatal("mixed addition failed")
}
aAffine := g.New().Set(a)
g.Affine(aAffine)
g.AddMixed(r0, a, aAffine)
g.Double(r1, a)
if !g.Equal(r0, r1) {
t.Fatal("mixed addition must double where points are equal")
}
}
}
func TestG2MultiplicationCross(t *testing.T) {
g := NewG2()
for i := 0; i < fuz; i++ {
a := g.randCorrect()
s, _ := new(Fr).Rand(rand.Reader)
sBig := s.ToBig()
res0, res1, res2, res3, res4 := g.New(), g.New(), g.New(), g.New(), g.New()
g.mulScalar(res0, a, s)
g.glvMulFr(res1, a, s)
g.glvMulBig(res2, a, sBig)
g.wnafMulFr(res3, a, s)
g.wnafMulBig(res4, a, sBig)
if !g.Equal(res0, res1) {
t.Fatal("cross multiplication failed (glv, fr)", i)
}
if !g.Equal(res0, res2) {
t.Fatal("cross multiplication failed (glv, big)", i)
}
if !g.Equal(res0, res3) {
t.Fatal("cross multiplication failed (wnaf, fr)", i)
}
if !g.Equal(res0, res4) {
t.Fatal("cross multiplication failed (wnaf, big)", i)
}
}
}
func TestG2MultiplicativeProperties(t *testing.T) {
g := NewG2()
t0, t1 := g.New(), g.New()
zero := g.Zero()
for i := 0; i < fuz; i++ {
a := g.randCorrect()
s1, _ := new(Fr).Rand(rand.Reader)
s2, _ := new(Fr).Rand(rand.Reader)
s3, _ := new(Fr).Rand(rand.Reader)
sone := &Fr{1}
g.MulScalar(t0, zero, s1)
if !g.Equal(t0, zero) {
t.Fatal(" 0 ^ s == 0")
}
g.MulScalar(t0, a, sone)
if !g.Equal(t0, a) {
t.Fatal(" a ^ 1 == a")
}
g.MulScalar(t0, zero, s1)
if !g.Equal(t0, zero) {
t.Fatal(" 0 ^ s == a")
}
g.MulScalar(t0, a, s1)
g.MulScalar(t0, t0, s2)
s3.Mul(s1, s2)
g.MulScalar(t1, a, s3)
if !g.Equal(t0, t1) {
t.Fatal(" (a ^ s1) ^ s2 == a ^ (s1 * s2)")
}
g.MulScalar(t0, a, s1)
g.MulScalar(t1, a, s2)
g.Add(t0, t0, t1)
s3.Add(s1, s2)
g.MulScalar(t1, a, s3)
if !g.Equal(t0, t1) {
t.Fatal(" (a ^ s1) + (a ^ s2) == a ^ (s1 + s2)")
}
}
}
func TestZKCryptoVectorsG2UncompressedValid(t *testing.T) {
data, err := ioutil.ReadFile("tests/g2_uncompressed_valid_test_vectors.dat")
if err != nil {
panic(err)
}
g := NewG2()
p1 := g.Zero()
for i := 0; i < 1000; i++ {
vector := data[i*192 : (i+1)*192]
p2, err := g.FromUncompressed(vector)
if err != nil {
t.Fatal("decoing fails", err, i)
}
uncompressed := g.ToUncompressed(p2)
if !bytes.Equal(vector, uncompressed) || !g.Equal(p1, p2) {
t.Fatal("serialization failed")
}
g.Add(p1, p1, &g2One)
}
}
func TestZKCryptoVectorsG2CompressedValid(t *testing.T) {
data, err := ioutil.ReadFile("tests/g2_compressed_valid_test_vectors.dat")
if err != nil {
panic(err)
}
g := NewG2()
p1 := g.Zero()
for i := 0; i < 1000; i++ {
vector := data[i*2*fpByteSize : (i+1)*2*fpByteSize]
p2, err := g.FromCompressed(vector)
if err != nil {
t.Fatal("decoing fails", err, i)
}
compressed := g.ToCompressed(p2)
if !bytes.Equal(vector, compressed) || !g.Equal(p1, p2) {
t.Fatal("serialization failed")
}
g.Add(p1, p1, &g2One)
}
}
func TestG2MultiExpExpected(t *testing.T) {
g := NewG2()
one := g.one()
var scalars [2]*Fr
var bases [2]*PointG2
scalars[0] = &Fr{2}
scalars[1] = &Fr{3}
bases[0], bases[1] = new(PointG2).Set(one), new(PointG2).Set(one)
expected, result := g.New(), g.New()
g.mulScalar(expected, one, &Fr{5})
_, _ = g.MultiExp(result, bases[:], scalars[:])
if !g.Equal(expected, result) {
t.Fatal("multi-exponentiation failed")
}
}
func TestG2MultiExpBigExpected(t *testing.T) {
g := NewG2()
one := g.one()
var scalars [2]*big.Int
var bases [2]*PointG2
scalars[0] = big.NewInt(2)
scalars[1] = big.NewInt(3)
bases[0], bases[1] = new(PointG2).Set(one), new(PointG2).Set(one)
expected, result := g.New(), g.New()
g.mulScalarBig(expected, one, big.NewInt(5))
_, _ = g.MultiExpBig(result, bases[:], scalars[:])
if !g.Equal(expected, result) {
t.Fatal("multi-exponentiation failed")
}
}
func TestG2MultiExp(t *testing.T) {
g := NewG2()
for n := 1; n < 1024+1; n = n * 2 {
bases := make([]*PointG2, n)
scalars := make([]*Fr, n)
var err error
for i := 0; i < n; i++ {
scalars[i], err = new(Fr).Rand(rand.Reader)
if err != nil {
t.Fatal(err)
}
bases[i] = g.rand()
}
expected, tmp := g.New(), g.New()
for i := 0; i < n; i++ {
g.mulScalar(tmp, bases[i], scalars[i])
g.Add(expected, expected, tmp)
}
result := g.New()
_, _ = g.MultiExp(result, bases, scalars)
if !g.Equal(expected, result) {
t.Fatal("multi-exponentiation failed")
}
}
}
func TestG2MultiExpBig(t *testing.T) {
g := NewG2()
for n := 1; n < 1024+1; n = n * 2 {
bases := make([]*PointG2, n)
scalars := make([]*big.Int, n)
var err error
for i := 0; i < n; i++ {
scalars[i], err = rand.Int(rand.Reader, qBig)
if err != nil {
t.Fatal(err)
}
bases[i] = g.rand()
}
expected, tmp := g.New(), g.New()
for i := 0; i < n; i++ {
g.mulScalarBig(tmp, bases[i], scalars[i])
g.Add(expected, expected, tmp)
}
result := g.New()
_, _ = g.MultiExpBig(result, bases, scalars)
if !g.Equal(expected, result) {
t.Fatal("multi-exponentiation failed")
}
}
}
func TestG2ClearCofactor(t *testing.T) {
g := NewG2()
for i := 0; i < fuz; i++ {
p0 := g.rand()
if g.InCorrectSubgroup(p0) {
t.Fatal("rand point should be out of correct subgroup")
}
g.ClearCofactor(p0)
if !g.InCorrectSubgroup(p0) {
t.Fatal("cofactor clearing is failed")
}
}
}
func TestG2MapToCurve(t *testing.T) {
for i, v := range []struct {
u []byte
expected []byte
}{
{
u: make([]byte, 2*fpByteSize),
expected: fromHex(-1, "0a67d12118b5a35bb02d2e86b3ebfa7e23410db93de39fb06d7025fa95e96ffa428a7a27c3ae4dd4b40bd251ac658892",
"018320896ec9eef9d5e619848dc29ce266f413d02dd31d9b9d44ec0c79cd61f18b075ddba6d7bd20b7ff27a4b324bfce",
"04c69777a43f0bda07679d5805e63f18cf4e0e7c6112ac7f70266d199b4f76ae27c6269a3ceebdae30806e9a76aadf5c",
"0260e03644d1a2c321256b3246bad2b895cad13890cbe6f85df55106a0d334604fb143c7a042d878006271865bc35941",
),
},
{
u: fromHex(-1,
"025fbc07711ba267b7e70c82caa70a16fbb1d470ae24ceef307f5e2000751677820b7013ad4e25492dcf30052d3e5eca",
"0e775d7827adf385b83e20e4445bd3fab21d7b4498426daf3c1d608b9d41e9edb5eda0df022e753b8bb4bc3bb7db4914",
),
expected: fromHex(-1,
"0d4333b77becbf9f9dfa3ca928002233d1ecc854b1447e5a71f751c9042d000f42db91c1d6649a5e0ad22bd7bf7398b8",
"027e4bfada0b47f9f07e04aec463c7371e68f2fd0c738cd517932ea3801a35acf09db018deda57387b0f270f7a219e4d",
"0cc76dc777ea0d447e02a41004f37a0a7b1fafb6746884e8d9fc276716ccf47e4e0899548a2ec71c2bdf1a2a50e876db",
"053674cba9ef516ddc218fedb37324e6c47de27f88ab7ef123b006127d738293c0277187f7e2f80a299a24d84ed03da7",
),
},
{
u: fromHex(-1,
"1870a7dbfd2a1deb74015a3546b20f598041bf5d5202997956a94a368d30d3f70f18cdaa1d33ce970a4e16af961cbdcb",
"045ab31ce4b5a8ba7c4b2851b64f063a66cd1223d3c85005b78e1beee65e33c90ceef0244e45fc45a5e1d6eab6644fdb",
),
expected: fromHex(-1,
"18f0f87b40af67c056915dbaf48534c592524e82c1c2b50c3734d02c0172c80df780a60b5683759298a3303c5d942778",
"09349f1cb5b2e55489dcd45a38545343451cc30a1681c57acd4fb0a6db125f8352c09f4a67eb7d1d8242cb7d3405f97b",
"10a2ba341bc689ab947b7941ce6ef39be17acaab067bd32bd652b471ab0792c53a2bd03bdac47f96aaafe96e441f63c0",
"02f2d9deb2c7742512f5b8230bf0fd83ea42279d7d39779543c1a43b61c885982b611f6a7a24b514995e8a098496b811",
),
},
{
u: fromHex(-1,
"088fe329b054db8a6474f21a7fbfdf17b4c18044db299d9007af582c3d5f17d00e56d99921d4b5640fce44b05219b5de",
"0b6e6135a4cd31ba980ddbd115ac48abef7ec60e226f264d7befe002c165f3a496f36f76dd524efd75d17422558d10b4",
),
expected: fromHex(-1,
"19808ec5930a53c7cf5912ccce1cc33f1b3dcff24a53ce1cc4cba41fd6996dbed4843ccdd2eaf6a0cd801e562718d163",
"149fe43777d34f0d25430dea463889bd9393bdfb4932946db23671727081c629ebb98a89604f3433fba1c67d356a4af7",
"04783e391c30c83f805ca271e353582fdf19d159f6a4c39b73acbb637a9b8ac820cfbe2738d683368a7c07ad020e3e33",
"04c0d6793a766233b2982087b5f4a254f261003ccb3262ea7c50903eecef3e871d1502c293f9e063d7d293f6384f4551",
),
},
{
u: fromHex(-1,
"03df16a66a05e4c1188c234788f43896e0565bfb64ac49b9639e6b284cc47dad73c47bb4ea7e677db8d496beb907fbb6",
"0f45b50647d67485295aa9eb2d91a877b44813677c67c8d35b2173ff3ba95f7bd0806f9ca8a1436b8b9d14ee81da4d7e",
),
expected: fromHex(-1,
"0b8e0094c886487870372eb6264613a6a087c7eb9804fab789be4e47a57b29eb19b1983a51165a1b5eb025865e9fc63a",
"0804152cbf8474669ad7d1796ab92d7ca21f32d8bed70898a748ed4e4e0ec557069003732fc86866d938538a2ae95552",
"14c80f068ece15a3936bb00c3c883966f75b4e8d9ddde809c11f781ab92d23a2d1d103ad48f6f3bb158bf3e3a4063449",
"09e5c8242dd7281ad32c03fe4af3f19167770016255fb25ad9b67ec51d62fade31a1af101e8f6172ec2ee8857662be3a",
),
},
} {
g := NewG2()
p0, err := g.MapToCurve(v.u)
if err != nil {
t.Fatal("map to curve fails", i, err)
}
if !bytes.Equal(g.ToBytes(p0), v.expected) {
t.Fatal("map to curve fails", i)
}
}
}
func TestG2EncodeToCurve(t *testing.T) {
domain := []byte("BLS12381G2_XMD:SHA-256_SSWU_NU_TESTGEN")
for i, v := range []struct {
msg []byte
expected []byte
}{
{
msg: []byte(""),
expected: fromHex(-1,
"0d4333b77becbf9f9dfa3ca928002233d1ecc854b1447e5a71f751c9042d000f42db91c1d6649a5e0ad22bd7bf7398b8",
"027e4bfada0b47f9f07e04aec463c7371e68f2fd0c738cd517932ea3801a35acf09db018deda57387b0f270f7a219e4d",
"0cc76dc777ea0d447e02a41004f37a0a7b1fafb6746884e8d9fc276716ccf47e4e0899548a2ec71c2bdf1a2a50e876db",
"053674cba9ef516ddc218fedb37324e6c47de27f88ab7ef123b006127d738293c0277187f7e2f80a299a24d84ed03da7",
),
},
{
msg: []byte("abc"),
expected: fromHex(-1,
"18f0f87b40af67c056915dbaf48534c592524e82c1c2b50c3734d02c0172c80df780a60b5683759298a3303c5d942778",
"09349f1cb5b2e55489dcd45a38545343451cc30a1681c57acd4fb0a6db125f8352c09f4a67eb7d1d8242cb7d3405f97b",
"10a2ba341bc689ab947b7941ce6ef39be17acaab067bd32bd652b471ab0792c53a2bd03bdac47f96aaafe96e441f63c0",
"02f2d9deb2c7742512f5b8230bf0fd83ea42279d7d39779543c1a43b61c885982b611f6a7a24b514995e8a098496b811",
),
},
{
msg: []byte("abcdef0123456789"),
expected: fromHex(-1,
"19808ec5930a53c7cf5912ccce1cc33f1b3dcff24a53ce1cc4cba41fd6996dbed4843ccdd2eaf6a0cd801e562718d163",
"149fe43777d34f0d25430dea463889bd9393bdfb4932946db23671727081c629ebb98a89604f3433fba1c67d356a4af7",
"04783e391c30c83f805ca271e353582fdf19d159f6a4c39b73acbb637a9b8ac820cfbe2738d683368a7c07ad020e3e33",
"04c0d6793a766233b2982087b5f4a254f261003ccb3262ea7c50903eecef3e871d1502c293f9e063d7d293f6384f4551",
),
},
{
msg: []byte("a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"),
expected: fromHex(-1,
"0b8e0094c886487870372eb6264613a6a087c7eb9804fab789be4e47a57b29eb19b1983a51165a1b5eb025865e9fc63a",
"0804152cbf8474669ad7d1796ab92d7ca21f32d8bed70898a748ed4e4e0ec557069003732fc86866d938538a2ae95552",
"14c80f068ece15a3936bb00c3c883966f75b4e8d9ddde809c11f781ab92d23a2d1d103ad48f6f3bb158bf3e3a4063449",
"09e5c8242dd7281ad32c03fe4af3f19167770016255fb25ad9b67ec51d62fade31a1af101e8f6172ec2ee8857662be3a",
),
},
} {
g := NewG2()
p0, err := g.EncodeToCurve(v.msg, domain)
if err != nil {
t.Fatal("encode to point fails", i, err)
}
if !bytes.Equal(g.ToBytes(p0), v.expected) {
t.Fatal("encode to point fails x", i)
}
}
}
func TestG2HashToCurve(t *testing.T) {
domain := []byte("BLS12381G2_XMD:SHA-256_SSWU_RO_TESTGEN")
for i, v := range []struct {
msg []byte
expected []byte
}{
{
msg: []byte(""),
expected: fromHex(-1,
"0fbdae26f9f9586a46d4b0b70390d09064ef2afe5c99348438a3c7d9756471e015cb534204c1b6824617a85024c772dc",
"0a650bd36ae7455cb3fe5d8bb1310594551456f5c6593aec9ee0c03d2f6cb693bd2c5e99d4e23cbaec767609314f51d3",
"02e5cf8f9b7348428cc9e66b9a9b36fe45ba0b0a146290c3a68d92895b1af0e1f2d9f889fb412670ae8478d8abd4c5aa",
"0d8d49e7737d8f9fc5cef7c4b8817633103faf2613016cb86a1f3fc29968fe2413e232d9208d2d74a89bf7a48ac36f83",
),
},
{
msg: []byte("abc"),
expected: fromHex(-1,
"03578447618463deb106b60e609c6f7cc446dc6035f84a72801ba17c94cd800583b493b948eff0033f09086fdd7f6175",
"1953ce6d4267939c7360756d9cca8eb34aac4633ef35369a7dc249445069888e7d1b3f9d2e75fbd468fbcbba7110ea02",
"0184d26779ae9d4670aca9b267dbd4d3b30443ad05b8546d36a195686e1ccc3a59194aea05ed5bce7c3144a29ec047c4",
"0882ab045b8fe4d7d557ebb59a63a35ac9f3d312581b509af0f8eaa2960cbc5e1e36bb969b6e22980b5cbdd0787fcf4e",
),
},
{
msg: []byte("abcdef0123456789"),
expected: fromHex(-1,
"195fad48982e186ce3c5c82133aefc9b26d55979b6f530992a8849d4263ec5d57f7a181553c8799bcc83da44847bdc8d",
"17b461fc3b96a30c2408958cbfa5f5927b6063a8ad199d5ebf2d7cdeffa9c20c85487204804fab53f950b2f87db365aa",
"005cdf3d984e3391e7e969276fb4bc02323c5924a4449af167030d855acc2600cf3d4fab025432c6d868c79571a95bef",
"174a3473a3af2d0302b9065e895ca4adba4ece6ce0b41148ba597001abb152f852dd9a96fb45c9de0a43d944746f833e",
),
},
{
msg: []byte("a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"),
expected: fromHex(-1,
"123b6bd9feeba26dd4ad00f8bfda2718c9700dc093ea5287d7711844644eb981848316d3f3f57d5d3a652c6cdc816aca",
"0a162306f3b0f2bb326f0c4fb0e1fea020019c3af796dcd1d7264f50ddae94cacf3cade74603834d44b9ab3d5d0a6c98",
"05483f3b96d9252dd4fc0868344dfaf3c9d145e3387db23fa8e449304fab6a7b6ec9c15f05c0a1ea66ff0efcc03e001a",
"15c1d4f1a685bb63ee67ca1fd96155e3d091e852a684b78d085fd34f6091e5249ddddbdcf2e7ec82ce6c04c63647eeb7",
),
},
} {
g := NewG2()
p0, err := g.HashToCurve(v.msg, domain)
if err != nil {
t.Fatal("encode to point fails", i, err)
}
if !bytes.Equal(g.ToBytes(p0), v.expected) {
t.Fatal("encode to point fails x", i)
}
}
}
func BenchmarkG2Add(t *testing.B) {
g2 := NewG2()
a, b, c := g2.rand(), g2.rand(), PointG2{}
t.ResetTimer()
for i := 0; i < t.N; i++ {
g2.Add(&c, a, b)
}
}
func BenchmarkG2MulWNAF(t *testing.B) {
g := NewG2()
p := new(PointG2).Set(&g2One)
s, _ := new(Fr).Rand(rand.Reader)
sBig := s.ToBig()
res := new(PointG2)
t.Run("Naive", func(t *testing.B) {
t.ResetTimer()
for i := 0; i < t.N; i++ {
g.mulScalar(res, p, s)
}
})
for i := 1; i < 8; i++ {
wnafMulWindowG2 = uint(i)
t.Run(fmt.Sprintf("Fr, window: %d", i), func(t *testing.B) {
t.ResetTimer()
for i := 0; i < t.N; i++ {
g.wnafMulFr(res, p, s)
}
})
t.Run(fmt.Sprintf("Big, window: %d", i), func(t *testing.B) {
t.ResetTimer()
for i := 0; i < t.N; i++ {
g.wnafMulBig(res, p, sBig)
}
})
}
}
func BenchmarkG2MulGLV(t *testing.B) {
g := NewG2()
p := new(PointG2).Set(&g2One)
s, _ := new(Fr).Rand(rand.Reader)
sBig := s.ToBig()
res := new(PointG2)
t.Run("Naive", func(t *testing.B) {
t.ResetTimer()
for i := 0; i < t.N; i++ {
g.mulScalar(res, p, s)
}
})
for i := 1; i < 8; i++ {
glvMulWindowG2 = uint(i)
t.Run(fmt.Sprintf("Fr, window: %d", i), func(t *testing.B) {
t.ResetTimer()
for i := 0; i < t.N; i++ {
g.glvMulFr(res, p, s)
}
})
t.Run(fmt.Sprintf("Big, window: %d", i), func(t *testing.B) {
t.ResetTimer()
for i := 0; i < t.N; i++ {
g.glvMulBig(res, p, sBig)
}
})
}
}
func BenchmarkG2MultiExp(t *testing.B) {
g := NewG2()
v := func(n int) ([]*PointG2, []*Fr) {
bases := make([]*PointG2, n)
scalars := make([]*Fr, n)
var err error
for i := 0; i < n; i++ {
scalars[i], err = new(Fr).Rand(rand.Reader)
if err != nil {
t.Fatal(err)
}
bases[i] = g.randAffine()
}
return bases, scalars
}
for _, i := range []int{2, 10, 100, 1000} {
t.Run(fmt.Sprint(i), func(t *testing.B) {
bases, scalars := v(i)
result := g.New()
t.ResetTimer()
for i := 0; i < t.N; i++ {
_, _ = g.MultiExp(result, bases, scalars)
}
})
}
}
func BenchmarkG2ClearCofactor(t *testing.B) {
g2 := NewG2()
a := g2.rand()
t.ResetTimer()
for i := 0; i < t.N; i++ {
g2.ClearCofactor(a)
}
}
func BenchmarkG2SubgroupCheck(t *testing.B) {
g2 := NewG2()
a := g2.rand()
t.ResetTimer()
for i := 0; i < t.N; i++ {
g2.InCorrectSubgroup(a)
}
}
func BenchmarkG2SWUMap(t *testing.B) {
a := fromHex(2*fpByteSize, "0x1234")
g2 := NewG2()
t.ResetTimer()
for i := 0; i < t.N; i++ {
_, err := g2.MapToCurve(a)
if err != nil {
t.Fatal(err)
}
}
}

View file

@ -1,200 +0,0 @@
package bls12381
import (
"math/big"
)
// Guide to Pairing Based Cryptography
// 6.3.2. Decompositions for the k = 12 BLS Family
// glvQ1 = x^2 * R / q
var glvQ1 = &Fr{0x63f6e522f6cfee30, 0x7c6becf1e01faadd, 0x1, 0}
var glvQ1Big = bigFromHex("0x017c6becf1e01faadd63f6e522f6cfee30")
// glvQ2 = R / q = 2
var glvQ2 = &Fr{0x02, 0, 0, 0}
var glvQ2Big = bigFromHex("0x02")
// glvB1 = x^2 - 1 = 0xac45a4010001a40200000000ffffffff
var glvB1 = &Fr{0x00000000ffffffff, 0xac45a4010001a402, 0, 0}
var glvB1Big = bigFromHex("0xac45a4010001a40200000000ffffffff")
// glvB2 = x^2 = 0xac45a4010001a4020000000100000000
var glvB2 = &Fr{0x0000000100000000, 0xac45a4010001a402, 0, 0}
var glvB2Big = bigFromHex("0xac45a4010001a4020000000100000000")
// glvLambdaA = x^2 - 1
var glvLambda = &Fr{0x00000000ffffffff, 0xac45a4010001a402, 0, 0}
var glvLambdaBig = bigFromHex("0xac45a4010001a40200000000ffffffff")
// halfR = 2**256 / 2
var halfR = &wideFr{0, 0, 0, 0x8000000000000000, 0, 0, 0}
var halfRBig = bigFromHex("0x8000000000000000000000000000000000000000000000000000000000000000")
// r128 = 2**128 - 1
var r128 = &Fr{0xffffffffffffffff, 0xffffffffffffffff, 0, 0}
// glvPhi1 ^ 3 = 1
var glvPhi1 = &fe{0xcd03c9e48671f071, 0x5dab22461fcda5d2, 0x587042afd3851b95, 0x8eb60ebe01bacb9e, 0x03f97d6e83d050d2, 0x18f0206554638741}
// glvPhi2 ^ 3 = 1
var glvPhi2 = &fe{0x30f1361b798a64e8, 0xf3b8ddab7ece5a2a, 0x16a8ca3ac61577f7, 0xc26a2ff874fd029b, 0x3636b76660701c6e, 0x051ba4ab241b6160}
var glvMulWindowG1 uint = 4
var glvMulWindowG2 uint = 4
type glvVector interface {
wnaf(w uint) (nafNumber, nafNumber)
}
type glvVectorFr struct {
k1 *Fr
k2 *Fr
neg1 bool
neg2 bool
}
type glvVectorBig struct {
k1 *big.Int
k2 *big.Int
}
func (v *glvVectorFr) wnaf(w uint) (nafNumber, nafNumber) {
naf1 := v.k1.toWNAF(w)
naf2 := v.k2.toWNAF(w)
if v.neg1 {
naf1.neg()
}
if !v.neg2 {
naf2.neg()
}
return naf1, naf2
}
func (v *glvVectorBig) wnaf(w uint) (nafNumber, nafNumber) {
naf1, naf2 := bigToWNAF(v.k1, w), bigToWNAF(v.k2, w)
zero := new(big.Int)
if v.k1.Cmp(zero) < 0 {
naf1.neg()
}
if v.k2.Cmp(zero) > 0 {
naf2.neg()
}
return naf1, naf2
}
func (v *glvVectorFr) new(m *Fr) *glvVectorFr {
// Guide to Pairing Based Cryptography
// 6.3.2. Decompositions for the k = 12 BLS Family
// alpha1 = round(x^2 * m / r)
alpha1 := alpha1(m)
// alpha2 = round(m / r)
alpha2 := alpha2(m)
z1, z2 := new(Fr), new(Fr)
// z1 = (x^2 - 1) * round(x^2 * m / r)
z1.Mul(alpha1, glvB1)
// z2 = x^2 * round(m / r)
z2.Mul(alpha2, glvB2)
k1, k2 := new(Fr), new(Fr)
// k1 = m - z1 - alpha2
k1.Sub(m, z1)
k1.Sub(k1, alpha2)
// k2 = z2 - alpha1
k2.Sub(z2, alpha1)
if k1.Cmp(r128) == 1 {
k1.Neg(k1)
v.neg1 = true
}
v.k1 = new(Fr).Set(k1)
if k2.Cmp(r128) == 1 {
k2.Neg(k2)
v.neg2 = true
}
v.k2 = new(Fr).Set(k2)
return v
}
func (v *glvVectorBig) new(m *big.Int) *glvVectorBig {
// Guide to Pairing Based Cryptography
// 6.3.2. Decompositions for the k = 12 BLS Family
// alpha1 = round(x^2 * m / r)
alpha1 := new(big.Int).Mul(m, glvQ1Big)
alpha1.Add(alpha1, halfRBig)
alpha1.Rsh(alpha1, fourWordBitSize)
// alpha2 = round(m / r)
alpha2 := new(big.Int).Mul(m, glvQ2Big)
alpha2.Add(alpha2, halfRBig)
alpha2.Rsh(alpha2, fourWordBitSize)
z1, z2 := new(big.Int), new(big.Int)
// z1 = (x^2 - 1) * round(x^2 * m / r)
z1.Mul(alpha1, glvB1Big).Mod(z1, qBig)
// z2 = x^2 * round(m / r)
z2.Mul(alpha2, glvB2Big).Mod(z2, qBig)
k1, k2 := new(big.Int), new(big.Int)
// k1 = m - z1 - alpha2
k1.Sub(m, z1)
k1.Sub(k1, alpha2)
// k2 = z2 - alpha1
k2.Sub(z2, alpha1)
v.k1 = new(big.Int).Set(k1)
v.k2 = new(big.Int).Set(k2)
return v
}
// round(x^2 * m / q)
func alpha1(m *Fr) *Fr {
a := new(wideFr)
a.mul(m, glvQ1)
return a.round()
}
// round(m / q)
func alpha2(m *Fr) *Fr {
a := new(wideFr)
a.mul(m, glvQ2)
return a.round()
}
func phi(a, b *fe) {
mul(a, b, glvPhi1)
}
func (e *fp2) phi(a, b *fe2) {
mul(&a[0], &b[0], glvPhi2)
mul(&a[1], &b[1], glvPhi2)
}
func (g *G1) glvEndomorphism(r, p *PointG1) {
t := g.Affine(p)
if g.IsZero(p) {
r.Zero()
return
}
r[1].set(&t[1])
phi(&r[0], &t[0])
r[2].one()
}
func (g *G2) glvEndomorphism(r, p *PointG2) {
t := g.Affine(p)
if g.IsZero(p) {
r.Zero()
return
}
r[1].set(&t[1])
g.f.phi(&r[0], &t[0])
r[2].one()
}

View file

@ -1,134 +0,0 @@
package bls12381
import (
"crypto/rand"
"math/big"
"testing"
)
func TestGLVConstruction(t *testing.T) {
t.Run("Parameters", func(t *testing.T) {
t0, t1 := new(Fr), new(Fr)
one := new(Fr).setUint64(1)
t0.Square(glvLambda)
t0.Add(t0, glvLambda)
t1.Sub(&q, one)
if !t0.Equal(t1) {
t.Fatal("lambda1^2 + lambda1 + 1 = 0")
}
c0 := new(fe)
square(c0, glvPhi1)
mul(c0, c0, glvPhi1)
if !c0.isOne() {
t.Fatal("phi1^3 = 1")
}
square(c0, glvPhi2)
mul(c0, c0, glvPhi2)
if !c0.isOne() {
t.Fatal("phi2^3 = 1")
}
})
t.Run("Endomorphism G1", func(t *testing.T) {
g := NewG1()
{
p0, p1 := g.randAffine(), g.New()
g.MulScalar(p1, p0, glvLambda)
g.Affine(p1)
r := g.New()
g.glvEndomorphism(r, p0)
if !g.Equal(r, p1) {
t.Fatal("f(x, y) = (phi * x, y)")
}
}
})
t.Run("Endomorphism G2", func(t *testing.T) {
g := NewG2()
{
p0, p1 := g.randAffine(), g.New()
g.MulScalar(p1, p0, glvLambda)
g.Affine(p1)
r := g.New()
g.glvEndomorphism(r, p0)
if !g.Equal(r, p1) {
t.Fatal("f(x, y) = (phi * x, y)")
}
}
})
t.Run("Scalar Decomposition", func(t *testing.T) {
for i := 0; i < fuz; i++ {
m, err := new(Fr).Rand(rand.Reader)
if err != nil {
t.Fatal(err)
}
mBig := m.ToBig()
var vFr *glvVectorFr
var vBig *glvVectorBig
{
vFr = new(glvVectorFr).new(m)
v := vFr
if v.k1.Cmp(r128) >= 0 {
t.Fatal("bad scalar component, k1")
}
if v.k2.Cmp(r128) >= 0 {
t.Fatal("bad scalar component, k2")
}
k := new(Fr)
if v.neg1 && v.neg2 {
k.Mul(glvLambda, v.k2)
k.Sub(k, v.k1)
} else if v.neg1 {
k.Mul(glvLambda, v.k2)
k.Add(k, v.k1)
k.Neg(k)
} else if v.neg2 {
k.Mul(glvLambda, v.k2)
k.Add(v.k1, k)
} else {
k.Mul(glvLambda, v.k2)
k.Sub(v.k1, k)
}
if !k.Equal(m) {
t.Fatal("scalar decomposing failed")
}
}
r128Big := r128.ToBig()
{
vBig = new(glvVectorBig).new(mBig)
if new(big.Int).Abs(vBig.k1).Cmp(r128Big) >= 0 {
t.Fatal("bad scalar component, big k1")
}
if new(big.Int).Abs(vBig.k2).Cmp(r128Big) >= 0 {
t.Fatal("bad scalar component, big k2")
}
k := new(big.Int)
k.Mul(glvLambdaBig, vBig.k2)
k.Sub(vBig.k1, k).Mod(k, qBig)
if k.Cmp(mBig) != 0 {
t.Fatal("scalar decomposing with big.Int failed", i)
}
}
zeroBig := new(big.Int)
k1Abs, k2Abs := new(big.Int).Abs(vBig.k1), new(big.Int).Abs(vBig.k2)
if vFr.neg1 != (vBig.k1.Cmp(zeroBig) == -1) {
t.Fatal("cross: scalar decomposing with failed neg1")
}
if vFr.neg2 != (vBig.k2.Cmp(zeroBig) == -1) {
t.Fatal("cross: scalar decomposing with failed neg2")
}
if k1Abs.Cmp(vFr.k1.ToBig()) != 0 {
t.Fatal("cross: scalar decomposing with failed k1", i)
}
if k2Abs.Cmp(vFr.k2.ToBig()) != 0 {
t.Fatal("cross: scalar decomposing with failed k2", i)
}
}
})
}

View file

@ -1,107 +0,0 @@
package bls12381
import (
"errors"
"math/big"
)
// E is type for target group element
type E = fe12
// GT is type for target multiplicative group GT.
type GT struct {
fp12 *fp12
}
// Set copies given value into the destination
func (e *E) Set(e2 *E) *E {
return e.set(e2)
}
// One sets a new target group element to one
func (e *E) One() *E {
e = new(fe12).one()
return e
}
// IsOne returns true if given element equals to one
func (e *E) IsOne() bool {
return e.isOne()
}
// Equal returns true if given two element is equal, otherwise returns false
func (g *E) Equal(g2 *E) bool {
return g.equal(g2)
}
// NewGT constructs new target group instance.
func NewGT() *GT {
fp12 := newFp12(nil)
return &GT{fp12}
}
// Q returns group order in big.Int.
func (g *GT) Q() *big.Int {
return new(big.Int).Set(qBig)
}
// FromBytes expects 576 byte input and returns target group element
// FromBytes returns error if given element is not on correct subgroup.
func (g *GT) FromBytes(in []byte) (*E, error) {
e, err := g.fp12.fromBytes(in)
if err != nil {
return nil, err
}
if !g.IsValid(e) {
return e, errors.New("invalid element")
}
return e, nil
}
// ToBytes serializes target group element.
func (g *GT) ToBytes(e *E) []byte {
return g.fp12.toBytes(e)
}
// IsValid checks whether given target group element is in correct subgroup.
func (g *GT) IsValid(e *E) bool {
r := g.New()
g.fp12.exp(r, e, qBig)
return r.isOne()
}
// New initializes a new target group element which is equal to one
func (g *GT) New() *E {
return new(E).One()
}
// Add adds two field element `a` and `b` and assigns the result to the element in first argument.
func (g *GT) Add(c, a, b *E) {
fp12Add(c, a, b)
}
// Sub subtracts two field element `a` and `b`, and assigns the result to the element in first argument.
func (g *GT) Sub(c, a, b *E) {
fp12Sub(c, a, b)
}
// Mul multiplies two field element `a` and `b` and assigns the result to the element in first argument.
func (g *GT) Mul(c, a, b *E) {
g.fp12.mul(c, a, b)
}
// Square squares an element `a` and assigns the result to the element in first argument.
func (g *GT) Square(c, a *E) {
c.set(a)
g.fp12.cyclotomicSquare(c)
}
// Exp exponents an element `a` by a scalar `s` and assigns the result to the element in first argument.
func (g *GT) Exp(c, a *E, s *big.Int) {
g.fp12.cyclotomicExp(c, a, s)
}
// Inverse inverses an element `a` and assigns the result to the element in first argument.
func (g *GT) Inverse(c, a *E) {
g.fp12.inverse(c, a)
}

View file

@ -1,70 +0,0 @@
package bls12381
import (
"crypto/sha256"
"errors"
)
func hashToFpXMDSHA256(msg []byte, domain []byte, count int) ([]*fe, error) {
randBytes, err := expandMsgSHA256XMD(msg, domain, count*64)
if err != nil {
return nil, err
}
els := make([]*fe, count)
for i := 0; i < count; i++ {
els[i], err = from64Bytes(randBytes[i*64 : (i+1)*64])
if err != nil {
return nil, err
}
}
return els, nil
}
func expandMsgSHA256XMD(msg []byte, domain []byte, outLen int) ([]byte, error) {
h := sha256.New()
domainLen := uint8(len(domain))
if domainLen > 255 {
return nil, errors.New("invalid domain length")
}
// DST_prime = DST || I2OSP(len(DST), 1)
// b_0 = H(Z_pad || msg || l_i_b_str || I2OSP(0, 1) || DST_prime)
_, _ = h.Write(make([]byte, h.BlockSize()))
_, _ = h.Write(msg)
_, _ = h.Write([]byte{uint8(outLen >> 8), uint8(outLen)})
_, _ = h.Write([]byte{0})
_, _ = h.Write(domain)
_, _ = h.Write([]byte{domainLen})
b0 := h.Sum(nil)
// b_1 = H(b_0 || I2OSP(1, 1) || DST_prime)
h.Reset()
_, _ = h.Write(b0)
_, _ = h.Write([]byte{1})
_, _ = h.Write(domain)
_, _ = h.Write([]byte{domainLen})
b1 := h.Sum(nil)
// b_i = H(strxor(b_0, b_(i - 1)) || I2OSP(i, 1) || DST_prime)
ell := (outLen + h.Size() - 1) / h.Size()
bi := b1
out := make([]byte, outLen)
for i := 1; i < ell; i++ {
h.Reset()
// b_i = H(strxor(b_0, b_(i - 1)) || I2OSP(i, 1) || DST_prime)
tmp := make([]byte, h.Size())
for j := 0; j < h.Size(); j++ {
tmp[j] = b0[j] ^ bi[j]
}
_, _ = h.Write(tmp)
_, _ = h.Write([]byte{1 + uint8(i)})
_, _ = h.Write(domain)
_, _ = h.Write([]byte{domainLen})
// b_1 || ... || b_(ell - 1)
copy(out[(i-1)*h.Size():i*h.Size()], bi[:])
bi = h.Sum(nil)
}
// b_ell
copy(out[(ell-1)*h.Size():], bi[:])
return out[:outLen], nil
}

View file

@ -1,215 +0,0 @@
package bls12381
// isogenyMapG1 applies 11-isogeny map for BLS12-381 G1 defined at draft-irtf-cfrg-hash-to-curve-06.
func isogenyMapG1(x, y *fe) {
xNum, xDen, yNum, yDen := new(fe), new(fe), new(fe), new(fe)
xNum.set(isogenyConstansG1[0][15])
xDen.set(isogenyConstansG1[1][15])
yNum.set(isogenyConstansG1[2][15])
yDen.set(isogenyConstansG1[3][15])
for i := 14; i > -1; i-- {
mul(xNum, xNum, x)
mul(xDen, xDen, x)
mul(yNum, yNum, x)
mul(yDen, yDen, x)
addAssign(xNum, isogenyConstansG1[0][i])
addAssign(xDen, isogenyConstansG1[1][i])
addAssign(yNum, isogenyConstansG1[2][i])
addAssign(yDen, isogenyConstansG1[3][i])
}
inverse(xDen, xDen)
inverse(yDen, yDen)
mul(x, xNum, xDen)
mul(yNum, yNum, yDen)
mul(y, y, yNum)
}
// isogenyMapG2 applies 3-isogeny map for BLS12-381 G2 defined at draft-irtf-cfrg-hash-to-curve-06.
func isogenyMapG2(e *fp2, x, y *fe2) {
if e == nil {
e = newFp2()
}
xNum := new(fe2).set(isogenyConstantsG2[0][3])
xDen := new(fe2).set(x)
yNum := new(fe2).set(isogenyConstantsG2[2][3])
yDen := new(fe2).set(x)
e.mulAssign(xNum, x)
e.mulAssign(yNum, x)
fp2AddAssign(xNum, isogenyConstantsG2[0][2])
fp2AddAssign(yNum, isogenyConstantsG2[2][2])
fp2AddAssign(yDen, isogenyConstantsG2[3][2])
e.mulAssign(xNum, x)
e.mulAssign(yNum, x)
e.mulAssign(yDen, x)
fp2AddAssign(xNum, isogenyConstantsG2[0][1])
fp2AddAssign(xDen, isogenyConstantsG2[1][1])
fp2AddAssign(yNum, isogenyConstantsG2[2][1])
fp2AddAssign(yDen, isogenyConstantsG2[3][1])
e.mulAssign(xNum, x)
e.mulAssign(xDen, x)
e.mulAssign(yNum, x)
e.mulAssign(yDen, x)
fp2AddAssign(xNum, isogenyConstantsG2[0][0])
fp2AddAssign(xDen, isogenyConstantsG2[1][0])
fp2AddAssign(yNum, isogenyConstantsG2[2][0])
fp2AddAssign(yDen, isogenyConstantsG2[3][0])
e.inverse(xDen, xDen)
e.inverse(yDen, yDen)
e.mul(x, xNum, xDen)
e.mulAssign(yNum, yDen)
e.mulAssign(y, yNum)
}
var isogenyConstansG1 = [4][16]*fe{
{
{0x4d18b6f3af00131c, 0x19fa219793fee28c, 0x3f2885f1467f19ae, 0x23dcea34f2ffb304, 0xd15b58d2ffc00054, 0x0913be200a20bef4},
{0x898985385cdbbd8b, 0x3c79e43cc7d966aa, 0x1597e193f4cd233a, 0x8637ef1e4d6623ad, 0x11b22deed20d827b, 0x07097bc5998784ad},
{0xa542583a480b664b, 0xfc7169c026e568c6, 0x5ba2ef314ed8b5a6, 0x5b5491c05102f0e7, 0xdf6e99707d2a0079, 0x0784151ed7605524},
{0x494e212870f72741, 0xab9be52fbda43021, 0x26f5577994e34c3d, 0x049dfee82aefbd60, 0x65dadd7828505289, 0x0e93d431ea011aeb},
{0x90ee774bd6a74d45, 0x7ada1c8a41bfb185, 0x0f1a8953b325f464, 0x104c24211be4805c, 0x169139d319ea7a8f, 0x09f20ead8e532bf6},
{0x6ddd93e2f43626b7, 0xa5482c9aa1ccd7bd, 0x143245631883f4bd, 0x2e0a94ccf77ec0db, 0xb0282d480e56489f, 0x18f4bfcbb4368929},
{0x23c5f0c953402dfd, 0x7a43ff6958ce4fe9, 0x2c390d3d2da5df63, 0xd0df5c98e1f9d70f, 0xffd89869a572b297, 0x1277ffc72f25e8fe},
{0x79f4f0490f06a8a6, 0x85f894a88030fd81, 0x12da3054b18b6410, 0xe2a57f6505880d65, 0xbba074f260e400f1, 0x08b76279f621d028},
{0xe67245ba78d5b00b, 0x8456ba9a1f186475, 0x7888bff6e6b33bb4, 0xe21585b9a30f86cb, 0x05a69cdcef55feee, 0x09e699dd9adfa5ac},
{0x0de5c357bff57107, 0x0a0db4ae6b1a10b2, 0xe256bb67b3b3cd8d, 0x8ad456574e9db24f, 0x0443915f50fd4179, 0x098c4bf7de8b6375},
{0xe6b0617e7dd929c7, 0xfe6e37d442537375, 0x1dafdeda137a489e, 0xe4efd1ad3f767ceb, 0x4a51d8667f0fe1cf, 0x054fdf4bbf1d821c},
{0x72db2a50658d767b, 0x8abf91faa257b3d5, 0xe969d6833764ab47, 0x464170142a1009eb, 0xb14f01aadb30be2f, 0x18ae6a856f40715d},
{0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0},
},
{
{0xb962a077fdb0f945, 0xa6a9740fefda13a0, 0xc14d568c3ed6c544, 0xb43fc37b908b133e, 0x9c0b3ac929599016, 0x0165aa6c93ad115f},
{0x23279a3ba506c1d9, 0x92cfca0a9465176a, 0x3b294ab13755f0ff, 0x116dda1c5070ae93, 0xed4530924cec2045, 0x083383d6ed81f1ce},
{0x9885c2a6449fecfc, 0x4a2b54ccd37733f0, 0x17da9ffd8738c142, 0xa0fba72732b3fafd, 0xff364f36e54b6812, 0x0f29c13c660523e2},
{0xe349cc118278f041, 0xd487228f2f3204fb, 0xc9d325849ade5150, 0x43a92bd69c15c2df, 0x1c2c7844bc417be4, 0x12025184f407440c},
{0x587f65ae6acb057b, 0x1444ef325140201f, 0xfbf995e71270da49, 0xccda066072436a42, 0x7408904f0f186bb2, 0x13b93c63edf6c015},
{0xfb918622cd141920, 0x4a4c64423ecaddb4, 0x0beb232927f7fb26, 0x30f94df6f83a3dc2, 0xaeedd424d780f388, 0x06cc402dd594bbeb},
{0xd41f761151b23f8f, 0x32a92465435719b3, 0x64f436e888c62cb9, 0xdf70a9a1f757c6e4, 0x6933a38d5b594c81, 0x0c6f7f7237b46606},
{0x693c08747876c8f7, 0x22c9850bf9cf80f0, 0x8e9071dab950c124, 0x89bc62d61c7baf23, 0xbc6be2d8dad57c23, 0x17916987aa14a122},
{0x1be3ff439c1316fd, 0x9965243a7571dfa7, 0xc7f7f62962f5cd81, 0x32c6aa9af394361c, 0xbbc2ee18e1c227f4, 0x0c102cbac531bb34},
{0x997614c97bacbf07, 0x61f86372b99192c0, 0x5b8c95fc14353fc3, 0xca2b066c2a87492f, 0x16178f5bbf698711, 0x12a6dcd7f0f4e0e8},
{0x760900000002fffd, 0xebf4000bc40c0002, 0x5f48985753c758ba, 0x77ce585370525745, 0x5c071a97a256ec6d, 0x15f65ec3fa80e493},
{0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0},
},
{
{0x2b567ff3e2837267, 0x1d4d9e57b958a767, 0xce028fea04bd7373, 0xcc31a30a0b6cd3df, 0x7d7b18a682692693, 0x0d300744d42a0310},
{0x99c2555fa542493f, 0xfe7f53cc4874f878, 0x5df0608b8f97608a, 0x14e03832052b49c8, 0x706326a6957dd5a4, 0x0a8dadd9c2414555},
{0x13d942922a5cf63a, 0x357e33e36e261e7d, 0xcf05a27c8456088d, 0x0000bd1de7ba50f0, 0x83d0c7532f8c1fde, 0x13f70bf38bbf2905},
{0x5c57fd95bfafbdbb, 0x28a359a65e541707, 0x3983ceb4f6360b6d, 0xafe19ff6f97e6d53, 0xb3468f4550192bf7, 0x0bb6cde49d8ba257},
{0x590b62c7ff8a513f, 0x314b4ce372cacefd, 0x6bef32ce94b8a800, 0x6ddf84a095713d5f, 0x64eace4cb0982191, 0x0386213c651b888d},
{0xa5310a31111bbcdd, 0xa14ac0f5da148982, 0xf9ad9cc95423d2e9, 0xaa6ec095283ee4a7, 0xcf5b1f022e1c9107, 0x01fddf5aed881793},
{0x65a572b0d7a7d950, 0xe25c2d8183473a19, 0xc2fcebe7cb877dbd, 0x05b2d36c769a89b0, 0xba12961be86e9efb, 0x07eb1b29c1dfde1f},
{0x93e09572f7c4cd24, 0x364e929076795091, 0x8569467e68af51b5, 0xa47da89439f5340f, 0xf4fa918082e44d64, 0x0ad52ba3e6695a79},
{0x911429844e0d5f54, 0xd03f51a3516bb233, 0x3d587e5640536e66, 0xfa86d2a3a9a73482, 0xa90ed5adf1ed5537, 0x149c9c326a5e7393},
{0x462bbeb03c12921a, 0xdc9af5fa0a274a17, 0x9a558ebde836ebed, 0x649ef8f11a4fae46, 0x8100e1652b3cdc62, 0x1862bd62c291dacb},
{0x05c9b8ca89f12c26, 0x0194160fa9b9ac4f, 0x6a643d5a6879fa2c, 0x14665bdd8846e19d, 0xbb1d0d53af3ff6bf, 0x12c7e1c3b28962e5},
{0xb55ebf900b8a3e17, 0xfedc77ec1a9201c4, 0x1f07db10ea1a4df4, 0x0dfbd15dc41a594d, 0x389547f2334a5391, 0x02419f98165871a4},
{0xb416af000745fc20, 0x8e563e9d1ea6d0f5, 0x7c763e17763a0652, 0x01458ef0159ebbef, 0x8346fe421f96bb13, 0x0d2d7b829ce324d2},
{0x93096bb538d64615, 0x6f2a2619951d823a, 0x8f66b3ea59514fa4, 0xf563e63704f7092f, 0x724b136c4cf2d9fa, 0x046959cfcfd0bf49},
{0xea748d4b6e405346, 0x91e9079c2c02d58f, 0x41064965946d9b59, 0xa06731f1d2bbe1ee, 0x07f897e267a33f1b, 0x1017290919210e5f},
{0x872aa6c17d985097, 0xeecc53161264562a, 0x07afe37afff55002, 0x54759078e5be6838, 0xc4b92d15db8acca8, 0x106d87d1b51d13b9},
},
{
{0xeb6c359d47e52b1c, 0x18ef5f8a10634d60, 0xddfa71a0889d5b7e, 0x723e71dcc5fc1323, 0x52f45700b70d5c69, 0x0a8b981ee47691f1},
{0x616a3c4f5535b9fb, 0x6f5f037395dbd911, 0xf25f4cc5e35c65da, 0x3e50dffea3c62658, 0x6a33dca523560776, 0x0fadeff77b6bfe3e},
{0x2be9b66df470059c, 0x24a2c159a3d36742, 0x115dbe7ad10c2a37, 0xb6634a652ee5884d, 0x04fe8bb2b8d81af4, 0x01c2a7a256fe9c41},
{0xf27bf8ef3b75a386, 0x898b367476c9073f, 0x24482e6b8c2f4e5f, 0xc8e0bbd6fe110806, 0x59b0c17f7631448a, 0x11037cd58b3dbfbd},
{0x31c7912ea267eec6, 0x1dbf6f1c5fcdb700, 0xd30d4fe3ba86fdb1, 0x3cae528fbee9a2a4, 0xb1cce69b6aa9ad9a, 0x044393bb632d94fb},
{0xc66ef6efeeb5c7e8, 0x9824c289dd72bb55, 0x71b1a4d2f119981d, 0x104fc1aafb0919cc, 0x0e49df01d942a628, 0x096c3a09773272d4},
{0x9abc11eb5fadeff4, 0x32dca50a885728f0, 0xfb1fa3721569734c, 0xc4b76271ea6506b3, 0xd466a75599ce728e, 0x0c81d4645f4cb6ed},
{0x4199f10e5b8be45b, 0xda64e495b1e87930, 0xcb353efe9b33e4ff, 0x9e9efb24aa6424c6, 0xf08d33680a237465, 0x0d3378023e4c7406},
{0x7eb4ae92ec74d3a5, 0xc341b4aa9fac3497, 0x5be603899e907687, 0x03bfd9cca75cbdeb, 0x564c2935a96bfa93, 0x0ef3c33371e2fdb5},
{0x7ee91fd449f6ac2e, 0xe5d5bd5cb9357a30, 0x773a8ca5196b1380, 0xd0fda172174ed023, 0x6cb95e0fa776aead, 0x0d22d5a40cec7cff},
{0xf727e09285fd8519, 0xdc9d55a83017897b, 0x7549d8bd057894ae, 0x178419613d90d8f8, 0xfce95ebdeb5b490a, 0x0467ffaef23fc49e},
{0xc1769e6a7c385f1b, 0x79bc930deac01c03, 0x5461c75a23ede3b5, 0x6e20829e5c230c45, 0x828e0f1e772a53cd, 0x116aefa749127bff},
{0x101c10bf2744c10a, 0xbbf18d053a6a3154, 0xa0ecf39ef026f602, 0xfc009d4996dc5153, 0xb9000209d5bd08d3, 0x189e5fe4470cd73c},
{0x7ebd546ca1575ed2, 0xe47d5a981d081b55, 0x57b2b625b6d4ca21, 0xb0a1ba04228520cc, 0x98738983c2107ff3, 0x13dddbc4799d81d6},
{0x09319f2e39834935, 0x039e952cbdb05c21, 0x55ba77a9a2f76493, 0xfd04e3dfc6086467, 0xfb95832e7d78742e, 0x0ef9c24eccaf5e0e},
{0x760900000002fffd, 0xebf4000bc40c0002, 0x5f48985753c758ba, 0x77ce585370525745, 0x5c071a97a256ec6d, 0x15f65ec3fa80e493},
},
}
var isogenyConstantsG2 = [4][4]*fe2{
{
{
{0x47f671c71ce05e62, 0x06dd57071206393e, 0x7c80cd2af3fd71a2, 0x048103ea9e6cd062, 0xc54516acc8d037f6, 0x13808f550920ea41},
{0x47f671c71ce05e62, 0x06dd57071206393e, 0x7c80cd2af3fd71a2, 0x048103ea9e6cd062, 0xc54516acc8d037f6, 0x13808f550920ea41},
},
{
{0, 0, 0, 0, 0, 0},
{0x5fe55555554c71d0, 0x873fffdd236aaaa3, 0x6a6b4619b26ef918, 0x21c2888408874945, 0x2836cda7028cabc5, 0x0ac73310a7fd5abd},
},
{
{0x0a0c5555555971c3, 0xdb0c00101f9eaaae, 0xb1fb2f941d797997, 0xd3960742ef416e1c, 0xb70040e2c20556f4, 0x149d7861e581393b},
{0xaff2aaaaaaa638e8, 0x439fffee91b55551, 0xb535a30cd9377c8c, 0x90e144420443a4a2, 0x941b66d3814655e2, 0x0563998853fead5e},
},
{
{0x40aac71c71c725ed, 0x190955557a84e38e, 0xd817050a8f41abc3, 0xd86485d4c87f6fb1, 0x696eb479f885d059, 0x198e1a74328002d2},
{0, 0, 0, 0, 0, 0},
},
},
{
{
{0, 0, 0, 0, 0, 0},
{0x1f3affffff13ab97, 0xf25bfc611da3ff3e, 0xca3757cb3819b208, 0x3e6427366f8cec18, 0x03977bc86095b089, 0x04f69db13f39a952},
},
{
{0x447600000027552e, 0xdcb8009a43480020, 0x6f7ee9ce4a6e8b59, 0xb10330b7c0a95bc6, 0x6140b1fcfb1e54b7, 0x0381be097f0bb4e1},
{0x7588ffffffd8557d, 0x41f3ff646e0bffdf, 0xf7b1e8d2ac426aca, 0xb3741acd32dbb6f8, 0xe9daf5b9482d581f, 0x167f53e0ba7431b8},
},
{
{0x760900000002fffd, 0xebf4000bc40c0002, 0x5f48985753c758ba, 0x77ce585370525745, 0x5c071a97a256ec6d, 0x15f65ec3fa80e493},
{0, 0, 0, 0, 0, 0},
},
{
{0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0},
},
},
{
{
{0x96d8f684bdfc77be, 0xb530e4f43b66d0e2, 0x184a88ff379652fd, 0x57cb23ecfae804e1, 0x0fd2e39eada3eba9, 0x08c8055e31c5d5c3},
{0x96d8f684bdfc77be, 0xb530e4f43b66d0e2, 0x184a88ff379652fd, 0x57cb23ecfae804e1, 0x0fd2e39eada3eba9, 0x08c8055e31c5d5c3},
},
{
{0, 0, 0, 0, 0, 0},
{0xbf0a71c71c91b406, 0x4d6d55d28b7638fd, 0x9d82f98e5f205aee, 0xa27aa27b1d1a18d5, 0x02c3b2b2d2938e86, 0x0c7d13420b09807f},
},
{
{0xd7f9555555531c74, 0x21cffff748daaaa8, 0x5a9ad1866c9bbe46, 0x4870a2210221d251, 0x4a0db369c0a32af1, 0x02b1ccc429ff56af},
{0xe205aaaaaaac8e37, 0xfcdc000768795556, 0x0c96011a8a1537dd, 0x1c06a963f163406e, 0x010df44c82a881e6, 0x174f45260f808feb},
},
{
{0xa470bda12f67f35c, 0xc0fe38e23327b425, 0xc9d3d0f2c6f0678d, 0x1c55c9935b5a982e, 0x27f6c0e2f0746764, 0x117c5e6e28aa9054},
{0, 0, 0, 0, 0, 0},
},
},
{
{
{0x0162fffffa765adf, 0x8f7bea480083fb75, 0x561b3c2259e93611, 0x11e19fc1a9c875d5, 0xca713efc00367660, 0x03c6a03d41da1151},
{0x0162fffffa765adf, 0x8f7bea480083fb75, 0x561b3c2259e93611, 0x11e19fc1a9c875d5, 0xca713efc00367660, 0x03c6a03d41da1151},
},
{
{0, 0, 0, 0, 0, 0},
{0x5db0fffffd3b02c5, 0xd713f52358ebfdba, 0x5ea60761a84d161a, 0xbb2c75a34ea6c44a, 0x0ac6735921c1119b, 0x0ee3d913bdacfbf6},
},
{
{0x66b10000003affc5, 0xcb1400e764ec0030, 0xa73e5eb56fa5d106, 0x8984c913a0fe09a9, 0x11e10afb78ad7f13, 0x05429d0e3e918f52},
{0x534dffffffc4aae6, 0x5397ff174c67ffcf, 0xbff273eb870b251d, 0xdaf2827152870915, 0x393a9cbaca9e2dc3, 0x14be74dbfaee5748},
},
{
{0x760900000002fffd, 0xebf4000bc40c0002, 0x5f48985753c758ba, 0x77ce585370525745, 0x5c071a97a256ec6d, 0x15f65ec3fa80e493},
{0, 0, 0, 0, 0, 0},
},
},
}

View file

@ -1,344 +0,0 @@
package bls12381
type pair struct {
g1 *PointG1
g2 *PointG2
}
func newPair(g1 *PointG1, g2 *PointG2) pair {
return pair{g1, g2}
}
// Engine is BLS12-381 elliptic curve pairing engine
type Engine struct {
G1 *G1
G2 *G2
fp12 *fp12
fp2 *fp2
pairingEngineTemp
pairs []pair
}
// NewEngine creates new pairing engine insteace.
func NewEngine() *Engine {
fp2 := newFp2()
fp6 := newFp6(fp2)
fp12 := newFp12(fp6)
g1 := NewG1()
g2 := newG2(fp2)
return &Engine{
fp2: fp2,
fp12: fp12,
G1: g1,
G2: g2,
pairingEngineTemp: newEngineTemp(),
}
}
type pairingEngineTemp struct {
t2 [9]*fe2
t12 [3]fe12
}
func newEngineTemp() pairingEngineTemp {
t2 := [9]*fe2{}
for i := 0; i < len(t2); i++ {
t2[i] = &fe2{}
}
t12 := [3]fe12{}
return pairingEngineTemp{t2, t12}
}
// AddPair adds a g1, g2 point pair to pairing engine
func (e *Engine) AddPair(g1 *PointG1, g2 *PointG2) *Engine {
p := newPair(g1, g2)
if !(e.G1.IsZero(p.g1) || e.G2.IsZero(p.g2)) {
e.G1.Affine(p.g1)
e.G2.Affine(p.g2)
e.pairs = append(e.pairs, p)
}
return e
}
// AddPairInv adds a G1, G2 point pair to pairing engine. G1 point is negated.
func (e *Engine) AddPairInv(g1 *PointG1, g2 *PointG2) *Engine {
ng1 := e.G1.New().Set(g1)
e.G1.Neg(ng1, g1)
e.AddPair(ng1, g2)
return e
}
// Reset deletes added pairs.
func (e *Engine) Reset() *Engine {
e.pairs = []pair{}
return e
}
func (e *Engine) double(f *fe12, r *PointG2, k int) {
fp2, t := e.fp2, e.t2
fp2.mul(t[0], &r[0], &r[1])
fp2.mul0(t[0], t[0], twoInv)
fp2.square(t[1], &r[1])
fp2.square(t[2], &r[2])
fp2Double(t[7], t[2])
fp2AddAssign(t[7], t[2])
fp2.mulByB(t[3], t[7])
fp2Double(t[4], t[3])
fp2AddAssign(t[4], t[3])
fp2Add(t[5], t[1], t[4])
fp2.mul0(t[5], t[5], twoInv)
fp2Add(t[6], &r[1], &r[2])
fp2.squareAssign(t[6])
fp2Add(t[7], t[2], t[1])
fp2SubAssign(t[6], t[7])
fp2Sub(t[8], t[3], t[1])
fp2.square(t[7], &r[0])
fp2Sub(t[4], t[1], t[4])
fp2.mul(&r[0], t[4], t[0])
fp2.square(t[2], t[3])
fp2Double(t[3], t[2])
fp2AddAssign(t[3], t[2])
fp2.squareAssign(t[5])
fp2Sub(&r[1], t[5], t[3])
fp2.mul(&r[2], t[1], t[6])
fp2Double(t[0], t[7])
fp2AddAssign(t[0], t[7])
fp2Neg(t[6], t[6])
// line eval
e.fp2.mul0Assign(t[6], &e.pairs[k].g1[1])
e.fp2.mul0Assign(t[0], &e.pairs[k].g1[0])
e.fp12.mul014(f, t[8], t[0], t[6])
}
func (e *Engine) add(f *fe12, r *PointG2, k int) {
fp2, t := e.fp2, e.t2
fp2.mul(t[0], &e.pairs[k].g2[1], &r[2])
fp2Neg(t[0], t[0])
fp2AddAssign(t[0], &r[1])
fp2.mul(t[1], &e.pairs[k].g2[0], &r[2])
fp2Neg(t[1], t[1])
fp2AddAssign(t[1], &r[0])
fp2.square(t[2], t[0])
fp2.square(t[3], t[1])
fp2.mul(t[4], t[1], t[3])
fp2.mul(t[2], &r[2], t[2])
fp2.mulAssign(t[3], &r[0])
fp2Double(t[5], t[3])
fp2Sub(t[5], t[4], t[5])
fp2AddAssign(t[5], t[2])
fp2.mul(&r[0], t[1], t[5])
fp2SubAssign(t[3], t[5])
fp2.mulAssign(t[3], t[0])
fp2.mul(t[2], &r[1], t[4])
fp2Sub(&r[1], t[3], t[2])
fp2.mulAssign(&r[2], t[4])
fp2.mul(t[2], t[1], &e.pairs[k].g2[1])
fp2.mul(t[3], t[0], &e.pairs[k].g2[0])
fp2SubAssign(t[3], t[2])
fp2Neg(t[0], t[0])
// line eval
e.fp2.mul0Assign(t[1], &e.pairs[k].g1[1])
e.fp2.mul0Assign(t[0], &e.pairs[k].g1[0])
e.fp12.mul014(f, t[3], t[0], t[1])
}
func (e *Engine) nDoubleAdd(f *fe12, r []PointG2, n int) {
for i := 0; i < n; i++ {
e.fp12.squareAssign(f)
for j := 0; j < len(e.pairs); j++ {
e.double(f, &r[j], j)
}
}
for j := 0; j < len(e.pairs); j++ {
e.add(f, &r[j], j)
}
}
func (e *Engine) nDouble(f *fe12, r []PointG2, n int) {
for i := 0; i < n; i++ {
e.fp12.squareAssign(f)
for j := 0; j < len(e.pairs); j++ {
e.double(f, &r[j], j)
}
}
}
func (e *Engine) millerLoop(f *fe12) {
f.one()
r := make([]PointG2, len(e.pairs))
for i := 0; i < len(e.pairs); i++ {
r[i].Set(e.pairs[i].g2)
}
for j := 0; j < len(e.pairs); j++ {
e.double(f, &r[j], j)
}
for j := 0; j < len(e.pairs); j++ {
e.add(f, &r[j], j)
}
e.nDoubleAdd(f, r, 2)
e.nDoubleAdd(f, r, 3)
e.nDoubleAdd(f, r, 9)
e.nDoubleAdd(f, r, 32)
e.nDouble(f, r, 16)
fp12Conjugate(f, f)
}
// exp raises element by x = -15132376222941642752
func (e *Engine) exp(c, a *fe12) {
c.set(a)
e.fp12.cyclotomicSquare(c) // (a ^ 2)
// (a ^ (2 + 1)) ^ (2 ^ 2) = a ^ 12
e.fp12.mulAssign(c, a)
e.fp12.cyclotomicSquare(c)
e.fp12.cyclotomicSquare(c)
// (a ^ (12 + 1)) ^ (2 ^ 3) = a ^ 104
e.fp12.mulAssign(c, a)
e.fp12.cyclotomicSquare(c)
e.fp12.cyclotomicSquare(c)
e.fp12.cyclotomicSquare(c)
// (a ^ (104 + 1)) ^ (2 ^ 9) = a ^ 53760
e.fp12.mulAssign(c, a)
e.fp12.cyclotomicSquare(c)
e.fp12.cyclotomicSquare(c)
e.fp12.cyclotomicSquare(c)
e.fp12.cyclotomicSquare(c)
e.fp12.cyclotomicSquare(c)
e.fp12.cyclotomicSquare(c)
e.fp12.cyclotomicSquare(c)
e.fp12.cyclotomicSquare(c)
e.fp12.cyclotomicSquare(c)
// (a ^ (53760 + 1)) ^ (2 ^ 32) = a ^ 230901736800256
e.fp12.mulAssign(c, a)
for i := 0; i < 32; i++ {
e.fp12.cyclotomicSquare(c)
}
// (a ^ (230901736800256 + 1)) ^ (2 ^ 16) = a ^ 15132376222941642752
e.fp12.mulAssign(c, a)
for i := 0; i < 16; i++ {
e.fp12.cyclotomicSquare(c)
}
// invert chain result since x is negative
fp12Conjugate(c, c)
}
// expDrop raises element by x = -15132376222941642752 / 2
func (e *Engine) expDrop(c, a *fe12) {
c.set(a)
e.fp12.cyclotomicSquare(c) // (a ^ 2)
// (a ^ (2 + 1)) ^ (2 ^ 2) = a ^ 12
e.fp12.mulAssign(c, a)
e.fp12.cyclotomicSquare(c)
e.fp12.cyclotomicSquare(c)
// (a ^ (12 + 1)) ^ (2 ^ 3) = a ^ 104
e.fp12.mulAssign(c, a)
e.fp12.cyclotomicSquare(c)
e.fp12.cyclotomicSquare(c)
e.fp12.cyclotomicSquare(c)
// (a ^ (104 + 1)) ^ (2 ^ 9) = a ^ 53760
e.fp12.mulAssign(c, a)
e.fp12.cyclotomicSquare(c)
e.fp12.cyclotomicSquare(c)
e.fp12.cyclotomicSquare(c)
e.fp12.cyclotomicSquare(c)
e.fp12.cyclotomicSquare(c)
e.fp12.cyclotomicSquare(c)
e.fp12.cyclotomicSquare(c)
e.fp12.cyclotomicSquare(c)
e.fp12.cyclotomicSquare(c)
// (a ^ (53760 + 1)) ^ (2 ^ 32) = a ^ 230901736800256
e.fp12.mulAssign(c, a)
for i := 0; i < 32; i++ {
e.fp12.cyclotomicSquare(c)
}
// (a ^ (230901736800256 + 1)) ^ (2 ^ 16) = a ^ 15132376222941642752
e.fp12.mulAssign(c, a)
for i := 0; i < 15; i++ {
e.fp12.cyclotomicSquare(c)
}
// invert chain result since x is negative
fp12Conjugate(c, c)
}
func (e *Engine) finalExp(f *fe12) {
t := e.t12
// Efficient Final Exponentiation via Cyclotomic Structure for Pairings over Families of Elliptic Curves
// https: //eprint.iacr.org/2020/875.pdf
// easy part
fp12Conjugate(&t[0], f)
e.fp12.inverse(f, f)
e.fp12.mulAssign(&t[0], f)
f.set(&t[0])
e.fp12.frobeniusMap2(f)
e.fp12.mulAssign(f, &t[0])
// hard part
t[0].set(f)
e.fp12.cyclotomicSquare(&t[0])
e.expDrop(&t[1], &t[0])
fp12Conjugate(&t[2], f)
e.fp12.mulAssign(&t[1], &t[2])
e.exp(&t[2], &t[1])
fp12Conjugate(&t[1], &t[1])
e.fp12.mulAssign(&t[1], &t[2])
e.exp(&t[2], &t[1])
e.fp12.frobeniusMap1(&t[1])
e.fp12.mulAssign(&t[1], &t[2])
e.fp12.mulAssign(f, &t[0])
e.exp(&t[0], &t[1])
e.exp(&t[2], &t[0])
t[0].set(&t[1])
e.fp12.frobeniusMap2(&t[0])
fp12Conjugate(&t[1], &t[1])
e.fp12.mulAssign(&t[1], &t[2])
e.fp12.mulAssign(&t[1], &t[0])
e.fp12.mulAssign(f, &t[1])
}
func (e *Engine) calculate() *fe12 {
f := e.fp12.one()
if len(e.pairs) == 0 {
return f
}
e.millerLoop(f)
e.finalExp(f)
return f
}
// Check computes pairing and checks if result is equal to one
func (e *Engine) Check() bool {
return e.calculate().isOne()
}
// Result computes pairing and returns target group element as result.
func (e *Engine) Result() *E {
r := e.calculate()
e.Reset()
return r
}
// GT returns target group instance.
func (e *Engine) GT() *GT {
return NewGT()
}

View file

@ -1,252 +0,0 @@
package bls12381
import (
"math/big"
"testing"
)
func TestPairingExpected(t *testing.T) {
bls := NewEngine()
G1, G2 := bls.G1, bls.G2
GT := bls.GT()
expected, err := GT.FromBytes(
fromHex(
fpByteSize,
"0x0f41e58663bf08cf068672cbd01a7ec73baca4d72ca93544deff686bfd6df543d48eaa24afe47e1efde449383b676631",
"0x04c581234d086a9902249b64728ffd21a189e87935a954051c7cdba7b3872629a4fafc05066245cb9108f0242d0fe3ef",
"0x03350f55a7aefcd3c31b4fcb6ce5771cc6a0e9786ab5973320c806ad360829107ba810c5a09ffdd9be2291a0c25a99a2",
"0x11b8b424cd48bf38fcef68083b0b0ec5c81a93b330ee1a677d0d15ff7b984e8978ef48881e32fac91b93b47333e2ba57",
"0x06fba23eb7c5af0d9f80940ca771b6ffd5857baaf222eb95a7d2809d61bfe02e1bfd1b68ff02f0b8102ae1c2d5d5ab1a",
"0x19f26337d205fb469cd6bd15c3d5a04dc88784fbb3d0b2dbdea54d43b2b73f2cbb12d58386a8703e0f948226e47ee89d",
"0x018107154f25a764bd3c79937a45b84546da634b8f6be14a8061e55cceba478b23f7dacaa35c8ca78beae9624045b4b6",
"0x01b2f522473d171391125ba84dc4007cfbf2f8da752f7c74185203fcca589ac719c34dffbbaad8431dad1c1fb597aaa5",
"0x193502b86edb8857c273fa075a50512937e0794e1e65a7617c90d8bd66065b1fffe51d7a579973b1315021ec3c19934f",
"0x1368bb445c7c2d209703f239689ce34c0378a68e72a6b3b216da0e22a5031b54ddff57309396b38c881c4c849ec23e87",
"0x089a1c5b46e5110b86750ec6a532348868a84045483c92b7af5af689452eafabf1a8943e50439f1d59882a98eaa0170f",
"0x1250ebd871fc0a92a7b2d83168d0d727272d441befa15c503dd8e90ce98db3e7b6d194f60839c508a84305aaca1789b6",
),
)
if err != nil {
t.Fatal(err)
}
r := bls.AddPair(G1.One(), G2.One()).Result()
if !r.Equal(expected) {
t.Fatal("expected pairing failed")
}
if !GT.IsValid(r) {
t.Fatal("element is not in correct subgroup")
}
}
func TestPairingNonDegeneracy(t *testing.T) {
bls := NewEngine()
G1, G2 := bls.G1, bls.G2
g1Zero, g2Zero, g1One, g2One := G1.Zero(), G2.Zero(), G1.One(), G2.One()
GT := bls.GT()
// e(g1^a, g2^b) != 1
bls.Reset()
{
bls.AddPair(g1One, g2One)
e := bls.Result()
if e.IsOne() {
t.Fatal("pairing result is not expected to be one")
}
if !GT.IsValid(e) {
t.Fatal("pairing result is not valid")
}
}
// e(g1^a, 0) == 1
bls.Reset()
{
bls.AddPair(g1One, g2Zero)
e := bls.Result()
if !e.IsOne() {
t.Fatal("pairing result is expected to be one")
}
}
// e(0, g2^b) == 1
bls.Reset()
{
bls.AddPair(g1Zero, g2One)
e := bls.Result()
if !e.IsOne() {
t.Fatal("pairing result is expected to be one")
}
}
//
bls.Reset()
{
bls.AddPair(g1Zero, g2One)
bls.AddPair(g1One, g2Zero)
bls.AddPair(g1Zero, g2Zero)
e := bls.Result()
if !e.IsOne() {
t.Fatal("pairing result is expected to be one")
}
}
//
bls.Reset()
{
expected, err := GT.FromBytes(
fromHex(
fpByteSize,
"0x0f41e58663bf08cf068672cbd01a7ec73baca4d72ca93544deff686bfd6df543d48eaa24afe47e1efde449383b676631",
"0x04c581234d086a9902249b64728ffd21a189e87935a954051c7cdba7b3872629a4fafc05066245cb9108f0242d0fe3ef",
"0x03350f55a7aefcd3c31b4fcb6ce5771cc6a0e9786ab5973320c806ad360829107ba810c5a09ffdd9be2291a0c25a99a2",
"0x11b8b424cd48bf38fcef68083b0b0ec5c81a93b330ee1a677d0d15ff7b984e8978ef48881e32fac91b93b47333e2ba57",
"0x06fba23eb7c5af0d9f80940ca771b6ffd5857baaf222eb95a7d2809d61bfe02e1bfd1b68ff02f0b8102ae1c2d5d5ab1a",
"0x19f26337d205fb469cd6bd15c3d5a04dc88784fbb3d0b2dbdea54d43b2b73f2cbb12d58386a8703e0f948226e47ee89d",
"0x018107154f25a764bd3c79937a45b84546da634b8f6be14a8061e55cceba478b23f7dacaa35c8ca78beae9624045b4b6",
"0x01b2f522473d171391125ba84dc4007cfbf2f8da752f7c74185203fcca589ac719c34dffbbaad8431dad1c1fb597aaa5",
"0x193502b86edb8857c273fa075a50512937e0794e1e65a7617c90d8bd66065b1fffe51d7a579973b1315021ec3c19934f",
"0x1368bb445c7c2d209703f239689ce34c0378a68e72a6b3b216da0e22a5031b54ddff57309396b38c881c4c849ec23e87",
"0x089a1c5b46e5110b86750ec6a532348868a84045483c92b7af5af689452eafabf1a8943e50439f1d59882a98eaa0170f",
"0x1250ebd871fc0a92a7b2d83168d0d727272d441befa15c503dd8e90ce98db3e7b6d194f60839c508a84305aaca1789b6",
),
)
if err != nil {
t.Fatal(err)
}
bls.AddPair(g1Zero, g2One)
bls.AddPair(g1One, g2Zero)
bls.AddPair(g1Zero, g2Zero)
bls.AddPair(g1One, g2One)
e := bls.Result()
if !e.Equal(expected) {
t.Fatal("pairing failed")
}
}
}
func TestPairingBilinearity(t *testing.T) {
bls := NewEngine()
g1, g2 := bls.G1, bls.G2
gt := bls.GT()
// e(a*G1, b*G2) = e(G1, G2)^c
{
a, b := big.NewInt(17), big.NewInt(117)
c := new(big.Int).Mul(a, b)
G1, G2 := g1.One(), g2.One()
e0 := bls.AddPair(G1, G2).Result()
P1, P2 := g1.New(), g2.New()
g1.MulScalarBig(P1, G1, a)
g2.MulScalarBig(P2, G2, b)
e1 := bls.AddPair(P1, P2).Result()
gt.Exp(e0, e0, c)
if !e0.Equal(e1) {
t.Fatal("pairing failed")
}
}
// e(a * G1, b * G2) = e((a * b) * G1, G2)
{
// scalars
a, b := big.NewInt(17), big.NewInt(117)
c := new(big.Int).Mul(a, b)
// LHS
G1, G2 := g1.One(), g2.One()
g1.MulScalarBig(G1, G1, c)
bls.AddPair(G1, G2)
// RHS
P1, P2 := g1.One(), g2.One()
g1.MulScalarBig(P1, P1, a)
g2.MulScalarBig(P2, P2, b)
bls.AddPairInv(P1, P2)
// should be one
if !bls.Check() {
t.Fatal("pairing failed")
}
}
// e(a * G1, b * G2) = e(G1, (a * b) * G2)
{
// scalars
a, b := big.NewInt(17), big.NewInt(117)
c := new(big.Int).Mul(a, b)
// LHS
G1, G2 := g1.One(), g2.One()
g2.MulScalarBig(G2, G2, c)
bls.AddPair(G1, G2)
// RHS
H1, H2 := g1.One(), g2.One()
g1.MulScalarBig(H1, H1, a)
g2.MulScalarBig(H2, H2, b)
bls.AddPairInv(H1, H2)
// should be one
if !bls.Check() {
t.Fatal("pairing failed")
}
}
}
func TestPairingMulti(t *testing.T) {
// e(G1, G2) ^ t == e(a01 * G1, a02 * G2) * e(a11 * G1, a12 * G2) * ... * e(an1 * G1, an2 * G2)
// where t = sum(ai1 * ai2)
bls := NewEngine()
g1, g2 := bls.G1, bls.G2
numOfPair := 100
targetExp := new(big.Int)
// RHS
for i := 0; i < numOfPair; i++ {
// (ai1 * G1, ai2 * G2)
a1, a2 := randScalar(qBig), randScalar(qBig)
P1, P2 := g1.One(), g2.One()
g1.MulScalarBig(P1, P1, a1)
g2.MulScalarBig(P2, P2, a2)
bls.AddPair(P1, P2)
// accumulate targetExp
// t += (ai1 * ai2)
a1.Mul(a1, a2)
targetExp.Add(targetExp, a1)
}
// LHS
// e(t * G1, G2)
T1, T2 := g1.One(), g2.One()
g1.MulScalarBig(T1, T1, targetExp)
bls.AddPairInv(T1, T2)
if !bls.Check() {
t.Fatal("fail multi pairing")
}
}
func TestPairingEmpty(t *testing.T) {
bls := NewEngine()
if !bls.Check() {
t.Fatal("empty check should be accepted")
}
if !bls.Result().IsOne() {
t.Fatal("empty pairing result should be one")
}
}
func BenchmarkPairing(t *testing.B) {
bls := NewEngine()
g1, g2, gt := bls.G1, bls.G2, bls.GT()
bls.AddPair(g1.One(), g2.One())
e := gt.New()
t.ResetTimer()
for i := 0; i < t.N; i++ {
e = bls.calculate()
}
_ = e
}
func BenchmarkMillerLoop(t *testing.B) {
bls := NewEngine()
g1, g2, gt := bls.G1, bls.G2, bls.GT()
bls.AddPair(g1.One(), g2.One())
f := gt.New().one()
t.ResetTimer()
for i := 0; i < t.N; i++ {
bls.millerLoop(f)
}
}
func BenchmarkFinalExp(t *testing.B) {
bls := NewEngine()
g1, g2, gt := bls.G1, bls.G2, bls.GT()
bls.AddPair(g1.One(), g2.One())
f := gt.New().one()
t.ResetTimer()
for i := 0; i < t.N; i++ {
bls.finalExp(f)
}
}

View file

@ -1,142 +0,0 @@
package bls12381
// swuMapG1 is implementation of Simplified Shallue-van de Woestijne-Ulas Method
// follows the implmentation at draft-irtf-cfrg-hash-to-curve-06.
func swuMapG1(u *fe) (*fe, *fe) {
var params = swuParamsForG1
var tv [4]*fe
for i := 0; i < 4; i++ {
tv[i] = new(fe)
}
square(tv[0], u)
mul(tv[0], tv[0], params.z)
square(tv[1], tv[0])
x1 := new(fe)
add(x1, tv[0], tv[1])
inverse(x1, x1)
e1 := x1.isZero()
one := new(fe).one()
add(x1, x1, one)
if e1 {
x1.set(params.zInv)
}
mul(x1, x1, params.minusBOverA)
gx1 := new(fe)
square(gx1, x1)
add(gx1, gx1, params.a)
mul(gx1, gx1, x1)
add(gx1, gx1, params.b)
x2 := new(fe)
mul(x2, tv[0], x1)
mul(tv[1], tv[0], tv[1])
gx2 := new(fe)
mul(gx2, gx1, tv[1])
e2 := !isQuadraticNonResidue(gx1)
x, y2 := new(fe), new(fe)
if e2 {
x.set(x1)
y2.set(gx1)
} else {
x.set(x2)
y2.set(gx2)
}
y := new(fe)
sqrt(y, y2)
if y.sign() != u.sign() {
neg(y, y)
}
return x, y
}
// swuMapG2 is implementation of Simplified Shallue-van de Woestijne-Ulas Method
// defined at draft-irtf-cfrg-hash-to-curve-06.
func swuMapG2(e *fp2, u *fe2) (*fe2, *fe2) {
if e == nil {
e = newFp2()
}
params := swuParamsForG2
var tv [4]*fe2
for i := 0; i < 4; i++ {
tv[i] = e.new()
}
e.square(tv[0], u)
e.mul(tv[0], tv[0], params.z)
e.square(tv[1], tv[0])
x1 := e.new()
fp2Add(x1, tv[0], tv[1])
e.inverse(x1, x1)
e1 := x1.isZero()
fp2Add(x1, x1, e.one())
if e1 {
x1.set(params.zInv)
}
e.mul(x1, x1, params.minusBOverA)
gx1 := e.new()
e.square(gx1, x1)
fp2Add(gx1, gx1, params.a)
e.mul(gx1, gx1, x1)
fp2Add(gx1, gx1, params.b)
x2 := e.new()
e.mul(x2, tv[0], x1)
e.mul(tv[1], tv[0], tv[1])
gx2 := e.new()
e.mul(gx2, gx1, tv[1])
e2 := !e.isQuadraticNonResidue(gx1)
x, y2 := e.new(), e.new()
if e2 {
x.set(x1)
y2.set(gx1)
} else {
x.set(x2)
y2.set(gx2)
}
y := e.new()
e.sqrtBLST(y, y2)
if y.sign() != u.sign() {
fp2Neg(y, y)
}
return x, y
}
var swuParamsForG1 = struct {
z *fe
zInv *fe
a *fe
b *fe
minusBOverA *fe
}{
a: &fe{0x2f65aa0e9af5aa51, 0x86464c2d1e8416c3, 0xb85ce591b7bd31e2, 0x27e11c91b5f24e7c, 0x28376eda6bfc1835, 0x155455c3e5071d85},
b: &fe{0xfb996971fe22a1e0, 0x9aa93eb35b742d6f, 0x8c476013de99c5c4, 0x873e27c3a221e571, 0xca72b5e45a52d888, 0x06824061418a386b},
z: &fe{0x886c00000023ffdc, 0x0f70008d3090001d, 0x77672417ed5828c3, 0x9dac23e943dc1740, 0x50553f1b9c131521, 0x078c712fbe0ab6e8},
zInv: &fe{0x0e8a2e8ba2e83e10, 0x5b28ba2ca4d745d1, 0x678cd5473847377a, 0x4c506dd8a8076116, 0x9bcb227d79284139, 0x0e8d3154b0ba099a},
minusBOverA: &fe{0x052583c93555a7fe, 0x3b40d72430f93c82, 0x1b75faa0105ec983, 0x2527e7dc63851767, 0x99fffd1f34fc181d, 0x097cab54770ca0d3},
}
var swuParamsForG2 = struct {
z *fe2
zInv *fe2
a *fe2
b *fe2
minusBOverA *fe2
}{
a: &fe2{
fe{0, 0, 0, 0, 0, 0},
fe{0xe53a000003135242, 0x01080c0fdef80285, 0xe7889edbe340f6bd, 0x0b51375126310601, 0x02d6985717c744ab, 0x1220b4e979ea5467},
},
b: &fe2{
fe{0x22ea00000cf89db2, 0x6ec832df71380aa4, 0x6e1b94403db5a66e, 0x75bf3c53a79473ba, 0x3dd3a569412c0a34, 0x125cdb5e74dc4fd1},
fe{0x22ea00000cf89db2, 0x6ec832df71380aa4, 0x6e1b94403db5a66e, 0x75bf3c53a79473ba, 0x3dd3a569412c0a34, 0x125cdb5e74dc4fd1},
},
z: &fe2{
fe{0x87ebfffffff9555c, 0x656fffe5da8ffffa, 0x0fd0749345d33ad2, 0xd951e663066576f4, 0xde291a3d41e980d3, 0x0815664c7dfe040d},
fe{0x43f5fffffffcaaae, 0x32b7fff2ed47fffd, 0x07e83a49a2e99d69, 0xeca8f3318332bb7a, 0xef148d1ea0f4c069, 0x040ab3263eff0206},
},
zInv: &fe2{
fe{0xacd0000000011110, 0x9dd9999dc88ccccd, 0xb5ca2ac9b76352bf, 0xf1b574bcf4bc90ce, 0x42dab41f28a77081, 0x132fc6ac14cd1e12},
fe{0xe396ffffffff2223, 0x4fbf332fcd0d9998, 0x0c4bbd3c1aff4cc4, 0x6b9c91267926ca58, 0x29ae4da6aef7f496, 0x10692e942f195791},
},
minusBOverA: &fe2{
fe{0x903c555555474fb3, 0x5f98cc95ce451105, 0x9f8e582eefe0fade, 0xc68946b6aebbd062, 0x467a4ad10ee6de53, 0x0e7146f483e23a05},
fe{0x29c2aaaaaab85af8, 0xbf133368e30eeefa, 0xc7a27a7206cffb45, 0x9dee04ce44c9425c, 0x04a15ce53464ce83, 0x0b8fcaf5b59dac95},
},
}

View file

@ -1,13 +0,0 @@
package bls12381
import (
"math/big"
)
func bigFromHex(hex string) *big.Int {
if len(hex) > 1 && hex[:2] == "0x" {
hex = hex[2:]
}
n, _ := new(big.Int).SetString(hex, 16)
return n
}

View file

@ -1,110 +0,0 @@
package bls12381
import (
"math/big"
)
type nafNumber []int
func (n nafNumber) neg() {
for i := 0; i < len(n); i++ {
n[i] = -n[i]
}
}
var bigZero = big.NewInt(0)
var bigOne = big.NewInt(1)
func (e *Fr) toWNAF(w uint) nafNumber {
naf := nafNumber{}
if w == 0 {
return naf
}
windowSize, halfSize, mask := 1<<(w+1), 1<<w, (1<<(w+1))-1
ee := new(Fr).Set(e)
z := new(Fr)
for !ee.IsZero() {
if !ee.isEven() {
nafSign := int(ee[0]) & mask
if nafSign >= halfSize {
nafSign = nafSign - windowSize
}
naf = append(naf, int(nafSign))
if nafSign < 0 {
laddAssignFR(ee, z.setUint64(uint64(-nafSign)))
} else {
lsubAssignFR(ee, z.setUint64(uint64(nafSign)))
}
} else {
naf = append(naf, 0)
}
ee.div2()
}
return naf
}
func (e *Fr) fromWNAF(naf nafNumber, w uint) *Fr {
if w == 0 {
return e
}
l := (1 << (w - 1))
table := make([]*Fr, l)
table[0] = new(Fr).One()
two := new(Fr).setUint64(2)
for i := 1; i < l; i++ {
table[i] = new(Fr)
table[i].Add(table[i-1], two)
}
acc := new(Fr).Zero()
for i := len(naf) - 1; i >= 0; i-- {
if naf[i] < 0 {
acc.Sub(acc, table[-naf[i]>>1])
} else if naf[i] > 0 {
acc.Add(acc, table[naf[i]>>1])
}
if i != 0 {
acc.Double(acc)
}
}
return e.Set(acc)
}
// caution: does not cover negative case
func bigToWNAF(e *big.Int, w uint) nafNumber {
naf := nafNumber{}
if w == 0 {
return naf
}
windowSize := new(big.Int).Lsh(bigOne, uint(w+1))
halfSize := new(big.Int).Rsh(windowSize, 1)
ee := new(big.Int).Abs(e)
for ee.Cmp(bigZero) != 0 {
if ee.Bit(0) == 1 {
nafSign := new(big.Int)
nafSign.Mod(ee, windowSize)
if nafSign.Cmp(halfSize) >= 0 {
nafSign.Sub(nafSign, windowSize)
}
naf = append(naf, int(nafSign.Int64()))
ee.Sub(ee, nafSign)
} else {
naf = append(naf, 0)
}
ee.Rsh(ee, 1)
}
return naf
}
func bigFromWNAF(naf nafNumber) *big.Int {
acc := new(big.Int)
k := new(big.Int).Set(bigOne)
for i := 0; i < len(naf); i++ {
if naf[i] != 0 {
z := new(big.Int).Mul(k, big.NewInt(int64(naf[i])))
acc.Add(acc, z)
}
k.Lsh(k, 1)
}
return acc
}

View file

@ -1,67 +0,0 @@
package bls12381
import (
"crypto/rand"
"math/big"
"testing"
)
var maxWindowSize uint = 9
func TestWNAFBig(t *testing.T) {
var w uint
for w = 1; w <= maxWindowSize; w++ {
for i := 0; i < fuz; i++ {
e0, err := rand.Int(rand.Reader, new(big.Int).SetUint64(100))
if err != nil {
t.Fatal(err)
}
n0 := bigToWNAF(e0, w)
e1 := bigFromWNAF(n0)
if e0.Cmp(e1) != 0 {
t.Fatal("wnaf conversion failed")
}
}
}
}
func TestFrWNAF(t *testing.T) {
var w uint
for w = 1; w <= maxWindowSize; w++ {
for i := 0; i < fuz; i++ {
a0, _ := new(Fr).Rand(rand.Reader)
naf := a0.toWNAF(w)
a1 := new(Fr).fromWNAF(naf, w)
if !a0.Equal(a1) {
t.Fatal("wnaf conversion failed")
}
naf.neg()
a1.fromWNAF(naf, w)
a0.Neg(a0)
if !a0.Equal(a1) {
t.Fatal("negated wnaf conversion failed")
}
}
}
}
func TestFrWNAFCrossAgainstBig(t *testing.T) {
var maxWindowSize uint = 20
var w uint
for w = 1; w <= maxWindowSize; w++ {
for i := 0; i < fuz; i++ {
a, _ := new(Fr).Rand(rand.Reader)
aBig := a.ToBig()
naf1 := a.toWNAF(w)
naf2 := bigToWNAF(aBig, w)
if len(naf1) != len(naf2) {
t.Fatal("naf conversion failed", len(naf1), len(naf2))
}
for i := 0; i < len(naf1); i++ {
if naf1[i] != naf2[i] {
t.Fatal("naf conversion failed", i)
}
}
}
}
}

View file

@ -31,7 +31,7 @@ import (
"github.com/consensys/gnark-crypto/ecc/bls12-381/fp" "github.com/consensys/gnark-crypto/ecc/bls12-381/fp"
"github.com/consensys/gnark-crypto/ecc/bls12-381/fr" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
bls12381 "github.com/ethereum/go-ethereum/crypto/bls12381" bls12381 "github.com/kilic/bls12-381"
blst "github.com/supranational/blst/bindings/go" blst "github.com/supranational/blst/bindings/go"
) )