mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 02:42:27 +00:00
crypto/bls12381: remove vendored library
This commit is contained in:
parent
1eab649970
commit
8c2bb6c383
37 changed files with 1 additions and 24101 deletions
|
|
@ -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)
|
|
||||||
|
|
@ -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
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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},
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
|
||||||
}
|
|
||||||
|
|
@ -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")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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)
|
|
||||||
}
|
|
||||||
|
|
@ -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])
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
||||||
}
|
|
||||||
|
|
@ -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")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
|
||||||
}
|
|
||||||
|
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
|
||||||
}
|
|
||||||
|
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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()
|
|
||||||
}
|
|
||||||
|
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
@ -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 >{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)
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
|
||||||
}
|
|
||||||
|
|
@ -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},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
@ -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()
|
|
||||||
}
|
|
||||||
|
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
|
||||||
}
|
|
||||||
|
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue