Add crypto library

This commit is contained in:
Austin Roberts 2021-09-13 15:12:49 -05:00
parent 244866381c
commit ffd0033781
191 changed files with 41961 additions and 0 deletions

View File

@ -0,0 +1,319 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package blake2b implements the BLAKE2b hash algorithm defined by RFC 7693
// and the extendable output function (XOF) BLAKE2Xb.
//
// For a detailed specification of BLAKE2b see https://blake2.net/blake2.pdf
// and for BLAKE2Xb see https://blake2.net/blake2x.pdf
//
// If you aren't sure which function you need, use BLAKE2b (Sum512 or New512).
// If you need a secret-key MAC (message authentication code), use the New512
// function with a non-nil key.
//
// BLAKE2X is a construction to compute hash values larger than 64 bytes. It
// can produce hash values between 0 and 4 GiB.
package blake2b
import (
"encoding/binary"
"errors"
"hash"
)
const (
// The blocksize of BLAKE2b in bytes.
BlockSize = 128
// The hash size of BLAKE2b-512 in bytes.
Size = 64
// The hash size of BLAKE2b-384 in bytes.
Size384 = 48
// The hash size of BLAKE2b-256 in bytes.
Size256 = 32
)
var (
useAVX2 bool
useAVX bool
useSSE4 bool
)
var (
errKeySize = errors.New("blake2b: invalid key size")
errHashSize = errors.New("blake2b: invalid hash size")
)
var iv = [8]uint64{
0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1,
0x510e527fade682d1, 0x9b05688c2b3e6c1f, 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179,
}
// Sum512 returns the BLAKE2b-512 checksum of the data.
func Sum512(data []byte) [Size]byte {
var sum [Size]byte
checkSum(&sum, Size, data)
return sum
}
// Sum384 returns the BLAKE2b-384 checksum of the data.
func Sum384(data []byte) [Size384]byte {
var sum [Size]byte
var sum384 [Size384]byte
checkSum(&sum, Size384, data)
copy(sum384[:], sum[:Size384])
return sum384
}
// Sum256 returns the BLAKE2b-256 checksum of the data.
func Sum256(data []byte) [Size256]byte {
var sum [Size]byte
var sum256 [Size256]byte
checkSum(&sum, Size256, data)
copy(sum256[:], sum[:Size256])
return sum256
}
// New512 returns a new hash.Hash computing the BLAKE2b-512 checksum. A non-nil
// key turns the hash into a MAC. The key must be between zero and 64 bytes long.
func New512(key []byte) (hash.Hash, error) { return newDigest(Size, key) }
// New384 returns a new hash.Hash computing the BLAKE2b-384 checksum. A non-nil
// key turns the hash into a MAC. The key must be between zero and 64 bytes long.
func New384(key []byte) (hash.Hash, error) { return newDigest(Size384, key) }
// New256 returns a new hash.Hash computing the BLAKE2b-256 checksum. A non-nil
// key turns the hash into a MAC. The key must be between zero and 64 bytes long.
func New256(key []byte) (hash.Hash, error) { return newDigest(Size256, key) }
// New returns a new hash.Hash computing the BLAKE2b checksum with a custom length.
// A non-nil key turns the hash into a MAC. The key must be between zero and 64 bytes long.
// The hash size can be a value between 1 and 64 but it is highly recommended to use
// values equal or greater than:
// - 32 if BLAKE2b is used as a hash function (The key is zero bytes long).
// - 16 if BLAKE2b is used as a MAC function (The key is at least 16 bytes long).
// When the key is nil, the returned hash.Hash implements BinaryMarshaler
// and BinaryUnmarshaler for state (de)serialization as documented by hash.Hash.
func New(size int, key []byte) (hash.Hash, error) { return newDigest(size, key) }
// F is a compression function for BLAKE2b. It takes as an argument the state
// vector `h`, message block vector `m`, offset counter `t`, final block indicator
// flag `f`, and number of rounds `rounds`. The state vector provided as the first
// parameter is modified by the function.
func F(h *[8]uint64, m [16]uint64, c [2]uint64, final bool, rounds uint32) {
var flag uint64
if final {
flag = 0xFFFFFFFFFFFFFFFF
}
f(h, &m, c[0], c[1], flag, uint64(rounds))
}
func newDigest(hashSize int, key []byte) (*digest, error) {
if hashSize < 1 || hashSize > Size {
return nil, errHashSize
}
if len(key) > Size {
return nil, errKeySize
}
d := &digest{
size: hashSize,
keyLen: len(key),
}
copy(d.key[:], key)
d.Reset()
return d, nil
}
func checkSum(sum *[Size]byte, hashSize int, data []byte) {
h := iv
h[0] ^= uint64(hashSize) | (1 << 16) | (1 << 24)
var c [2]uint64
if length := len(data); length > BlockSize {
n := length &^ (BlockSize - 1)
if length == n {
n -= BlockSize
}
hashBlocks(&h, &c, 0, data[:n])
data = data[n:]
}
var block [BlockSize]byte
offset := copy(block[:], data)
remaining := uint64(BlockSize - offset)
if c[0] < remaining {
c[1]--
}
c[0] -= remaining
hashBlocks(&h, &c, 0xFFFFFFFFFFFFFFFF, block[:])
for i, v := range h[:(hashSize+7)/8] {
binary.LittleEndian.PutUint64(sum[8*i:], v)
}
}
func hashBlocks(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) {
var m [16]uint64
c0, c1 := c[0], c[1]
for i := 0; i < len(blocks); {
c0 += BlockSize
if c0 < BlockSize {
c1++
}
for j := range m {
m[j] = binary.LittleEndian.Uint64(blocks[i:])
i += 8
}
f(h, &m, c0, c1, flag, 12)
}
c[0], c[1] = c0, c1
}
type digest struct {
h [8]uint64
c [2]uint64
size int
block [BlockSize]byte
offset int
key [BlockSize]byte
keyLen int
}
const (
magic = "b2b"
marshaledSize = len(magic) + 8*8 + 2*8 + 1 + BlockSize + 1
)
func (d *digest) MarshalBinary() ([]byte, error) {
if d.keyLen != 0 {
return nil, errors.New("crypto/blake2b: cannot marshal MACs")
}
b := make([]byte, 0, marshaledSize)
b = append(b, magic...)
for i := 0; i < 8; i++ {
b = appendUint64(b, d.h[i])
}
b = appendUint64(b, d.c[0])
b = appendUint64(b, d.c[1])
// Maximum value for size is 64
b = append(b, byte(d.size))
b = append(b, d.block[:]...)
b = append(b, byte(d.offset))
return b, nil
}
func (d *digest) UnmarshalBinary(b []byte) error {
if len(b) < len(magic) || string(b[:len(magic)]) != magic {
return errors.New("crypto/blake2b: invalid hash state identifier")
}
if len(b) != marshaledSize {
return errors.New("crypto/blake2b: invalid hash state size")
}
b = b[len(magic):]
for i := 0; i < 8; i++ {
b, d.h[i] = consumeUint64(b)
}
b, d.c[0] = consumeUint64(b)
b, d.c[1] = consumeUint64(b)
d.size = int(b[0])
b = b[1:]
copy(d.block[:], b[:BlockSize])
b = b[BlockSize:]
d.offset = int(b[0])
return nil
}
func (d *digest) BlockSize() int { return BlockSize }
func (d *digest) Size() int { return d.size }
func (d *digest) Reset() {
d.h = iv
d.h[0] ^= uint64(d.size) | (uint64(d.keyLen) << 8) | (1 << 16) | (1 << 24)
d.offset, d.c[0], d.c[1] = 0, 0, 0
if d.keyLen > 0 {
d.block = d.key
d.offset = BlockSize
}
}
func (d *digest) Write(p []byte) (n int, err error) {
n = len(p)
if d.offset > 0 {
remaining := BlockSize - d.offset
if n <= remaining {
d.offset += copy(d.block[d.offset:], p)
return
}
copy(d.block[d.offset:], p[:remaining])
hashBlocks(&d.h, &d.c, 0, d.block[:])
d.offset = 0
p = p[remaining:]
}
if length := len(p); length > BlockSize {
nn := length &^ (BlockSize - 1)
if length == nn {
nn -= BlockSize
}
hashBlocks(&d.h, &d.c, 0, p[:nn])
p = p[nn:]
}
if len(p) > 0 {
d.offset += copy(d.block[:], p)
}
return
}
func (d *digest) Sum(sum []byte) []byte {
var hash [Size]byte
d.finalize(&hash)
return append(sum, hash[:d.size]...)
}
func (d *digest) finalize(hash *[Size]byte) {
var block [BlockSize]byte
copy(block[:], d.block[:d.offset])
remaining := uint64(BlockSize - d.offset)
c := d.c
if c[0] < remaining {
c[1]--
}
c[0] -= remaining
h := d.h
hashBlocks(&h, &c, 0xFFFFFFFFFFFFFFFF, block[:])
for i, v := range h {
binary.LittleEndian.PutUint64(hash[8*i:], v)
}
}
func appendUint64(b []byte, x uint64) []byte {
var a [8]byte
binary.BigEndian.PutUint64(a[:], x)
return append(b, a[:]...)
}
func appendUint32(b []byte, x uint32) []byte {
var a [4]byte
binary.BigEndian.PutUint32(a[:], x)
return append(b, a[:]...)
}
func consumeUint64(b []byte) ([]byte, uint64) {
x := binary.BigEndian.Uint64(b)
return b[8:], x
}
func consumeUint32(b []byte) ([]byte, uint32) {
x := binary.BigEndian.Uint32(b)
return b[4:], x
}

View File

@ -0,0 +1,37 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build go1.7,amd64,!gccgo,!appengine
package blake2b
import "golang.org/x/sys/cpu"
func init() {
useAVX2 = cpu.X86.HasAVX2
useAVX = cpu.X86.HasAVX
useSSE4 = cpu.X86.HasSSE41
}
//go:noescape
func fAVX2(h *[8]uint64, m *[16]uint64, c0, c1 uint64, flag uint64, rounds uint64)
//go:noescape
func fAVX(h *[8]uint64, m *[16]uint64, c0, c1 uint64, flag uint64, rounds uint64)
//go:noescape
func fSSE4(h *[8]uint64, m *[16]uint64, c0, c1 uint64, flag uint64, rounds uint64)
func f(h *[8]uint64, m *[16]uint64, c0, c1 uint64, flag uint64, rounds uint64) {
switch {
case useAVX2:
fAVX2(h, m, c0, c1, flag, rounds)
case useAVX:
fAVX(h, m, c0, c1, flag, rounds)
case useSSE4:
fSSE4(h, m, c0, c1, flag, rounds)
default:
fGeneric(h, m, c0, c1, flag, rounds)
}
}

View File

@ -0,0 +1,717 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build go1.7,amd64,!gccgo,!appengine
#include "textflag.h"
DATA ·AVX2_iv0<>+0x00(SB)/8, $0x6a09e667f3bcc908
DATA ·AVX2_iv0<>+0x08(SB)/8, $0xbb67ae8584caa73b
DATA ·AVX2_iv0<>+0x10(SB)/8, $0x3c6ef372fe94f82b
DATA ·AVX2_iv0<>+0x18(SB)/8, $0xa54ff53a5f1d36f1
GLOBL ·AVX2_iv0<>(SB), (NOPTR+RODATA), $32
DATA ·AVX2_iv1<>+0x00(SB)/8, $0x510e527fade682d1
DATA ·AVX2_iv1<>+0x08(SB)/8, $0x9b05688c2b3e6c1f
DATA ·AVX2_iv1<>+0x10(SB)/8, $0x1f83d9abfb41bd6b
DATA ·AVX2_iv1<>+0x18(SB)/8, $0x5be0cd19137e2179
GLOBL ·AVX2_iv1<>(SB), (NOPTR+RODATA), $32
DATA ·AVX2_c40<>+0x00(SB)/8, $0x0201000706050403
DATA ·AVX2_c40<>+0x08(SB)/8, $0x0a09080f0e0d0c0b
DATA ·AVX2_c40<>+0x10(SB)/8, $0x0201000706050403
DATA ·AVX2_c40<>+0x18(SB)/8, $0x0a09080f0e0d0c0b
GLOBL ·AVX2_c40<>(SB), (NOPTR+RODATA), $32
DATA ·AVX2_c48<>+0x00(SB)/8, $0x0100070605040302
DATA ·AVX2_c48<>+0x08(SB)/8, $0x09080f0e0d0c0b0a
DATA ·AVX2_c48<>+0x10(SB)/8, $0x0100070605040302
DATA ·AVX2_c48<>+0x18(SB)/8, $0x09080f0e0d0c0b0a
GLOBL ·AVX2_c48<>(SB), (NOPTR+RODATA), $32
DATA ·AVX_iv0<>+0x00(SB)/8, $0x6a09e667f3bcc908
DATA ·AVX_iv0<>+0x08(SB)/8, $0xbb67ae8584caa73b
GLOBL ·AVX_iv0<>(SB), (NOPTR+RODATA), $16
DATA ·AVX_iv1<>+0x00(SB)/8, $0x3c6ef372fe94f82b
DATA ·AVX_iv1<>+0x08(SB)/8, $0xa54ff53a5f1d36f1
GLOBL ·AVX_iv1<>(SB), (NOPTR+RODATA), $16
DATA ·AVX_iv2<>+0x00(SB)/8, $0x510e527fade682d1
DATA ·AVX_iv2<>+0x08(SB)/8, $0x9b05688c2b3e6c1f
GLOBL ·AVX_iv2<>(SB), (NOPTR+RODATA), $16
DATA ·AVX_iv3<>+0x00(SB)/8, $0x1f83d9abfb41bd6b
DATA ·AVX_iv3<>+0x08(SB)/8, $0x5be0cd19137e2179
GLOBL ·AVX_iv3<>(SB), (NOPTR+RODATA), $16
DATA ·AVX_c40<>+0x00(SB)/8, $0x0201000706050403
DATA ·AVX_c40<>+0x08(SB)/8, $0x0a09080f0e0d0c0b
GLOBL ·AVX_c40<>(SB), (NOPTR+RODATA), $16
DATA ·AVX_c48<>+0x00(SB)/8, $0x0100070605040302
DATA ·AVX_c48<>+0x08(SB)/8, $0x09080f0e0d0c0b0a
GLOBL ·AVX_c48<>(SB), (NOPTR+RODATA), $16
#define VPERMQ_0x39_Y1_Y1 BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xc9; BYTE $0x39
#define VPERMQ_0x93_Y1_Y1 BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xc9; BYTE $0x93
#define VPERMQ_0x4E_Y2_Y2 BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xd2; BYTE $0x4e
#define VPERMQ_0x93_Y3_Y3 BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xdb; BYTE $0x93
#define VPERMQ_0x39_Y3_Y3 BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xdb; BYTE $0x39
#define ROUND_AVX2(m0, m1, m2, m3, t, c40, c48) \
VPADDQ m0, Y0, Y0; \
VPADDQ Y1, Y0, Y0; \
VPXOR Y0, Y3, Y3; \
VPSHUFD $-79, Y3, Y3; \
VPADDQ Y3, Y2, Y2; \
VPXOR Y2, Y1, Y1; \
VPSHUFB c40, Y1, Y1; \
VPADDQ m1, Y0, Y0; \
VPADDQ Y1, Y0, Y0; \
VPXOR Y0, Y3, Y3; \
VPSHUFB c48, Y3, Y3; \
VPADDQ Y3, Y2, Y2; \
VPXOR Y2, Y1, Y1; \
VPADDQ Y1, Y1, t; \
VPSRLQ $63, Y1, Y1; \
VPXOR t, Y1, Y1; \
VPERMQ_0x39_Y1_Y1; \
VPERMQ_0x4E_Y2_Y2; \
VPERMQ_0x93_Y3_Y3; \
VPADDQ m2, Y0, Y0; \
VPADDQ Y1, Y0, Y0; \
VPXOR Y0, Y3, Y3; \
VPSHUFD $-79, Y3, Y3; \
VPADDQ Y3, Y2, Y2; \
VPXOR Y2, Y1, Y1; \
VPSHUFB c40, Y1, Y1; \
VPADDQ m3, Y0, Y0; \
VPADDQ Y1, Y0, Y0; \
VPXOR Y0, Y3, Y3; \
VPSHUFB c48, Y3, Y3; \
VPADDQ Y3, Y2, Y2; \
VPXOR Y2, Y1, Y1; \
VPADDQ Y1, Y1, t; \
VPSRLQ $63, Y1, Y1; \
VPXOR t, Y1, Y1; \
VPERMQ_0x39_Y3_Y3; \
VPERMQ_0x4E_Y2_Y2; \
VPERMQ_0x93_Y1_Y1
#define VMOVQ_SI_X11_0 BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x1E
#define VMOVQ_SI_X12_0 BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x26
#define VMOVQ_SI_X13_0 BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x2E
#define VMOVQ_SI_X14_0 BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x36
#define VMOVQ_SI_X15_0 BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x3E
#define VMOVQ_SI_X11(n) BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x5E; BYTE $n
#define VMOVQ_SI_X12(n) BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x66; BYTE $n
#define VMOVQ_SI_X13(n) BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x6E; BYTE $n
#define VMOVQ_SI_X14(n) BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x76; BYTE $n
#define VMOVQ_SI_X15(n) BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x7E; BYTE $n
#define VPINSRQ_1_SI_X11_0 BYTE $0xC4; BYTE $0x63; BYTE $0xA1; BYTE $0x22; BYTE $0x1E; BYTE $0x01
#define VPINSRQ_1_SI_X12_0 BYTE $0xC4; BYTE $0x63; BYTE $0x99; BYTE $0x22; BYTE $0x26; BYTE $0x01
#define VPINSRQ_1_SI_X13_0 BYTE $0xC4; BYTE $0x63; BYTE $0x91; BYTE $0x22; BYTE $0x2E; BYTE $0x01
#define VPINSRQ_1_SI_X14_0 BYTE $0xC4; BYTE $0x63; BYTE $0x89; BYTE $0x22; BYTE $0x36; BYTE $0x01
#define VPINSRQ_1_SI_X15_0 BYTE $0xC4; BYTE $0x63; BYTE $0x81; BYTE $0x22; BYTE $0x3E; BYTE $0x01
#define VPINSRQ_1_SI_X11(n) BYTE $0xC4; BYTE $0x63; BYTE $0xA1; BYTE $0x22; BYTE $0x5E; BYTE $n; BYTE $0x01
#define VPINSRQ_1_SI_X12(n) BYTE $0xC4; BYTE $0x63; BYTE $0x99; BYTE $0x22; BYTE $0x66; BYTE $n; BYTE $0x01
#define VPINSRQ_1_SI_X13(n) BYTE $0xC4; BYTE $0x63; BYTE $0x91; BYTE $0x22; BYTE $0x6E; BYTE $n; BYTE $0x01
#define VPINSRQ_1_SI_X14(n) BYTE $0xC4; BYTE $0x63; BYTE $0x89; BYTE $0x22; BYTE $0x76; BYTE $n; BYTE $0x01
#define VPINSRQ_1_SI_X15(n) BYTE $0xC4; BYTE $0x63; BYTE $0x81; BYTE $0x22; BYTE $0x7E; BYTE $n; BYTE $0x01
#define VMOVQ_R8_X15 BYTE $0xC4; BYTE $0x41; BYTE $0xF9; BYTE $0x6E; BYTE $0xF8
#define VPINSRQ_1_R9_X15 BYTE $0xC4; BYTE $0x43; BYTE $0x81; BYTE $0x22; BYTE $0xF9; BYTE $0x01
// load msg: Y12 = (i0, i1, i2, i3)
// i0, i1, i2, i3 must not be 0
#define LOAD_MSG_AVX2_Y12(i0, i1, i2, i3) \
VMOVQ_SI_X12(i0*8); \
VMOVQ_SI_X11(i2*8); \
VPINSRQ_1_SI_X12(i1*8); \
VPINSRQ_1_SI_X11(i3*8); \
VINSERTI128 $1, X11, Y12, Y12
// load msg: Y13 = (i0, i1, i2, i3)
// i0, i1, i2, i3 must not be 0
#define LOAD_MSG_AVX2_Y13(i0, i1, i2, i3) \
VMOVQ_SI_X13(i0*8); \
VMOVQ_SI_X11(i2*8); \
VPINSRQ_1_SI_X13(i1*8); \
VPINSRQ_1_SI_X11(i3*8); \
VINSERTI128 $1, X11, Y13, Y13
// load msg: Y14 = (i0, i1, i2, i3)
// i0, i1, i2, i3 must not be 0
#define LOAD_MSG_AVX2_Y14(i0, i1, i2, i3) \
VMOVQ_SI_X14(i0*8); \
VMOVQ_SI_X11(i2*8); \
VPINSRQ_1_SI_X14(i1*8); \
VPINSRQ_1_SI_X11(i3*8); \
VINSERTI128 $1, X11, Y14, Y14
// load msg: Y15 = (i0, i1, i2, i3)
// i0, i1, i2, i3 must not be 0
#define LOAD_MSG_AVX2_Y15(i0, i1, i2, i3) \
VMOVQ_SI_X15(i0*8); \
VMOVQ_SI_X11(i2*8); \
VPINSRQ_1_SI_X15(i1*8); \
VPINSRQ_1_SI_X11(i3*8); \
VINSERTI128 $1, X11, Y15, Y15
#define LOAD_MSG_AVX2_0_2_4_6_1_3_5_7_8_10_12_14_9_11_13_15() \
VMOVQ_SI_X12_0; \
VMOVQ_SI_X11(4*8); \
VPINSRQ_1_SI_X12(2*8); \
VPINSRQ_1_SI_X11(6*8); \
VINSERTI128 $1, X11, Y12, Y12; \
LOAD_MSG_AVX2_Y13(1, 3, 5, 7); \
LOAD_MSG_AVX2_Y14(8, 10, 12, 14); \
LOAD_MSG_AVX2_Y15(9, 11, 13, 15)
#define LOAD_MSG_AVX2_14_4_9_13_10_8_15_6_1_0_11_5_12_2_7_3() \
LOAD_MSG_AVX2_Y12(14, 4, 9, 13); \
LOAD_MSG_AVX2_Y13(10, 8, 15, 6); \
VMOVQ_SI_X11(11*8); \
VPSHUFD $0x4E, 0*8(SI), X14; \
VPINSRQ_1_SI_X11(5*8); \
VINSERTI128 $1, X11, Y14, Y14; \
LOAD_MSG_AVX2_Y15(12, 2, 7, 3)
#define LOAD_MSG_AVX2_11_12_5_15_8_0_2_13_10_3_7_9_14_6_1_4() \
VMOVQ_SI_X11(5*8); \
VMOVDQU 11*8(SI), X12; \
VPINSRQ_1_SI_X11(15*8); \
VINSERTI128 $1, X11, Y12, Y12; \
VMOVQ_SI_X13(8*8); \
VMOVQ_SI_X11(2*8); \
VPINSRQ_1_SI_X13_0; \
VPINSRQ_1_SI_X11(13*8); \
VINSERTI128 $1, X11, Y13, Y13; \
LOAD_MSG_AVX2_Y14(10, 3, 7, 9); \
LOAD_MSG_AVX2_Y15(14, 6, 1, 4)
#define LOAD_MSG_AVX2_7_3_13_11_9_1_12_14_2_5_4_15_6_10_0_8() \
LOAD_MSG_AVX2_Y12(7, 3, 13, 11); \
LOAD_MSG_AVX2_Y13(9, 1, 12, 14); \
LOAD_MSG_AVX2_Y14(2, 5, 4, 15); \
VMOVQ_SI_X15(6*8); \
VMOVQ_SI_X11_0; \
VPINSRQ_1_SI_X15(10*8); \
VPINSRQ_1_SI_X11(8*8); \
VINSERTI128 $1, X11, Y15, Y15
#define LOAD_MSG_AVX2_9_5_2_10_0_7_4_15_14_11_6_3_1_12_8_13() \
LOAD_MSG_AVX2_Y12(9, 5, 2, 10); \
VMOVQ_SI_X13_0; \
VMOVQ_SI_X11(4*8); \
VPINSRQ_1_SI_X13(7*8); \
VPINSRQ_1_SI_X11(15*8); \
VINSERTI128 $1, X11, Y13, Y13; \
LOAD_MSG_AVX2_Y14(14, 11, 6, 3); \
LOAD_MSG_AVX2_Y15(1, 12, 8, 13)
#define LOAD_MSG_AVX2_2_6_0_8_12_10_11_3_4_7_15_1_13_5_14_9() \
VMOVQ_SI_X12(2*8); \
VMOVQ_SI_X11_0; \
VPINSRQ_1_SI_X12(6*8); \
VPINSRQ_1_SI_X11(8*8); \
VINSERTI128 $1, X11, Y12, Y12; \
LOAD_MSG_AVX2_Y13(12, 10, 11, 3); \
LOAD_MSG_AVX2_Y14(4, 7, 15, 1); \
LOAD_MSG_AVX2_Y15(13, 5, 14, 9)
#define LOAD_MSG_AVX2_12_1_14_4_5_15_13_10_0_6_9_8_7_3_2_11() \
LOAD_MSG_AVX2_Y12(12, 1, 14, 4); \
LOAD_MSG_AVX2_Y13(5, 15, 13, 10); \
VMOVQ_SI_X14_0; \
VPSHUFD $0x4E, 8*8(SI), X11; \
VPINSRQ_1_SI_X14(6*8); \
VINSERTI128 $1, X11, Y14, Y14; \
LOAD_MSG_AVX2_Y15(7, 3, 2, 11)
#define LOAD_MSG_AVX2_13_7_12_3_11_14_1_9_5_15_8_2_0_4_6_10() \
LOAD_MSG_AVX2_Y12(13, 7, 12, 3); \
LOAD_MSG_AVX2_Y13(11, 14, 1, 9); \
LOAD_MSG_AVX2_Y14(5, 15, 8, 2); \
VMOVQ_SI_X15_0; \
VMOVQ_SI_X11(6*8); \
VPINSRQ_1_SI_X15(4*8); \
VPINSRQ_1_SI_X11(10*8); \
VINSERTI128 $1, X11, Y15, Y15
#define LOAD_MSG_AVX2_6_14_11_0_15_9_3_8_12_13_1_10_2_7_4_5() \
VMOVQ_SI_X12(6*8); \
VMOVQ_SI_X11(11*8); \
VPINSRQ_1_SI_X12(14*8); \
VPINSRQ_1_SI_X11_0; \
VINSERTI128 $1, X11, Y12, Y12; \
LOAD_MSG_AVX2_Y13(15, 9, 3, 8); \
VMOVQ_SI_X11(1*8); \
VMOVDQU 12*8(SI), X14; \
VPINSRQ_1_SI_X11(10*8); \
VINSERTI128 $1, X11, Y14, Y14; \
VMOVQ_SI_X15(2*8); \
VMOVDQU 4*8(SI), X11; \
VPINSRQ_1_SI_X15(7*8); \
VINSERTI128 $1, X11, Y15, Y15
#define LOAD_MSG_AVX2_10_8_7_1_2_4_6_5_15_9_3_13_11_14_12_0() \
LOAD_MSG_AVX2_Y12(10, 8, 7, 1); \
VMOVQ_SI_X13(2*8); \
VPSHUFD $0x4E, 5*8(SI), X11; \
VPINSRQ_1_SI_X13(4*8); \
VINSERTI128 $1, X11, Y13, Y13; \
LOAD_MSG_AVX2_Y14(15, 9, 3, 13); \
VMOVQ_SI_X15(11*8); \
VMOVQ_SI_X11(12*8); \
VPINSRQ_1_SI_X15(14*8); \
VPINSRQ_1_SI_X11_0; \
VINSERTI128 $1, X11, Y15, Y15
// func fAVX2(h *[8]uint64, m *[16]uint64, c0, c1 uint64, flag uint64, rounds uint64)
TEXT ·fAVX2(SB), 4, $64-48 // frame size = 32 + 32 byte alignment
MOVQ h+0(FP), AX
MOVQ m+8(FP), SI
MOVQ c0+16(FP), R8
MOVQ c1+24(FP), R9
MOVQ flag+32(FP), CX
MOVQ rounds+40(FP), BX
MOVQ SP, DX
MOVQ SP, R10
ADDQ $31, R10
ANDQ $~31, R10
MOVQ R10, SP
MOVQ CX, 16(SP)
XORQ CX, CX
MOVQ CX, 24(SP)
VMOVDQU ·AVX2_c40<>(SB), Y4
VMOVDQU ·AVX2_c48<>(SB), Y5
VMOVDQU 0(AX), Y8
VMOVDQU 32(AX), Y9
VMOVDQU ·AVX2_iv0<>(SB), Y6
VMOVDQU ·AVX2_iv1<>(SB), Y7
MOVQ R8, 0(SP)
MOVQ R9, 8(SP)
VMOVDQA Y8, Y0
VMOVDQA Y9, Y1
VMOVDQA Y6, Y2
VPXOR 0(SP), Y7, Y3
loop:
SUBQ $1, BX; JCS done
LOAD_MSG_AVX2_0_2_4_6_1_3_5_7_8_10_12_14_9_11_13_15()
ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
SUBQ $1, BX; JCS done
LOAD_MSG_AVX2_14_4_9_13_10_8_15_6_1_0_11_5_12_2_7_3()
ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
SUBQ $1, BX; JCS done
LOAD_MSG_AVX2_11_12_5_15_8_0_2_13_10_3_7_9_14_6_1_4()
ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
SUBQ $1, BX; JCS done
LOAD_MSG_AVX2_7_3_13_11_9_1_12_14_2_5_4_15_6_10_0_8()
ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
SUBQ $1, BX; JCS done
LOAD_MSG_AVX2_9_5_2_10_0_7_4_15_14_11_6_3_1_12_8_13()
ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
SUBQ $1, BX; JCS done
LOAD_MSG_AVX2_2_6_0_8_12_10_11_3_4_7_15_1_13_5_14_9()
ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
SUBQ $1, BX; JCS done
LOAD_MSG_AVX2_12_1_14_4_5_15_13_10_0_6_9_8_7_3_2_11()
ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
SUBQ $1, BX; JCS done
LOAD_MSG_AVX2_13_7_12_3_11_14_1_9_5_15_8_2_0_4_6_10()
ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
SUBQ $1, BX; JCS done
LOAD_MSG_AVX2_6_14_11_0_15_9_3_8_12_13_1_10_2_7_4_5()
ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
SUBQ $1, BX; JCS done
LOAD_MSG_AVX2_10_8_7_1_2_4_6_5_15_9_3_13_11_14_12_0()
ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
JMP loop
done:
VPXOR Y0, Y8, Y8
VPXOR Y1, Y9, Y9
VPXOR Y2, Y8, Y8
VPXOR Y3, Y9, Y9
VMOVDQU Y8, 0(AX)
VMOVDQU Y9, 32(AX)
VZEROUPPER
MOVQ DX, SP
RET
#define VPUNPCKLQDQ_X2_X2_X15 BYTE $0xC5; BYTE $0x69; BYTE $0x6C; BYTE $0xFA
#define VPUNPCKLQDQ_X3_X3_X15 BYTE $0xC5; BYTE $0x61; BYTE $0x6C; BYTE $0xFB
#define VPUNPCKLQDQ_X7_X7_X15 BYTE $0xC5; BYTE $0x41; BYTE $0x6C; BYTE $0xFF
#define VPUNPCKLQDQ_X13_X13_X15 BYTE $0xC4; BYTE $0x41; BYTE $0x11; BYTE $0x6C; BYTE $0xFD
#define VPUNPCKLQDQ_X14_X14_X15 BYTE $0xC4; BYTE $0x41; BYTE $0x09; BYTE $0x6C; BYTE $0xFE
#define VPUNPCKHQDQ_X15_X2_X2 BYTE $0xC4; BYTE $0xC1; BYTE $0x69; BYTE $0x6D; BYTE $0xD7
#define VPUNPCKHQDQ_X15_X3_X3 BYTE $0xC4; BYTE $0xC1; BYTE $0x61; BYTE $0x6D; BYTE $0xDF
#define VPUNPCKHQDQ_X15_X6_X6 BYTE $0xC4; BYTE $0xC1; BYTE $0x49; BYTE $0x6D; BYTE $0xF7
#define VPUNPCKHQDQ_X15_X7_X7 BYTE $0xC4; BYTE $0xC1; BYTE $0x41; BYTE $0x6D; BYTE $0xFF
#define VPUNPCKHQDQ_X15_X3_X2 BYTE $0xC4; BYTE $0xC1; BYTE $0x61; BYTE $0x6D; BYTE $0xD7
#define VPUNPCKHQDQ_X15_X7_X6 BYTE $0xC4; BYTE $0xC1; BYTE $0x41; BYTE $0x6D; BYTE $0xF7
#define VPUNPCKHQDQ_X15_X13_X3 BYTE $0xC4; BYTE $0xC1; BYTE $0x11; BYTE $0x6D; BYTE $0xDF
#define VPUNPCKHQDQ_X15_X13_X7 BYTE $0xC4; BYTE $0xC1; BYTE $0x11; BYTE $0x6D; BYTE $0xFF
#define SHUFFLE_AVX() \
VMOVDQA X6, X13; \
VMOVDQA X2, X14; \
VMOVDQA X4, X6; \
VPUNPCKLQDQ_X13_X13_X15; \
VMOVDQA X5, X4; \
VMOVDQA X6, X5; \
VPUNPCKHQDQ_X15_X7_X6; \
VPUNPCKLQDQ_X7_X7_X15; \
VPUNPCKHQDQ_X15_X13_X7; \
VPUNPCKLQDQ_X3_X3_X15; \
VPUNPCKHQDQ_X15_X2_X2; \
VPUNPCKLQDQ_X14_X14_X15; \
VPUNPCKHQDQ_X15_X3_X3; \
#define SHUFFLE_AVX_INV() \
VMOVDQA X2, X13; \
VMOVDQA X4, X14; \
VPUNPCKLQDQ_X2_X2_X15; \
VMOVDQA X5, X4; \
VPUNPCKHQDQ_X15_X3_X2; \
VMOVDQA X14, X5; \
VPUNPCKLQDQ_X3_X3_X15; \
VMOVDQA X6, X14; \
VPUNPCKHQDQ_X15_X13_X3; \
VPUNPCKLQDQ_X7_X7_X15; \
VPUNPCKHQDQ_X15_X6_X6; \
VPUNPCKLQDQ_X14_X14_X15; \
VPUNPCKHQDQ_X15_X7_X7; \
#define HALF_ROUND_AVX(v0, v1, v2, v3, v4, v5, v6, v7, m0, m1, m2, m3, t0, c40, c48) \
VPADDQ m0, v0, v0; \
VPADDQ v2, v0, v0; \
VPADDQ m1, v1, v1; \
VPADDQ v3, v1, v1; \
VPXOR v0, v6, v6; \
VPXOR v1, v7, v7; \
VPSHUFD $-79, v6, v6; \
VPSHUFD $-79, v7, v7; \
VPADDQ v6, v4, v4; \
VPADDQ v7, v5, v5; \
VPXOR v4, v2, v2; \
VPXOR v5, v3, v3; \
VPSHUFB c40, v2, v2; \
VPSHUFB c40, v3, v3; \
VPADDQ m2, v0, v0; \
VPADDQ v2, v0, v0; \
VPADDQ m3, v1, v1; \
VPADDQ v3, v1, v1; \
VPXOR v0, v6, v6; \
VPXOR v1, v7, v7; \
VPSHUFB c48, v6, v6; \
VPSHUFB c48, v7, v7; \
VPADDQ v6, v4, v4; \
VPADDQ v7, v5, v5; \
VPXOR v4, v2, v2; \
VPXOR v5, v3, v3; \
VPADDQ v2, v2, t0; \
VPSRLQ $63, v2, v2; \
VPXOR t0, v2, v2; \
VPADDQ v3, v3, t0; \
VPSRLQ $63, v3, v3; \
VPXOR t0, v3, v3
// load msg: X12 = (i0, i1), X13 = (i2, i3), X14 = (i4, i5), X15 = (i6, i7)
// i0, i1, i2, i3, i4, i5, i6, i7 must not be 0
#define LOAD_MSG_AVX(i0, i1, i2, i3, i4, i5, i6, i7) \
VMOVQ_SI_X12(i0*8); \
VMOVQ_SI_X13(i2*8); \
VMOVQ_SI_X14(i4*8); \
VMOVQ_SI_X15(i6*8); \
VPINSRQ_1_SI_X12(i1*8); \
VPINSRQ_1_SI_X13(i3*8); \
VPINSRQ_1_SI_X14(i5*8); \
VPINSRQ_1_SI_X15(i7*8)
// load msg: X12 = (0, 2), X13 = (4, 6), X14 = (1, 3), X15 = (5, 7)
#define LOAD_MSG_AVX_0_2_4_6_1_3_5_7() \
VMOVQ_SI_X12_0; \
VMOVQ_SI_X13(4*8); \
VMOVQ_SI_X14(1*8); \
VMOVQ_SI_X15(5*8); \
VPINSRQ_1_SI_X12(2*8); \
VPINSRQ_1_SI_X13(6*8); \
VPINSRQ_1_SI_X14(3*8); \
VPINSRQ_1_SI_X15(7*8)
// load msg: X12 = (1, 0), X13 = (11, 5), X14 = (12, 2), X15 = (7, 3)
#define LOAD_MSG_AVX_1_0_11_5_12_2_7_3() \
VPSHUFD $0x4E, 0*8(SI), X12; \
VMOVQ_SI_X13(11*8); \
VMOVQ_SI_X14(12*8); \
VMOVQ_SI_X15(7*8); \
VPINSRQ_1_SI_X13(5*8); \
VPINSRQ_1_SI_X14(2*8); \
VPINSRQ_1_SI_X15(3*8)
// load msg: X12 = (11, 12), X13 = (5, 15), X14 = (8, 0), X15 = (2, 13)
#define LOAD_MSG_AVX_11_12_5_15_8_0_2_13() \
VMOVDQU 11*8(SI), X12; \
VMOVQ_SI_X13(5*8); \
VMOVQ_SI_X14(8*8); \
VMOVQ_SI_X15(2*8); \
VPINSRQ_1_SI_X13(15*8); \
VPINSRQ_1_SI_X14_0; \
VPINSRQ_1_SI_X15(13*8)
// load msg: X12 = (2, 5), X13 = (4, 15), X14 = (6, 10), X15 = (0, 8)
#define LOAD_MSG_AVX_2_5_4_15_6_10_0_8() \
VMOVQ_SI_X12(2*8); \
VMOVQ_SI_X13(4*8); \
VMOVQ_SI_X14(6*8); \
VMOVQ_SI_X15_0; \
VPINSRQ_1_SI_X12(5*8); \
VPINSRQ_1_SI_X13(15*8); \
VPINSRQ_1_SI_X14(10*8); \
VPINSRQ_1_SI_X15(8*8)
// load msg: X12 = (9, 5), X13 = (2, 10), X14 = (0, 7), X15 = (4, 15)
#define LOAD_MSG_AVX_9_5_2_10_0_7_4_15() \
VMOVQ_SI_X12(9*8); \
VMOVQ_SI_X13(2*8); \
VMOVQ_SI_X14_0; \
VMOVQ_SI_X15(4*8); \
VPINSRQ_1_SI_X12(5*8); \
VPINSRQ_1_SI_X13(10*8); \
VPINSRQ_1_SI_X14(7*8); \
VPINSRQ_1_SI_X15(15*8)
// load msg: X12 = (2, 6), X13 = (0, 8), X14 = (12, 10), X15 = (11, 3)
#define LOAD_MSG_AVX_2_6_0_8_12_10_11_3() \
VMOVQ_SI_X12(2*8); \
VMOVQ_SI_X13_0; \
VMOVQ_SI_X14(12*8); \
VMOVQ_SI_X15(11*8); \
VPINSRQ_1_SI_X12(6*8); \
VPINSRQ_1_SI_X13(8*8); \
VPINSRQ_1_SI_X14(10*8); \
VPINSRQ_1_SI_X15(3*8)
// load msg: X12 = (0, 6), X13 = (9, 8), X14 = (7, 3), X15 = (2, 11)
#define LOAD_MSG_AVX_0_6_9_8_7_3_2_11() \
MOVQ 0*8(SI), X12; \
VPSHUFD $0x4E, 8*8(SI), X13; \
MOVQ 7*8(SI), X14; \
MOVQ 2*8(SI), X15; \
VPINSRQ_1_SI_X12(6*8); \
VPINSRQ_1_SI_X14(3*8); \
VPINSRQ_1_SI_X15(11*8)
// load msg: X12 = (6, 14), X13 = (11, 0), X14 = (15, 9), X15 = (3, 8)
#define LOAD_MSG_AVX_6_14_11_0_15_9_3_8() \
MOVQ 6*8(SI), X12; \
MOVQ 11*8(SI), X13; \
MOVQ 15*8(SI), X14; \
MOVQ 3*8(SI), X15; \
VPINSRQ_1_SI_X12(14*8); \
VPINSRQ_1_SI_X13_0; \
VPINSRQ_1_SI_X14(9*8); \
VPINSRQ_1_SI_X15(8*8)
// load msg: X12 = (5, 15), X13 = (8, 2), X14 = (0, 4), X15 = (6, 10)
#define LOAD_MSG_AVX_5_15_8_2_0_4_6_10() \
MOVQ 5*8(SI), X12; \
MOVQ 8*8(SI), X13; \
MOVQ 0*8(SI), X14; \
MOVQ 6*8(SI), X15; \
VPINSRQ_1_SI_X12(15*8); \
VPINSRQ_1_SI_X13(2*8); \
VPINSRQ_1_SI_X14(4*8); \
VPINSRQ_1_SI_X15(10*8)
// load msg: X12 = (12, 13), X13 = (1, 10), X14 = (2, 7), X15 = (4, 5)
#define LOAD_MSG_AVX_12_13_1_10_2_7_4_5() \
VMOVDQU 12*8(SI), X12; \
MOVQ 1*8(SI), X13; \
MOVQ 2*8(SI), X14; \
VPINSRQ_1_SI_X13(10*8); \
VPINSRQ_1_SI_X14(7*8); \
VMOVDQU 4*8(SI), X15
// load msg: X12 = (15, 9), X13 = (3, 13), X14 = (11, 14), X15 = (12, 0)
#define LOAD_MSG_AVX_15_9_3_13_11_14_12_0() \
MOVQ 15*8(SI), X12; \
MOVQ 3*8(SI), X13; \
MOVQ 11*8(SI), X14; \
MOVQ 12*8(SI), X15; \
VPINSRQ_1_SI_X12(9*8); \
VPINSRQ_1_SI_X13(13*8); \
VPINSRQ_1_SI_X14(14*8); \
VPINSRQ_1_SI_X15_0
// func fAVX(h *[8]uint64, m *[16]uint64, c0, c1 uint64, flag uint64, rounds uint64)
TEXT ·fAVX(SB), 4, $24-48 // frame size = 8 + 16 byte alignment
MOVQ h+0(FP), AX
MOVQ m+8(FP), SI
MOVQ c0+16(FP), R8
MOVQ c1+24(FP), R9
MOVQ flag+32(FP), CX
MOVQ rounds+40(FP), BX
MOVQ SP, BP
MOVQ SP, R10
ADDQ $15, R10
ANDQ $~15, R10
MOVQ R10, SP
VMOVDQU ·AVX_c40<>(SB), X0
VMOVDQU ·AVX_c48<>(SB), X1
VMOVDQA X0, X8
VMOVDQA X1, X9
VMOVDQU ·AVX_iv3<>(SB), X0
VMOVDQA X0, 0(SP)
XORQ CX, 0(SP) // 0(SP) = ·AVX_iv3 ^ (CX || 0)
VMOVDQU 0(AX), X10
VMOVDQU 16(AX), X11
VMOVDQU 32(AX), X2
VMOVDQU 48(AX), X3
VMOVQ_R8_X15
VPINSRQ_1_R9_X15
VMOVDQA X10, X0
VMOVDQA X11, X1
VMOVDQU ·AVX_iv0<>(SB), X4
VMOVDQU ·AVX_iv1<>(SB), X5
VMOVDQU ·AVX_iv2<>(SB), X6
VPXOR X15, X6, X6
VMOVDQA 0(SP), X7
loop:
SUBQ $1, BX; JCS done
LOAD_MSG_AVX_0_2_4_6_1_3_5_7()
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
SHUFFLE_AVX()
LOAD_MSG_AVX(8, 10, 12, 14, 9, 11, 13, 15)
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
SHUFFLE_AVX_INV()
SUBQ $1, BX; JCS done
LOAD_MSG_AVX(14, 4, 9, 13, 10, 8, 15, 6)
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
SHUFFLE_AVX()
LOAD_MSG_AVX_1_0_11_5_12_2_7_3()
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
SHUFFLE_AVX_INV()
SUBQ $1, BX; JCS done
LOAD_MSG_AVX_11_12_5_15_8_0_2_13()
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
SHUFFLE_AVX()
LOAD_MSG_AVX(10, 3, 7, 9, 14, 6, 1, 4)
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
SHUFFLE_AVX_INV()
SUBQ $1, BX; JCS done
LOAD_MSG_AVX(7, 3, 13, 11, 9, 1, 12, 14)
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
SHUFFLE_AVX()
LOAD_MSG_AVX_2_5_4_15_6_10_0_8()
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
SHUFFLE_AVX_INV()
SUBQ $1, BX; JCS done
LOAD_MSG_AVX_9_5_2_10_0_7_4_15()
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
SHUFFLE_AVX()
LOAD_MSG_AVX(14, 11, 6, 3, 1, 12, 8, 13)
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
SHUFFLE_AVX_INV()
SUBQ $1, BX; JCS done
LOAD_MSG_AVX_2_6_0_8_12_10_11_3()
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
SHUFFLE_AVX()
LOAD_MSG_AVX(4, 7, 15, 1, 13, 5, 14, 9)
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
SHUFFLE_AVX_INV()
SUBQ $1, BX; JCS done
LOAD_MSG_AVX(12, 1, 14, 4, 5, 15, 13, 10)
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
SHUFFLE_AVX()
LOAD_MSG_AVX_0_6_9_8_7_3_2_11()
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
SHUFFLE_AVX_INV()
SUBQ $1, BX; JCS done
LOAD_MSG_AVX(13, 7, 12, 3, 11, 14, 1, 9)
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
SHUFFLE_AVX()
LOAD_MSG_AVX_5_15_8_2_0_4_6_10()
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
SHUFFLE_AVX_INV()
SUBQ $1, BX; JCS done
LOAD_MSG_AVX_6_14_11_0_15_9_3_8()
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
SHUFFLE_AVX()
LOAD_MSG_AVX_12_13_1_10_2_7_4_5()
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
SHUFFLE_AVX_INV()
SUBQ $1, BX; JCS done
LOAD_MSG_AVX(10, 8, 7, 1, 2, 4, 6, 5)
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
SHUFFLE_AVX()
LOAD_MSG_AVX_15_9_3_13_11_14_12_0()
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
SHUFFLE_AVX_INV()
JMP loop
done:
VMOVDQU 32(AX), X14
VMOVDQU 48(AX), X15
VPXOR X0, X10, X10
VPXOR X1, X11, X11
VPXOR X2, X14, X14
VPXOR X3, X15, X15
VPXOR X4, X10, X10
VPXOR X5, X11, X11
VPXOR X6, X14, X2
VPXOR X7, X15, X3
VMOVDQU X2, 32(AX)
VMOVDQU X3, 48(AX)
VMOVDQU X10, 0(AX)
VMOVDQU X11, 16(AX)
VZEROUPPER
MOVQ BP, SP
RET

View File

@ -0,0 +1,24 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !go1.7,amd64,!gccgo,!appengine
package blake2b
import "golang.org/x/sys/cpu"
func init() {
useSSE4 = cpu.X86.HasSSE41
}
//go:noescape
func fSSE4(h *[8]uint64, m *[16]uint64, c0, c1 uint64, flag uint64, rounds uint64)
func f(h *[8]uint64, m *[16]uint64, c0, c1 uint64, flag uint64, rounds uint64) {
if useSSE4 {
fSSE4(h, m, c0, c1, flag, rounds)
} else {
fGeneric(h, m, c0, c1, flag, rounds)
}
}

View File

@ -0,0 +1,253 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build amd64,!gccgo,!appengine
#include "textflag.h"
DATA ·iv0<>+0x00(SB)/8, $0x6a09e667f3bcc908
DATA ·iv0<>+0x08(SB)/8, $0xbb67ae8584caa73b
GLOBL ·iv0<>(SB), (NOPTR+RODATA), $16
DATA ·iv1<>+0x00(SB)/8, $0x3c6ef372fe94f82b
DATA ·iv1<>+0x08(SB)/8, $0xa54ff53a5f1d36f1
GLOBL ·iv1<>(SB), (NOPTR+RODATA), $16
DATA ·iv2<>+0x00(SB)/8, $0x510e527fade682d1
DATA ·iv2<>+0x08(SB)/8, $0x9b05688c2b3e6c1f
GLOBL ·iv2<>(SB), (NOPTR+RODATA), $16
DATA ·iv3<>+0x00(SB)/8, $0x1f83d9abfb41bd6b
DATA ·iv3<>+0x08(SB)/8, $0x5be0cd19137e2179
GLOBL ·iv3<>(SB), (NOPTR+RODATA), $16
DATA ·c40<>+0x00(SB)/8, $0x0201000706050403
DATA ·c40<>+0x08(SB)/8, $0x0a09080f0e0d0c0b
GLOBL ·c40<>(SB), (NOPTR+RODATA), $16
DATA ·c48<>+0x00(SB)/8, $0x0100070605040302
DATA ·c48<>+0x08(SB)/8, $0x09080f0e0d0c0b0a
GLOBL ·c48<>(SB), (NOPTR+RODATA), $16
#define SHUFFLE(v2, v3, v4, v5, v6, v7, t1, t2) \
MOVO v4, t1; \
MOVO v5, v4; \
MOVO t1, v5; \
MOVO v6, t1; \
PUNPCKLQDQ v6, t2; \
PUNPCKHQDQ v7, v6; \
PUNPCKHQDQ t2, v6; \
PUNPCKLQDQ v7, t2; \
MOVO t1, v7; \
MOVO v2, t1; \
PUNPCKHQDQ t2, v7; \
PUNPCKLQDQ v3, t2; \
PUNPCKHQDQ t2, v2; \
PUNPCKLQDQ t1, t2; \
PUNPCKHQDQ t2, v3
#define SHUFFLE_INV(v2, v3, v4, v5, v6, v7, t1, t2) \
MOVO v4, t1; \
MOVO v5, v4; \
MOVO t1, v5; \
MOVO v2, t1; \
PUNPCKLQDQ v2, t2; \
PUNPCKHQDQ v3, v2; \
PUNPCKHQDQ t2, v2; \
PUNPCKLQDQ v3, t2; \
MOVO t1, v3; \
MOVO v6, t1; \
PUNPCKHQDQ t2, v3; \
PUNPCKLQDQ v7, t2; \
PUNPCKHQDQ t2, v6; \
PUNPCKLQDQ t1, t2; \
PUNPCKHQDQ t2, v7
#define HALF_ROUND(v0, v1, v2, v3, v4, v5, v6, v7, m0, m1, m2, m3, t0, c40, c48) \
PADDQ m0, v0; \
PADDQ m1, v1; \
PADDQ v2, v0; \
PADDQ v3, v1; \
PXOR v0, v6; \
PXOR v1, v7; \
PSHUFD $0xB1, v6, v6; \
PSHUFD $0xB1, v7, v7; \
PADDQ v6, v4; \
PADDQ v7, v5; \
PXOR v4, v2; \
PXOR v5, v3; \
PSHUFB c40, v2; \
PSHUFB c40, v3; \
PADDQ m2, v0; \
PADDQ m3, v1; \
PADDQ v2, v0; \
PADDQ v3, v1; \
PXOR v0, v6; \
PXOR v1, v7; \
PSHUFB c48, v6; \
PSHUFB c48, v7; \
PADDQ v6, v4; \
PADDQ v7, v5; \
PXOR v4, v2; \
PXOR v5, v3; \
MOVOU v2, t0; \
PADDQ v2, t0; \
PSRLQ $63, v2; \
PXOR t0, v2; \
MOVOU v3, t0; \
PADDQ v3, t0; \
PSRLQ $63, v3; \
PXOR t0, v3
#define LOAD_MSG(m0, m1, m2, m3, i0, i1, i2, i3, i4, i5, i6, i7) \
MOVQ i0*8(SI), m0; \
PINSRQ $1, i1*8(SI), m0; \
MOVQ i2*8(SI), m1; \
PINSRQ $1, i3*8(SI), m1; \
MOVQ i4*8(SI), m2; \
PINSRQ $1, i5*8(SI), m2; \
MOVQ i6*8(SI), m3; \
PINSRQ $1, i7*8(SI), m3
// func fSSE4(h *[8]uint64, m *[16]uint64, c0, c1 uint64, flag uint64, rounds uint64)
TEXT ·fSSE4(SB), 4, $24-48 // frame size = 8 + 16 byte alignment
MOVQ h+0(FP), AX
MOVQ m+8(FP), SI
MOVQ c0+16(FP), R8
MOVQ c1+24(FP), R9
MOVQ flag+32(FP), CX
MOVQ rounds+40(FP), BX
MOVQ SP, BP
MOVQ SP, R10
ADDQ $15, R10
ANDQ $~15, R10
MOVQ R10, SP
MOVOU ·iv3<>(SB), X0
MOVO X0, 0(SP)
XORQ CX, 0(SP) // 0(SP) = ·iv3 ^ (CX || 0)
MOVOU ·c40<>(SB), X13
MOVOU ·c48<>(SB), X14
MOVOU 0(AX), X12
MOVOU 16(AX), X15
MOVQ R8, X8
PINSRQ $1, R9, X8
MOVO X12, X0
MOVO X15, X1
MOVOU 32(AX), X2
MOVOU 48(AX), X3
MOVOU ·iv0<>(SB), X4
MOVOU ·iv1<>(SB), X5
MOVOU ·iv2<>(SB), X6
PXOR X8, X6
MOVO 0(SP), X7
loop:
SUBQ $1, BX; JCS done
LOAD_MSG(X8, X9, X10, X11, 0, 2, 4, 6, 1, 3, 5, 7)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9)
LOAD_MSG(X8, X9, X10, X11, 8, 10, 12, 14, 9, 11, 13, 15)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9)
SUBQ $1, BX; JCS done
LOAD_MSG(X8, X9, X10, X11, 14, 4, 9, 13, 10, 8, 15, 6)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9)
LOAD_MSG(X8, X9, X10, X11, 1, 0, 11, 5, 12, 2, 7, 3)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9)
SUBQ $1, BX; JCS done
LOAD_MSG(X8, X9, X10, X11, 11, 12, 5, 15, 8, 0, 2, 13)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9)
LOAD_MSG(X8, X9, X10, X11, 10, 3, 7, 9, 14, 6, 1, 4)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9)
SUBQ $1, BX; JCS done
LOAD_MSG(X8, X9, X10, X11, 7, 3, 13, 11, 9, 1, 12, 14)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9)
LOAD_MSG(X8, X9, X10, X11, 2, 5, 4, 15, 6, 10, 0, 8)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9)
SUBQ $1, BX; JCS done
LOAD_MSG(X8, X9, X10, X11, 9, 5, 2, 10, 0, 7, 4, 15)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9)
LOAD_MSG(X8, X9, X10, X11, 14, 11, 6, 3, 1, 12, 8, 13)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9)
SUBQ $1, BX; JCS done
LOAD_MSG(X8, X9, X10, X11, 2, 6, 0, 8, 12, 10, 11, 3)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9)
LOAD_MSG(X8, X9, X10, X11, 4, 7, 15, 1, 13, 5, 14, 9)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9)
SUBQ $1, BX; JCS done
LOAD_MSG(X8, X9, X10, X11, 12, 1, 14, 4, 5, 15, 13, 10)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9)
LOAD_MSG(X8, X9, X10, X11, 0, 6, 9, 8, 7, 3, 2, 11)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9)
SUBQ $1, BX; JCS done
LOAD_MSG(X8, X9, X10, X11, 13, 7, 12, 3, 11, 14, 1, 9)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9)
LOAD_MSG(X8, X9, X10, X11, 5, 15, 8, 2, 0, 4, 6, 10)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9)
SUBQ $1, BX; JCS done
LOAD_MSG(X8, X9, X10, X11, 6, 14, 11, 0, 15, 9, 3, 8)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9)
LOAD_MSG(X8, X9, X10, X11, 12, 13, 1, 10, 2, 7, 4, 5)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9)
SUBQ $1, BX; JCS done
LOAD_MSG(X8, X9, X10, X11, 10, 8, 7, 1, 2, 4, 6, 5)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9)
LOAD_MSG(X8, X9, X10, X11, 15, 9, 3, 13, 11, 14, 12, 0)
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9)
JMP loop
done:
MOVOU 32(AX), X10
MOVOU 48(AX), X11
PXOR X0, X12
PXOR X1, X15
PXOR X2, X10
PXOR X3, X11
PXOR X4, X12
PXOR X5, X15
PXOR X6, X10
PXOR X7, X11
MOVOU X10, 32(AX)
MOVOU X11, 48(AX)
MOVOU X12, 0(AX)
MOVOU X15, 16(AX)
MOVQ BP, SP
RET

View File

@ -0,0 +1,57 @@
// +build gofuzz
package blake2b
import (
"encoding/binary"
)
func Fuzz(data []byte) int {
// Make sure the data confirms to the input model
if len(data) != 211 {
return 0
}
// Parse everything and call all the implementations
var (
rounds = binary.BigEndian.Uint16(data[0:2])
h [8]uint64
m [16]uint64
t [2]uint64
f uint64
)
for i := 0; i < 8; i++ {
offset := 2 + i*8
h[i] = binary.LittleEndian.Uint64(data[offset : offset+8])
}
for i := 0; i < 16; i++ {
offset := 66 + i*8
m[i] = binary.LittleEndian.Uint64(data[offset : offset+8])
}
t[0] = binary.LittleEndian.Uint64(data[194:202])
t[1] = binary.LittleEndian.Uint64(data[202:210])
if data[210]%2 == 1 { // Avoid spinning the fuzzer to hit 0/1
f = 0xFFFFFFFFFFFFFFFF
}
// Run the blake2b compression on all instruction sets and cross reference
want := h
fGeneric(&want, &m, t[0], t[1], f, uint64(rounds))
have := h
fSSE4(&have, &m, t[0], t[1], f, uint64(rounds))
if have != want {
panic("SSE4 mismatches generic algo")
}
have = h
fAVX(&have, &m, t[0], t[1], f, uint64(rounds))
if have != want {
panic("AVX mismatches generic algo")
}
have = h
fAVX2(&have, &m, t[0], t[1], f, uint64(rounds))
if have != want {
panic("AVX2 mismatches generic algo")
}
return 1
}

View File

@ -0,0 +1,59 @@
package blake2b
import (
"fmt"
"reflect"
"testing"
)
func TestF(t *testing.T) {
for i, test := range testVectorsF {
t.Run(fmt.Sprintf("test vector %v", i), func(t *testing.T) {
//toEthereumTestCase(test)
h := test.hIn
F(&h, test.m, test.c, test.f, test.rounds)
if !reflect.DeepEqual(test.hOut, h) {
t.Errorf("Unexpected result\nExpected: [%#x]\nActual: [%#x]\n", test.hOut, h)
}
})
}
}
type testVector struct {
hIn [8]uint64
m [16]uint64
c [2]uint64
f bool
rounds uint32
hOut [8]uint64
}
// https://tools.ietf.org/html/rfc7693#appendix-A
var testVectorsF = []testVector{
{
hIn: [8]uint64{
0x6a09e667f2bdc948, 0xbb67ae8584caa73b,
0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1,
0x510e527fade682d1, 0x9b05688c2b3e6c1f,
0x1f83d9abfb41bd6b, 0x5be0cd19137e2179,
},
m: [16]uint64{
0x0000000000636261, 0x0000000000000000, 0x0000000000000000,
0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
0x0000000000000000,
},
c: [2]uint64{3, 0},
f: true,
rounds: 12,
hOut: [8]uint64{
0x0D4D1C983FA580BA, 0xE9F6129FB697276A, 0xB7C45A68142F214C,
0xD1A2FFDB6FBB124B, 0x2D79AB2A39C5877D, 0x95CC3345DED552C2,
0x5A92F1DBA88AD318, 0x239900D4ED8623B9,
},
},
}

View File

@ -0,0 +1,180 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package blake2b
import (
"encoding/binary"
"math/bits"
)
// the precomputed values for BLAKE2b
// there are 10 16-byte arrays - one for each round
// the entries are calculated from the sigma constants.
var precomputed = [10][16]byte{
{0, 2, 4, 6, 1, 3, 5, 7, 8, 10, 12, 14, 9, 11, 13, 15},
{14, 4, 9, 13, 10, 8, 15, 6, 1, 0, 11, 5, 12, 2, 7, 3},
{11, 12, 5, 15, 8, 0, 2, 13, 10, 3, 7, 9, 14, 6, 1, 4},
{7, 3, 13, 11, 9, 1, 12, 14, 2, 5, 4, 15, 6, 10, 0, 8},
{9, 5, 2, 10, 0, 7, 4, 15, 14, 11, 6, 3, 1, 12, 8, 13},
{2, 6, 0, 8, 12, 10, 11, 3, 4, 7, 15, 1, 13, 5, 14, 9},
{12, 1, 14, 4, 5, 15, 13, 10, 0, 6, 9, 8, 7, 3, 2, 11},
{13, 7, 12, 3, 11, 14, 1, 9, 5, 15, 8, 2, 0, 4, 6, 10},
{6, 14, 11, 0, 15, 9, 3, 8, 12, 13, 1, 10, 2, 7, 4, 5},
{10, 8, 7, 1, 2, 4, 6, 5, 15, 9, 3, 13, 11, 14, 12, 0},
}
func hashBlocksGeneric(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) {
var m [16]uint64
c0, c1 := c[0], c[1]
for i := 0; i < len(blocks); {
c0 += BlockSize
if c0 < BlockSize {
c1++
}
for j := range m {
m[j] = binary.LittleEndian.Uint64(blocks[i:])
i += 8
}
fGeneric(h, &m, c0, c1, flag, 12)
}
c[0], c[1] = c0, c1
}
func fGeneric(h *[8]uint64, m *[16]uint64, c0, c1 uint64, flag uint64, rounds uint64) {
v0, v1, v2, v3, v4, v5, v6, v7 := h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7]
v8, v9, v10, v11, v12, v13, v14, v15 := iv[0], iv[1], iv[2], iv[3], iv[4], iv[5], iv[6], iv[7]
v12 ^= c0
v13 ^= c1
v14 ^= flag
for i := 0; i < int(rounds); i++ {
s := &(precomputed[i%10])
v0 += m[s[0]]
v0 += v4
v12 ^= v0
v12 = bits.RotateLeft64(v12, -32)
v8 += v12
v4 ^= v8
v4 = bits.RotateLeft64(v4, -24)
v1 += m[s[1]]
v1 += v5
v13 ^= v1
v13 = bits.RotateLeft64(v13, -32)
v9 += v13
v5 ^= v9
v5 = bits.RotateLeft64(v5, -24)
v2 += m[s[2]]
v2 += v6
v14 ^= v2
v14 = bits.RotateLeft64(v14, -32)
v10 += v14
v6 ^= v10
v6 = bits.RotateLeft64(v6, -24)
v3 += m[s[3]]
v3 += v7
v15 ^= v3
v15 = bits.RotateLeft64(v15, -32)
v11 += v15
v7 ^= v11
v7 = bits.RotateLeft64(v7, -24)
v0 += m[s[4]]
v0 += v4
v12 ^= v0
v12 = bits.RotateLeft64(v12, -16)
v8 += v12
v4 ^= v8
v4 = bits.RotateLeft64(v4, -63)
v1 += m[s[5]]
v1 += v5
v13 ^= v1
v13 = bits.RotateLeft64(v13, -16)
v9 += v13
v5 ^= v9
v5 = bits.RotateLeft64(v5, -63)
v2 += m[s[6]]
v2 += v6
v14 ^= v2
v14 = bits.RotateLeft64(v14, -16)
v10 += v14
v6 ^= v10
v6 = bits.RotateLeft64(v6, -63)
v3 += m[s[7]]
v3 += v7
v15 ^= v3
v15 = bits.RotateLeft64(v15, -16)
v11 += v15
v7 ^= v11
v7 = bits.RotateLeft64(v7, -63)
v0 += m[s[8]]
v0 += v5
v15 ^= v0
v15 = bits.RotateLeft64(v15, -32)
v10 += v15
v5 ^= v10
v5 = bits.RotateLeft64(v5, -24)
v1 += m[s[9]]
v1 += v6
v12 ^= v1
v12 = bits.RotateLeft64(v12, -32)
v11 += v12
v6 ^= v11
v6 = bits.RotateLeft64(v6, -24)
v2 += m[s[10]]
v2 += v7
v13 ^= v2
v13 = bits.RotateLeft64(v13, -32)
v8 += v13
v7 ^= v8
v7 = bits.RotateLeft64(v7, -24)
v3 += m[s[11]]
v3 += v4
v14 ^= v3
v14 = bits.RotateLeft64(v14, -32)
v9 += v14
v4 ^= v9
v4 = bits.RotateLeft64(v4, -24)
v0 += m[s[12]]
v0 += v5
v15 ^= v0
v15 = bits.RotateLeft64(v15, -16)
v10 += v15
v5 ^= v10
v5 = bits.RotateLeft64(v5, -63)
v1 += m[s[13]]
v1 += v6
v12 ^= v1
v12 = bits.RotateLeft64(v12, -16)
v11 += v12
v6 ^= v11
v6 = bits.RotateLeft64(v6, -63)
v2 += m[s[14]]
v2 += v7
v13 ^= v2
v13 = bits.RotateLeft64(v13, -16)
v8 += v13
v7 ^= v8
v7 = bits.RotateLeft64(v7, -63)
v3 += m[s[15]]
v3 += v4
v14 ^= v3
v14 = bits.RotateLeft64(v14, -16)
v9 += v14
v4 ^= v9
v4 = bits.RotateLeft64(v4, -63)
}
h[0] ^= v0 ^ v8
h[1] ^= v1 ^ v9
h[2] ^= v2 ^ v10
h[3] ^= v3 ^ v11
h[4] ^= v4 ^ v12
h[5] ^= v5 ^ v13
h[6] ^= v6 ^ v14
h[7] ^= v7 ^ v15
}

View File

@ -0,0 +1,11 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !amd64 appengine gccgo
package blake2b
func f(h *[8]uint64, m *[16]uint64, c0, c1 uint64, flag uint64, rounds uint64) {
fGeneric(h, m, c0, c1, flag, rounds)
}

View File

@ -0,0 +1,871 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package blake2b
import (
"bytes"
"encoding"
"encoding/hex"
"fmt"
"hash"
"io"
"testing"
)
func fromHex(s string) []byte {
b, err := hex.DecodeString(s)
if err != nil {
panic(err)
}
return b
}
func TestHashes(t *testing.T) {
defer func(sse4, avx, avx2 bool) {
useSSE4, useAVX, useAVX2 = sse4, avx, avx2
}(useSSE4, useAVX, useAVX2)
if useAVX2 {
t.Log("AVX2 version")
testHashes(t)
useAVX2 = false
}
if useAVX {
t.Log("AVX version")
testHashes(t)
useAVX = false
}
if useSSE4 {
t.Log("SSE4 version")
testHashes(t)
useSSE4 = false
}
t.Log("generic version")
testHashes(t)
}
func TestHashes2X(t *testing.T) {
defer func(sse4, avx, avx2 bool) {
useSSE4, useAVX, useAVX2 = sse4, avx, avx2
}(useSSE4, useAVX, useAVX2)
if useAVX2 {
t.Log("AVX2 version")
testHashes2X(t)
useAVX2 = false
}
if useAVX {
t.Log("AVX version")
testHashes2X(t)
useAVX = false
}
if useSSE4 {
t.Log("SSE4 version")
testHashes2X(t)
useSSE4 = false
}
t.Log("generic version")
testHashes2X(t)
}
func TestMarshal(t *testing.T) {
input := make([]byte, 255)
for i := range input {
input[i] = byte(i)
}
for _, size := range []int{Size, Size256, Size384, 12, 25, 63} {
for i := 0; i < 256; i++ {
h, err := New(size, nil)
if err != nil {
t.Fatalf("size=%d, len(input)=%d: error from New(%v, nil): %v", size, i, size, err)
}
h2, err := New(size, nil)
if err != nil {
t.Fatalf("size=%d, len(input)=%d: error from New(%v, nil): %v", size, i, size, err)
}
h.Write(input[:i/2])
halfstate, err := h.(encoding.BinaryMarshaler).MarshalBinary()
if err != nil {
t.Fatalf("size=%d, len(input)=%d: could not marshal: %v", size, i, err)
}
err = h2.(encoding.BinaryUnmarshaler).UnmarshalBinary(halfstate)
if err != nil {
t.Fatalf("size=%d, len(input)=%d: could not unmarshal: %v", size, i, err)
}
h.Write(input[i/2 : i])
sum := h.Sum(nil)
h2.Write(input[i/2 : i])
sum2 := h2.Sum(nil)
if !bytes.Equal(sum, sum2) {
t.Fatalf("size=%d, len(input)=%d: results do not match; sum = %v, sum2 = %v", size, i, sum, sum2)
}
h3, err := New(size, nil)
if err != nil {
t.Fatalf("size=%d, len(input)=%d: error from New(%v, nil): %v", size, i, size, err)
}
h3.Write(input[:i])
sum3 := h3.Sum(nil)
if !bytes.Equal(sum, sum3) {
t.Fatalf("size=%d, len(input)=%d: sum = %v, want %v", size, i, sum, sum3)
}
}
}
}
func testHashes(t *testing.T) {
key, _ := hex.DecodeString("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f")
input := make([]byte, 255)
for i := range input {
input[i] = byte(i)
}
for i, expectedHex := range hashes {
h, err := New512(key)
if err != nil {
t.Fatalf("#%d: error from New512: %v", i, err)
}
h.Write(input[:i])
sum := h.Sum(nil)
if gotHex := fmt.Sprintf("%x", sum); gotHex != expectedHex {
t.Fatalf("#%d (single write): got %s, wanted %s", i, gotHex, expectedHex)
}
h.Reset()
for j := 0; j < i; j++ {
h.Write(input[j : j+1])
}
sum = h.Sum(sum[:0])
if gotHex := fmt.Sprintf("%x", sum); gotHex != expectedHex {
t.Fatalf("#%d (byte-by-byte): got %s, wanted %s", i, gotHex, expectedHex)
}
}
}
func testHashes2X(t *testing.T) {
key, _ := hex.DecodeString("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f")
input := make([]byte, 256)
for i := range input {
input[i] = byte(i)
}
for i, expectedHex := range hashes2X {
length := uint32(len(expectedHex) / 2)
sum := make([]byte, int(length))
h, err := NewXOF(length, key)
if err != nil {
t.Fatalf("#%d: error from NewXOF: %v", i, err)
}
if _, err := h.Write(input); err != nil {
t.Fatalf("#%d (single write): error from Write: %v", i, err)
}
if _, err := h.Read(sum); err != nil {
t.Fatalf("#%d (single write): error from Read: %v", i, err)
}
if n, err := h.Read(sum); n != 0 || err != io.EOF {
t.Fatalf("#%d (single write): Read did not return (0, io.EOF) after exhaustion, got (%v, %v)", i, n, err)
}
if gotHex := fmt.Sprintf("%x", sum); gotHex != expectedHex {
t.Fatalf("#%d (single write): got %s, wanted %s", i, gotHex, expectedHex)
}
h.Reset()
for j := 0; j < len(input); j++ {
h.Write(input[j : j+1])
}
for j := 0; j < len(sum); j++ {
h = h.Clone()
if _, err := h.Read(sum[j : j+1]); err != nil {
t.Fatalf("#%d (byte-by-byte) - Read %d: error from Read: %v", i, j, err)
}
}
if gotHex := fmt.Sprintf("%x", sum); gotHex != expectedHex {
t.Fatalf("#%d (byte-by-byte): got %s, wanted %s", i, gotHex, expectedHex)
}
}
h, err := NewXOF(OutputLengthUnknown, key)
if err != nil {
t.Fatalf("#unknown length: error from NewXOF: %v", err)
}
if _, err := h.Write(input); err != nil {
t.Fatalf("#unknown length: error from Write: %v", err)
}
var result [64]byte
if n, err := h.Read(result[:]); err != nil {
t.Fatalf("#unknown length: error from Read: %v", err)
} else if n != len(result) {
t.Fatalf("#unknown length: Read returned %d bytes, want %d", n, len(result))
}
const expected = "3dbba8516da76bf7330055c66ea36cf1005e92714262b24d9710f51d9e126406e1bcd6497059f9331f1091c3634b695428d475ed432f987040575520a1c29f5e"
if fmt.Sprintf("%x", result) != expected {
t.Fatalf("#unknown length: bad result %x, wanted %s", result, expected)
}
}
func generateSequence(out []byte, seed uint32) {
a := 0xDEAD4BAD * seed // prime
b := uint32(1)
for i := range out { // fill the buf
a, b = b, a+b
out[i] = byte(b >> 24)
}
}
func computeMAC(msg []byte, hashSize int, key []byte) (sum []byte) {
var h hash.Hash
switch hashSize {
case Size:
h, _ = New512(key)
case Size384:
h, _ = New384(key)
case Size256:
h, _ = New256(key)
case 20:
h, _ = newDigest(20, key)
default:
panic("unexpected hashSize")
}
h.Write(msg)
return h.Sum(sum)
}
func computeHash(msg []byte, hashSize int) (sum []byte) {
switch hashSize {
case Size:
hash := Sum512(msg)
return hash[:]
case Size384:
hash := Sum384(msg)
return hash[:]
case Size256:
hash := Sum256(msg)
return hash[:]
case 20:
var hash [64]byte
checkSum(&hash, 20, msg)
return hash[:20]
default:
panic("unexpected hashSize")
}
}
// Test function from RFC 7693.
func TestSelfTest(t *testing.T) {
hashLens := [4]int{20, 32, 48, 64}
msgLens := [6]int{0, 3, 128, 129, 255, 1024}
msg := make([]byte, 1024)
key := make([]byte, 64)
h, _ := New256(nil)
for _, hashSize := range hashLens {
for _, msgLength := range msgLens {
generateSequence(msg[:msgLength], uint32(msgLength)) // unkeyed hash
md := computeHash(msg[:msgLength], hashSize)
h.Write(md)
generateSequence(key[:], uint32(hashSize)) // keyed hash
md = computeMAC(msg[:msgLength], hashSize, key[:hashSize])
h.Write(md)
}
}
sum := h.Sum(nil)
expected := [32]byte{
0xc2, 0x3a, 0x78, 0x00, 0xd9, 0x81, 0x23, 0xbd,
0x10, 0xf5, 0x06, 0xc6, 0x1e, 0x29, 0xda, 0x56,
0x03, 0xd7, 0x63, 0xb8, 0xbb, 0xad, 0x2e, 0x73,
0x7f, 0x5e, 0x76, 0x5a, 0x7b, 0xcc, 0xd4, 0x75,
}
if !bytes.Equal(sum, expected[:]) {
t.Fatalf("got %x, wanted %x", sum, expected)
}
}
// Benchmarks
func benchmarkSum(b *testing.B, size int, sse4, avx, avx2 bool) {
// Enable the correct set of instructions
defer func(sse4, avx, avx2 bool) {
useSSE4, useAVX, useAVX2 = sse4, avx, avx2
}(useSSE4, useAVX, useAVX2)
useSSE4, useAVX, useAVX2 = sse4, avx, avx2
data := make([]byte, size)
b.SetBytes(int64(size))
b.ResetTimer()
for i := 0; i < b.N; i++ {
Sum512(data)
}
}
func benchmarkWrite(b *testing.B, size int, sse4, avx, avx2 bool) {
// Enable the correct set of instructions
defer func(sse4, avx, avx2 bool) {
useSSE4, useAVX, useAVX2 = sse4, avx, avx2
}(useSSE4, useAVX, useAVX2)
useSSE4, useAVX, useAVX2 = sse4, avx, avx2
data := make([]byte, size)
h, _ := New512(nil)
b.SetBytes(int64(size))
b.ResetTimer()
for i := 0; i < b.N; i++ {
h.Write(data)
}
}
func BenchmarkWrite128Generic(b *testing.B) { benchmarkWrite(b, 128, false, false, false) }
func BenchmarkWrite1KGeneric(b *testing.B) { benchmarkWrite(b, 1024, false, false, false) }
func BenchmarkWrite128SSE4(b *testing.B) { benchmarkWrite(b, 128, true, false, false) }
func BenchmarkWrite1KSSE4(b *testing.B) { benchmarkWrite(b, 1024, true, false, false) }
func BenchmarkWrite128AVX(b *testing.B) { benchmarkWrite(b, 128, false, true, false) }
func BenchmarkWrite1KAVX(b *testing.B) { benchmarkWrite(b, 1024, false, true, false) }
func BenchmarkWrite128AVX2(b *testing.B) { benchmarkWrite(b, 128, false, false, true) }
func BenchmarkWrite1KAVX2(b *testing.B) { benchmarkWrite(b, 1024, false, false, true) }
func BenchmarkSum128Generic(b *testing.B) { benchmarkSum(b, 128, false, false, false) }
func BenchmarkSum1KGeneric(b *testing.B) { benchmarkSum(b, 1024, false, false, false) }
func BenchmarkSum128SSE4(b *testing.B) { benchmarkSum(b, 128, true, false, false) }
func BenchmarkSum1KSSE4(b *testing.B) { benchmarkSum(b, 1024, true, false, false) }
func BenchmarkSum128AVX(b *testing.B) { benchmarkSum(b, 128, false, true, false) }
func BenchmarkSum1KAVX(b *testing.B) { benchmarkSum(b, 1024, false, true, false) }
func BenchmarkSum128AVX2(b *testing.B) { benchmarkSum(b, 128, false, false, true) }
func BenchmarkSum1KAVX2(b *testing.B) { benchmarkSum(b, 1024, false, false, true) }
// These values were taken from https://blake2.net/blake2b-test.txt.
var hashes = []string{
"10ebb67700b1868efb4417987acf4690ae9d972fb7a590c2f02871799aaa4786b5e996e8f0f4eb981fc214b005f42d2ff4233499391653df7aefcbc13fc51568",
"961f6dd1e4dd30f63901690c512e78e4b45e4742ed197c3c5e45c549fd25f2e4187b0bc9fe30492b16b0d0bc4ef9b0f34c7003fac09a5ef1532e69430234cebd",
"da2cfbe2d8409a0f38026113884f84b50156371ae304c4430173d08a99d9fb1b983164a3770706d537f49e0c916d9f32b95cc37a95b99d857436f0232c88a965",
"33d0825dddf7ada99b0e7e307104ad07ca9cfd9692214f1561356315e784f3e5a17e364ae9dbb14cb2036df932b77f4b292761365fb328de7afdc6d8998f5fc1",
"beaa5a3d08f3807143cf621d95cd690514d0b49efff9c91d24b59241ec0eefa5f60196d407048bba8d2146828ebcb0488d8842fd56bb4f6df8e19c4b4daab8ac",
"098084b51fd13deae5f4320de94a688ee07baea2800486689a8636117b46c1f4c1f6af7f74ae7c857600456a58a3af251dc4723a64cc7c0a5ab6d9cac91c20bb",
"6044540d560853eb1c57df0077dd381094781cdb9073e5b1b3d3f6c7829e12066bbaca96d989a690de72ca3133a83652ba284a6d62942b271ffa2620c9e75b1f",
"7a8cfe9b90f75f7ecb3acc053aaed6193112b6f6a4aeeb3f65d3de541942deb9e2228152a3c4bbbe72fc3b12629528cfbb09fe630f0474339f54abf453e2ed52",
"380beaf6ea7cc9365e270ef0e6f3a64fb902acae51dd5512f84259ad2c91f4bc4108db73192a5bbfb0cbcf71e46c3e21aee1c5e860dc96e8eb0b7b8426e6abe9",
"60fe3c4535e1b59d9a61ea8500bfac41a69dffb1ceadd9aca323e9a625b64da5763bad7226da02b9c8c4f1a5de140ac5a6c1124e4f718ce0b28ea47393aa6637",
"4fe181f54ad63a2983feaaf77d1e7235c2beb17fa328b6d9505bda327df19fc37f02c4b6f0368ce23147313a8e5738b5fa2a95b29de1c7f8264eb77b69f585cd",
"f228773ce3f3a42b5f144d63237a72d99693adb8837d0e112a8a0f8ffff2c362857ac49c11ec740d1500749dac9b1f4548108bf3155794dcc9e4082849e2b85b",
"962452a8455cc56c8511317e3b1f3b2c37df75f588e94325fdd77070359cf63a9ae6e930936fdf8e1e08ffca440cfb72c28f06d89a2151d1c46cd5b268ef8563",
"43d44bfa18768c59896bf7ed1765cb2d14af8c260266039099b25a603e4ddc5039d6ef3a91847d1088d401c0c7e847781a8a590d33a3c6cb4df0fab1c2f22355",
"dcffa9d58c2a4ca2cdbb0c7aa4c4c1d45165190089f4e983bb1c2cab4aaeff1fa2b5ee516fecd780540240bf37e56c8bcca7fab980e1e61c9400d8a9a5b14ac6",
"6fbf31b45ab0c0b8dad1c0f5f4061379912dde5aa922099a030b725c73346c524291adef89d2f6fd8dfcda6d07dad811a9314536c2915ed45da34947e83de34e",
"a0c65bddde8adef57282b04b11e7bc8aab105b99231b750c021f4a735cb1bcfab87553bba3abb0c3e64a0b6955285185a0bd35fb8cfde557329bebb1f629ee93",
"f99d815550558e81eca2f96718aed10d86f3f1cfb675cce06b0eff02f617c5a42c5aa760270f2679da2677c5aeb94f1142277f21c7f79f3c4f0cce4ed8ee62b1",
"95391da8fc7b917a2044b3d6f5374e1ca072b41454d572c7356c05fd4bc1e0f40b8bb8b4a9f6bce9be2c4623c399b0dca0dab05cb7281b71a21b0ebcd9e55670",
"04b9cd3d20d221c09ac86913d3dc63041989a9a1e694f1e639a3ba7e451840f750c2fc191d56ad61f2e7936bc0ac8e094b60caeed878c18799045402d61ceaf9",
"ec0e0ef707e4ed6c0c66f9e089e4954b058030d2dd86398fe84059631f9ee591d9d77375355149178c0cf8f8e7c49ed2a5e4f95488a2247067c208510fadc44c",
"9a37cce273b79c09913677510eaf7688e89b3314d3532fd2764c39de022a2945b5710d13517af8ddc0316624e73bec1ce67df15228302036f330ab0cb4d218dd",
"4cf9bb8fb3d4de8b38b2f262d3c40f46dfe747e8fc0a414c193d9fcf753106ce47a18f172f12e8a2f1c26726545358e5ee28c9e2213a8787aafbc516d2343152",
"64e0c63af9c808fd893137129867fd91939d53f2af04be4fa268006100069b2d69daa5c5d8ed7fddcb2a70eeecdf2b105dd46a1e3b7311728f639ab489326bc9",
"5e9c93158d659b2def06b0c3c7565045542662d6eee8a96a89b78ade09fe8b3dcc096d4fe48815d88d8f82620156602af541955e1f6ca30dce14e254c326b88f",
"7775dff889458dd11aef417276853e21335eb88e4dec9cfb4e9edb49820088551a2ca60339f12066101169f0dfe84b098fddb148d9da6b3d613df263889ad64b",
"f0d2805afbb91f743951351a6d024f9353a23c7ce1fc2b051b3a8b968c233f46f50f806ecb1568ffaa0b60661e334b21dde04f8fa155ac740eeb42e20b60d764",
"86a2af316e7d7754201b942e275364ac12ea8962ab5bd8d7fb276dc5fbffc8f9a28cae4e4867df6780d9b72524160927c855da5b6078e0b554aa91e31cb9ca1d",
"10bdf0caa0802705e706369baf8a3f79d72c0a03a80675a7bbb00be3a45e516424d1ee88efb56f6d5777545ae6e27765c3a8f5e493fc308915638933a1dfee55",
"b01781092b1748459e2e4ec178696627bf4ebafebba774ecf018b79a68aeb84917bf0b84bb79d17b743151144cd66b7b33a4b9e52c76c4e112050ff5385b7f0b",
"c6dbc61dec6eaeac81e3d5f755203c8e220551534a0b2fd105a91889945a638550204f44093dd998c076205dffad703a0e5cd3c7f438a7e634cd59fededb539e",
"eba51acffb4cea31db4b8d87e9bf7dd48fe97b0253ae67aa580f9ac4a9d941f2bea518ee286818cc9f633f2a3b9fb68e594b48cdd6d515bf1d52ba6c85a203a7",
"86221f3ada52037b72224f105d7999231c5e5534d03da9d9c0a12acb68460cd375daf8e24386286f9668f72326dbf99ba094392437d398e95bb8161d717f8991",
"5595e05c13a7ec4dc8f41fb70cb50a71bce17c024ff6de7af618d0cc4e9c32d9570d6d3ea45b86525491030c0d8f2b1836d5778c1ce735c17707df364d054347",
"ce0f4f6aca89590a37fe034dd74dd5fa65eb1cbd0a41508aaddc09351a3cea6d18cb2189c54b700c009f4cbf0521c7ea01be61c5ae09cb54f27bc1b44d658c82",
"7ee80b06a215a3bca970c77cda8761822bc103d44fa4b33f4d07dcb997e36d55298bceae12241b3fa07fa63be5576068da387b8d5859aeab701369848b176d42",
"940a84b6a84d109aab208c024c6ce9647676ba0aaa11f86dbb7018f9fd2220a6d901a9027f9abcf935372727cbf09ebd61a2a2eeb87653e8ecad1bab85dc8327",
"2020b78264a82d9f4151141adba8d44bf20c5ec062eee9b595a11f9e84901bf148f298e0c9f8777dcdbc7cc4670aac356cc2ad8ccb1629f16f6a76bcefbee760",
"d1b897b0e075ba68ab572adf9d9c436663e43eb3d8e62d92fc49c9be214e6f27873fe215a65170e6bea902408a25b49506f47babd07cecf7113ec10c5dd31252",
"b14d0c62abfa469a357177e594c10c194243ed2025ab8aa5ad2fa41ad318e0ff48cd5e60bec07b13634a711d2326e488a985f31e31153399e73088efc86a5c55",
"4169c5cc808d2697dc2a82430dc23e3cd356dc70a94566810502b8d655b39abf9e7f902fe717e0389219859e1945df1af6ada42e4ccda55a197b7100a30c30a1",
"258a4edb113d66c839c8b1c91f15f35ade609f11cd7f8681a4045b9fef7b0b24c82cda06a5f2067b368825e3914e53d6948ede92efd6e8387fa2e537239b5bee",
"79d2d8696d30f30fb34657761171a11e6c3f1e64cbe7bebee159cb95bfaf812b4f411e2f26d9c421dc2c284a3342d823ec293849e42d1e46b0a4ac1e3c86abaa",
"8b9436010dc5dee992ae38aea97f2cd63b946d94fedd2ec9671dcde3bd4ce9564d555c66c15bb2b900df72edb6b891ebcadfeff63c9ea4036a998be7973981e7",
"c8f68e696ed28242bf997f5b3b34959508e42d613810f1e2a435c96ed2ff560c7022f361a9234b9837feee90bf47922ee0fd5f8ddf823718d86d1e16c6090071",
"b02d3eee4860d5868b2c39ce39bfe81011290564dd678c85e8783f29302dfc1399ba95b6b53cd9ebbf400cca1db0ab67e19a325f2d115812d25d00978ad1bca4",
"7693ea73af3ac4dad21ca0d8da85b3118a7d1c6024cfaf557699868217bc0c2f44a199bc6c0edd519798ba05bd5b1b4484346a47c2cadf6bf30b785cc88b2baf",
"a0e5c1c0031c02e48b7f09a5e896ee9aef2f17fc9e18e997d7f6cac7ae316422c2b1e77984e5f3a73cb45deed5d3f84600105e6ee38f2d090c7d0442ea34c46d",
"41daa6adcfdb69f1440c37b596440165c15ada596813e2e22f060fcd551f24dee8e04ba6890387886ceec4a7a0d7fc6b44506392ec3822c0d8c1acfc7d5aebe8",
"14d4d40d5984d84c5cf7523b7798b254e275a3a8cc0a1bd06ebc0bee726856acc3cbf516ff667cda2058ad5c3412254460a82c92187041363cc77a4dc215e487",
"d0e7a1e2b9a447fee83e2277e9ff8010c2f375ae12fa7aaa8ca5a6317868a26a367a0b69fbc1cf32a55d34eb370663016f3d2110230eba754028a56f54acf57c",
"e771aa8db5a3e043e8178f39a0857ba04a3f18e4aa05743cf8d222b0b095825350ba422f63382a23d92e4149074e816a36c1cd28284d146267940b31f8818ea2",
"feb4fd6f9e87a56bef398b3284d2bda5b5b0e166583a66b61e538457ff0584872c21a32962b9928ffab58de4af2edd4e15d8b35570523207ff4e2a5aa7754caa",
"462f17bf005fb1c1b9e671779f665209ec2873e3e411f98dabf240a1d5ec3f95ce6796b6fc23fe171903b502023467dec7273ff74879b92967a2a43a5a183d33",
"d3338193b64553dbd38d144bea71c5915bb110e2d88180dbc5db364fd6171df317fc7268831b5aef75e4342b2fad8797ba39eddcef80e6ec08159350b1ad696d",
"e1590d585a3d39f7cb599abd479070966409a6846d4377acf4471d065d5db94129cc9be92573b05ed226be1e9b7cb0cabe87918589f80dadd4ef5ef25a93d28e",
"f8f3726ac5a26cc80132493a6fedcb0e60760c09cfc84cad178175986819665e76842d7b9fedf76dddebf5d3f56faaad4477587af21606d396ae570d8e719af2",
"30186055c07949948183c850e9a756cc09937e247d9d928e869e20bafc3cd9721719d34e04a0899b92c736084550186886efba2e790d8be6ebf040b209c439a4",
"f3c4276cb863637712c241c444c5cc1e3554e0fddb174d035819dd83eb700b4ce88df3ab3841ba02085e1a99b4e17310c5341075c0458ba376c95a6818fbb3e2",
"0aa007c4dd9d5832393040a1583c930bca7dc5e77ea53add7e2b3f7c8e231368043520d4a3ef53c969b6bbfd025946f632bd7f765d53c21003b8f983f75e2a6a",
"08e9464720533b23a04ec24f7ae8c103145f765387d738777d3d343477fd1c58db052142cab754ea674378e18766c53542f71970171cc4f81694246b717d7564",
"d37ff7ad297993e7ec21e0f1b4b5ae719cdc83c5db687527f27516cbffa822888a6810ee5c1ca7bfe3321119be1ab7bfa0a502671c8329494df7ad6f522d440f",
"dd9042f6e464dcf86b1262f6accfafbd8cfd902ed3ed89abf78ffa482dbdeeb6969842394c9a1168ae3d481a017842f660002d42447c6b22f7b72f21aae021c9",
"bd965bf31e87d70327536f2a341cebc4768eca275fa05ef98f7f1b71a0351298de006fba73fe6733ed01d75801b4a928e54231b38e38c562b2e33ea1284992fa",
"65676d800617972fbd87e4b9514e1c67402b7a331096d3bfac22f1abb95374abc942f16e9ab0ead33b87c91968a6e509e119ff07787b3ef483e1dcdccf6e3022",
"939fa189699c5d2c81ddd1ffc1fa207c970b6a3685bb29ce1d3e99d42f2f7442da53e95a72907314f4588399a3ff5b0a92beb3f6be2694f9f86ecf2952d5b41c",
"c516541701863f91005f314108ceece3c643e04fc8c42fd2ff556220e616aaa6a48aeb97a84bad74782e8dff96a1a2fa949339d722edcaa32b57067041df88cc",
"987fd6e0d6857c553eaebb3d34970a2c2f6e89a3548f492521722b80a1c21a153892346d2cba6444212d56da9a26e324dccbc0dcde85d4d2ee4399eec5a64e8f",
"ae56deb1c2328d9c4017706bce6e99d41349053ba9d336d677c4c27d9fd50ae6aee17e853154e1f4fe7672346da2eaa31eea53fcf24a22804f11d03da6abfc2b",
"49d6a608c9bde4491870498572ac31aac3fa40938b38a7818f72383eb040ad39532bc06571e13d767e6945ab77c0bdc3b0284253343f9f6c1244ebf2ff0df866",
"da582ad8c5370b4469af862aa6467a2293b2b28bd80ae0e91f425ad3d47249fdf98825cc86f14028c3308c9804c78bfeeeee461444ce243687e1a50522456a1d",
"d5266aa3331194aef852eed86d7b5b2633a0af1c735906f2e13279f14931a9fc3b0eac5ce9245273bd1aa92905abe16278ef7efd47694789a7283b77da3c70f8",
"2962734c28252186a9a1111c732ad4de4506d4b4480916303eb7991d659ccda07a9911914bc75c418ab7a4541757ad054796e26797feaf36e9f6ad43f14b35a4",
"e8b79ec5d06e111bdfafd71e9f5760f00ac8ac5d8bf768f9ff6f08b8f026096b1cc3a4c973333019f1e3553e77da3f98cb9f542e0a90e5f8a940cc58e59844b3",
"dfb320c44f9d41d1efdcc015f08dd5539e526e39c87d509ae6812a969e5431bf4fa7d91ffd03b981e0d544cf72d7b1c0374f8801482e6dea2ef903877eba675e",
"d88675118fdb55a5fb365ac2af1d217bf526ce1ee9c94b2f0090b2c58a06ca58187d7fe57c7bed9d26fca067b4110eefcd9a0a345de872abe20de368001b0745",
"b893f2fc41f7b0dd6e2f6aa2e0370c0cff7df09e3acfcc0e920b6e6fad0ef747c40668417d342b80d2351e8c175f20897a062e9765e6c67b539b6ba8b9170545",
"6c67ec5697accd235c59b486d7b70baeedcbd4aa64ebd4eef3c7eac189561a726250aec4d48cadcafbbe2ce3c16ce2d691a8cce06e8879556d4483ed7165c063",
"f1aa2b044f8f0c638a3f362e677b5d891d6fd2ab0765f6ee1e4987de057ead357883d9b405b9d609eea1b869d97fb16d9b51017c553f3b93c0a1e0f1296fedcd",
"cbaa259572d4aebfc1917acddc582b9f8dfaa928a198ca7acd0f2aa76a134a90252e6298a65b08186a350d5b7626699f8cb721a3ea5921b753ae3a2dce24ba3a",
"fa1549c9796cd4d303dcf452c1fbd5744fd9b9b47003d920b92de34839d07ef2a29ded68f6fc9e6c45e071a2e48bd50c5084e96b657dd0404045a1ddefe282ed",
"5cf2ac897ab444dcb5c8d87c495dbdb34e1838b6b629427caa51702ad0f9688525f13bec503a3c3a2c80a65e0b5715e8afab00ffa56ec455a49a1ad30aa24fcd",
"9aaf80207bace17bb7ab145757d5696bde32406ef22b44292ef65d4519c3bb2ad41a59b62cc3e94b6fa96d32a7faadae28af7d35097219aa3fd8cda31e40c275",
"af88b163402c86745cb650c2988fb95211b94b03ef290eed9662034241fd51cf398f8073e369354c43eae1052f9b63b08191caa138aa54fea889cc7024236897",
"48fa7d64e1ceee27b9864db5ada4b53d00c9bc7626555813d3cd6730ab3cc06ff342d727905e33171bde6e8476e77fb1720861e94b73a2c538d254746285f430",
"0e6fd97a85e904f87bfe85bbeb34f69e1f18105cf4ed4f87aec36c6e8b5f68bd2a6f3dc8a9ecb2b61db4eedb6b2ea10bf9cb0251fb0f8b344abf7f366b6de5ab",
"06622da5787176287fdc8fed440bad187d830099c94e6d04c8e9c954cda70c8bb9e1fc4a6d0baa831b9b78ef6648681a4867a11da93ee36e5e6a37d87fc63f6f",
"1da6772b58fabf9c61f68d412c82f182c0236d7d575ef0b58dd22458d643cd1dfc93b03871c316d8430d312995d4197f0874c99172ba004a01ee295abac24e46",
"3cd2d9320b7b1d5fb9aab951a76023fa667be14a9124e394513918a3f44096ae4904ba0ffc150b63bc7ab1eeb9a6e257e5c8f000a70394a5afd842715de15f29",
"04cdc14f7434e0b4be70cb41db4c779a88eaef6accebcb41f2d42fffe7f32a8e281b5c103a27021d0d08362250753cdf70292195a53a48728ceb5844c2d98bab",
"9071b7a8a075d0095b8fb3ae5113785735ab98e2b52faf91d5b89e44aac5b5d4ebbf91223b0ff4c71905da55342e64655d6ef8c89a4768c3f93a6dc0366b5bc8",
"ebb30240dd96c7bc8d0abe49aa4edcbb4afdc51ff9aaf720d3f9e7fbb0f9c6d6571350501769fc4ebd0b2141247ff400d4fd4be414edf37757bb90a32ac5c65a",
"8532c58bf3c8015d9d1cbe00eef1f5082f8f3632fbe9f1ed4f9dfb1fa79e8283066d77c44c4af943d76b300364aecbd0648c8a8939bd204123f4b56260422dec",
"fe9846d64f7c7708696f840e2d76cb4408b6595c2f81ec6a28a7f2f20cb88cfe6ac0b9e9b8244f08bd7095c350c1d0842f64fb01bb7f532dfcd47371b0aeeb79",
"28f17ea6fb6c42092dc264257e29746321fb5bdaea9873c2a7fa9d8f53818e899e161bc77dfe8090afd82bf2266c5c1bc930a8d1547624439e662ef695f26f24",
"ec6b7d7f030d4850acae3cb615c21dd25206d63e84d1db8d957370737ba0e98467ea0ce274c66199901eaec18a08525715f53bfdb0aacb613d342ebdceeddc3b",
"b403d3691c03b0d3418df327d5860d34bbfcc4519bfbce36bf33b208385fadb9186bc78a76c489d89fd57e7dc75412d23bcd1dae8470ce9274754bb8585b13c5",
"31fc79738b8772b3f55cd8178813b3b52d0db5a419d30ba9495c4b9da0219fac6df8e7c23a811551a62b827f256ecdb8124ac8a6792ccfecc3b3012722e94463",
"bb2039ec287091bcc9642fc90049e73732e02e577e2862b32216ae9bedcd730c4c284ef3968c368b7d37584f97bd4b4dc6ef6127acfe2e6ae2509124e66c8af4",
"f53d68d13f45edfcb9bd415e2831e938350d5380d3432278fc1c0c381fcb7c65c82dafe051d8c8b0d44e0974a0e59ec7bf7ed0459f86e96f329fc79752510fd3",
"8d568c7984f0ecdf7640fbc483b5d8c9f86634f6f43291841b309a350ab9c1137d24066b09da9944bac54d5bb6580d836047aac74ab724b887ebf93d4b32eca9",
"c0b65ce5a96ff774c456cac3b5f2c4cd359b4ff53ef93a3da0778be4900d1e8da1601e769e8f1b02d2a2f8c5b9fa10b44f1c186985468feeb008730283a6657d",
"4900bba6f5fb103ece8ec96ada13a5c3c85488e05551da6b6b33d988e611ec0fe2e3c2aa48ea6ae8986a3a231b223c5d27cec2eadde91ce07981ee652862d1e4",
"c7f5c37c7285f927f76443414d4357ff789647d7a005a5a787e03c346b57f49f21b64fa9cf4b7e45573e23049017567121a9c3d4b2b73ec5e9413577525db45a",
"ec7096330736fdb2d64b5653e7475da746c23a4613a82687a28062d3236364284ac01720ffb406cfe265c0df626a188c9e5963ace5d3d5bb363e32c38c2190a6",
"82e744c75f4649ec52b80771a77d475a3bc091989556960e276a5f9ead92a03f718742cdcfeaee5cb85c44af198adc43a4a428f5f0c2ddb0be36059f06d7df73",
"2834b7a7170f1f5b68559ab78c1050ec21c919740b784a9072f6e5d69f828d70c919c5039fb148e39e2c8a52118378b064ca8d5001cd10a5478387b966715ed6",
"16b4ada883f72f853bb7ef253efcab0c3e2161687ad61543a0d2824f91c1f81347d86be709b16996e17f2dd486927b0288ad38d13063c4a9672c39397d3789b6",
"78d048f3a69d8b54ae0ed63a573ae350d89f7c6cf1f3688930de899afa037697629b314e5cd303aa62feea72a25bf42b304b6c6bcb27fae21c16d925e1fbdac3",
"0f746a48749287ada77a82961f05a4da4abdb7d77b1220f836d09ec814359c0ec0239b8c7b9ff9e02f569d1b301ef67c4612d1de4f730f81c12c40cc063c5caa",
"f0fc859d3bd195fbdc2d591e4cdac15179ec0f1dc821c11df1f0c1d26e6260aaa65b79fafacafd7d3ad61e600f250905f5878c87452897647a35b995bcadc3a3",
"2620f687e8625f6a412460b42e2cef67634208ce10a0cbd4dff7044a41b7880077e9f8dc3b8d1216d3376a21e015b58fb279b521d83f9388c7382c8505590b9b",
"227e3aed8d2cb10b918fcb04f9de3e6d0a57e08476d93759cd7b2ed54a1cbf0239c528fb04bbf288253e601d3bc38b21794afef90b17094a182cac557745e75f",
"1a929901b09c25f27d6b35be7b2f1c4745131fdebca7f3e2451926720434e0db6e74fd693ad29b777dc3355c592a361c4873b01133a57c2e3b7075cbdb86f4fc",
"5fd7968bc2fe34f220b5e3dc5af9571742d73b7d60819f2888b629072b96a9d8ab2d91b82d0a9aaba61bbd39958132fcc4257023d1eca591b3054e2dc81c8200",
"dfcce8cf32870cc6a503eadafc87fd6f78918b9b4d0737db6810be996b5497e7e5cc80e312f61e71ff3e9624436073156403f735f56b0b01845c18f6caf772e6",
"02f7ef3a9ce0fff960f67032b296efca3061f4934d690749f2d01c35c81c14f39a67fa350bc8a0359bf1724bffc3bca6d7c7bba4791fd522a3ad353c02ec5aa8",
"64be5c6aba65d594844ae78bb022e5bebe127fd6b6ffa5a13703855ab63b624dcd1a363f99203f632ec386f3ea767fc992e8ed9686586aa27555a8599d5b808f",
"f78585505c4eaa54a8b5be70a61e735e0ff97af944ddb3001e35d86c4e2199d976104b6ae31750a36a726ed285064f5981b503889fef822fcdc2898dddb7889a",
"e4b5566033869572edfd87479a5bb73c80e8759b91232879d96b1dda36c012076ee5a2ed7ae2de63ef8406a06aea82c188031b560beafb583fb3de9e57952a7e",
"e1b3e7ed867f6c9484a2a97f7715f25e25294e992e41f6a7c161ffc2adc6daaeb7113102d5e6090287fe6ad94ce5d6b739c6ca240b05c76fb73f25dd024bf935",
"85fd085fdc12a080983df07bd7012b0d402a0f4043fcb2775adf0bad174f9b08d1676e476985785c0a5dcc41dbff6d95ef4d66a3fbdc4a74b82ba52da0512b74",
"aed8fa764b0fbff821e05233d2f7b0900ec44d826f95e93c343c1bc3ba5a24374b1d616e7e7aba453a0ada5e4fab5382409e0d42ce9c2bc7fb39a99c340c20f0",
"7ba3b2e297233522eeb343bd3ebcfd835a04007735e87f0ca300cbee6d416565162171581e4020ff4cf176450f1291ea2285cb9ebffe4c56660627685145051c",
"de748bcf89ec88084721e16b85f30adb1a6134d664b5843569babc5bbd1a15ca9b61803c901a4fef32965a1749c9f3a4e243e173939dc5a8dc495c671ab52145",
"aaf4d2bdf200a919706d9842dce16c98140d34bc433df320aba9bd429e549aa7a3397652a4d768277786cf993cde2338673ed2e6b66c961fefb82cd20c93338f",
"c408218968b788bf864f0997e6bc4c3dba68b276e2125a4843296052ff93bf5767b8cdce7131f0876430c1165fec6c4f47adaa4fd8bcfacef463b5d3d0fa61a0",
"76d2d819c92bce55fa8e092ab1bf9b9eab237a25267986cacf2b8ee14d214d730dc9a5aa2d7b596e86a1fd8fa0804c77402d2fcd45083688b218b1cdfa0dcbcb",
"72065ee4dd91c2d8509fa1fc28a37c7fc9fa7d5b3f8ad3d0d7a25626b57b1b44788d4caf806290425f9890a3a2a35a905ab4b37acfd0da6e4517b2525c9651e4",
"64475dfe7600d7171bea0b394e27c9b00d8e74dd1e416a79473682ad3dfdbb706631558055cfc8a40e07bd015a4540dcdea15883cbbf31412df1de1cd4152b91",
"12cd1674a4488a5d7c2b3160d2e2c4b58371bedad793418d6f19c6ee385d70b3e06739369d4df910edb0b0a54cbff43d54544cd37ab3a06cfa0a3ddac8b66c89",
"60756966479dedc6dd4bcff8ea7d1d4ce4d4af2e7b097e32e3763518441147cc12b3c0ee6d2ecabf1198cec92e86a3616fba4f4e872f5825330adbb4c1dee444",
"a7803bcb71bc1d0f4383dde1e0612e04f872b715ad30815c2249cf34abb8b024915cb2fc9f4e7cc4c8cfd45be2d5a91eab0941c7d270e2da4ca4a9f7ac68663a",
"b84ef6a7229a34a750d9a98ee2529871816b87fbe3bc45b45fa5ae82d5141540211165c3c5d7a7476ba5a4aa06d66476f0d9dc49a3f1ee72c3acabd498967414",
"fae4b6d8efc3f8c8e64d001dabec3a21f544e82714745251b2b4b393f2f43e0da3d403c64db95a2cb6e23ebb7b9e94cdd5ddac54f07c4a61bd3cb10aa6f93b49",
"34f7286605a122369540141ded79b8957255da2d4155abbf5a8dbb89c8eb7ede8eeef1daa46dc29d751d045dc3b1d658bb64b80ff8589eddb3824b13da235a6b",
"3b3b48434be27b9eababba43bf6b35f14b30f6a88dc2e750c358470d6b3aa3c18e47db4017fa55106d8252f016371a00f5f8b070b74ba5f23cffc5511c9f09f0",
"ba289ebd6562c48c3e10a8ad6ce02e73433d1e93d7c9279d4d60a7e879ee11f441a000f48ed9f7c4ed87a45136d7dccdca482109c78a51062b3ba4044ada2469",
"022939e2386c5a37049856c850a2bb10a13dfea4212b4c732a8840a9ffa5faf54875c5448816b2785a007da8a8d2bc7d71a54e4e6571f10b600cbdb25d13ede3",
"e6fec19d89ce8717b1a087024670fe026f6c7cbda11caef959bb2d351bf856f8055d1c0ebdaaa9d1b17886fc2c562b5e99642fc064710c0d3488a02b5ed7f6fd",
"94c96f02a8f576aca32ba61c2b206f907285d9299b83ac175c209a8d43d53bfe683dd1d83e7549cb906c28f59ab7c46f8751366a28c39dd5fe2693c9019666c8",
"31a0cd215ebd2cb61de5b9edc91e6195e31c59a5648d5c9f737e125b2605708f2e325ab3381c8dce1a3e958886f1ecdc60318f882cfe20a24191352e617b0f21",
"91ab504a522dce78779f4c6c6ba2e6b6db5565c76d3e7e7c920caf7f757ef9db7c8fcf10e57f03379ea9bf75eb59895d96e149800b6aae01db778bb90afbc989",
"d85cabc6bd5b1a01a5afd8c6734740da9fd1c1acc6db29bfc8a2e5b668b028b6b3154bfb8703fa3180251d589ad38040ceb707c4bad1b5343cb426b61eaa49c1",
"d62efbec2ca9c1f8bd66ce8b3f6a898cb3f7566ba6568c618ad1feb2b65b76c3ce1dd20f7395372faf28427f61c9278049cf0140df434f5633048c86b81e0399",
"7c8fdc6175439e2c3db15bafa7fb06143a6a23bc90f449e79deef73c3d492a671715c193b6fea9f036050b946069856b897e08c00768f5ee5ddcf70b7cd6d0e0",
"58602ee7468e6bc9df21bd51b23c005f72d6cb013f0a1b48cbec5eca299299f97f09f54a9a01483eaeb315a6478bad37ba47ca1347c7c8fc9e6695592c91d723",
"27f5b79ed256b050993d793496edf4807c1d85a7b0a67c9c4fa99860750b0ae66989670a8ffd7856d7ce411599e58c4d77b232a62bef64d15275be46a68235ff",
"3957a976b9f1887bf004a8dca942c92d2b37ea52600f25e0c9bc5707d0279c00c6e85a839b0d2d8eb59c51d94788ebe62474a791cadf52cccf20f5070b6573fc",
"eaa2376d55380bf772ecca9cb0aa4668c95c707162fa86d518c8ce0ca9bf7362b9f2a0adc3ff59922df921b94567e81e452f6c1a07fc817cebe99604b3505d38",
"c1e2c78b6b2734e2480ec550434cb5d613111adcc21d475545c3b1b7e6ff12444476e5c055132e2229dc0f807044bb919b1a5662dd38a9ee65e243a3911aed1a",
"8ab48713389dd0fcf9f965d3ce66b1e559a1f8c58741d67683cd971354f452e62d0207a65e436c5d5d8f8ee71c6abfe50e669004c302b31a7ea8311d4a916051",
"24ce0addaa4c65038bd1b1c0f1452a0b128777aabc94a29df2fd6c7e2f85f8ab9ac7eff516b0e0a825c84a24cfe492eaad0a6308e46dd42fe8333ab971bb30ca",
"5154f929ee03045b6b0c0004fa778edee1d139893267cc84825ad7b36c63de32798e4a166d24686561354f63b00709a1364b3c241de3febf0754045897467cd4",
"e74e907920fd87bd5ad636dd11085e50ee70459c443e1ce5809af2bc2eba39f9e6d7128e0e3712c316da06f4705d78a4838e28121d4344a2c79c5e0db307a677",
"bf91a22334bac20f3fd80663b3cd06c4e8802f30e6b59f90d3035cc9798a217ed5a31abbda7fa6842827bdf2a7a1c21f6fcfccbb54c6c52926f32da816269be1",
"d9d5c74be5121b0bd742f26bffb8c89f89171f3f934913492b0903c271bbe2b3395ef259669bef43b57f7fcc3027db01823f6baee66e4f9fead4d6726c741fce",
"50c8b8cf34cd879f80e2faab3230b0c0e1cc3e9dcadeb1b9d97ab923415dd9a1fe38addd5c11756c67990b256e95ad6d8f9fedce10bf1c90679cde0ecf1be347",
"0a386e7cd5dd9b77a035e09fe6fee2c8ce61b5383c87ea43205059c5e4cd4f4408319bb0a82360f6a58e6c9ce3f487c446063bf813bc6ba535e17fc1826cfc91",
"1f1459cb6b61cbac5f0efe8fc487538f42548987fcd56221cfa7beb22504769e792c45adfb1d6b3d60d7b749c8a75b0bdf14e8ea721b95dca538ca6e25711209",
"e58b3836b7d8fedbb50ca5725c6571e74c0785e97821dab8b6298c10e4c079d4a6cdf22f0fedb55032925c16748115f01a105e77e00cee3d07924dc0d8f90659",
"b929cc6505f020158672deda56d0db081a2ee34c00c1100029bdf8ea98034fa4bf3e8655ec697fe36f40553c5bb46801644a627d3342f4fc92b61f03290fb381",
"72d353994b49d3e03153929a1e4d4f188ee58ab9e72ee8e512f29bc773913819ce057ddd7002c0433ee0a16114e3d156dd2c4a7e80ee53378b8670f23e33ef56",
"c70ef9bfd775d408176737a0736d68517ce1aaad7e81a93c8c1ed967ea214f56c8a377b1763e676615b60f3988241eae6eab9685a5124929d28188f29eab06f7",
"c230f0802679cb33822ef8b3b21bf7a9a28942092901d7dac3760300831026cf354c9232df3e084d9903130c601f63c1f4a4a4b8106e468cd443bbe5a734f45f",
"6f43094cafb5ebf1f7a4937ec50f56a4c9da303cbb55ac1f27f1f1976cd96beda9464f0e7b9c54620b8a9fba983164b8be3578425a024f5fe199c36356b88972",
"3745273f4c38225db2337381871a0c6aafd3af9b018c88aa02025850a5dc3a42a1a3e03e56cbf1b0876d63a441f1d2856a39b8801eb5af325201c415d65e97fe",
"c50c44cca3ec3edaae779a7e179450ebdda2f97067c690aa6c5a4ac7c30139bb27c0df4db3220e63cb110d64f37ffe078db72653e2daacf93ae3f0a2d1a7eb2e",
"8aef263e385cbc61e19b28914243262af5afe8726af3ce39a79c27028cf3ecd3f8d2dfd9cfc9ad91b58f6f20778fd5f02894a3d91c7d57d1e4b866a7f364b6be",
"28696141de6e2d9bcb3235578a66166c1448d3e905a1b482d423be4bc5369bc8c74dae0acc9cc123e1d8ddce9f97917e8c019c552da32d39d2219b9abf0fa8c8",
"2fb9eb2085830181903a9dafe3db428ee15be7662224efd643371fb25646aee716e531eca69b2bdc8233f1a8081fa43da1500302975a77f42fa592136710e9dc",
"66f9a7143f7a3314a669bf2e24bbb35014261d639f495b6c9c1f104fe8e320aca60d4550d69d52edbd5a3cdeb4014ae65b1d87aa770b69ae5c15f4330b0b0ad8",
"f4c4dd1d594c3565e3e25ca43dad82f62abea4835ed4cd811bcd975e46279828d44d4c62c3679f1b7f7b9dd4571d7b49557347b8c5460cbdc1bef690fb2a08c0",
"8f1dc9649c3a84551f8f6e91cac68242a43b1f8f328ee92280257387fa7559aa6db12e4aeadc2d26099178749c6864b357f3f83b2fb3efa8d2a8db056bed6bcc",
"3139c1a7f97afd1675d460ebbc07f2728aa150df849624511ee04b743ba0a833092f18c12dc91b4dd243f333402f59fe28abdbbbae301e7b659c7a26d5c0f979",
"06f94a2996158a819fe34c40de3cf0379fd9fb85b3e363ba3926a0e7d960e3f4c2e0c70c7ce0ccb2a64fc29869f6e7ab12bd4d3f14fce943279027e785fb5c29",
"c29c399ef3eee8961e87565c1ce263925fc3d0ce267d13e48dd9e732ee67b0f69fad56401b0f10fcaac119201046cca28c5b14abdea3212ae65562f7f138db3d",
"4cec4c9df52eef05c3f6faaa9791bc7445937183224ecc37a1e58d0132d35617531d7e795f52af7b1eb9d147de1292d345fe341823f8e6bc1e5badca5c656108",
"898bfbae93b3e18d00697eab7d9704fa36ec339d076131cefdf30edbe8d9cc81c3a80b129659b163a323bab9793d4feed92d54dae966c77529764a09be88db45",
"ee9bd0469d3aaf4f14035be48a2c3b84d9b4b1fff1d945e1f1c1d38980a951be197b25fe22c731f20aeacc930ba9c4a1f4762227617ad350fdabb4e80273a0f4",
"3d4d3113300581cd96acbf091c3d0f3c310138cd6979e6026cde623e2dd1b24d4a8638bed1073344783ad0649cc6305ccec04beb49f31c633088a99b65130267",
"95c0591ad91f921ac7be6d9ce37e0663ed8011c1cfd6d0162a5572e94368bac02024485e6a39854aa46fe38e97d6c6b1947cd272d86b06bb5b2f78b9b68d559d",
"227b79ded368153bf46c0a3ca978bfdbef31f3024a5665842468490b0ff748ae04e7832ed4c9f49de9b1706709d623e5c8c15e3caecae8d5e433430ff72f20eb",
"5d34f3952f0105eef88ae8b64c6ce95ebfade0e02c69b08762a8712d2e4911ad3f941fc4034dc9b2e479fdbcd279b902faf5d838bb2e0c6495d372b5b7029813",
"7f939bf8353abce49e77f14f3750af20b7b03902e1a1e7fb6aaf76d0259cd401a83190f15640e74f3e6c5a90e839c7821f6474757f75c7bf9002084ddc7a62dc",
"062b61a2f9a33a71d7d0a06119644c70b0716a504de7e5e1be49bd7b86e7ed6817714f9f0fc313d06129597e9a2235ec8521de36f7290a90ccfc1ffa6d0aee29",
"f29e01eeae64311eb7f1c6422f946bf7bea36379523e7b2bbaba7d1d34a22d5ea5f1c5a09d5ce1fe682cced9a4798d1a05b46cd72dff5c1b355440b2a2d476bc",
"ec38cd3bbab3ef35d7cb6d5c914298351d8a9dc97fcee051a8a02f58e3ed6184d0b7810a5615411ab1b95209c3c810114fdeb22452084e77f3f847c6dbaafe16",
"c2aef5e0ca43e82641565b8cb943aa8ba53550caef793b6532fafad94b816082f0113a3ea2f63608ab40437ecc0f0229cb8fa224dcf1c478a67d9b64162b92d1",
"15f534efff7105cd1c254d074e27d5898b89313b7d366dc2d7d87113fa7d53aae13f6dba487ad8103d5e854c91fdb6e1e74b2ef6d1431769c30767dde067a35c",
"89acbca0b169897a0a2714c2df8c95b5b79cb69390142b7d6018bb3e3076b099b79a964152a9d912b1b86412b7e372e9cecad7f25d4cbab8a317be36492a67d7",
"e3c0739190ed849c9c962fd9dbb55e207e624fcac1eb417691515499eea8d8267b7e8f1287a63633af5011fde8c4ddf55bfdf722edf88831414f2cfaed59cb9a",
"8d6cf87c08380d2d1506eee46fd4222d21d8c04e585fbfd08269c98f702833a156326a0724656400ee09351d57b440175e2a5de93cc5f80db6daf83576cf75fa",
"da24bede383666d563eeed37f6319baf20d5c75d1635a6ba5ef4cfa1ac95487e96f8c08af600aab87c986ebad49fc70a58b4890b9c876e091016daf49e1d322e",
"f9d1d1b1e87ea7ae753a029750cc1cf3d0157d41805e245c5617bb934e732f0ae3180b78e05bfe76c7c3051e3e3ac78b9b50c05142657e1e03215d6ec7bfd0fc",
"11b7bc1668032048aa43343de476395e814bbbc223678db951a1b03a021efac948cfbe215f97fe9a72a2f6bc039e3956bfa417c1a9f10d6d7ba5d3d32ff323e5",
"b8d9000e4fc2b066edb91afee8e7eb0f24e3a201db8b6793c0608581e628ed0bcc4e5aa6787992a4bcc44e288093e63ee83abd0bc3ec6d0934a674a4da13838a",
"ce325e294f9b6719d6b61278276ae06a2564c03bb0b783fafe785bdf89c7d5acd83e78756d301b445699024eaeb77b54d477336ec2a4f332f2b3f88765ddb0c3",
"29acc30e9603ae2fccf90bf97e6cc463ebe28c1b2f9b4b765e70537c25c702a29dcbfbf14c99c54345ba2b51f17b77b5f15db92bbad8fa95c471f5d070a137cc",
"3379cbaae562a87b4c0425550ffdd6bfe1203f0d666cc7ea095be407a5dfe61ee91441cd5154b3e53b4f5fb31ad4c7a9ad5c7af4ae679aa51a54003a54ca6b2d",
"3095a349d245708c7cf550118703d7302c27b60af5d4e67fc978f8a4e60953c7a04f92fcf41aee64321ccb707a895851552b1e37b00bc5e6b72fa5bcef9e3fff",
"07262d738b09321f4dbccec4bb26f48cb0f0ed246ce0b31b9a6e7bc683049f1f3e5545f28ce932dd985c5ab0f43bd6de0770560af329065ed2e49d34624c2cbb",
"b6405eca8ee3316c87061cc6ec18dba53e6c250c63ba1f3bae9e55dd3498036af08cd272aa24d713c6020d77ab2f3919af1a32f307420618ab97e73953994fb4",
"7ee682f63148ee45f6e5315da81e5c6e557c2c34641fc509c7a5701088c38a74756168e2cd8d351e88fd1a451f360a01f5b2580f9b5a2e8cfc138f3dd59a3ffc",
"1d263c179d6b268f6fa016f3a4f29e943891125ed8593c81256059f5a7b44af2dcb2030d175c00e62ecaf7ee96682aa07ab20a611024a28532b1c25b86657902",
"106d132cbdb4cd2597812846e2bc1bf732fec5f0a5f65dbb39ec4e6dc64ab2ce6d24630d0f15a805c3540025d84afa98e36703c3dbee713e72dde8465bc1be7e",
"0e79968226650667a8d862ea8da4891af56a4e3a8b6d1750e394f0dea76d640d85077bcec2cc86886e506751b4f6a5838f7f0b5fef765d9dc90dcdcbaf079f08",
"521156a82ab0c4e566e5844d5e31ad9aaf144bbd5a464fdca34dbd5717e8ff711d3ffebbfa085d67fe996a34f6d3e4e60b1396bf4b1610c263bdbb834d560816",
"1aba88befc55bc25efbce02db8b9933e46f57661baeabeb21cc2574d2a518a3cba5dc5a38e49713440b25f9c744e75f6b85c9d8f4681f676160f6105357b8406",
"5a9949fcb2c473cda968ac1b5d08566dc2d816d960f57e63b898fa701cf8ebd3f59b124d95bfbbedc5f1cf0e17d5eaed0c02c50b69d8a402cabcca4433b51fd4",
"b0cead09807c672af2eb2b0f06dde46cf5370e15a4096b1a7d7cbb36ec31c205fbefca00b7a4162fa89fb4fb3eb78d79770c23f44e7206664ce3cd931c291e5d",
"bb6664931ec97044e45b2ae420ae1c551a8874bc937d08e969399c3964ebdba8346cdd5d09caafe4c28ba7ec788191ceca65ddd6f95f18583e040d0f30d0364d",
"65bc770a5faa3792369803683e844b0be7ee96f29f6d6a35568006bd5590f9a4ef639b7a8061c7b0424b66b60ac34af3119905f33a9d8c3ae18382ca9b689900",
"ea9b4dca333336aaf839a45c6eaa48b8cb4c7ddabffea4f643d6357ea6628a480a5b45f2b052c1b07d1fedca918b6f1139d80f74c24510dcbaa4be70eacc1b06",
"e6342fb4a780ad975d0e24bce149989b91d360557e87994f6b457b895575cc02d0c15bad3ce7577f4c63927ff13f3e381ff7e72bdbe745324844a9d27e3f1c01",
"3e209c9b33e8e461178ab46b1c64b49a07fb745f1c8bc95fbfb94c6b87c69516651b264ef980937fad41238b91ddc011a5dd777c7efd4494b4b6ecd3a9c22ac0",
"fd6a3d5b1875d80486d6e69694a56dbb04a99a4d051f15db2689776ba1c4882e6d462a603b7015dc9f4b7450f05394303b8652cfb404a266962c41bae6e18a94",
"951e27517e6bad9e4195fc8671dee3e7e9be69cee1422cb9fecfce0dba875f7b310b93ee3a3d558f941f635f668ff832d2c1d033c5e2f0997e4c66f147344e02",
"8eba2f874f1ae84041903c7c4253c82292530fc8509550bfdc34c95c7e2889d5650b0ad8cb988e5c4894cb87fbfbb19612ea93ccc4c5cad17158b9763464b492",
"16f712eaa1b7c6354719a8e7dbdfaf55e4063a4d277d947550019b38dfb564830911057d50506136e2394c3b28945cc964967d54e3000c2181626cfb9b73efd2",
"c39639e7d5c7fb8cdd0fd3e6a52096039437122f21c78f1679cea9d78a734c56ecbeb28654b4f18e342c331f6f7229ec4b4bc281b2d80a6eb50043f31796c88c",
"72d081af99f8a173dcc9a0ac4eb3557405639a29084b54a40172912a2f8a395129d5536f0918e902f9e8fa6000995f4168ddc5f893011be6a0dbc9b8a1a3f5bb",
"c11aa81e5efd24d5fc27ee586cfd8847fbb0e27601ccece5ecca0198e3c7765393bb74457c7e7a27eb9170350e1fb53857177506be3e762cc0f14d8c3afe9077",
"c28f2150b452e6c0c424bcde6f8d72007f9310fed7f2f87de0dbb64f4479d6c1441ba66f44b2accee61609177ed340128b407ecec7c64bbe50d63d22d8627727",
"f63d88122877ec30b8c8b00d22e89000a966426112bd44166e2f525b769ccbe9b286d437a0129130dde1a86c43e04bedb594e671d98283afe64ce331de9828fd",
"348b0532880b88a6614a8d7408c3f913357fbb60e995c60205be9139e74998aede7f4581e42f6b52698f7fa1219708c14498067fd1e09502de83a77dd281150c",
"5133dc8bef725359dff59792d85eaf75b7e1dcd1978b01c35b1b85fcebc63388ad99a17b6346a217dc1a9622ebd122ecf6913c4d31a6b52a695b86af00d741a0",
"2753c4c0e98ecad806e88780ec27fccd0f5c1ab547f9e4bf1659d192c23aa2cc971b58b6802580baef8adc3b776ef7086b2545c2987f348ee3719cdef258c403",
"b1663573ce4b9d8caefc865012f3e39714b9898a5da6ce17c25a6a47931a9ddb9bbe98adaa553beed436e89578455416c2a52a525cf2862b8d1d49a2531b7391",
"64f58bd6bfc856f5e873b2a2956ea0eda0d6db0da39c8c7fc67c9f9feefcff3072cdf9e6ea37f69a44f0c61aa0da3693c2db5b54960c0281a088151db42b11e8",
"0764c7be28125d9065c4b98a69d60aede703547c66a12e17e1c618994132f5ef82482c1e3fe3146cc65376cc109f0138ed9a80e49f1f3c7d610d2f2432f20605",
"f748784398a2ff03ebeb07e155e66116a839741a336e32da71ec696001f0ad1b25cd48c69cfca7265eca1dd71904a0ce748ac4124f3571076dfa7116a9cf00e9",
"3f0dbc0186bceb6b785ba78d2a2a013c910be157bdaffae81bb6663b1a73722f7f1228795f3ecada87cf6ef0078474af73f31eca0cc200ed975b6893f761cb6d",
"d4762cd4599876ca75b2b8fe249944dbd27ace741fdab93616cbc6e425460feb51d4e7adcc38180e7fc47c89024a7f56191adb878dfde4ead62223f5a2610efe",
"cd36b3d5b4c91b90fcbba79513cfee1907d8645a162afd0cd4cf4192d4a5f4c892183a8eacdb2b6b6a9d9aa8c11ac1b261b380dbee24ca468f1bfd043c58eefe",
"98593452281661a53c48a9d8cd790826c1a1ce567738053d0bee4a91a3d5bd92eefdbabebe3204f2031ca5f781bda99ef5d8ae56e5b04a9e1ecd21b0eb05d3e1",
"771f57dd2775ccdab55921d3e8e30ccf484d61fe1c1b9c2ae819d0fb2a12fab9be70c4a7a138da84e8280435daade5bbe66af0836a154f817fb17f3397e725a3",
"c60897c6f828e21f16fbb5f15b323f87b6c8955eabf1d38061f707f608abdd993fac3070633e286cf8339ce295dd352df4b4b40b2f29da1dd50b3a05d079e6bb",
"8210cd2c2d3b135c2cf07fa0d1433cd771f325d075c6469d9c7f1ba0943cd4ab09808cabf4acb9ce5bb88b498929b4b847f681ad2c490d042db2aec94214b06b",
"1d4edfffd8fd80f7e4107840fa3aa31e32598491e4af7013c197a65b7f36dd3ac4b478456111cd4309d9243510782fa31b7c4c95fa951520d020eb7e5c36e4ef",
"af8e6e91fab46ce4873e1a50a8ef448cc29121f7f74deef34a71ef89cc00d9274bc6c2454bbb3230d8b2ec94c62b1dec85f3593bfa30ea6f7a44d7c09465a253",
"29fd384ed4906f2d13aa9fe7af905990938bed807f1832454a372ab412eea1f5625a1fcc9ac8343b7c67c5aba6e0b1cc4644654913692c6b39eb9187ceacd3ec",
"a268c7885d9874a51c44dffed8ea53e94f78456e0b2ed99ff5a3924760813826d960a15edbedbb5de5226ba4b074e71b05c55b9756bb79e55c02754c2c7b6c8a",
"0cf8545488d56a86817cd7ecb10f7116b7ea530a45b6ea497b6c72c997e09e3d0da8698f46bb006fc977c2cd3d1177463ac9057fdd1662c85d0c126443c10473",
"b39614268fdd8781515e2cfebf89b4d5402bab10c226e6344e6b9ae000fb0d6c79cb2f3ec80e80eaeb1980d2f8698916bd2e9f747236655116649cd3ca23a837",
"74bef092fc6f1e5dba3663a3fb003b2a5ba257496536d99f62b9d73f8f9eb3ce9ff3eec709eb883655ec9eb896b9128f2afc89cf7d1ab58a72f4a3bf034d2b4a",
"3a988d38d75611f3ef38b8774980b33e573b6c57bee0469ba5eed9b44f29945e7347967fba2c162e1c3be7f310f2f75ee2381e7bfd6b3f0baea8d95dfb1dafb1",
"58aedfce6f67ddc85a28c992f1c0bd0969f041e66f1ee88020a125cbfcfebcd61709c9c4eba192c15e69f020d462486019fa8dea0cd7a42921a19d2fe546d43d",
"9347bd291473e6b4e368437b8e561e065f649a6d8ada479ad09b1999a8f26b91cf6120fd3bfe014e83f23acfa4c0ad7b3712b2c3c0733270663112ccd9285cd9",
"b32163e7c5dbb5f51fdc11d2eac875efbbcb7e7699090a7e7ff8a8d50795af5d74d9ff98543ef8cdf89ac13d0485278756e0ef00c817745661e1d59fe38e7537",
"1085d78307b1c4b008c57a2e7e5b234658a0a82e4ff1e4aaac72b312fda0fe27d233bc5b10e9cc17fdc7697b540c7d95eb215a19a1a0e20e1abfa126efd568c7",
"4e5c734c7dde011d83eac2b7347b373594f92d7091b9ca34cb9c6f39bdf5a8d2f134379e16d822f6522170ccf2ddd55c84b9e6c64fc927ac4cf8dfb2a17701f2",
"695d83bd990a1117b3d0ce06cc888027d12a054c2677fd82f0d4fbfc93575523e7991a5e35a3752e9b70ce62992e268a877744cdd435f5f130869c9a2074b338",
"a6213743568e3b3158b9184301f3690847554c68457cb40fc9a4b8cfd8d4a118c301a07737aeda0f929c68913c5f51c80394f53bff1c3e83b2e40ca97eba9e15",
"d444bfa2362a96df213d070e33fa841f51334e4e76866b8139e8af3bb3398be2dfaddcbc56b9146de9f68118dc5829e74b0c28d7711907b121f9161cb92b69a9",
"142709d62e28fcccd0af97fad0f8465b971e82201dc51070faa0372aa43e92484be1c1e73ba10906d5d1853db6a4106e0a7bf9800d373d6dee2d46d62ef2a461",
}
var hashes2X = []string{
"64",
"f457",
"e8c045",
"a74c6d0d",
"eb02ae482a",
"be65b981275e",
"8540ccd083a455",
"074a02fa58d7c7c0",
"da6da05e10db3022b6",
"542a5aae2f28f2c3b68c",
"ca3af2afc4afe891da78b1",
"e0f66b8dcebf4edc85f12c85",
"744224d383733b3fa2c53bfcf5",
"b09b653e85b72ef5cdf8fcfa95f3",
"dd51877f31f1cf7b9f68bbb09064a3",
"f5ebf68e7ebed6ad445ffc0c47e82650",
"ebdcfe03bcb7e21a9091202c5938c0a1bb",
"860fa5a72ff92efafc48a89df1632a4e2809",
"0d6d49daa26ae2818041108df3ce0a4db48c8d",
"e5d7e1bc5715f5ae991e4043e39533af5d53e47f",
"5232028a43b9d4dfa7f37439b49495926481ab8a29",
"c118803c922f9ae2397fb676a2ab7603dd9c29c21fe4",
"2af924f48b9bd7076bfd68794bba6402e2a7ae048de3ea",
"61255ac38231087c79ea1a0fa14538c26be1c851b6f318c0",
"f9712b8e42f0532162822f142cb946c40369f2f0e77b6b186e",
"76da0b89558df66f9b1e66a61d1e795b178ce77a359087793ff2",
"9036fd1eb32061bdecebc4a32aa524b343b8098a16768ee774d93c",
"f4ce5a05934e125d159678bea521f585574bcf9572629f155f63efcc",
"5e1c0d9fae56393445d3024d6b82692d1339f7b5936f68b062c691d3bf",
"538e35f3e11111d7c4bab69f83b30ade4f67addf1f45cdd2ac74bf299509",
"17572c4dcbb17faf8785f3bba9f6903895394352eae79b01ebd758377694cc",
"29f6bb55de7f8868e053176c878c9fe6c2055c4c5413b51ab0386c277fdbac75",
"bad026c8b2bd3d294907f2280a7145253ec2117d76e3800357be6d431b16366e41",
"386b7cb6e0fd4b27783125cbe80065af8eb9981fafc3ed18d8120863d972fa7427d9",
"06e8e6e26e756fff0b83b226dce974c21f970e44fb5b3e5bbada6e4b12f81cca666f48",
"2f9bd300244f5bc093ba6dcdb4a89fa29da22b1de9d2c9762af919b5fedf6998fbda305b",
"cf6bdcc46d788074511f9e8f0a4b86704365b2d3f98340b8db53920c385b959a38c8869ae7",
"1171e603e5cdeb4cda8fd7890222dd8390ede87b6f3284cac0f0d832d8250c9200715af7913d",
"bda7b2ad5d02bd35ffb009bdd72b7d7bc9c28b3a32f32b0ba31d6cbd3ee87c60b7b98c03404621",
"2001455324e748503aa08eff2fb2e52ae0170e81a6e9368ada054a36ca340fb779393fb045ac72b3",
"45f0761aefafbf87a68f9f1f801148d9bba52616ad5ee8e8ac9207e9846a782f487d5cca8b20355a18",
"3a7e05708be62f087f17b41ac9f20e4ef8115c5ab6d08e84d46af8c273fb46d3ce1aabebae5eea14e018",
"ea318da9d042ca337ccdfb2bee3e96ecb8f907876c8d143e8e44569178353c2e593e4a82c265931ba1dd79",
"e0f7c08f5bd712f87094b04528fadb283d83c9ceb82a3e39ec31c19a42a1a1c3bee5613b5640abe069b0d690",
"d35e63fb1f3f52ab8f7c6cd7c8247e9799042e53922fbaea808ab979fa0c096588cfea3009181d2f93002dfc11",
"b8b0ab69e3ae55a8699eb481dd665b6a2424c89bc6b7cca02d15fdf1b9854139cab49d34de498b50b2c7e8b910cf",
"fb65e3222a2950eae1701d4cdd4736266f65bf2c0d2e77968996eadb60ef74fb786f6234973a2524bdfe32d100aa0e",
"f28b4bb3a2e2c4d5c01a23ff134558559a2d3d704b75402983ee4e0f71d273ae056842c4153b18ee5c47e2bfa54313d4",
"7bb78794e58a53c3e4b1aeb161e756af051583d14e0a5a3205e094b7c9a8cf62d098fa9ea1db12f330a51ab9852c17f983",
"a879a8ebae4d0987789bcc58ec3448e35ba1fa1ee58c668d8295aba4eaeaf2762b053a677e25404f635a53037996974d418a",
"695865b353ec701ecc1cb38f3154489eed0d39829fc192bb68db286d20fa0a64235cde5639137819f7e99f86bd89afcef84a0f",
"a6ec25f369f71176952fb9b33305dc768589a6070463ee4c35996e1ced4964a865a5c3dc8f0d809eab71366450de702318e4834d",
"604749f7bfadb069a036409ffac5ba291fa05be8cba2f141554132f56d9bcb88d1ce12f2004cd3ade1aa66a26e6ef64e327514096d",
"daf9fa7dc2464a899533594e7916fc9bc585bd29dd60c930f3bfa78bc47f6c8439448043a45119fc9228c15bce5fd24f46baf9de736b",
"943ea5647a8666763084da6a6f15dcf0e8dc24f27fd0d9194805d25180fe3a6d98f4b2b5e0d6a04e9b41869817030f16ae975dd41fc35c",
"af4f73cbfc093760dfeb52d57ef45207bbd1a515f5523404e5d95a73c237d97ae65bd195b472de6d514c2c448b12fafc282166da132258e9",
"605f4ed72ed7f5046a342fe4cf6808100d4632e610d59f7ebb016e367d0ff0a95cf45b02c727ba71f147e95212f52046804d376c918cadd260",
"3750d8ab0a6b13f78e51d321dfd1aa801680e958de45b7b977d05732ee39f856b27cb2bcce8fbf3db6666d35e21244c2881fdcc27fbfea6b1672",
"8f1b929e80ab752b58abe9731b7b34eb61369536995abef1c0980d93903c1880da3637d367456895f0cb4769d6de3a979e38ed6f5f6ac4d48e9b32",
"d8469b7aa538b36cdc711a591d60dafecca22bd421973a70e2deef72f69d8014a6f0064eabfbebf5383cbb90f452c6e113d2110e4b1092c54a38b857",
"7d1f1ad2029f4880e1898af8289c23bc933a40863cc4ab697fead79c58b6b8e25b68cf5324579b0fe879fe7a12e6d03907f0140dfe7b29d33d6109ecf1",
"87a77aca6d551642288a0dff66078225ae39d288801607429d6725ca949eed7a6f199dd8a65523b4ee7cfa4187400e96597bfffc3e38ade0ae0ab88536a9",
"e101f43179d8e8546e5ce6a96d7556b7e6b9d4a7d00e7aade5579d085d527ce34a9329551ebcaf6ba946949bbe38e30a62ae344c1950b4bde55306b3bac432",
"4324561d76c370ef35ac36a4adf8f3773a50d86504bd284f71f7ce9e2bc4c1f1d34a7fb2d67561d101955d448b67577eb30dfee96a95c7f921ef53e20be8bc44",
"78f0ed6e220b3da3cc9381563b2f72c8dc830cb0f39a48c6ae479a6a78dcfa94002631dec467e9e9b47cc8f0887eb680e340aec3ec009d4a33d241533c76c8ca8c",
"9f6589c31a472e0a736f4eb22b6c70a9d332cc15304ccb66a6b97cd051b6ed82f8990e1d9bee2e4bb1c3c45e550ae0e7b96e93ae23f2fb8f63b309131e72b36cba6a",
"c138077ee4ed3d7ffa85ba851dfdf6e9843fc1dc00889d117237bfaad9aa757192f73556b959f98e6d24886ce48869f2a01a48c371785f12b6484eb2078f08c22066e1",
"f83e7c9e0954a500576ea1fc90a3db2cbd7994eaef647dab5b34e88ab9dc0b47addbc807b21c8e6dd3d0bd357f008471d4f3e0abb18450e1d4919e03a34545b9643f870e",
"3277a11f2628544fc66f50428f1ad56bcba6ee36ba2ca6ecdf7e255effc0c30235c039d13e01f04cf1efe95b5c2033ab72adda30994b62f2851d17c9920eadca9a251752dc",
"c2a834281a06fe7b730d3a03f90761daf02714c066e33fc07e1f59ac801ec2f4433486b5a2da8faa51a0cf3c34e29b2960cd0013378938dbd47c3a3d12d70db01d7d06c3e91e",
"47680182924a51cabe142a6175c9253e8ba7ea579ece8d9bcb78b1e9ca00db844fa08abcf41702bd758ee2c608d9612fed50e85854469cb4ef3038acf1e35b6ba4390561d8ae82",
"cec45830cd71869e83b109a99a3cd7d935f83a95de7c582f3adbd34e4938fa2f3f922f52f14f169c38cc6618d3f306a8a4d607b345b8a9c48017136fbf825aecf7b620e85f837fae",
"46fb53c70ab105079d5d78dc60eaa30d938f26e4d0b9df122e21ec85deda94744c1daf8038b8a6652d1ff3e7e15376f5abd30e564784a999f665078340d66b0e939e0c2ef03f9c08bb",
"7b0dcb52791a170cc52f2e8b95d8956f325c3751d3ef3b2b83b41d82d4496b46228a750d02b71a96012e56b0720949ca77dc68be9b1ef1ad6d6a5ceb86bf565cb972279039e209dddcdc",
"7153fd43e6b05f5e1a4401e0fef954a737ed142ec2f60bc4daeef9ce73ea1b40a0fcaf1a1e03a3513f930dd5335723632f59f7297fe3a98b68e125eadf478eb045ed9fc4ee566d13f537f5",
"c7f569c79c801dab50e9d9ca6542f25774b3841e49c83efe0b89109f569509ce7887bc0d2b57b50320eb81fab9017f16c4c870e59edb6c26620d93748500231d70a36f48a7c60747ca2d5986",
"0a81e0c547648595adca65623ce783411aac7f7d30c3ad269efafab288e7186f6895261972f5137877669c550f34f5128850ebb50e1884814ea1055ee29a866afd04b2087abed02d9592573428",
"6a7b6769e1f1c95314b0c7fe77013567891bd23416374f23e4f43e27bc4c55cfada13b53b1581948e07fb96a50676baa2756db0988077b0f27d36ac088e0ff0fe72eda1e8eb4b8facff3218d9af0",
"a399474595cb1ccab6107f18e80f03b1707745c7bf769fc9f260094dc9f8bc6fe09271cb0b131ebb2acd073de4a6521c8368e664278be86be216d1622393f23435fae4fbc6a2e7c961282a777c2d75",
"4f0fc590b2755a515ae6b46e9628092369d9c8e589e3239320639aa8f7aa44f8111c7c4b3fdbe6e55e036fbf5ebc9c0aa87a4e66851c11e86f6cbf0bd9eb1c98a378c7a7d3af900f55ee108b59bc9e5c",
"ed96a046f08dd675107331d267379c6fce3c352a9f8d7b243008a74cb4e9410836afaabe871dab6038ca94ce5f6d41fa922ce08aba58169f94cfc86d9f688f396abd24c11a6a9b0830572105a477c33e92",
"379955f539abf0eb2972ee99ed9546c4bbee363403991833005dc27904c271ef22a799bc32cb39f08d2e4ba6717d55153feb692d7c5efae70890bf29d96df02333c7b05ccc314e4835b018fec9141a82c745",
"e16cc8d41b96547ede0d0cf4d908c5fa393399daa4a9696e76a4c1f6a2a9fef70f17fb53551a8145ed88f18db8fe780a079d94732437023f7c1d1849ef69ad536a76204239e8ba5d97e507c36c7d042f87fe0e",
"a81de50750ece3f84536728f227208bf01ec5b7721579d007de72c88ee20663318332efe5bc7c09ad1fa8342be51f0609046ccf760a7957a7d8dc88941adb93666a4521ebe76618e5ddc2dd3261493d400b50073",
"b72c5fb7c7f60d243928fa41a2d711157b96aef290185c64b4de3dcfa3d644da67a8f37c2ac55caad79ec695a473e8b481f658c497edb8a191526592b11a412282d2a4010c90ef4647bd6ce745ebc9244a71d4876b",
"9550703877079c90e200e830f277b605624954c549e729c359ee01ee2b07741ecc4255cb37f96682dafcdbaade1063e2c5ccbd1918fb669926a67744101fb6de3ac016be4c74165a1e5a696b704ba2ebf4a953d44b95",
"a17eb44d4de502dc04a80d5a5e9507d17f27c96467f24c79b06bc98a4c410741d4ac2db98ec02c2a976d788531f1a4451b6c6204cef6dae1b6ebbcd0bde23e6fffb02754043c8fd3c783d90a670b16879ce68b5554fe1c",
"41d3ea1eaba5be4a206732dbb5b70b79b66a6e5908795ad4fb7cf9e67efb13f06fef8f90acb080ce082aadec6a1b543af759ab63fa6f1d3941186482b0c2b312f1151ea8386253a13ed3708093279b8eb04185636488b226",
"5e7cdd8373dc42a243c96013cd29df9283b5f28bb50453a903c85e2ce57f35861bf93f03029072b70dac0804e7d51fd0c578c8d9fa619f1e9ce3d8044f65d55634dba611280c1d5cfb59c836a595c803124f696b07ddfac718",
"26a14c4aa168907cb5de0d12a82e1373a128fb21f2ed11feba108b1bebce934ad63ed89f4ed7ea5e0bc8846e4fc10142f82de0bebd39d68f7874f615c3a9c896bab34190e85df05aaa316e14820b5e478d838fa89dfc94a7fc1e",
"0211dfc3c35881adc170e4ba6daab1b702dff88933db9a6829a76b8f4a7c2a6d658117132a974f0a0b3a38ceea1efc2488da21905345909e1d859921dc2b5054f09bce8eeb91fa2fc6d048ce00b9cd655e6aafbdaa3a2f19270a16",
"ddf015b01b68c4f5f72c3145d54049867d99ee6bef24282abf0eecdb506e295bacf8f23ffa65a4cd891f76a046b9dd82cae43a8d01e18a8dff3b50aeb92672be69d7c087ec1fa2d3b2a39196ea5b49b7baede37a586fea71aded587f",
"6ee721f71ca4dd5c9ce7873c5c04c6ce76a2c824b984251c15535afc96adc9a4d48ca314bfeb6b8ee65092f14cf2a7ca9614e1dcf24c2a7f0f0c11207d3d8aed4af92873b56e8b9ba2fbd659c3f4ca90fa24f113f74a37181bf0fdf758",
"689bd150e65ac123612524f720f54def78c095eaab8a87b8bcc72b443408e3227f5c8e2bd5af9bcac684d497bc3e41b7a022c28fb5458b95e8dfa2e8caccde0492936ff1902476bb7b4ef2125b19aca2cd3384d922d9f36dddbcd96ae0d6",
"3a3c0ef066fa4390ec76ad6be1dc9c31ddf45fef43fbfa1f49b439caa2eb9f3042253a9853e96a9cf86b4f873785a5d2c5d3b05f6501bc876e09031188e05f48937bf3c9b667d14800db62437590b84ce96aa70bb5141ee2ea41b55a6fd944",
"741ce384e5e0edaebb136701ce38b3d33215415197758ae81235307a4115777d4dab23891db530c6d28f63a957428391421f742789a0e04c99c828373d9903b64dd57f26b3a38b67df829ae243feef731ead0abfca049924667fdec49d40f665",
"a513f450d66cd5a48a115aee862c65b26e836f35a5eb6894a80519e2cd96cc4cad8ed7eb922b4fc9bbc55c973089d627b1da9c3a95f6c019ef1d47143cc545b15e4244424be28199c51a5efc7234dcd94e72d229897c392af85f523c2633427825",
"71f1554d2d49bb7bd9e62e71fa049fb54a2c097032f61ebda669b3e1d4593962e47fc62a0ab5d85706aebd6a2f9a192c88aa1ee2f6a46710cf4af6d3c25b7e68ad5c3db23ac009c8f13625ff85dc8e50a9a1b2682d3329330b973ec8cbb7bb73b2bd",
"167cc1067bc08a8d2c1a0c10041ebe1fc327b37043f6bd8f1c63569e9d36ded58519e66b162f34b6d8f1107ef1e3de199d97b36b44141a1fc4f49b883f40507ff11f909a017869dc8a2357fc7336ae68703d25f75710b0ff5f9765321c0fa53a51675c",
"cb859b35dc70e264efaad2a809fea1e71cd4a3f924be3b5a13f8687a1166b538c40b2ad51d5c3e47b0de482497382673140f547068ff0b3b0fb7501209e1bf36082509ae85f60bb98fd02ac50d883a1a8daa704952d83c1f6da60c9624bc7c99912930bf",
"afb1f0c6b7125b04fa2578dd40f60cb411b35ebc7026c702e25b3f0ae3d4695d44cfdf37cb755691dd9c365edadf21ee44245620e6a24d4c2497135b37cd7ac67e3bd0aaee9f63f107746f9b88859ea902bc7d6895406aa2161f480cad56327d0a5bba2836",
"13e9c0522587460d90c7cb354604de8f1bf850e75b4b176bda92862d35ec810861f7d5e7ff6ba9302f2c2c8642ff8b7776a2f53665790f570fcef3cac069a90d50db42227331c4affb33d6c040d75b9aeafc9086eb83ced38bb02c759e95ba08c92b17031288",
"0549812d62d3ed497307673a4806a21060987a4dbbf43d352b9b170a29240954cf04bc3e1e250476e6800b79e843a8bd8253b7d743de01ab336e978d4bea384eaff700ce020691647411b10a60acacb6f8837fb08ad666b8dcc9eaa87ccb42aef6914a3f3bc30a",
"3a263efbe1f2d463f20526e1d0fd735035fd3f808925f058b32c4d8788aeeab9b8ce233b3c34894731cd73361f465bd350395aebcabd2fb63010298ca025d849c1fa3cd573309b74d7f824bbfe383f09db24bcc565f636b877333206a6ad70815c3bef5574c5fc1c",
"3c6a7d8a84ef7e3eaa812fc1eb8e85105467230d2c9e4562edbfd808f4d1ac15d16b786cc6a02959c2bc17149c2ce74c6f85ee5ef22a8a96b9be1f197cffd214c1ab02a06a9227f37cd432579f8c28ff2b5ac91cca8ffe6240932739d56788c354e92c591e1dd76499",
"b571859294b02af17541a0b5e899a5f67d6f5e36d38255bc417486e69240db56b09cf2607fbf4f95d085a779358a8a8b41f36503438c1860c8f361ce0f2783a08b21bd7232b50ca6d35428335272a5c05b436b2631d8d5c84d60e8040083768ce56a250727fb0579dd5c",
"98ee1b7269d2a0dd490ca38d447279870ea55326571a1b430adbb2cf65c492131136f504145df3ab113a13abfb72c33663266b8bc9c458db4bf5d7ef03e1d3b8a99d5de0c024be8fabc8dc4f5dac82a0342d8ed65c329e7018d6997e69e29a01350516c86beaf153da65ac",
"41c5c95f088df320d35269e5bf86d10248f17aec6776f0fe653f1c356aae409788c938befeb67c86d1c8870e8099ca0ce61a80fbb5a6654c44529368f70fc9b9c2f912f5092047d0ffc339577d24142300e34948e086f62e23ecaca410d24f8a36b5c8c5a80e0926bc8aa16a",
"9f93c41f533b2a82a4df893c78faaaa793c1506974ba2a604cd33101713ca4adfd30819ffd8403402b8d40aff78106f3357f3e2c24312c0d3603a17184d7b999fc9908d14d50192aebabd90d05073da7af4be37dd3d81c90acc80e8333df546f17ab6874f1ec204392d1c0571e",
"3da5207245ac270a915fc91cdb314e5a2577c4f8e269c4e701f0d7493ba716de79935918b917a2bd5db98050dbd1eb3894b65fac5abf13e075abebc011e651c03cafb6127147771a5c8418223e1548137a89206635c26ca9c235ccc108dc25cf846e4732444bd0c2782b197b262b",
"96011af3965bb941dc8f749932ea484eccb9ba94e34b39f24c1e80410f96ce1d4f6e0aa5be606def4f54301e930493d4b55d484d93ab9dd4dc2c9cfb79345363af31ad42f4bd1aa6c77b8afc9f0d551bef7570b13b927afe3e7ac4de7603a0876d5edb1ad9be05e9ee8b53941e8f59",
"51dbbf2a7ca224e524e3454fe82ddc901fafd2120fa8603bc343f129484e9600f688586e040566de0351d1693829045232d04ff31aa6b80125c763faab2a9b233313d931903dcfaba490538b06e4688a35886dc24cdd32a13875e6acf45454a8eb8a315ab95e608ad8b6a49aef0e299a",
"5a6a422529e22104681e8b18d64bc0463a45df19ae2633751c7aae412c250f8fb2cd5e1270d3d0cf009c8aa69688ccd4e2b6536f5747a5bc479b20c135bf4e89d33a26118705a614c6be7ecfe766932471ad4ba01c4f045b1abb5070f90ec78439a27a1788db9327d1c32f939e5fb1d5ba",
"5d26c983642093cb12ff0afabd87b7c56e211d01844ad6da3f623b9f20a0c968034299f2a65e6673530c5980a532beb831c7d0697d12760445986681076dfb6fae5f3a4d8f17a0db5008ce8619f566d2cfe4cf2a6d6f9c3664e3a48564a351c0b3c945c5ee24587521e4112c57e318be1b6a",
"52641dbc6e36be4d905d8d60311e303e8e859cc47901ce30d6f67f152343e3c4030e3a33463793c19effd81fb7c4d631a9479a7505a983a052b1e948ce093b30efa595fab3a00f4cef9a2f664ceeb07ec61719212d58966bca9f00a7d7a8cb4024cf6476bab7fbccee5fd4e7c3f5e2b2975aa2",
"a34ce135b37bf3db1c4aaa4878b4499bd2ee17b85578fcaf605d41e1826b45fdaa1b083d8235dc642787f11469a5493e36806504fe2a2063905e821475e2d5ee217057950370492f5024995e77b82aa51b4f5bd8ea24dc71e0a8a640b0592c0d80c24a726169cf0a10b40944747113d03b52708c",
"46b3cdf4946e15a5334fc3244d6680f5fc132afa67bf43bfade23d0c9e0ec64e7dab76faaeca1870c05f96b7d019411d8b0873d9fed04fa5057c039d5949a4d592827f619471359d6171691cfa8a5d7cb07ef2804f6ccad4821c56d4988bea7765f660f09ef87405f0a80bcf8559efa111f2a0b419",
"8b9fc21691477f11252fca050b121c5334eb4280aa11659e267297de1fec2b2294c7ccee9b59a149b9930b08bd320d3943130930a7d931b71d2f10234f4480c67f1de883d9894ada5ed5071660e221d78ae402f1f05af47761e13fec979f2671e3c63fb0ae7aa1327cf9b8313adab90794a52686bbc4",
"cd6598924ce847de7ff45b20ac940aa6292a8a99b56a74eddc24f2cfb45797188614a21d4e8867e23ff75afd7cd324248d58fcf1ddc73fbd115dfa8c09e62022fab540a59f87c989c12a86ded05130939f00cd2f3b512963dfe0289f0e54acad881c1027d2a0292138fdee902d67d9669c0ca1034a9456",
"594e1cd7337248704e691854af0fdb021067ddf7832b049ba7b684438c32b029eded2df2c89a6ff5f2f2c311522ae2dc6db5a815afc60637b15ec24ef9541f1550409db2a006da3affffe548a1eaee7bd114e9b805d0756c8e90c4dc33cb05226bc2b393b18d953f8730d4c7ae693159cdba758ad28964e2",
"1f0d292453f04406ada8be4c161b82e3cdd69099a8637659e0ee40b8f6da46005cfc6085db9804852decfbe9f7b4dda019a7112612895a144ed430a960c8b2f5458d3d56b7f427cee6358915aee7146278aed2a0296cdd929e4d21ef95a3adf8b7a6beba673cdccdbdcfb2474711732d972ad054b2dc64f38d",
"b65a72d4e1f9f9f75911cc46ad0806b9b18c87d105332a3fe183f45f063a746c892dc6c4b9181b1485b3e3a2cc3b453eba2d4c39d6905a774ed3fb755468beb190925ecd8e57ecb0d985125741650c6b6a1b2a3a50e93e3892c21d47ed5884eed83aa94e1602288f2f49fe286624de9d01fcb54433a0dc4ad70b",
"705ce0ffa469250782aff725248fc88fe98eb76659e8407edc1c4842c9867d61fe64fb86f74e980598b92bc213d06f337bd5654fc28643c7ba769a4c31563427543c00808b627a19c90d86c322f33566ce020121cc322229c3337943d46f68ef939d613dcef0077269f88151d6398b6b009abb763410b154ad76a3",
"7fa881ce87498440ab6af13854f0d851a7e0404de33896999a9b3292a5d2f5b3ad033530c558168fe5d2fdb9b89a2354c46cf32a0e612afc6c6485d789511bfef26800c74bf1a4cfbe30bda310d5f6029c3dccdedb6149e4971274e276dccfabd63bc4b9955e8303feb57f8a688db55ecb4b33d1f9fe1b3a8ba7ac32",
"23a98f71c01c0408ae16843dc03be7db0aeaf055f951709d4e0dfdf64fffbffaf900ee592ee10929648e56f6c1e9f5be5793f7df66453eb56502c7c56c0f0c88da77abc8fa371e434104627ef7c663c49f40998dbad63fa6c7aa4fac17ae138d8bbe081f9bd168cd33c1fbc92fa35ed687679f48a64b87db1fe5bae675",
"7b8970b6a33237e5a7bcb39272703edb92285c55842b30b9a48834b1b507cc02a6764739f2f7ee6ae02a7b715a1c455e59e8c77a1ae98abb10161853f1234d20da99016588cd8602d6b7ec7e177d4011edfa61e6b3766a3c6f8d6e9eac893c568903eb6e6aba9c4725774f6b4343b7acaa6c031593a36eef6c72806ff309",
"f7f4d328ba108b7b1de4443e889a985ed52f485f3ca4e0c246aa5526590cbed344e9f4fe53e4eea0e761c82324649206ca8c2b45152157d4115e68c818644b03b65bb47ad79f94d37cb03c1d953b74c2b8adfa0e1c418bda9c518ddcd7050e0f149044740a2b16479413b63fc13c36144f80c73687513dca761ba8642a8ae0",
"2d7dc80c19a1d12d5fe3963569547a5d1d3e821e6f06c5d5e2c09401f946c9f7e13cd019f2f9a878b62dd850453b6294b99ccaa068e542993524b0f63832d48e865be31e8ec1ee103c718340c904b32efb69170b67f038d50a3252794b1b4076c0620621ab3d91215d55ffea99f23d54e161a90d8d4902fda5931d9f6a27146a",
"77dff4c7ad30c954338c4b23639dae4b275086cbe654d401a2343528065e4c9f1f2eca22aa025d49ca823e76fdbb35df78b1e5075ff2c82b680bca385c6d57f7ea7d1030bb392527b25dd73e9eeff97bea397cf3b9dda0c817a9c870ed12c006cc054968c64000e0da874e9b7d7d621b0679866912243ea096c7b38a1344e98f74",
"83bed0d556798f2b419f7056e6d3ffada06e939b95a688d0ec8c6ac5ea45ab73a4cf01043e0a170766e21395f27ab4b78c435f5f0dfe6e93ab80df38610e41158429ddf20296f53a06a017723359fe22dc08b5da33f0800a4fe50118e8d7eab2f83a85cd764bf8a166903bd0e9dcfeeceba44ff4ca4439846458d31ea2bb564645d1",
"ea12cf5a113543e39504123036f15a5bafa9c555562469f99cd29996a4dfaaab2a34b00557ccf15f37fc0cc1b3be427e725f2cd952e50af7970dda9200cd5ce252b1f29c40067fea3027ed686190803b59d834179d1b8f5b55abe55ad174b2a1188f7753ec0ae2fc01316e7d498b68ee3598a0e9baaaa664a60f7fb4f90edbed494ad7",
"55266358332d8d9e68bd13432088beadf95833aab67a0eb3b10650414255f299e2670c3e1a5b2976159a46c72a7ce57d59b7be14c15798e09ed50fa312a431b0264d7a1396aa6168bde897e208ece53d2cfc83786113b1e6eac5e9bb98984abb6c8d64eebb991903254abc650c999bb9958a5d7937434b869bc940e21b9dc1cc8982f2ba",
"4d6104ded730aefe02873f4c741232c8234a6d66d85393aff57fbf56ba6347666988dfc4d58f3cc895a0da598822edeee4533d24ec0ee292fd5e1ad04898ffbc1ff4bef14dec220babcb0f28fffe32a6e2c28aaaac16442bf4feb02917d18bb3a415d84fa9358d5a9852688d846c92271911f934181c30f82434d915f93f155a1ffbf0b125",
"eb5f579a4c476af554aac11e5719d378549497e613b35a929d6f36bb8831d7a466aa76de9be24ebb55543f1c13924f64cfd648a5b3fa90387315c16174dbf1e9a183c196d9bb8f84af65f1f8212429aadc11ef2426d07d4716062b85c8d5d2dff8e21b9e62b7fa7dbd57d72633054b464fb28583a56ca13ccc5ddc74dae942492f31731e7046",
"ebddec3dcaf18063e45a76ebeac39af85a1adc2818881ccce48c106288f5988365cca2b4b1d7f037322da46840f42bebdcbc7193838d426e101087d8cea03aaff743d573eb4f4e9a71a2c884390769a6503874125d194bee8d46a3a0d5e4fcf28ff8465887d8e9df771d70157e75df3642b331d2778ceb32ceba868640171ab7a5d22eede1ee44",
"26d87ec70b57691e3bb359633d3ddba17f029d62cdfe977f5fd42274d79b444a32494d1c01e9f72d03cce78c806df96e93ea78da3a054209924ed765edc4d570f66168dc25ee3114e4017e387440349c8f0a94804761c3055f88e4fda2a49b860b1486a9609095f6250f268b6a4d1aecc03a505632ebf0b9dc22d0755a736faf7ad7000858b5864b",
"3880f5cc2d08fa70ef44b1f263fcf534d062a298c1bd5ee2eee8c3265806c4ce50b004f3a1fc1fa5b024aaac7f528c023c8181f67c6e1c357425dc4d573bd46b93a542afa3a19bdb140a2ce666e1a01f5c4d2dcd681fa9f5839b797813c394738d5ee4971386c12c7c117d17c7bec324b760aa30cda9ab2aa850284ba6fa97946f710f02449d1883c6",
"3317d2f452105dd3f4a96f9257af8285a80be58066b50f6f54bd633749b49f6ab9d57d45652d2ae852a2f6940cd5ec3159dd7f333358b12f502325df38843508faf7e246352d201280babd90b14fbf7722641c3601d0e458474439973c611bb5502fd0eb3078f87124ca7e1a016fcb6cfeff65f6a565985aca7122cfa8c5a11da0cb47797c5132333179",
"f2c5c955d0224e784a46b9125f8fef8a5e1271e145eb08bbbd07ca8e1cfc848cef14fa3b36221ac62006403dbb7f7d77958ccc54a8566c837858b809f3e310ace8ca682515bc655d2a397cab238a663b464d511f02dc5d033dad4cb5e0e519e94a54b62a3896e460ec70e5716b5921bf8396aa86a60123e6287e34570bb01bdc602e113670bf498af2ff10",
"180e275205691a83630cf4b0c7b80e6df8fad6ef1c23ba8013d2f09aef7abade1827f23af230de90676240b4b3b0673f8afdea0327330055041741f65560d90348de696d34ca80dfe8afae582fe4879d4594b80e9408fb53e800e01ca58552b905c365e7f1416e51c080f517d6bbd30e64ae1535d59decdc76c6624d737868f49f2f719da39ba1344d59eab9",
"c517a84e4631a7f65ace170d1e5c2fdb259841535d88da323e68c0883e6af7b041cfe05908815a5a9d1b14fa712c2c16fadcf1ca54d3aa954d411240df331b2aebdfb65aced84d0b8aace56ec0aa7c13ec7d75ca883b6bcf6db74c9e98463c484a8262684f29910373430651f90ecffe18b072170e61ee58de20e2a6ff67b3ab00fccbb80af943f20b56b98107",
"d1a56a5ee990e02b84b5862fde62f69ec07567be2d7ccb769a461c4989d11fdda6c945d942fb8b2da795ed97e43a5b7dbdde7f8fd2ff7154544336d5c50fb7380341e660d4898c7fbc39b2b782f28defac6873523c7c1de8e52c65e4395c686ba483c35a220b0416d46357a063fa4c33fa9c52d5c207a1304ae141c791e62ba6a7374ed922b8dd94079b72b69302",
"4720b88d6bfb1ab43958e26827730d852d9ec30173ebd0fe0d273edcece2e788558984cd9306fe5978086a5cb6d37975755d2a3daeb16f99a8a11544b8247a8b7ed5587afc5bea1daf85dcea5703c5905cf56ae7cc76408ccabb8fcc25cacc5ff456db3f62fa559c45b9c71505eb5073df1f10fc4c9060843f0cd68bbb4e8edfb48d0fd81d9c21e53b28a2aae4f7ba",
"f4639b511db9e092823d47d2947efacbaae0e5b912dec3b284d2350b9262f3a51796a0cd9f8bc5a65879d6578ec24a060e293100c2e12ad82d5b2a0e9d22965858030e7cdf2ab3562bfa8ac084c6e8237aa22f54b94c4e92d69f22169ced6c85a293f5e16bfc326153bf629cdd6393675c6627cd949cd367eef02e0f54779f4d5210197698e4754a5fe490a3a7521c1c",
"3d9e7a860a718565e3670c29079ce80e381969fea91017cfd5952e0d8a4a79bb08e2cd1e26161f30ee03a24891d1bfa8c212861b51618d07429fb48000ff87ef09c6fca526567777e9c076d58a642d5c521b1caa5fb0fb3a4b8982dc14a444732b72b239b8f01fc8ba8ee86b3013b5d3e98a92b2aeaecd4879fca5d5e9e0bd880dbfffa6f96f94f3998812aac6a714f331",
"4d9bf551d7fd531e7482e2ec875c0651b0bcc6caa738f7497befd11e67ae0e036c9d7ae4301cc3c7906f0d0e1ed4738753f414f9b3cd9b8a71176e325c4c74ce020680ecbfb146889597f5b40487e93f974cd866817fb9fb24c7c7c16177e6e120bfe349e83aa82ba40e59e917565788658a2b254f25cf99bc65070b3794cea2259eb10e42bb54852cba3110baa773dcd70c",
"b91f65ab5bc059bfa5b43b6ebae243b1c46826f3da061338b5af02b2da76bb5ebad2b426de3c3134a633499c7c36a120369727cb48a0c6cbab0acecdda137057159aa117a5d687c4286868f561a272e0c18966b2fec3e55d75abea818ce2d339e26adc005c2658493fe06271ad0cc33fcb25065e6a2a286af45a518aee5e2532f81ec9256f93ff2d0d41c9b9a2efdb1a2af899",
"736f6e387acb9acbee026a6080f8a9eb8dbb5d7c54ac7053ce75dd184b2cb7b942e22a3497419ddb3a04cf9e4eb9340a1a6f9474c06ee1dcfc8513979fee1fc4768087617fd424f4d65f54782c787a1d2de6efc81534343e855f20b3f3589027a5436201eee747d45b9b8375e4294d72ab6a52e04dfbb2914db92ee58f134b026527ed52d4f794459e02a43a17b0d51ea69bd7f3",
"9242d3eb31d26d923b99d66954cfade94f25a18912e6356810b63b971ae74bb53bc58b3c01424208ea1e0b1499936daea27e63d904f9ed65fdf69de40780a3027b2e89d94bdf214f585472613ce328f628f4f0d56217dfb53db5f7a07f54c8d71db16e27de7cdb8d23988837b49b65c12f1771d979e8b192c9f4a16b8d9fba917bcf74ce5a82aac2075608ba6c2d485fa59864b9de",
"5da68704f4b592d41f08aca08f62d85e2e2466e5f3be010315d11d113db674c4b98764a509a2f5aacc7ae72c9deff2bcc42810b47f64d429b35745b9efff0b18c58653461e968aaa3c2c7fc455bc5771a8f10cd184be831040df767201ab8d32cb9a58c89afbebecb524502c9b940c1b838f8361bbcde90d272715017f67609ea39b20fac985332d82daaa023999e3f8bfa5f3758bb8",
"71ea2af9c8ac2e5ae44a176662882e01027ca3cdb41ec2c6785606a07d7231cd4a2bded7155c2feef3d44d8fd42afa73265cef826f6e03aa761c5c51d5b1f129ddc27503ff50d9c2d748322df4b13dd5cdc7d46381528ab22b79b0049011e4d2e57fe2735e0d58d8d56e92c75dbeac8c76c4239d7f3f24fb56697593b3e4afa6671d5bbc96c079a1c154fe20212ade67b05d49ceaa7a84",
"1d133170582fa4bff59a21953ebbc01bc202d43cd79c083d1f5c02fa15a43a0f519e36acb710bdabac880f04bc003800641c2487930de9c03c0e0deb347fa815efca0a38c6c5de694db698743bc955581f6a945deec4ae988ef7cdf40498b77796ddea3fae0ea844891ab751c7ee20917c5a4af53cd4ebd82170078f41ada2795e6eea17593fa90cbf5290a1095e299fc7f507f360f187cd",
"5ec4ac45d48fc15c72471d795066bdf8e99a483d5fdd599511b9cdc408de7c0616491b73924d0266da34a495331a935c4b8884f57d7ad8cce4cbe586875aa52482215ed39d7626cce55d50349c7767981c8bd6890f132a196184247343566fc972b86fe3c5369d6a6519e9f07942f0522b77ad01c751dcf7defe31e471a0ec00963765dd8518144a3b8c3c978ad108056516a25dbe3092e73c",
"0d5e74b78290c689f2b3cfea45fc9b6a84c822639cd438a7f05c07c374adced42cdc12d2a9233a4ffe80307efc1ac13cb04300e165f8d90dd01c0ea955e7657332c6e86ad6b43e78ba4c13c675aed83192d8427866fb6484e6a3071b2369a46fba9005f31232da7ffec7952f831aaaddf63e225263531c2cf387f8cc14fa856c8795137142c3a52ffa69b8e30ebc88ce3bbc227597bcc8dddd89",
"a0fe36f983259921dc2fa7d89002b3066241d63bfc2448caf7e10522a35562be0bfedc3dce49cfce2e614a04d4c64cfc0ab898873a7fc26928dc1927c009d12f6f9b7a278205d3d0057604f4ac746f8b9287c3bc6b929832bf253b6586192ac43fdd29ba585dbd9059aab9c6ff6000a7867c67fec1457b733f6b620881166b8fed92bc8d84f0426002e7be7fcd6ee0abf3755e2babfe5636ca0b37",
"1d29b6d8eca793bb801becf90b7d7de215b17618ec32340da4bac707cdbb58b951d5036ec02e105d83b5960e2a72002d19b7fa8e1128cc7c5049ed1f76b82a59eac6ed09e56eb73d9ade38a6739f0e07155afa6ec0d9f5cf13c4b30f5f9a465b162a9c3ba04b5a0b3363c2a63f13f2a3b57c590ec6aa7f64f4dcf7f1582d0ca157eb3b3e53b20e306b1f24e9bda87397d413f01b453ceffeca1fb1e7",
"6a2860c110cd0fc5a19bcaafcd30762ee10242d34739638e716bd89fd537ea4dc630e6f85d1bd88a25ad3892ca554c232c9830bd56980c9f08d378d28f7fa6fa7df4fcbf6ad98b1adfff3ec1f63310e50f920c99a5200b8e64c2c2ca249399a149942261f737d5d72da949e914c024d57c4b639cb89990fed2b38a37e5bcd24d17ca12dfcd36ce04691fd03c32f6ed5de2a2191ed7c826375ba81f78d0",
"7132aa291ddc9210c60dbe7eb3c19f9053f2dd74742cf57fdc5df98312adbf4710a73245de4a0c3b24e21ab8b466a77ae29d15500d5142555ef3088cbccbe685ed9119a10755148f0b9f0dbcf02b2b9bcadc8517c88346ea4e78285e9cbab122f824cc18faf53b742a87c008bb6aa47eed8e1c8709b8c2b9adb4cc4f07fb423e5830a8e503ab4f7945a2a02ab0a019b65d4fd71dc364d07bdc6e637990e3",
"3e664da330f2c6007bff0d5101d88288aaacd3c07913c09e871cce16e55a39fde1ce4db6b8379977c46cce08983ca686778afe0a77a41baf447854b9aa286c398c2b83c95a127b053101b6799c1638e5efd67273b2618df6ec0b96d8d040e8c1ee01a99b9b5c8fe63fea2f749e6c90d31f6fae4e1469ac09884c4fe1a8539acb313f42c941224a0e79c059e18affc2bcb6724975c436f7bf949ebdd8aef51c",
"7a6ea63a271eb49470f5ce77519ed61ae9b2f1be07a96855726bc3df1d0723af3a703fdfc2e739c9d31d25814daf661a23558b50982e66ee37ad880f5c8f11c8130fac8a5d0250583700d5a324894fae6d61993f6bf9327214f8674649f355b23fd634940b2c467973a839e659169c773119919f5b81ee171edb2e5f6940d7551f9e5a70625d9ea88711ad0ed8ab2da720ad358bef954456cb2d5636425717c2",
"c5106bbda114168c449172e49590c7eeb827fa4e1a2a7a87a3c1f721a9047d0c0a50fbf244731be1b7eb1a2ef30f5ae846a9f38f0df44f32af61b68dbdcd0226e741dfb6ef81a2503691af5e4b3171f48c59ba4ef91eba344b5b697f261df7bbbb734ca6e6daebaa4a179feb17002823281b8534d55a6531c59305f6e3fd3fa63b747bcf0deb654c392a02fe687a269effb1238f38bcaea6b208b221c45fe7fbe7",
"597716a5ebeebc4bf524c15518816f0b5dcda39cc833c3d66b6368ce39f3fd02ceba8d12072bfe6137c68d3acd50c849873150928b320b4fbc31c1456679ea1d0acaeeabf666d1f1bad3e6b9312c5cbdecf9b799d3e30b0316bed5f41245107b693366accc8b2bcef2a6be54209ffabc0bb6f93377abdcd57d1b25a89e046f16d8fd00f99d1c0cd247aafa72234386ae484510c084ee609f08aad32a005a0a5710cb",
"0771ffe789f4135704b6970b617bae41666bc9a6939d47bd04282e140d5a861c44cf05e0aa57190f5b02e298f1431265a365d29e3127d6fccd86ec0df600e26bcdda2d8f487d2e4b38fbb20f1667591f9b5730930788f2691b9ee1564829d1ada15fffc53e785e0c5e5dd11705a5a71e390ca66f4a592785be188fefe89b4bd085b2024b22a210cb7f4a71c2ad215f082ec63746c7367c22aedb5601f513d9f1ffc1f3",
"be6556c94313739c115895a7bad2b620c0708e24f0390daa55521c31d2c6782acf41156271238885c367a57c72b4fe999c160e804ad58d8e565edbce14a2dd90e443eb80626b3eab9d7ab75d6f8a062d7ca89b7af8eb292c98eaf87ad1dfd0db103d1bb6188bd7e7a63502153cf3ce23d43b60c5782602bac8ad92fb2324f5a79453898c5de18415639ecc5c7974d3077f76fc1df5b956723bb19a624d7ea3ec13ba3d86",
"4bc33729f14cd2f1dc2ff459abee8f6860dda1062845e4adab78b53c835d106bdfa35dd9e77219eaef403d4e80488ca6bd1c93dd76ef9d543fbb7c8904dccc5f71509a6214f73d0f4e467c3e038ea639b29e7fc442ee29f57117740576188ada15a739827c647a46b0271817ab235c023c30c90f2115e5c90cd8501e7b286962fc66ffc3fe7e8978746168314908a41998bd83a1eeffda9d714b864f4d490fdeb9c7a6edfa",
"ab12faea205b3d3a803cf6cb32b9698c32301a1e7f7c6c23a20174c95e98b7c3cfe93fffb3c970face8f5751312a261741141b948d777b8a2ea286fe69fc8ac84d34116a4674bb09a1a0b6af90a748e511749de4697908f4acb22be08e96ebc58ab1690acf73914286c198a2b57f1dd70ea8a52325d3045b8bdfe9a09792521526b7564a2a5fcd01e291f1f8894017ce7d3e8a5dba15332fb410fcfc8d62195a48a9e7c86fc4",
"7d421e59a567af70594757a49809a9c22e07fe14061090b9a041875bb77933deae36c823a9b47044fa0599187c75426b6b5ed94982ab1af7882d9e952eca399ee80a8903c4bc8ebe7a0fb035b6b26a2a013536e57fa9c94b16f8c2753c9dd79fb568f638966b06da81ce87cd77ac0793b7a36c45b8687c995bf4414d28289dbee977e77bf05d931b4feaa359a397ca41be529910077c8d498e0e8fb06e8e660cc6ebf07b77a02f",
"0c18ab727725d62fd3a2714b7185c09faca130438eff1675b38beca7f93a6962d7b98cb300ea33067a2035cdd694348784aa2eda2f16c731eca119a050d3b3ce7d5c0fd6c234354a1da98c0642451922f670984d035f8c6f35031d6188bbeb31a95e99e21b26f6eb5e2af3c7f8eea426357b3b5f83e0029f4c4732bca366c9aa625748297f039327c276cd8d9c9bf692a47af098aa50ca97b99961bef8bc2a7a802e0b8cfdb84319",
"92d5909d18a8b2b9971cd1627b461e98a74ba377186a6a9df5bd133635250b300abccb2254cacb775df6d99f7c7d0952653c28e6909b9f9a45adce691f7adc1afffcd9b06e49f775364cc2c62825b9c1a86089080e26b57e732aac98d80d009bfe50df01b95205aa07ed8ec5c873da3b92d00d53af825aa64b3c634c5ece40bff152c331222d3453fd92e0ca17cef19ecb96a6eed4961b627aca48b12fecd091754f770d52ba861546",
"802f22e4a388e874927fef24c797408254e03910bab5bf372320207f8067f2b1ea543917d4a27df89f5bf936ba12e04302bde23119533d0976beca9e20cc16b4dbf17a2ddc44b66aba76c61ad59d5e90de02a88327ead0a8b75463a1a68e307a6e2e53ecc1986274b9ee80bc9f3140671d5285bc5fb57b281042a8978a1175900c6073fd7bd740122956602c1aa773dd2896674d0a6beab24454b107f7c847acb31a0d332b4dfc5e3f2f",
"3844fe65db11c92fb90bf15e2e0cd216b5b5be91604baf3b84a0ca480e41ecfaca3709b32f8c6e8761406a635b88eec91e075c48799a16ca08f295d9766d74475c47f3f2a274eae8a6ee1d191a7f37ee413a4bf42cad52acd5564a651715ae42ac2cddd52f819c692ecdef52ecb763270322cdca7bd5aef71428fa73e844568b96b43c89bf1ed42a0abf209ffad0eeec286c6f141e8af073ba4adfbbdeda253752ae36c9957dfc905b4c49",
"329377f7bf3c8d74991a7d61b0cf39baff5d485d79751b0d5ad017d23bec570fb19810105bab79ab5acb102ab972165224d4ec888ec7de5148077fa9c1bb6820e0d91ae4e2591a21fec2f820606ce4bafc1e377f8dc3a5bd1a9e2772a57abccd0b757164d768872c91d02789545ab5b203f688d71dd08522a3fd2f5bcd7df507aebf1ca27ddff0a82afb7aa9c180008f49d1325adf97d047e77238fc75f56356de4e87d8c961575c9f6362c9",
"f7f269929b0d71ea8eef7120e55ccba691c582dd534692abef35c0fe9dec7dae973cd9702e5ad420d278fe0e653fdcb22fdcb63148109ec7e94f2d0750b28157dd1764376ae10fdb0a4aef3b304bd82793e0595f941226a2d72abbc929f53134dc495b0d65ced409914f94c2523f3dfbbdeeac84ae247ab5d1b9ea33dce1a808885a55be1f3683b46f4be73d9b62eec2585f690056858dfc427aabf591cd276724885bcd4c00b93bb51fb7484d",
"ac022309aa2c4d7fb628255b8b7fb4c3e3ae64b1cb65e0de711a6def1653d95d8088871cb8905fe8ae76423604988a8f77589f3f776dc1e4b30dbe9dd262b2187db02518a132d219bd1a06ebac13132b5164b6c420b37dd2ccee7d69b3b7fa12e54f0a53b853d490a68379ea1fa2d79762830ffb71bf86aab506b51f85c4b6a41b69325c7d0c7aa85b93b7144489d213e8f33dbb879fce22849865337b620b155cb2d2d36a68832889e30194d36d",
"d009c2b78a8f02e5e5dbb586ef71fc324b375092e15913ca1a5bfd22d516baadb96867bee3562e77c4a4852344a1a76c30728be5e22400b4cc41711f66754c246a520498d8c24f0205b9c873748dbeb67fe1ad099ad04cf89f4b517f0aa481136d9f6de2d727df01c6aa4099da59d4382b51e25fd47c33d9842c32b62331e50794bfe8b61b3ba9de1b8b704779c6d65edff3af00f121ab4a7ea384edabe47c6d0098a48991f387ca4444135ec59d46",
"c00bab36cce69899817d1425016d222d7303197ed3e3fdcac744705e7f178a1ac745968900f69299163e19b3161f3e0a4cc55aa2e4e71e0ee6ac427d1f4d14e063f68d303ddfbb18118335cfa7a6a90d99c38319ee76f7a884846a9e0b68030bf28e78bfbd56359b9368842814da42b04cb0e307d5d846dc22f049147bae31b9a956d17676a8cc348dafa3cabc2007a30e730e3894dddf9999fb8819086311f0703e141613ed6dcd7af8510e2dc435b0",
"c9789152a9fc29698d49ed95f09bd11b75f18a8c5615a73dbe54ae5e550027fd0ae6a8b60667040c1b12de3d1ee3f6bf061c78c951a3210effc912e19f482dd4de152063c588c44903bc11761706fd935afa040df085b08144d83d0dde32b46ab52f4fae98ac116c7ff11d7f553450c2e37b9c5f0b1dd9e0b8640a24cba6f2a5246c41f197f46e3dc8a29131c79bef3351c6e277a0a34442274d546ccd058891277473d668420f121750d19cd684267405",
"06a15a0731ce52557e368bcbaa11ef3399299e36fb9f2eda6e5726907c1d29c5c6fc581405ba48c7e2e522206a8f128d7c1c939d1132a00bd7d6366aa82724e968964eb2e373563f607dfa649590dcf5589114df69da5547fef8d1604cc4c6de1ed5783c8746918a4dd31168d6bc8784cd0c769206bd803d6ca8557b66748770402b075ef44b38157d4c0da7c6281725a2065d087b1f7b23455fa673bdeeba45b983311c44eabe9ef4b7bde3420ae9881863",
"d08aacef2d7a41aec09473bd8a44f628e15addb7b9e5b77a1e09c8ab4942f379a0bfcb324d580b774666f18ae78dd36710824ff12393f059068fe4b559c53662c2b0e6c69e23785c8f32554e837ec1714bee902e60737b639dd933af4f68cb9d7de77e1f3b28e5b122891afce62b79acd5b1ab4ba411662cc77d806449e69c5a45a143b742d98ac84a0826d68433b9b700ace6cd472ba2d58a90847f42ce9c43f38ffc017db4bf40450b2eee1f4594dc740c0f",
"6a6058b0a498b7ea76a93c646eb9b8629f0cba4a0c726420c5f67ba9b0412cade356abdf0a4fb94384bad32ce0d5dd9e23dcaae1d6f28ff8683616b30f1392890c67b3a2c04b360893b801f127e527e4da82e239f4c878da13f4a4f1c76db07190e77ec123995168102fb274434a2d1e12913b9b5cbab4aacaad2bd89d88b3ca2b8e60dacf7c22c9379097ff60880f552e320ca3b571994f52534470feee2b39e0dadb5cd88257a3e459a4cc6f12f17b8d54e1bb",
"adeced01fc5671531cbb45679f5ddd42b3a95151677b6125aaf6f5e8f82fbabaa5ecf7c3552c2458587224f0042870f178f5fca5465250e75d71352e652eeed23cdb7f915f5ebb44099b6db116ca1be45530ac8ed32b7f161d60ed4397ad3d7d649ae6bf75ca5bec891d8e595605be9764f3a03965e1fe0eaffbf212e3df4f0fa35e08ff9d0091e6d4ac4748edfe43b611085a6ffec163014655fdd839fd9e81b63b1fa8cae4ec335ec343289758e389a79ceedfae",
"d014592f3a83ba40af366f137c674724916c3cdd3f6cf9d4c5c7c8d6d51ebf26e315e2c12b3546be56fb52382904046ecbd2f5b883aa4ff473de6f0c26ab862c3fa34bf3d880cc1911ce39a4088c6617c179dc5faf68a2c488bbde12d67b50f73abcfab0e3b062e68c95363e11f5f1de8ec36ed01ea21442518089045df67d346135283ad5b3fff80cf57f20876849f6db9fa139728358415a90610f69ec720fc92d8234e3e122551e9df2c644c4a2c4e3734d07de8e",
"c0d0c37838873ba8757d6e41b409605043bc1635edcd731219587676d94217e9f0ab44b71de25000661ce7303b7015f45e6eaa7b7ebef92b8f4a34c902c908d2172185505fa33aca5a41be83079316cdfdd430fc2c45f505f85d867e6d516f7e1bf19c001d9f43018968aab65ec031b3801399231c83ec9e622dab5629922a6b424cab938c135ff7310501c2c02971bfd2f577e25904d1a618baf0859f77f4e8b1d0cde9544e95ec52ff710c0672fdb3d891feeea2b017",
"7022e7f00902219ba97baa0e940e8ac7727f58955aa068c29680fac4a16bcd812c03eeb5adbcfe867a7f7c6b5d89f4641adb9173b76a1a8438866f9b4f640ce2aedf5f1080c890bcf515b4be4e3e512352f1e5323c62ec46cb73f3d71be8235fee55a154763f7c3f9aeb61ffd28f4cd93d3310f608e2133586bf1ab3f102de96f64c68a4668de8acb2a76a7ce0cddddc8fa3df5e9d230823da16ed9ebb402d36e38e6e018795e5a71517ecab5f9ca472b9ced8ff69d2d195",
"acaf4baf3681ab865ab9abfae41697141ead9d5e98523c2e0e1eeb6373dd15405242a3393611e19b693cabaa4e45ac866cc66663a6e898dc73095a4132d43fb78ff7166724f06562fc6c546c78f2d5087467fcfb780478ec871ac38d9516c2f62bdb66c00218747e959b24f1f1795fafe39ee4109a1f84e3f82e96436a3f8e2c74ef1a665b0daaa459c7a80757b52c905e2fb4e30c4a3f882e87bce35d70e2925a1671205c28c89886a49e045e31434abaab4a7aed077ff22c",
"84cb6ec8a2da4f6c3b15edf77f9af9e44e13d67acc17b24bd4c7a33980f37050c0301ba3aa15ad92efe842cd3ebd3636cf945bb1f199fe0682037b9dacf86f162dadabfa625239c37f8b8db9901df0e618ff56fa62a57499f7ba83baebc085eaf3dda850835520344a67e09419368d81012168e5de5ea45158397af9a5c6a1657b26f319b66f816cd2c28996547d697e8df2bb163ccb9dda4d6691dffd102a13667ab9cde60ffbfb872187d9c425a7f67c1d9fffff9276ed0aeb",
"6a52c9bbbba454c14540b2be58230d78ecbeb391646a0c6fcce2f789086a78364b81ae85d5396d7cfa8b46bda41e3083ec5cf7b4c47dc601c8a697df52f557defca248506dbebab25657f5a561d09625b7f4b2f0119a12beeac087efc9d350a735c35d2431c1da7dda99befb17f41a3dc4da0f00bb95366be128538ce27763d81f832fe3c1d4efc07b5b08ad8dc9e65fb5e48546664e18cb2d3bb3fe1f56fa7aae718c5e3bbdeaf70e15023f6a25b72a2d177fcfd04211d40664fe",
"c3c4d3b31f1f5f9538923df3478c84fffaef411520a542da9a220ee4132eabb9d718b5076fb2f985485e8ba058330aed27ddfd3afa3db34aa60301088caec3d0053828c0c2bc87e2e61db5ea5a29f62fdad9c8b5fc5063ec4ee865e5b2e35fac0c7a835d5f57a1b1079833c25fc38fcb14311c54f8a3bd251bca19342d69e5785f9c2e43cf189d421c76c8e8db925d70fa0fae5ee3a28c4047c23a2b8a167ce53f35ced33bec822b88b06f41558c47d4fed1bfa3e21eb060df4d8ba1",
"8d55e92136992ba23856c1aea109766fc44772477efc932b3194af2265e433ed77d63b44d2a1cff2e8680eff120a430fe012f0f09c6201d546e13ad46fc4ce910eab27bb1569879abed2d9c37fae9f1267c2216ec5debcb20d4de58461a621e6ce8946899de81c0add44d35e27b7982a97f2a5e6314901caebe41dbba35f48bc9244ca6dca2bdde7306435892f287036df088633a070c2e385815ab3e2bfc1a47c05a5b9fe0e80dd6e38e4713a70c8f82bd32475eea8400c7bc67f59cf",
"5016284e20362610fa05ca9d789cad25f6d43263787e7e085476764ce4a8908ce99b262b375e9d106170b1bec1f473d5e777e0c1896533040e39c8c1465e07907ef5860e14e4d8310013e35f12090e0bfc687474b1f15f3dd2033a0edac5246102da4deec7e188c3517d84d9c2a0a4497a4c5f82a30f1ba009e45ee6eb3ab4368c720ea6feee428ffd2c4cc52debb8d634a64176572c72368f94a66689f23f8a01218f532117af5a8060d140e7ca435a92882fcb5630ebe14a4805f1dc83",
"05456ec59b8d41bbd736727976b96b38c43827f9e16169be673ff37870c2ecd5f0d1ea1a136be4cc7b047a02a4421d484fd2a12ece418e42ee391a13a0b1df5a0162b29ab70d3fe3e04ba6ab26b37d62b7cf05a5e2f033611bf970b8e1f30e198e483e740fa9618c1e8677e07b61296b94a9787a68fba622d7653b5568f4a8628025939b0f74389ea8fced6098c065bf2a869fd8e07d705eadb53006be2abb716a3114ceb0236d7e916f037cb954cf977720855d12be76d900ca124a2a66bb",
"eb6f60b83fcee77060ff346aaf6ec34d82a8af469947d3b5074cde8eb26566eb1fa039bcc707738df1e95869bd827c246e88436f0614d9834ead5392ef376105c4a9f370071cdeaaff6ca0f18b74c3a48d19a717253c49bd9009ccbfdd5728a08b7d112a2ed8dbafbbb46d7a75dc9a05e09bfde1a0a92d74a51887f9d123d7896e9f9d0057b660ed7d55454c069d3c5260411db4cdc67e7b74f680d7ac4b9dcc2f8baf72e15e6b3cafebcdf449a6436ed2c398b675f79c644747c57553bf7ea2",
"187a88e88514f6c4157c1ba40b442baae1ae563a6c989277443b12a219aa484cb9fa8adbb9a29d429f50155321b15664926317477079c7060dfdaa84c1d74bba78892c34e6f21ad35208d2ae622012401696bff5cd57b6485944b3db7b9071fa5f57fbfb1085d91bb9cff5808d662cdc6c8157249478262c44b7fbc397ed42a4977b202e817717bfccc9f0467294062313f7705251ed09573f16d23429361fada259dfb300369c4198f07341b38e84d02cdb74af5de6aab1fc2026208ea7c418c0",
"be31bc96606d0fab007e5caeded2f1c9f747c759777e9b6eef962bed49e45a1d4fc993e279d024915e600865ecb087b960584be18c41114d3c43f92169b9e0e1f85a0ebcd4e196376ccdc920e66103cd3b1c58407d0aafd0e003c4e341a1daddb9f4faba974362a32f35db83384b05ae8e3322d728893861afd8b1c940de5a17f691e763ce4969b6d94f67fb4a0235d100225bd8602f291388f0ca4a568748ad0d6040f1262eac2aede6cd27419bb78a394c1ffad72c262be8c3f9d9619d633e51d0",
"4d83d85ca838b4518588f2a90228a4dd18f14dd5b4c012d26298a97d848abbd825d221d02cceb6e8c701b4ad00e1dee4889b5c533e4bb60f1f41a4a61ee5478be2c1b1016c30345afd7a5253668260515e70751f22c8b4022d7fe4877d7bbce90b46531507dd3e89549e7fd58ea28f4cb23d33662bd003c1345ba94cc4b06867f778957901a8c441bee0f3b12e16463a51f7e50690356971dd73a686a49fda1eae46c9d54fba262811d698025d0ee053f1c58591c3bb3cbde69de0b31549ef5b69cf10",
"cdeb07d36dc5f9a1cd717a9e9cca37a2ce93caa298eee63571f7d6c5fde2a11c666cf53cf2dcb41ca2ea2319e7230ca68e38c647905928713a13982bf47fe33d7095ebd50b2df976208920a43eb2e29b942f32467403c45cea18bf44e0f6aeb155b48a8e5c471fec972a9d62f7ae093d2758f0aaec7ca50cb4725bfa219f1a3a46ad6bde7361f445f86b94d66b8ece080e56c510250693a5d0ea0ae87b4421860b853bcf0381eae4f1bf7c5c0472a93ad18407bc88475ab8560d344a921d3e86a02da397",
"a598fad52852c5d51ae3b10528fc1f722e21d44fbd42ae5acdf20e85a28532e646a223d27fd907bfd38eb8bb75175636892f8242877aab89e8c0824d368f3339ce7a82aa4e5af6db1f3b588a4d667a00f67bee37cfd2724dde06d2909fb9e58d892f4cfd2c4ca85acdf8256f5458b030a6bda151154ff2e6d7a8da90b54a2884c8a99fab5a4ac211ff23dc0975f4f592fd1b6b9dc7783bdcd2d4ca4e68d2902f2013e122cb62e2bff6b0a98ec55ba25837e21f1cfe67739b568d43e6413dab2bd1dc471e5a",
"17b68c74c9fe4926e8102070916a4e381b9fe25f5973c9bd4b04ce25749fc18931f37a65a356d3f5e5a1ef125d546f4f0ea797c15fb2efea6fbfcc5739c564693d47adeb12dcb3d98a2830719b13247792cb2491dca159a28138c6cff925aca42f4fdb02e73fbd508ec49b25c60703a7595a3e8f44b155b371d525e48e7e5dc84ac7b17c52bf5e526a67e7187234a2f19f57c548c70fc0b27183df73ffa53fa58b658034c896fa791ae9a7fd2620f5e46ce84c842a6e60e9324ae4db224ffc87d9617cb85ca2",
"b9e4267ea39e1de1fed0579f93bb351007c9f8fcdd811053fae33f09e2753d7428f04e1a9efcd45ea701a5d87a35b3afb2e6b65365dee6ead0bbb611b7797b212ac688653f542e604a39df277f12514ddfee3b4e27b98395c2cd97a203f1f1153c50327965770802ec2c9783edc428271762b275471e7ac65ac36523df28b0d7e6e6ccc7674268a132a63411fc82c0738dbb68af003b769a0bf9e6587b36476cb465350fee13f88ea355d47ffac7b0f964f4139db11b7642cb8d75fe1bc74d859b6d9e884f75ac",
"8ca704fe7208fe5f9c23110c0b3b4eee0ef632cae82bda68d8db2436ad409aa05cf159223586e1e6d8bdae9f316ea786809fbe7fe81ec61c61552d3a83cd6beaf652d1263862664df6aae321d0323440430f400f291c3efbe5d5c690b0cc6b0bf871b3933befb40bc870e2ee1ebb68025a2dcc11b68daadef6be29b5f21e440374301bde1e80dcfade4c9d681480e65ec494a6af48df232c3d51447b9d06be714949249c44c43cf73ed13ef0d533e770284e51369d94ae241a5fb2f163893071b2b4c118aeaf9eae",
"4fd8dd01012bb4df82bf42e0683f998e6f52dd9c5617bae33f867d6c0b69798cead8179346d70acc941abbbdd26e3229d5651361d2252c72ff22db2938d06ff6fc29a42fdf800ae967d06479bc7bbb8e71f40b1190a4b7189ffc9a7096cdb76d40aec424e1388e1eb7ef4ac3b34f3f089da8fda7d1927f5d775c0b2801d22dd1265c973158f640cec93edfed06dc80b20ef8c496b98289d54d46ccd205951cbb0f4e7daeb866b60bacb483411e4382b6f04d472843186bd0e31fbaa93e5c901ec028efafeb45fc551a",
"e9ee1b22b04b321a5fdd8301627011f583887d77560fb0f35552e207561f81e38ac58a0d0aeaf832d1ee72d913720d01f75574e9a321864fe95f4d0d8f0b8db97649a53e71e940aede5c40b4b9105daa42a6fb2811b61209247534cbaf830b07abe338d75d2f5f4eb1c3cf151e9edabe2c8d5f6fff08fac1495ef48160b100d30dcb0676700bcceb28723a29980ab0766a93abb8cb3d1963007db8458ed99b689d2a7c28c788743c80e8c1239b20982c81dadd0eed6740c65fbc4ef15c7b5569cb9fc997c6550a34b3b2",
"ec01e3a60964360f7f23ab0b22e021815765ad706f242265ebc19a2bb9e4eac94393952dcf61aae47682671a10f9165f0b20adf83a6706bfbdcf04c6faba6114653a35584267267873291c6fe7ff5f7695243143421509502c8875aafa9e9afe5be5ef2c851c7f35d69be5d3896000ccdbbfab5c238bb34d607cfe2d55d748880545b4aa7ca61137992925189025c62654b1f20d49c3ccd75aa73ce99cd7258dabedd6480a9f5185531fc0118beb68cc0a9cd182f6973287cf9252e12be5b619f15c25b65c71b7a316ebfd",
"db51a2f84704b78414093aa93708ec5e78573595c6e3a16c9e15744fa0f98ec78a1b3ed1e16f9717c01f6cab1bff0d56367ffc516c2e33261074935e0735ccf0d018744b4d28450f9a4db0dcf7ff504d3183aa967f76a507357948da9018fc38f150db53e2df6cea14466f03792f8bc11bdb5266dd6d508cde9e12ff04305c0295de29de19d491ad86e766774bb517e7e65befb1c5e2c267f013e235d8483e177214f89978b4cdc81aa7eff8b39f2825ad3a1b6ac1424e30edd49b067d770f16e74dd7a9c3af2ad74289a676",
"00e40f30ae3746edad0f5dd03d0e640933cf3d1694804c1e1ed6399ac36611d405196ee48f129344a8512feda16a354517871322bd5d9c6a1b592933eab531923efb393ffb23d9109cbe1075cebfa5fb917b40df028a621460ff6783c798792cb1d9635b5a6f84ec13918fa302924649b5c7fcb1f7007f0d2f06e9cfd7c27491e565a96c68a0c3644f92cd8f38857258c33801c5d537a83dfe583cba59d7eec7e394199c0a2660a62fabe3ed2099d57f315a6cd8de1a4ade29d977f15d65759cff433e5ac0c182aef3761163e1",
"3c5ea24d0d9b618294a263f062b2414a722be4eb10dfc346a6ec3b821d7396eba61cd6ef33618b04cd087a811f299d4606820227f16000d7c839062b96d3e3f59cd1a082448d13fc8f56b3fa7fb5f66d0350aa3b72dd7c165d590282f7da2e12cfe9e60e1796122bb8c2d40fdc2997af634b9c6b127a893dfb3467909378300db3da911be1d7b616bb8e0572433e65527e15d936500a2c60e9f9909dcf22ab5e4b6700f0238c205b4a813626fac3d945bab2637fb08203044a73d20c9a3fcf7c3fc4eb7807c3276dd5f73ce89597",
"9271aeeebfac46f4de85df78f1bfd36136aa8905e15835c9e1941176f71e3aa5b1b131843d40479735e23e182a2bd71f66f6149dccb7ed8c16469079dc8590bbf165374951785f4531f7e7361de62f936cfb23a2b5bdf186632e7042a0dd451fdc9b7208f923f3a5f250ae590ec348c63a16c3aacaf7379f53b5dd4152dcd40d23e683e2156e64c592ffc07e2cd6bbeebef4dd590b2f6b2bcbf08fcd111c079f5c4033adb6c17574f8756ecd87be27eff1d7c8e8d0324438d59ae171d5a17128fbcb5533d921bd044a2038a5046b33",
"4e3e533d5bcb15793d1b9d0468aaee801f32fdb486b11027183553a09ddbee8213924296f2815dc61577297459e834bf1c7a53f87d43782209e589b8295219ba7073a8fff18ad647fdb474fa39e1faa69911bf83438d5f64fe52f38ce6a991f25812c8f548de7bf2fdea7e9b4782beb4011d3567184c817521a2ba0ebad75b892f7f8e35d68b099827a1b08a84ec5e8125651d6f260295684d0ab1011a9209d2bdeb75128bf5364774d7df91e0746b7b08bda9185035f4f226e7d0a1946fcaa9c607a66b185d8546aac2800e85b74e67",
"b5d89fa2d94531093365d1259cc6fe8827fea48e6374c8b9a8c4d2209c280fa5c44958a1847222a692a59e6aa2696e6cdc8a543dd89b0ce03bc293b4e78d6ef48e1839694ccd5c65661143095c705b07e3ced84a0f5959114dd89deb956ab3fac8130eb4a878278205b801ae41a29e34146192308c4e759b374757b0c3b00319bce92a1b95a4d2ee179fd6714ff96155d26f693a5bc973f84ac8b3b91e3926276297532d98b46992a3f104c08100bf1671c43134bac280c617da711e90a0100137525375ebb12802a428885ae7fce6514a",
"40e3d8048fc10650cb8a7fc2e7113e26dec34f9ca2d5129cd10a8e8e44d113d61ee48c7d003e19fd307fc6debd70feb30243f298c510ccc4418355ce143066f067ad7c6de7288c3080e7ad46a23c8d34deb55a43e652fe90444ad3c57d3ec1e1c489d63ef915a24bc74a7925a0a7b1e1523f21ca8fee78df24e3d0a68d0013423db97c280799a0618229c0f2c167289a891e5c8d6661ab21285951c31710e3b5fe55f6347fe16d9b40507948a59252efeb616df83e5c098b07d0a7247cd371daff0e50491c582503fd89f79ba94d6af9ed76",
"1fa444de01dd3901e2b4684e3d7a799ffa02d85afd35fb30fe4c9d672837bee6dd8a3b8608b4bb5e589220ad5a854f46b46e41c6d57ad124a46beab4169ff69fee7e3838a6165e19dad8eb5d7bf53d4edd3cd2769daf219510a02fdd2afe0c0e1da3cd30fcd1aa88b68965586f07a25a1720fbd90a096ea30fc8e945e3637d7857c8a9c0ab4154ffb2000e57b5f9adfa4e4eaf8065bc3c2b2e75f495963325588785a6ce417dcddffd299873b15dcccca128d63cd4eeeadb64cda28099a9ad7c80d34844901f26b88b00b9aafeb2f90286d29d",
"fde0a0d9d813983bd1f55cf778a003a2023b34a555322ab280584537bc6bdd844d22a7d6066c18da83ec09f3d8d5a1aab4be0d5ce19b436052f6e259a4b49017a1f47f1fe2bf115d5bc8599fb216351c60dd6b1bedb2e6f4dcadf424b833501b6f099cbfad9e2290680fb69c25032b42a6274f7cb9b5c5950401354838a45f7cb77b95bf54718e2f3d3d9fb91eb2311903980277396398d9736d8e92fd838594ac8a537c6c529db5a8a4f89290e6ba6f20ac0e5ed6fef40901d0e0e8e3e502990811f9acaae555dd54eb1bcd96b513e2fe751bec",
"9f8e0caec87858599f5ab29bff86da78a841a918a023a111098687ecdf2747612d3f3809d9ca400b878bd4f92c43a1004f1c17c7f19a3cd1ce449bd2b23aff551623c37dd8c0be56bf3fd857b500c2b9f9ccea62481944090a3cf3b6ee81d9af8eeb60f65ef150f9fa4d3ed6ce4762d3d4f174ee8ccd460c25cafac0ea5ec8a6a4b2f9e8c0520cb7061155e532cb65f188b01e4b9086db951f504b060c296b326b3fc1c590498ecce594f828f4a10ea416675720ae505295d38a791bd0e93f428448a8f4c1fc0af53604a9e8255384d29ae5c334e2",
"33d1e683a4c97ee6bbaa5f9df1a88cb53b7f3c157b6045d70a56fda0ccbd3a1fa1f049cd564da072b53f415bf5fb843771c1d2551fd075d33377362b2f7c0645f9723123d11975991db8a2b518f02e2c7c30342a044754290bae2c77496d755e5981f12e6b0a0174280b958bf11ed628a9062775993ced04bf752ea8d165e3ac2177d7cd1b9371c44efa98f0b3e68602a839d384eec007979f46429dafb138cbc231ad928a9f65f7d66fac77416395e8f1debaaf76ec2e4e03e8674102cd26f614739f3ec9f949033df1fb97e87c2326d65aef94ed5f",
"180048f09d0b480887af7fd548a85abf605440c1ddde6afe4c30c30670233f7bf928f43b4681f59279ebbda5e8f8f2a1abefdee129e18ac60f9224e90b38b0aabd01308e0a27f41b6fb2ee07ee176ec9048c5fe33c3f7c791469c81f30e28170585b9f3e7e3c8c2e9d74370cb4518f13bf2dee048cbd98ffa32d85e43bcc64a626b40efb51ce712925fdd6fee006dc68b88004a81549d2121986dd1966084cd654a7c6686b3bae32afbd9625e09344e85cf9611ea08dfce835a2e5b3726e69ae8a76a97db60fcc539944ba4b1e8449e4d9802ae99fae86",
"13c0bc2f5eb887cd90eae426143764cf82b3545998c386007cca871890912217aa143ac4ed4ddb5a7495b704aa4de18419b8664b15bc26cfc6596a4d2ae408f98b47a566476d5802d594ba84c2f538def9d016661f6404bb2337a3932a24f6e30073a6c9c274b940c62c727242e24466084a3ea336365d71ea8fa6499c0ea8d59eea505f1126b99c795023c4963aa0d99323d0391e8701110edf551b2d3799e1063ca443f1add162156e445502ca1a052fe70c289838593b58839fc63de128a03e2bbf389e22ae0cf957fd03315ee407b096cc1cfd92dee6",
"6f1eb607d679efef065df08987a1174aab41bdac8aece7726dfa65805d6fff5b3d17a672d96b770dc32165f144f0f7324822a5c87563b7cd9e37a742ae83ef245d09006d91576f435a03476f509ea2936636232f66aa7f6cdf1ac187bbd1fcb8e20f8791866e60ed96c73374c12ac16795e999b891c64507d2dbd97e5fc29fac750ad27f2937cbcd29fdafccf27ab22453834d475f6186eaf975a36fad5c8bd61c21da554e1ded46c4c39765dcf5c8f5ccfb49b6a4dc562c919d0c7d8940ec536ab2448ec3c9a9c8b0e8fd4870cad9de2577c7b0c38563f355",
"dcdd993c94d3acbc555f464871a32c5da6f13b3d5bbc3e34429705e8ad2e76393fdd96a69a94acb652f5dc3c120d41187e9aa919669f727c4868013b0cb6acc165c1b7706c52248e15c3bf81eb6c147619467945c7c48fa14a73e7c3d5bec91706c567145342a026c9d97eff97ec672c5debb9df1a998083b0b0081d65c517b3e5634c95e347e781aa30ca1c8af815e2e494d844e847fdcb41622894a518dc36571123a40bfdbe8c4f4cff44d83c61dd9dcd24c464c53b395edb31efee9f3aa080e87cdc3d22d613ae84a53c9249c32c96f9a3bc4629bb126a70",
"49971f9823e63c3a72574d977953329e813b22a8387cd13f56d8ea77a5d1a8a20012632d1d8732bbcb9f756b9675aab5db927beacab7ca263e5718b8dfa7b2eed9a91bf5ed163b16139d45f7b8cc7e3f7bdda6202106f67dfb23b7c315ee3e17a09d466b1e6b13e7c7428184a979f5358667b4fa8bd40bcc8ea46058db44587a85377ac46bf155136c09ac58cb6c27f28e17028c91e7e8f74d5b500e56293b316974f02b9d9ea205d9b6ac4cfb74eb8eb0c944577fd2f41316368307beab3e327bf7dbaa0a4428836ec4e895dea635234abeaf113ceeadac33c7a3",
"c57a9cc958cee983599b04fe694f15fb470fcbc53e4bfcc00a27351b12d5d2434444253ad4184e87b81b738922ffd7ff1dc1e54f39c5518b49fb8fe50d63e3935f99e4bd125e8dc0ba8a17fd62de709339a43fabe15cf86d96a54010112170c340cfac4132182eed7301402bc7c8276089dec38488af145cb6222525894658f03501204b7a66aba0be1b557b28a2f652d66f7313ed825ecc4d8596c1be7420d4425b86a1a90a5b7f30d0f24e0d1aae0eb619ca457a71699e44be612a4011c597ee80b94d5507e429d7fc6af22579cd6ad642723b05ef169fade526fb",
"0568a672cd1ecbaa947045b712e2ac27995392fbef8f9488f79803cbee561c212287f080eca95adb5ba42739d78e3ba667f06045d87850d3a0499358649caa257ad29f1a9c511e7054db20554d15cbb55ff854afa45cae475c729cea72ede953522031865bc02b95589ed4d9841c552a8cc94904a93ed09ed77222f6c178195056be59bc4e96a815adf534e6b466fb47e262ff79c803c157a21b6e2269c2e0abeb494113cd868d8466e82d4b2f6a28b73645853d96bc9242515d803e33294848d3fe42fdff68da53c03491636beede47ff1399dd3d54a5e914d55d7adf",
"3f19f61a4cd085796731ac9f85a75a8bce77031932c31762d87d8b8d07b8bd19ff78d6b7d1bd1e87f3a4f41aad03b6c4d17a6cbc86be55f7c8b88ada047bb04f8d49f1c34bcf81cc0f3389ad01a758fc7eeb0072aa9ad1481992bfdde82e438e75590a4423832dfbe3756e2229ea873bc3606e6d72174cb2163bf40b5d49c81009dab85ecc03e311351bbf96e32c030a2b276a7698cb25bc2c967acb3213161a1fdde7d912cd6a804490f8056c47da1333f6e35c41e749c2c23919cb9af5eec5652e6e072b034fb1682e9aaa194a9c0bd456ea0b008d14dbce37967a7a8e",
"705f98f632d99d3651793825c38dc4deda56c59eac539da6a0159c83131cf8ab6f2ee0c3b74111fde351f7aa1a8c500a0cecab17c212d2c58ca09eae608c8eefc922b9902ef8d6832f799ba48c3c28aa702b3242107edeba01daafe424406a3822965056cfe8783455a671e93b1e2eae2321364f1871471c82124df33bc09e1b52882bd7e1c4c7d0b2f3dd4a28c2a002a43246768af0700f9659de99d62167be93177aabf19d678e79e9c726ac510d94e74873eda99620a3961930cd91937c88a06d8153d64fd60da7ca38cf26d1d4f04a0df273f52127c53fdc593f0f8df9",
"ea6f8e977c954657b45f25480ff42c36c7a10c77caa26eb1c907062e24fbca5aebc65cacca0de10abea8c78322f08672e13d8ac16996eca1aa17402eaea4c1cc6c800b22dc18cb8d620192d74bac02c07b5cfa61e513c7f28b7e29b9700e0e442720bf4c669d4995da19d19f841d9eb68cc74153592591e3bf059ef616b95305aa453b32fe99a91afb35bd482cf2b7aa42702837a53be3c38883d2963020e347556f841254ec6b85854485fe8c520b05f2ea67a9bf3981555c20991e2bacd4db5b418228b6002d8d41c025cb472bf5443aaa885974a408ea7f2e3f932c600deb",
"408190134ed06556811b1af808ab2d986aff152a28de2c41a2207c0ccc18125ac20f48384de89ea7c80cda1da14e60cc1599943646b4c0082bbcda2d9fa55a13e9df2934edf15eb4fd41f25fa3dd706ab6de522ed351b106321e494e7a27d5f7caf44ec6fadf1122d227eefc0f57aefc140d2c63d07dcbfd65790b1099745ed042cfd1548242076b98e616b76ff0d53db5179df8dd62c06a36a8b9e95a671e2a9b9dd3fb187a31ae5828d218ec5851913e0b52e2532bd4bf9e7b349f32de2b6d5d3cdf9f372d49617b6220c93c05962327e99a0480488443349f0fd54c1860f7c8",
"5f9e5c6f38573a85010a9d84d33f29c057003b2645e3ea6f72cbc7af95d197ce6a06b13fea81722853e6991791b8b15091cd066f5ed913592ed3d3af5370d39ba22beeb2a582a414b16824b77e194a094c2afdcc09aa73ce36f4943cca5ae32c5017dc398801dd92a47382d9327c9f6cffd38ca4167cd836f7855fc5ff048d8efba378cdde224905a0425e6b1de061fc951c5e624a5153b008ad41160a710b3ff2081748d5e02deb9f841f4fc6cf4a15153dd4fe874fd447482696283e79ee0e6bc8c1c0409baa5ab02c5209c319e3169b2476149c0c6e541c6197ca46e004eef533",
"218c6b3508aec69574f2b5039b30b942b72a8349d05f48ff945bbbe5c8957d5a6199492a6bf54bab821c9377e2edfa4c908384664d2c80112d5e805d66e0a551b941021be17dd20bd825bea9a3b6afb1b8c605805b3bda58750f03ea5c953a698494b425d8980c69f34d1c3f6b5866e8717031152a127215c256e08873c21b0f5cc85875d0f7c94601659150c04cd5fe5d381ba29983a2d94fcd3a65a94c53c7279cd000dddd4253d8cff8d7f6ace10247fe3bc30d63ba4bb54f557b3d22a3924369430d71ab37b701e9500bda70b5a643704858beed4726a889b6c9c91584194c68f1",
"dac26aa7273fc25d6e044c79fc2bfa46e59892a42bbca59a86826c91e76ab03e4bd9f7c0b5f08d1931d88b36ea77d94f7ba67cd4f1d3086e529427201119096ae066ae6f170940830ed7900de7bb9d66e09788287403a4ecc93c6da975d2fb08e918840a236c15f5d3a8f7375c2eeebbf6f01a6e7f29ca2b8d42df158414c320777433663c59fdcd1f39ca68e3473db721be7ce8c6dba5fddc024f94fedb286b0477581d451313ca8c737484daf60d67f9b2d56d4bcc271f7e9ae958c7f258efbc74d25753e0516f28282461941bf2dcc7dd8c7df6173b89760cefcac07190243ff863fb",
"c46e6512e6797cc7a54254a1b26b2de29aa83d6c4b1ea5a2786fbcec388270625b12635eae39e1fba013f8a65219421bca8b52a8ddfd431cda60299bdf160734d5a7450ec79620058522702174ae451b9bfa7c4a455fbbee3e1d048c7d4bac5131018228f137c8e130440c7059b4f15eaa34ce872a851a16ce86f982df78a00be4d564da2003a450ddee9ab43ea876b8b4b65c84f0b39265fd5456417afb5bc54997c986e66fc222f2123ba5e719c4d6b9a177b188277df384f1125821cf19d5248cef0be183ccdc84ac194506f740ed2188b2689ea4c9236a9e9e3a2fff85b6af4e9b49a3",
"1ccd4d278d67b65cf2564ecd4de1b55fe07adc80e1f735fe2f08ea53fd3977323689122c29c798957abaff6aba09bdcbf661d77f4dc8913ab1fe2bef38846166e3834785e7105d746484eff8c656af5d8c7854abc1c62b7fadb65521dc6f793d978bda9838eb3800417d32e8a24d8c8cb1d18a5de6ca79d9e1b0ff9aa25e6218fe944cf18666fecc1e31334b390260dbe0997539e1b02f6366b2aea4f4a21efe04f4b97568fcb39e59919d5ebac6543d5d0f48fc66b923c34aac377dc95c20329b837b6ed5e8d9a3d2089cd0d8f025658006ff41cbdaccca618822ca590ab155253f8bc1c7f5",
"9875209588395ee3c9fdd793fd48717cc84c8c3ea622b2ccc4a1be4448e6034b7810569855255031f10be5ffd714b05f9ce01972d712d40abf03d4d0ce175813a7a668f761324996093fc2aa5912f7fc2abdadd8775d2b4d9ad492216293381460ed8f6db3d641d1525f4242c348bbfe504c704f215dc461de51b5c75c1aae967936963848f16c673eca5e78dfd47eb19001d52d1bcf96c98956dad5ddf594a5da757e7ca35f2f69803b784e66ac5a58b75c228b8266ec592505e5d1ca87d81225738855f15bc0914677e81593fd409e77d159f8a908f67788de9eb06c5561547aada96c47c535",
"40c90e375e366f3756d89091eb3eed9fe0fbfc5638700af4617d358812bac53124a2205dd6756456787d49cd6a35e302479a0992288f47532e4ea7ab62fc5ad5adc690a5d9a446f7e035ad4641bd8dae83946aee3338ec984ccb5cc633e1409f2531eeffe05532a8b0062ba99454c9aeabf8ecb94db195af7032bfebc22912f49d39330add47ff8fa5720612d697f0b602738930e060a1bb214efc5e292224cf34e29deaea6b1b1ff847e94ecc997325ac38df61db45d82bf0e74a664d2fe085c20b04c39e90d6a170b68d2f1d373f00c731c524456ada73d659aaac9df3191a7a3865083343fc13",
"e8800d82e072210ca6d7fa2472028974780b76aad4bcb9ad362422dd05ae3232668251d164daa375a43b26a38cce28dbeb3dee1a4a579f70d0fe7febb29b5ece8aa836e050fb3d188c63aa9c3c0da6c717d86458a6096b5effceb964efdec7035960c09ccd10dea3c5f1c7f9f478d5887ebbe2e15c5ff85dbacbc444bb951c4eec7abecb89ed80187e409e2972ffe1a5f01562af109f2cf09471cf72cf83a3bb8f4e2ef38ed0e326b698296394e5b2718a5000c01425708e8ad0461e62462d8819c2377f13ab1be2c7c9f33dc06fe23cad27b87569f2ce2e56e4b2c60c7b1b3d370841d89ebdc1f192",
"796d6d1447d5b7e8c55cd8b2f8b7010db39f27565f907e3fc0e464ea2d4bb52b37f10e7c6dcfc59231b9cdee12c32aeb4adbc42b86e86eb6defb5b69e6ca75e1f4d0dae3e124e5a1b8b6697f7e10b0403f1f0a5ff848eef3752837a9ba17780f16a9a709188a8d5b89a2fa74adb2e651163b1c2b3d261e225c9158dcd9eb7ac3d6704cee290cdff6bcb3cb90cee030aa0d19d4693655c3c30ac6fc06d2ae37787c47126d57ed9a6bef5f8a6c56859aefc08755739a95aac57a4dd916a92ba9f3afbf969df8085949615033365c751a9a3e1a18cee98a69d22e64009bebf8307169b6c61de0617ecfafdf",
"4f9057183566153cf337b07c3f5556006de54c56b2a1e5326c07aaeabd1886ec6f1641358925db232b2f0dbf75229c796a7395b2f934c1f99090bec1123f3c841b1cb3c5b1ec42ed5408f2940f0c48a9470b852c46d6557853d459cecd2c32bbcd8ee21fa11e385eef0857cba4d8545a61b52a484cdd779db4739fbc7aa9860dcabe0488b98fa0b60c3f7d6153db279000a52ffb573dab37d2ab1896a90e5deb7ac6bbe56239085c325d83a917dc6e8a448425b718c2356b9f3066163555ec444f372e184e02c8c4c69b1c1c2ae2b51e45b98f73d933d18750968945ca85d6bbb22014b4c4015262e3c40d",
"79dcca7d8b81a61359e4aece21f3df7b99518ce70bd2f57a18bab5e7114af2add0a0cea7f319d69f231f060e0a539d9a23fb3e95451ce8c6340cfb09edf931df84203a39226dd9eb278f11b691ef612585b973daab373e65d11325898badf6732100371fd759960fa8fec373268421d28bffdb9b12a430b92fe4b07566ca0c89e616e49f8fc75ccd9cdc66db820d7c02e109aa5ed86b89770262918a518f90a2292f6b68d68ae03992e4259a17a23c84ec2a417f082b5abf3a26e44d2278ecb8ba9456965303a75f25394d1aaf5544590e74b14d8a4cc4050be2b0ebcfe4d2db6b12a02c68a3bcdda70301f3",
"848755dc31e25e9a42f9ec12d847d19f292c14c162c9aba49e972cb123b58b8e57bb263a923929833373858594ff52dbc298dbbc078599194e4c07b0e5fc1e10808bbacdb6e93c72b333685cf961f28eb0d5a395c63266b01f130d25db384b356e5da6d01042fc2359581b89c63b3bb2d1ce897fbc9e83fe85d9666cb60e6a8c657f70caad5387b8a045bf91095606802c8424ea8ac52ef29386dc46183378a5fcb2cb927428b8c070f1c42aafd3bc70ca25437807696a46873cfeb7b80ba2ebc3c4272443d445e46343a1465253a9eebd532a0d1d2c18264b91ff45159f245404ae9335f2af55c802772426b4",
"ecaa6e999ef355a0768730edb835db411829a3764f79d764bb5682af6d00f51b313e017b83fffe2e332cd4a3de0a81d6a52084d5748346a1f81eb9b183ff6d93d05edc00e938d001c90872dfe234e8dd085f639af168af4a07e18f1c56ca6c7c1addffc4a70eb4660666dda0321636c3f83479ad3b64e23d749620413a2ecdcc52ad4e6e63f2b817ce99c15b5d2da3792721d7158297cce65e0c04fe810d7e2434b969e4c7892b3840623e153576356e9a696fd9e7a801c25de621a7849da3f99158d3d09bf039f43c510c8ffb00fa3e9a3c12d2c8062dd25b8dabe53d8581e30427e81c3dfc2d455352487e1255",
"23a3fe80e3636313fdf922a1359514d9f31775e1adf24285e8001c04dbce866df055edf25b506e18953492a173ba5aa0c1ec758123406a97025ba9b6b7a97eb14734424d1a7841ec0eaeba0051d6e9734263bea1af9895a3b8c83d8c854da2ae7832bdd7c285b73f8113c3821cced38b3656b4e6369a9f8327cd368f04128f1d78b6b4260f55995277feffa15e34532cd0306c1f47354667c17018ee012a791af2dbbc7afc92c388008c601740cccbbe66f1eb06ea657e9d478066c2bd2093ab62cd94abadc002722f50968e8acf361658fc64f50685a5b1b004888b3b4f64a4ddb67bec7e4ac64c9ee8deeda896b9",
"758f3567cd992228386a1c01930f7c52a9dcce28fdc1aaa54b0fed97d9a54f1df805f31bac12d559e90a2063cd7df8311a148f6904f78c5440f75e49877c0c0855d59c7f7ee52837e6ef3e54a568a7b38a0d5b896e298c8e46a56d24d8cabda8aeff85a622a3e7c87483ba921f34156defd185f608e2241224286e38121a162c2ba7604f68484717196f6628861a948180e8f06c6cc1ec66d032cf8d16da039cd74277cde31e535bc1692a44046e16881c954af3cd91dc49b443a3680e4bc42a954a46ebd1368b1398edd7580f935514b15c7fbfa9b40048a35122283af731f5e460aa85b66e65f49a9d158699bd2870",
"fe511e86971cea2b6af91b2afa898d9b067fa71780790bb409189f5debe719f405e16acf7c4306a6e6ac5cd535290efe088943b9e6c5d25bfc508023c1b105d20d57252fee8cdbddb4d34a6ec2f72e8d55be55afcafd2e922ab8c31888bec4e816d04f0b2cd23df6e04720969c5152b3563c6da37e4608554cc7b8715bc10aba6a2e3b6fbcd35408df0dd73a9076bfad32b741fcdb0edfb563b3f753508b9b26f0a91673255f9bcda2b9a120f6bfa0632b6551ca517d846a747b66ebda1b2170891ece94c19ce8bf682cc94afdf0053fba4e4f0530935c07cdd6f879c999a8c4328ef6d3e0a37974a230ada83910604337",
"a6024f5b959698c0de45f4f29e1803f99dc8112989c536e5a1337e281bc856ff721e986de183d7b0ea9eb61166830ae5d6d6bc857dc833ff189b52889b8e2bd3f35b4937624d9b36dc5f19db44f0772508029784c7dac9568d28609058bc437e2f79f95b12307d8a8fb042d7fd6ee910a9e8df609ede3283f958ba918a9925a0b1d0f9f9f232062315f28a52cbd60e71c09d83e0f6600f508f0ae8ad7642c080ffc618fcd2314e26f67f1529342569f6df37017f7e3b2dac32ad88d56d175ab22205ee7e3ee94720d76933a21132e110fefbb0689a3adbaa4c685f43652136d09b3a359b5c671e38f11915cb5612db2ae294",
"af6de0e227bd78494acb559ddf34d8a7d55a03912384831be21c38376f39cda8a864aff7a48aed758f6bdf777779a669068a75ce82a06f6b3325c855ed83daf5513a078a61f7dc6c1622a633367e5f3a33e765c8ec5d8d54f48494006fdbf8922063e5340013e312871b7f8f8e5ea439c0d4cb78e2f19dd11f010729b692c65dd0d347f0ce53de9d849224666ea2f6487f1c6f953e8f9dbfd3d6de291c3e9d045e633cfd83c89d2f2327d0b2f31f72ac1604a3db1febc5f22cad08153278047210cc2894582c251a014c652e3951593e70e52a5d7451be8924b64f85c8247dab6268d24710b39fc1c07b4ac829fbda34ed79b5",
"d7314e8b1ff82100b8f5870da62b61c31ab37ace9e6a7b6f7d294571523783c1fdedcbc00dd487dd6f848c34aab493507d07071b5eb59d1a2346068c7f356755fbde3d2cab67514f8c3a12d6ff9f96a977a9ac9263491bd33122a904da5386b943d35a6ba383932df07f259b6b45f69e9b27b4ca124fb3ae143d709853eed86690bc2754d5f8865c355a44b5279d8eb31cdc00f7407fb5f5b34edc57fc7ace943565da2222dc80632ccf42f2f125ceb19714ea964c2e50603c9f8960c3f27c2ed0e18a559931c4352bd7422109a28c5e145003f55c9b7c664fdc985168868950396eaf6fefc7b73d815c1aca721d7c67da632925",
"2928b55c0e4d0f5cb4b60af59e9a702e3d616a8cf427c8bb03981fb8c29026d8f7d89161f36c11654f9a5e8ccb703595a58d671ecdc22c6a784abe363158682be4643002a7da5c9d268a30ea9a8d4cc24f562ab59f55c2b43af7dbcecc7e5ebe7494e82d74145a1e7d442125eb0431c5ea0939b27afa47f8ca97849f341f707660c7fbe49b7a0712fbcb6f7562ae2961425f27c7779c7534ecdeb8047ff3cb89a25159f3e1cefe42f9ef16426241f2c4d62c11d7ac43c4500dfcd184436bb4ef33260366f875230f26d81613c334dbda4736ba9d1d2966502914ec01bbe72d885606ec11da7a2cb01b29d35eebedbb0ecc73ed6c35",
"fd993f50e8a68c7b2c7f87511ce65b93c0aa94dcbdf2c9cca93816f0f3b2ab34c62c586fc507b4900a34cf9d0517e0fe10a89d154c5419c1f5e38de00e8834fe3dc1032abdeb10729a81655a69a12856a78ca6e12110580de879b086fd6608726541cfa9616326bdd36064bc0d1e5f9c93b41278bff6a13b2494b81e238c0c45aea1b07d855e8f3fe1478e373bd9d3957cf8a5e5b9003386793d994c7c575cff2322e2428cbbaa4f47560316ae3354a7478842ff7cc5dcbacb6e871e72b36f06d63a9aaeb9044cfb7974afdc238a5816f537dcf33ee40b4e1a5eb3cff2402b46d548264e133008d284f11b7e4e450bc3c5ff9f79b9c4",
"8df21892f5fc303b0de4adef1970186db6fe71bb3ea3094922e13afcfabf1d0be009f36d6f6310c5f9fda51f1a946507a055b645c296370440e5e83d8e906a2fb51f2b42de8856a81a4f28a73a8825c68ea08e5e366730bce8047011cb7d6d9be8c6f4211308fad21856284d5bc47d199988e0abf5badf8693ceeed0a2d98e8ae94b7775a42925edb1f697ffbd8e806af23145054a85e071819cca4cd48875290ca65e5ee72a9a54ff9f19c10ef4adaf8d04c9a9afcc73853fc128bbebc61f78702787c966ca6e1b1a0e4dab646acdfcd3c6bf3e5cfbec5ebe3e06c8abaa1de56e48421d87c46b5c78030afcafd91f27e7d7c85eb4872b",
"48ec6ec520f8e593d7b3f653eb15553de246723b81a6d0c3221aaa42a37420fba98a23796338dff5f845dce6d5a449be5ecc1887356619270461087e08d05fb60433a83d7bd00c002b09ea210b428965124b9b27d9105a71c826c1a2491cfd60e4cfa86c2da0c7100a8dc1c3f2f94b280d54e01e043acf0e966200d9fa8a41daf3b9382820786c75cadbb8841a1b2be5b6cbeb64878e4a231ae063a99b4e2308960ef0c8e2a16bb3545cc43bdf171493fb89a84f47e7973dc60cf75aeeca71e0a7ebe17d161d4fb9fe009941cc438f16a5bae6c99fcad08cac486eb2a48060b023d8730bf1d82fe60a2f036e6f52a5bff95f43bbe088933f",
"f4d84ed3e564c102600a795eaa9b1eaf4ad12f1a4deca1d042a0a2750ddf6201db03073d8bf553cb9dde48a1b0083827a609f7242b86584cc180964ae794b12ce55661e00e36a6ba4dbc389e6a5a85f1b45df9af7ead1b0a54db56e68639b9d438a91504e82c35d40c7bc7e048a53ac0b04accd0dadf4ac9884b0ca0e3cb5ba4336e3581be4c4760a553823ffa283a1120d4e145af56a59f2533903650f0b9e9ad9fe2e8a3c3c3dd03a1fcb709032c8835324839c735b0c051d0cbd8b5d867617c11023432e4bd275d3d0eb98a0b6cf58071a5b712922f2bc751ac7c2588c447444cde2f37a8ea5ec126425bf517e0d17c9e2999f52fee14b3",
"2ccea21bac9c2b70d3923309cbf2d7cb7abd1fcc8b8b002688870a80029c62397350c3c898194e5deea360bb963d26d485cb7963f8167586976ec0556950b2e86135f4a2800991ce8473bfd44a3c5e937a48b5e355ba5141bccf2131a83988d9d2a9e8e7635a956105b3512c05ef708139ced51d7a4e204c12d8a49a21e8dc6de2629a2fd092326885d9f218745fe09f6d91fb6afce250a30a63689534b6be1f26899ffa3767d835cf586aa47776700f94241bc999b1e3deefe188f37ff734f5f16ee6a00914323dc7b8a143c9137cdcc5cd08ae9566f04bb2941532674c97dff6ffa5ce3405ef8e5d27ec403114253dd6394c0167d72a0044c5",
"2b681c6398aee63bf862770341648bbcd31d7de7903c5903fe3d9469311320bb24d914f2af0cdca199c97214c7c679dc32a2800ba484a03c010ea6be3bb9f2c87e30a98b606050b8a3f297f12b8f92caaeceb3e844652115934874e0a1ab093a73d759b53f6a6c3096940dd22c2bb96ce6820a7b9c6d71a208de9892aa6a7209b0fff56a0cafea52b952cdd6f5752cff3309d448800b4e4c878aa595595b56b12b83fcd6ca89520c7da664e449d7b4438fc455888aad5de0fad9a06eed14afd3513b5ebbffe01775549b701181bd26370764f56eba52fdb24286ad1ac0f5418a7c429f7dfc7f3168437fa8eed7a2ed7c723a485e4c3ed14dea2e07",
"aadfd505a89f4aade2c3018258a7e039401b1fc6a7f3d87910dddbb880d372ec8a13c70d92245de5b8e5f9a285c33b99dc82fa2b22decee72b93a72211656ad7a52696c8e570f78be28c0e427a371dafde856e8d5ed24f83b0660b51e7fac05d93a8666dfde6def59af863f80f3e5f6801182c87422203df390dcb736b8f830052a8832eeeb0b4e27e732aaf793d166b5a3ec7745aeef3766937c2b75a276bddd145f6010c29d035e343e267cb2d828436876ec3a7ebe3b6347d4172f7a99d6821ce152e039e53deb33340b324c7f068ffb94b3cde35a8eaa12d15c3806a7ad0acec3e8c7078c1d32a28fd3eec9f32cb86e4c22166ff69e83785e851",
"1605b8cce529a9d6262fd4390d9e4ae5e14e0adc0ec89b028ef68dd0f373ea259aaa96f2967091dd0874c0105385e9e6da9ca68297c31afa44ef834535fb302ce5b4e49edacbbdf359fe1228a8172495b3e57014c27edd58b685110980056c50c398a64f4923f2d720b4df16d75cb36b4233660694182099c35028a972519c24764fc94e18e582b24deb3491535fc06b83837c7958522800e822201d694af0bd0aa3834e17d4b1ba36f470905ae5f8bbeeb6c4c8604d8af02baa347b07086d6989867ddd5e8e8ed7740c3469bfa2810519c55c6add1332c4c54ee9097961d6741cb12a09713a0d07645f784f42f5ad94b48b836b34263130b0483f15e3",
"ff9c6125b2f60bfd6c2427b279df070e430075096647599bdc68c531152c58e13858b82385d78c856092d6c74106e87ccf51ac7e673936332d9b223444eaa0e762ee258d8a733d3a515ec68ed73285e5ca183ae3278b4820b0ab2797feb1e7d8cc864df585dfb5ebe02a993325a9ad5e2d7d49d3132cf66013898351d044e0fe908ccdfeeebf651983601e3673a1f92d36510c0cc19b2e75856db8e4a41f92a51efa66d6cc22e414944c2c34a5a89ccde0be76f51410824e330d8e7c613194338c93732e8aea651fca18bcf1ac1824340c5553aff1e58d4ab8d7c8842b4712021e517cd6c140f6743c69c7bee05b10a8f24050a8caa4f96d1664909c5a06",
"6e85c2f8e1fdc3aaeb969da1258cb504bbf0070cd03d23b3fb5ee08feea5ee2e0ee1c71a5d0f4f701b351f4e4b4d74cb1e2ae6184814f77b62d2f08134b7236ebf6b67d8a6c9f01b4248b30667c555f5d8646dbfe291151b23c9c9857e33a4d5c847be29a5ee7b402e03bac02d1a4319acc0dd8f25e9c7a266f5e5c896cc11b5b238df96a0963ae806cb277abc515c298a3e61a3036b177acf87a56ca4478c4c6d0d468913de602ec891318bbaf52c97a77c35c5b7d164816cf24e4c4b0b5f45853882f716d61eb947a45ce2efa78f1c70a918512af1ad536cbe6148083385b34e207f5f690d7a954021e4b5f4258a385fd8a87809a481f34202af4caccb82",
"1e9b2c454e9de3a2d723d850331037dbf54133dbe27488ff757dd255833a27d8eb8a128ad12d0978b6884e25737086a704fb289aaaccf930d5b582ab4df1f55f0c429b6875edec3fe45464fa74164be056a55e243c4222c586bec5b18f39036aa903d98180f24f83d09a454dfa1e03a60e6a3ba4613e99c35f874d790174ee48a557f4f021ade4d1b278d7997ef094569b37b3db0505951e9ee8400adaea275c6db51b325ee730c69df97745b556ae41cd98741e28aa3a49544541eeb3da1b1e8fa4e8e9100d66dd0c7f5e2c271b1ecc077de79c462b9fe4c273543ecd82a5bea63c5acc01eca5fb780c7d7c8c9fe208ae8bd50cad1769693d92c6c8649d20d8",
}

View File

@ -0,0 +1,177 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package blake2b
import (
"encoding/binary"
"errors"
"io"
)
// XOF defines the interface to hash functions that
// support arbitrary-length output.
type XOF interface {
// Write absorbs more data into the hash's state. It panics if called
// after Read.
io.Writer
// Read reads more output from the hash. It returns io.EOF if the limit
// has been reached.
io.Reader
// Clone returns a copy of the XOF in its current state.
Clone() XOF
// Reset resets the XOF to its initial state.
Reset()
}
// OutputLengthUnknown can be used as the size argument to NewXOF to indicate
// the length of the output is not known in advance.
const OutputLengthUnknown = 0
// magicUnknownOutputLength is a magic value for the output size that indicates
// an unknown number of output bytes.
const magicUnknownOutputLength = (1 << 32) - 1
// maxOutputLength is the absolute maximum number of bytes to produce when the
// number of output bytes is unknown.
const maxOutputLength = (1 << 32) * 64
// NewXOF creates a new variable-output-length hash. The hash either produce a
// known number of bytes (1 <= size < 2**32-1), or an unknown number of bytes
// (size == OutputLengthUnknown). In the latter case, an absolute limit of
// 256GiB applies.
//
// A non-nil key turns the hash into a MAC. The key must between
// zero and 32 bytes long.
func NewXOF(size uint32, key []byte) (XOF, error) {
if len(key) > Size {
return nil, errKeySize
}
if size == magicUnknownOutputLength {
// 2^32-1 indicates an unknown number of bytes and thus isn't a
// valid length.
return nil, errors.New("blake2b: XOF length too large")
}
if size == OutputLengthUnknown {
size = magicUnknownOutputLength
}
x := &xof{
d: digest{
size: Size,
keyLen: len(key),
},
length: size,
}
copy(x.d.key[:], key)
x.Reset()
return x, nil
}
type xof struct {
d digest
length uint32
remaining uint64
cfg, root, block [Size]byte
offset int
nodeOffset uint32
readMode bool
}
func (x *xof) Write(p []byte) (n int, err error) {
if x.readMode {
panic("blake2b: write to XOF after read")
}
return x.d.Write(p)
}
func (x *xof) Clone() XOF {
clone := *x
return &clone
}
func (x *xof) Reset() {
x.cfg[0] = byte(Size)
binary.LittleEndian.PutUint32(x.cfg[4:], uint32(Size)) // leaf length
binary.LittleEndian.PutUint32(x.cfg[12:], x.length) // XOF length
x.cfg[17] = byte(Size) // inner hash size
x.d.Reset()
x.d.h[1] ^= uint64(x.length) << 32
x.remaining = uint64(x.length)
if x.remaining == magicUnknownOutputLength {
x.remaining = maxOutputLength
}
x.offset, x.nodeOffset = 0, 0
x.readMode = false
}
func (x *xof) Read(p []byte) (n int, err error) {
if !x.readMode {
x.d.finalize(&x.root)
x.readMode = true
}
if x.remaining == 0 {
return 0, io.EOF
}
n = len(p)
if uint64(n) > x.remaining {
n = int(x.remaining)
p = p[:n]
}
if x.offset > 0 {
blockRemaining := Size - x.offset
if n < blockRemaining {
x.offset += copy(p, x.block[x.offset:])
x.remaining -= uint64(n)
return
}
copy(p, x.block[x.offset:])
p = p[blockRemaining:]
x.offset = 0
x.remaining -= uint64(blockRemaining)
}
for len(p) >= Size {
binary.LittleEndian.PutUint32(x.cfg[8:], x.nodeOffset)
x.nodeOffset++
x.d.initConfig(&x.cfg)
x.d.Write(x.root[:])
x.d.finalize(&x.block)
copy(p, x.block[:])
p = p[Size:]
x.remaining -= uint64(Size)
}
if todo := len(p); todo > 0 {
if x.remaining < uint64(Size) {
x.cfg[0] = byte(x.remaining)
}
binary.LittleEndian.PutUint32(x.cfg[8:], x.nodeOffset)
x.nodeOffset++
x.d.initConfig(&x.cfg)
x.d.Write(x.root[:])
x.d.finalize(&x.block)
x.offset = copy(p, x.block[:todo])
x.remaining -= uint64(todo)
}
return
}
func (d *digest) initConfig(cfg *[Size]byte) {
d.offset, d.c[0], d.c[1] = 0, 0, 0
for i := range d.h {
d.h[i] = iv[i] ^ binary.LittleEndian.Uint64(cfg[i*8:])
}
}

View File

@ -0,0 +1,32 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build go1.9
package blake2b
import (
"crypto"
"hash"
)
func init() {
newHash256 := func() hash.Hash {
h, _ := New256(nil)
return h
}
newHash384 := func() hash.Hash {
h, _ := New384(nil)
return h
}
newHash512 := func() hash.Hash {
h, _ := New512(nil)
return h
}
crypto.RegisterHash(crypto.BLAKE2b_256, newHash256)
crypto.RegisterHash(crypto.BLAKE2b_384, newHash384)
crypto.RegisterHash(crypto.BLAKE2b_512, newHash512)
}

View File

@ -0,0 +1,83 @@
// 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/>.
// +build amd64,blsasm amd64,blsadx
package bls12381
import (
"golang.org/x/sys/cpu"
)
func init() {
if !enableADX || !cpu.X86.HasADX || !cpu.X86.HasBMI2 {
mul = mulNoADX
}
}
// Use ADX backend for default
var mul func(c, a, b *fe) = mulADX
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 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)

View File

@ -0,0 +1,566 @@
// Native go field arithmetic code is generated with 'goff'
// https://github.com/ConsenSys/goff
// Many function signature of field operations are renamed.
// Copyright 2020 ConsenSys AG
//
// 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.
// field modulus q =
//
// 4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787
// Code generated by goff DO NOT EDIT
// goff version: v0.1.0 - build: 790f1f56eac432441e043abff8819eacddd1d668
// fe are assumed to be in Montgomery form in all methods
// /!\ 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 bls (generated by goff) contains field arithmetics operations
// +build !amd64 !blsasm,!blsadx
package bls12381
import (
"math/bits"
)
func add(z, x, y *fe) {
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], carry = bits.Add64(x[3], y[3], carry)
z[4], carry = bits.Add64(x[4], y[4], carry)
z[5], _ = bits.Add64(x[5], y[5], carry)
// if z > q --> z -= q
// note: this is NOT constant time
if !(z[5] < 1873798617647539866 || (z[5] == 1873798617647539866 && (z[4] < 5412103778470702295 || (z[4] == 5412103778470702295 && (z[3] < 7239337960414712511 || (z[3] == 7239337960414712511 && (z[2] < 7435674573564081700 || (z[2] == 7435674573564081700 && (z[1] < 2210141511517208575 || (z[1] == 2210141511517208575 && (z[0] < 13402431016077863595))))))))))) {
var b uint64
z[0], b = bits.Sub64(z[0], 13402431016077863595, 0)
z[1], b = bits.Sub64(z[1], 2210141511517208575, b)
z[2], b = bits.Sub64(z[2], 7435674573564081700, b)
z[3], b = bits.Sub64(z[3], 7239337960414712511, b)
z[4], b = bits.Sub64(z[4], 5412103778470702295, b)
z[5], _ = bits.Sub64(z[5], 1873798617647539866, b)
}
}
func addAssign(x, y *fe) {
var carry uint64
x[0], carry = bits.Add64(x[0], y[0], 0)
x[1], carry = bits.Add64(x[1], y[1], carry)
x[2], carry = bits.Add64(x[2], y[2], carry)
x[3], carry = bits.Add64(x[3], y[3], carry)
x[4], carry = bits.Add64(x[4], y[4], carry)
x[5], _ = bits.Add64(x[5], y[5], carry)
// if z > q --> z -= q
// note: this is NOT constant time
if !(x[5] < 1873798617647539866 || (x[5] == 1873798617647539866 && (x[4] < 5412103778470702295 || (x[4] == 5412103778470702295 && (x[3] < 7239337960414712511 || (x[3] == 7239337960414712511 && (x[2] < 7435674573564081700 || (x[2] == 7435674573564081700 && (x[1] < 2210141511517208575 || (x[1] == 2210141511517208575 && (x[0] < 13402431016077863595))))))))))) {
var b uint64
x[0], b = bits.Sub64(x[0], 13402431016077863595, 0)
x[1], b = bits.Sub64(x[1], 2210141511517208575, b)
x[2], b = bits.Sub64(x[2], 7435674573564081700, b)
x[3], b = bits.Sub64(x[3], 7239337960414712511, b)
x[4], b = bits.Sub64(x[4], 5412103778470702295, b)
x[5], _ = bits.Sub64(x[5], 1873798617647539866, b)
}
}
func ladd(z, x, y *fe) {
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], carry = bits.Add64(x[3], y[3], carry)
z[4], carry = bits.Add64(x[4], y[4], carry)
z[5], _ = bits.Add64(x[5], y[5], carry)
}
func laddAssign(x, y *fe) {
var carry uint64
x[0], carry = bits.Add64(x[0], y[0], 0)
x[1], carry = bits.Add64(x[1], y[1], carry)
x[2], carry = bits.Add64(x[2], y[2], carry)
x[3], carry = bits.Add64(x[3], y[3], carry)
x[4], carry = bits.Add64(x[4], y[4], carry)
x[5], _ = bits.Add64(x[5], y[5], carry)
}
func double(z, x *fe) {
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], carry = bits.Add64(x[3], x[3], carry)
z[4], carry = bits.Add64(x[4], x[4], carry)
z[5], _ = bits.Add64(x[5], x[5], carry)
// if z > q --> z -= q
// note: this is NOT constant time
if !(z[5] < 1873798617647539866 || (z[5] == 1873798617647539866 && (z[4] < 5412103778470702295 || (z[4] == 5412103778470702295 && (z[3] < 7239337960414712511 || (z[3] == 7239337960414712511 && (z[2] < 7435674573564081700 || (z[2] == 7435674573564081700 && (z[1] < 2210141511517208575 || (z[1] == 2210141511517208575 && (z[0] < 13402431016077863595))))))))))) {
var b uint64
z[0], b = bits.Sub64(z[0], 13402431016077863595, 0)
z[1], b = bits.Sub64(z[1], 2210141511517208575, b)
z[2], b = bits.Sub64(z[2], 7435674573564081700, b)
z[3], b = bits.Sub64(z[3], 7239337960414712511, b)
z[4], b = bits.Sub64(z[4], 5412103778470702295, b)
z[5], _ = bits.Sub64(z[5], 1873798617647539866, b)
}
}
func doubleAssign(z *fe) {
var carry uint64
z[0], carry = bits.Add64(z[0], z[0], 0)
z[1], carry = bits.Add64(z[1], z[1], carry)
z[2], carry = bits.Add64(z[2], z[2], carry)
z[3], carry = bits.Add64(z[3], z[3], carry)
z[4], carry = bits.Add64(z[4], z[4], carry)
z[5], _ = bits.Add64(z[5], z[5], carry)
// if z > q --> z -= q
// note: this is NOT constant time
if !(z[5] < 1873798617647539866 || (z[5] == 1873798617647539866 && (z[4] < 5412103778470702295 || (z[4] == 5412103778470702295 && (z[3] < 7239337960414712511 || (z[3] == 7239337960414712511 && (z[2] < 7435674573564081700 || (z[2] == 7435674573564081700 && (z[1] < 2210141511517208575 || (z[1] == 2210141511517208575 && (z[0] < 13402431016077863595))))))))))) {
var b uint64
z[0], b = bits.Sub64(z[0], 13402431016077863595, 0)
z[1], b = bits.Sub64(z[1], 2210141511517208575, b)
z[2], b = bits.Sub64(z[2], 7435674573564081700, b)
z[3], b = bits.Sub64(z[3], 7239337960414712511, b)
z[4], b = bits.Sub64(z[4], 5412103778470702295, b)
z[5], _ = bits.Sub64(z[5], 1873798617647539866, b)
}
}
func ldouble(z, x *fe) {
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], carry = bits.Add64(x[3], x[3], carry)
z[4], carry = bits.Add64(x[4], x[4], carry)
z[5], _ = bits.Add64(x[5], x[5], carry)
}
func sub(z, x, y *fe) {
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)
z[4], b = bits.Sub64(x[4], y[4], b)
z[5], b = bits.Sub64(x[5], y[5], b)
if b != 0 {
var c uint64
z[0], c = bits.Add64(z[0], 13402431016077863595, 0)
z[1], c = bits.Add64(z[1], 2210141511517208575, c)
z[2], c = bits.Add64(z[2], 7435674573564081700, c)
z[3], c = bits.Add64(z[3], 7239337960414712511, c)
z[4], c = bits.Add64(z[4], 5412103778470702295, c)
z[5], _ = bits.Add64(z[5], 1873798617647539866, c)
}
}
func subAssign(z, x *fe) {
var b uint64
z[0], b = bits.Sub64(z[0], x[0], 0)
z[1], b = bits.Sub64(z[1], x[1], b)
z[2], b = bits.Sub64(z[2], x[2], b)
z[3], b = bits.Sub64(z[3], x[3], b)
z[4], b = bits.Sub64(z[4], x[4], b)
z[5], b = bits.Sub64(z[5], x[5], b)
if b != 0 {
var c uint64
z[0], c = bits.Add64(z[0], 13402431016077863595, 0)
z[1], c = bits.Add64(z[1], 2210141511517208575, c)
z[2], c = bits.Add64(z[2], 7435674573564081700, c)
z[3], c = bits.Add64(z[3], 7239337960414712511, c)
z[4], c = bits.Add64(z[4], 5412103778470702295, c)
z[5], _ = bits.Add64(z[5], 1873798617647539866, c)
}
}
func lsubAssign(z, x *fe) {
var b uint64
z[0], b = bits.Sub64(z[0], x[0], 0)
z[1], b = bits.Sub64(z[1], x[1], b)
z[2], b = bits.Sub64(z[2], x[2], b)
z[3], b = bits.Sub64(z[3], x[3], b)
z[4], b = bits.Sub64(z[4], x[4], b)
z[5], _ = bits.Sub64(z[5], x[5], b)
}
func neg(z *fe, x *fe) {
if x.isZero() {
z.zero()
return
}
var borrow uint64
z[0], borrow = bits.Sub64(13402431016077863595, x[0], 0)
z[1], borrow = bits.Sub64(2210141511517208575, x[1], borrow)
z[2], borrow = bits.Sub64(7435674573564081700, x[2], borrow)
z[3], borrow = bits.Sub64(7239337960414712511, x[3], borrow)
z[4], borrow = bits.Sub64(5412103778470702295, x[4], borrow)
z[5], _ = bits.Sub64(1873798617647539866, x[5], borrow)
}
func mul(z, x, y *fe) {
var t [6]uint64
var c [3]uint64
{
// round 0
v := x[0]
c[1], c[0] = bits.Mul64(v, y[0])
m := c[0] * 9940570264628428797
c[2] = madd0(m, 13402431016077863595, c[0])
c[1], c[0] = madd1(v, y[1], c[1])
c[2], t[0] = madd2(m, 2210141511517208575, c[2], c[0])
c[1], c[0] = madd1(v, y[2], c[1])
c[2], t[1] = madd2(m, 7435674573564081700, c[2], c[0])
c[1], c[0] = madd1(v, y[3], c[1])
c[2], t[2] = madd2(m, 7239337960414712511, c[2], c[0])
c[1], c[0] = madd1(v, y[4], c[1])
c[2], t[3] = madd2(m, 5412103778470702295, c[2], c[0])
c[1], c[0] = madd1(v, y[5], c[1])
t[5], t[4] = madd3(m, 1873798617647539866, c[0], c[2], c[1])
}
{
// round 1
v := x[1]
c[1], c[0] = madd1(v, y[0], t[0])
m := c[0] * 9940570264628428797
c[2] = madd0(m, 13402431016077863595, c[0])
c[1], c[0] = madd2(v, y[1], c[1], t[1])
c[2], t[0] = madd2(m, 2210141511517208575, c[2], c[0])
c[1], c[0] = madd2(v, y[2], c[1], t[2])
c[2], t[1] = madd2(m, 7435674573564081700, c[2], c[0])
c[1], c[0] = madd2(v, y[3], c[1], t[3])
c[2], t[2] = madd2(m, 7239337960414712511, c[2], c[0])
c[1], c[0] = madd2(v, y[4], c[1], t[4])
c[2], t[3] = madd2(m, 5412103778470702295, c[2], c[0])
c[1], c[0] = madd2(v, y[5], c[1], t[5])
t[5], t[4] = madd3(m, 1873798617647539866, c[0], c[2], c[1])
}
{
// round 2
v := x[2]
c[1], c[0] = madd1(v, y[0], t[0])
m := c[0] * 9940570264628428797
c[2] = madd0(m, 13402431016077863595, c[0])
c[1], c[0] = madd2(v, y[1], c[1], t[1])
c[2], t[0] = madd2(m, 2210141511517208575, c[2], c[0])
c[1], c[0] = madd2(v, y[2], c[1], t[2])
c[2], t[1] = madd2(m, 7435674573564081700, c[2], c[0])
c[1], c[0] = madd2(v, y[3], c[1], t[3])
c[2], t[2] = madd2(m, 7239337960414712511, c[2], c[0])
c[1], c[0] = madd2(v, y[4], c[1], t[4])
c[2], t[3] = madd2(m, 5412103778470702295, c[2], c[0])
c[1], c[0] = madd2(v, y[5], c[1], t[5])
t[5], t[4] = madd3(m, 1873798617647539866, c[0], c[2], c[1])
}
{
// round 3
v := x[3]
c[1], c[0] = madd1(v, y[0], t[0])
m := c[0] * 9940570264628428797
c[2] = madd0(m, 13402431016077863595, c[0])
c[1], c[0] = madd2(v, y[1], c[1], t[1])
c[2], t[0] = madd2(m, 2210141511517208575, c[2], c[0])
c[1], c[0] = madd2(v, y[2], c[1], t[2])
c[2], t[1] = madd2(m, 7435674573564081700, c[2], c[0])
c[1], c[0] = madd2(v, y[3], c[1], t[3])
c[2], t[2] = madd2(m, 7239337960414712511, c[2], c[0])
c[1], c[0] = madd2(v, y[4], c[1], t[4])
c[2], t[3] = madd2(m, 5412103778470702295, c[2], c[0])
c[1], c[0] = madd2(v, y[5], c[1], t[5])
t[5], t[4] = madd3(m, 1873798617647539866, c[0], c[2], c[1])
}
{
// round 4
v := x[4]
c[1], c[0] = madd1(v, y[0], t[0])
m := c[0] * 9940570264628428797
c[2] = madd0(m, 13402431016077863595, c[0])
c[1], c[0] = madd2(v, y[1], c[1], t[1])
c[2], t[0] = madd2(m, 2210141511517208575, c[2], c[0])
c[1], c[0] = madd2(v, y[2], c[1], t[2])
c[2], t[1] = madd2(m, 7435674573564081700, c[2], c[0])
c[1], c[0] = madd2(v, y[3], c[1], t[3])
c[2], t[2] = madd2(m, 7239337960414712511, c[2], c[0])
c[1], c[0] = madd2(v, y[4], c[1], t[4])
c[2], t[3] = madd2(m, 5412103778470702295, c[2], c[0])
c[1], c[0] = madd2(v, y[5], c[1], t[5])
t[5], t[4] = madd3(m, 1873798617647539866, c[0], c[2], c[1])
}
{
// round 5
v := x[5]
c[1], c[0] = madd1(v, y[0], t[0])
m := c[0] * 9940570264628428797
c[2] = madd0(m, 13402431016077863595, c[0])
c[1], c[0] = madd2(v, y[1], c[1], t[1])
c[2], z[0] = madd2(m, 2210141511517208575, c[2], c[0])
c[1], c[0] = madd2(v, y[2], c[1], t[2])
c[2], z[1] = madd2(m, 7435674573564081700, c[2], c[0])
c[1], c[0] = madd2(v, y[3], c[1], t[3])
c[2], z[2] = madd2(m, 7239337960414712511, c[2], c[0])
c[1], c[0] = madd2(v, y[4], c[1], t[4])
c[2], z[3] = madd2(m, 5412103778470702295, c[2], c[0])
c[1], c[0] = madd2(v, y[5], c[1], t[5])
z[5], z[4] = madd3(m, 1873798617647539866, c[0], c[2], c[1])
}
// if z > q --> z -= q
// note: this is NOT constant time
if !(z[5] < 1873798617647539866 || (z[5] == 1873798617647539866 && (z[4] < 5412103778470702295 || (z[4] == 5412103778470702295 && (z[3] < 7239337960414712511 || (z[3] == 7239337960414712511 && (z[2] < 7435674573564081700 || (z[2] == 7435674573564081700 && (z[1] < 2210141511517208575 || (z[1] == 2210141511517208575 && (z[0] < 13402431016077863595))))))))))) {
var b uint64
z[0], b = bits.Sub64(z[0], 13402431016077863595, 0)
z[1], b = bits.Sub64(z[1], 2210141511517208575, b)
z[2], b = bits.Sub64(z[2], 7435674573564081700, b)
z[3], b = bits.Sub64(z[3], 7239337960414712511, b)
z[4], b = bits.Sub64(z[4], 5412103778470702295, b)
z[5], _ = bits.Sub64(z[5], 1873798617647539866, b)
}
}
func square(z, x *fe) {
var p [6]uint64
var u, v uint64
{
// round 0
u, p[0] = bits.Mul64(x[0], x[0])
m := p[0] * 9940570264628428797
C := madd0(m, 13402431016077863595, p[0])
var t uint64
t, u, v = madd1sb(x[0], x[1], u)
C, p[0] = madd2(m, 2210141511517208575, v, C)
t, u, v = madd1s(x[0], x[2], t, u)
C, p[1] = madd2(m, 7435674573564081700, v, C)
t, u, v = madd1s(x[0], x[3], t, u)
C, p[2] = madd2(m, 7239337960414712511, v, C)
t, u, v = madd1s(x[0], x[4], t, u)
C, p[3] = madd2(m, 5412103778470702295, v, C)
_, u, v = madd1s(x[0], x[5], t, u)
p[5], p[4] = madd3(m, 1873798617647539866, v, C, u)
}
{
// round 1
m := p[0] * 9940570264628428797
C := madd0(m, 13402431016077863595, p[0])
u, v = madd1(x[1], x[1], p[1])
C, p[0] = madd2(m, 2210141511517208575, v, C)
var t uint64
t, u, v = madd2sb(x[1], x[2], p[2], u)
C, p[1] = madd2(m, 7435674573564081700, v, C)
t, u, v = madd2s(x[1], x[3], p[3], t, u)
C, p[2] = madd2(m, 7239337960414712511, v, C)
t, u, v = madd2s(x[1], x[4], p[4], t, u)
C, p[3] = madd2(m, 5412103778470702295, v, C)
_, u, v = madd2s(x[1], x[5], p[5], t, u)
p[5], p[4] = madd3(m, 1873798617647539866, v, C, u)
}
{
// round 2
m := p[0] * 9940570264628428797
C := madd0(m, 13402431016077863595, p[0])
C, p[0] = madd2(m, 2210141511517208575, p[1], C)
u, v = madd1(x[2], x[2], p[2])
C, p[1] = madd2(m, 7435674573564081700, v, C)
var t uint64
t, u, v = madd2sb(x[2], x[3], p[3], u)
C, p[2] = madd2(m, 7239337960414712511, v, C)
t, u, v = madd2s(x[2], x[4], p[4], t, u)
C, p[3] = madd2(m, 5412103778470702295, v, C)
_, u, v = madd2s(x[2], x[5], p[5], t, u)
p[5], p[4] = madd3(m, 1873798617647539866, v, C, u)
}
{
// round 3
m := p[0] * 9940570264628428797
C := madd0(m, 13402431016077863595, p[0])
C, p[0] = madd2(m, 2210141511517208575, p[1], C)
C, p[1] = madd2(m, 7435674573564081700, p[2], C)
u, v = madd1(x[3], x[3], p[3])
C, p[2] = madd2(m, 7239337960414712511, v, C)
var t uint64
t, u, v = madd2sb(x[3], x[4], p[4], u)
C, p[3] = madd2(m, 5412103778470702295, v, C)
_, u, v = madd2s(x[3], x[5], p[5], t, u)
p[5], p[4] = madd3(m, 1873798617647539866, v, C, u)
}
{
// round 4
m := p[0] * 9940570264628428797
C := madd0(m, 13402431016077863595, p[0])
C, p[0] = madd2(m, 2210141511517208575, p[1], C)
C, p[1] = madd2(m, 7435674573564081700, p[2], C)
C, p[2] = madd2(m, 7239337960414712511, p[3], C)
u, v = madd1(x[4], x[4], p[4])
C, p[3] = madd2(m, 5412103778470702295, v, C)
_, u, v = madd2sb(x[4], x[5], p[5], u)
p[5], p[4] = madd3(m, 1873798617647539866, v, C, u)
}
{
// round 5
m := p[0] * 9940570264628428797
C := madd0(m, 13402431016077863595, p[0])
C, z[0] = madd2(m, 2210141511517208575, p[1], C)
C, z[1] = madd2(m, 7435674573564081700, p[2], C)
C, z[2] = madd2(m, 7239337960414712511, p[3], C)
C, z[3] = madd2(m, 5412103778470702295, p[4], C)
u, v = madd1(x[5], x[5], p[5])
z[5], z[4] = madd3(m, 1873798617647539866, v, C, u)
}
// if z > q --> z -= q
// note: this is NOT constant time
if !(z[5] < 1873798617647539866 || (z[5] == 1873798617647539866 && (z[4] < 5412103778470702295 || (z[4] == 5412103778470702295 && (z[3] < 7239337960414712511 || (z[3] == 7239337960414712511 && (z[2] < 7435674573564081700 || (z[2] == 7435674573564081700 && (z[1] < 2210141511517208575 || (z[1] == 2210141511517208575 && (z[0] < 13402431016077863595))))))))))) {
var b uint64
z[0], b = bits.Sub64(z[0], 13402431016077863595, 0)
z[1], b = bits.Sub64(z[1], 2210141511517208575, b)
z[2], b = bits.Sub64(z[2], 7435674573564081700, b)
z[3], b = bits.Sub64(z[3], 7239337960414712511, b)
z[4], b = bits.Sub64(z[4], 5412103778470702295, b)
z[5], _ = bits.Sub64(z[5], 1873798617647539866, b)
}
}
// arith.go
// Copyright 2020 ConsenSys AG
//
// 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 DO NOT EDIT
func madd(a, b, t, u, v uint64) (uint64, uint64, uint64) {
var carry uint64
hi, lo := bits.Mul64(a, b)
v, carry = bits.Add64(lo, v, 0)
u, carry = bits.Add64(hi, u, carry)
t, _ = bits.Add64(t, 0, carry)
return t, u, v
}
// 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
}
// madd2s superhi, hi, lo = 2*a*b + c + d + e
func madd2s(a, b, c, d, e uint64) (superhi, hi, lo uint64) {
var carry, sum uint64
hi, lo = bits.Mul64(a, b)
lo, carry = bits.Add64(lo, lo, 0)
hi, superhi = bits.Add64(hi, hi, carry)
sum, carry = bits.Add64(c, e, 0)
hi, _ = bits.Add64(hi, 0, carry)
lo, carry = bits.Add64(lo, sum, 0)
hi, _ = bits.Add64(hi, 0, carry)
hi, _ = bits.Add64(hi, 0, d)
return
}
func madd1s(a, b, d, e uint64) (superhi, hi, lo uint64) {
var carry uint64
hi, lo = bits.Mul64(a, b)
lo, carry = bits.Add64(lo, lo, 0)
hi, superhi = bits.Add64(hi, hi, carry)
lo, carry = bits.Add64(lo, e, 0)
hi, _ = bits.Add64(hi, 0, carry)
hi, _ = bits.Add64(hi, 0, d)
return
}
func madd2sb(a, b, c, e uint64) (superhi, hi, lo uint64) {
var carry, sum uint64
hi, lo = bits.Mul64(a, b)
lo, carry = bits.Add64(lo, lo, 0)
hi, superhi = bits.Add64(hi, hi, carry)
sum, carry = bits.Add64(c, e, 0)
hi, _ = bits.Add64(hi, 0, carry)
lo, carry = bits.Add64(lo, sum, 0)
hi, _ = bits.Add64(hi, 0, carry)
return
}
func madd1sb(a, b, e uint64) (superhi, hi, lo uint64) {
var carry uint64
hi, lo = bits.Mul64(a, b)
lo, carry = bits.Add64(lo, lo, 0)
hi, superhi = bits.Add64(hi, hi, carry)
lo, carry = bits.Add64(lo, e, 0)
hi, _ = bits.Add64(hi, 0, carry)
return
}
func madd3(a, b, c, d, e uint64) (hi uint64, lo uint64) {
var carry uint64
hi, lo = bits.Mul64(a, b)
c, carry = bits.Add64(c, d, 0)
hi, _ = bits.Add64(hi, 0, carry)
lo, carry = bits.Add64(lo, c, 0)
hi, _ = bits.Add64(hi, e, carry)
return
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,24 @@
// 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/>.
// +build amd64,blsadx
package bls12381
// enableADX is true if the ADX/BMI2 instruction set was requested for the BLS
// implementation. The system may still fall back to plain ASM if the necessary
// instructions are unavailable on the CPU.
const enableADX = true

View File

@ -0,0 +1,24 @@
// 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/>.
// +build amd64,blsasm
package bls12381
// enableADX is true if the ADX/BMI2 instruction set was requested for the BLS
// implementation. The system may still fall back to plain ASM if the necessary
// instructions are unavailable on the CPU.
const enableADX = false

View File

@ -0,0 +1,230 @@
// 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/>.
package bls12381
/*
Field Constants
*/
// Base field modulus
// p = 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab
// Size of six words
// r = 2 ^ 384
// modulus = p
var modulus = fe{0xb9feffffffffaaab, 0x1eabfffeb153ffff, 0x6730d2a0f6b0f624, 0x64774b84f38512bf, 0x4b1ba7b6434bacd7, 0x1a0111ea397fe69a}
var (
// -p^(-1) mod 2^64
inp uint64 = 0x89f3fffcfffcfffd
// This value is used in assembly code
_ = inp
)
// r mod p
var r1 = &fe{0x760900000002fffd, 0xebf4000bc40c0002, 0x5f48985753c758ba, 0x77ce585370525745, 0x5c071a97a256ec6d, 0x15f65ec3fa80e493}
// r^2 mod p
var r2 = &fe{
0xf4df1f341c341746, 0x0a76e6a609d104f1, 0x8de5476c4c95b6d5, 0x67eb88a9939d83c0, 0x9a793e85b519952d, 0x11988fe592cae3aa,
}
// -1 + 0 * u
var negativeOne2 = &fe2{
fe{0x43f5fffffffcaaae, 0x32b7fff2ed47fffd, 0x07e83a49a2e99d69, 0xeca8f3318332bb7a, 0xef148d1ea0f4c069, 0x040ab3263eff0206},
fe{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000},
}
// 2 ^ (-1)
var twoInv = &fe{0x1804000000015554, 0x855000053ab00001, 0x633cb57c253c276f, 0x6e22d1ec31ebb502, 0xd3916126f2d14ca2, 0x17fbb8571a006596}
// (p - 3) / 4
var pMinus3Over4 = bigFromHex("0x680447a8e5ff9a692c6e9ed90d2eb35d91dd2e13ce144afd9cc34a83dac3d8907aaffffac54ffffee7fbfffffffeaaa")
// (p + 1) / 4
var pPlus1Over4 = bigFromHex("0x680447a8e5ff9a692c6e9ed90d2eb35d91dd2e13ce144afd9cc34a83dac3d8907aaffffac54ffffee7fbfffffffeaab")
// (p - 1) / 2
var pMinus1Over2 = bigFromHex("0xd0088f51cbff34d258dd3db21a5d66bb23ba5c279c2895fb39869507b587b120f55ffff58a9ffffdcff7fffffffd555")
// -1
var nonResidue1 = &fe{0x43f5fffffffcaaae, 0x32b7fff2ed47fffd, 0x07e83a49a2e99d69, 0xeca8f3318332bb7a, 0xef148d1ea0f4c069, 0x040ab3263eff0206}
// (1 + 1 * u)
var nonResidue2 = &fe2{
fe{0x760900000002fffd, 0xebf4000bc40c0002, 0x5f48985753c758ba, 0x77ce585370525745, 0x5c071a97a256ec6d, 0x15f65ec3fa80e493},
fe{0x760900000002fffd, 0xebf4000bc40c0002, 0x5f48985753c758ba, 0x77ce585370525745, 0x5c071a97a256ec6d, 0x15f65ec3fa80e493},
}
/*
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},
}
// Curve order
var q = bigFromHex("0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001")
// Efficient cofactor of G1
var cofactorEFFG1 = bigFromHex("0xd201000000010001")
// Efficient cofactor of G2
var cofactorEFFG2 = bigFromHex("0x0bc69f08f2ee75b3584c6a0ea91b352888e2a8e9145ad7689986ff031508ffe1329c2f178731db956d82bf015d1212b02ec0ec69d7477c1ae954cbc06689f6a359894c0adebbf6b4e8020005aaa95551")
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 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},
},
}
/*
Frobenious Coeffs
*/
var frobeniusCoeffs61 = [6]fe2{
fe2{
fe{0x760900000002fffd, 0xebf4000bc40c0002, 0x5f48985753c758ba, 0x77ce585370525745, 0x5c071a97a256ec6d, 0x15f65ec3fa80e493},
fe{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000},
},
fe2{
fe{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000},
fe{0xcd03c9e48671f071, 0x5dab22461fcda5d2, 0x587042afd3851b95, 0x8eb60ebe01bacb9e, 0x03f97d6e83d050d2, 0x18f0206554638741},
},
fe2{
fe{0x30f1361b798a64e8, 0xf3b8ddab7ece5a2a, 0x16a8ca3ac61577f7, 0xc26a2ff874fd029b, 0x3636b76660701c6e, 0x051ba4ab241b6160},
fe{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000},
},
fe2{
fe{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000},
fe{0x760900000002fffd, 0xebf4000bc40c0002, 0x5f48985753c758ba, 0x77ce585370525745, 0x5c071a97a256ec6d, 0x15f65ec3fa80e493},
},
fe2{
fe{0xcd03c9e48671f071, 0x5dab22461fcda5d2, 0x587042afd3851b95, 0x8eb60ebe01bacb9e, 0x03f97d6e83d050d2, 0x18f0206554638741},
fe{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000},
},
fe2{
fe{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000},
fe{0x30f1361b798a64e8, 0xf3b8ddab7ece5a2a, 0x16a8ca3ac61577f7, 0xc26a2ff874fd029b, 0x3636b76660701c6e, 0x051ba4ab241b6160},
},
}
var frobeniusCoeffs62 = [6]fe2{
fe2{
fe{0x760900000002fffd, 0xebf4000bc40c0002, 0x5f48985753c758ba, 0x77ce585370525745, 0x5c071a97a256ec6d, 0x15f65ec3fa80e493},
fe{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000},
},
fe2{
fe{0x890dc9e4867545c3, 0x2af322533285a5d5, 0x50880866309b7e2c, 0xa20d1b8c7e881024, 0x14e4f04fe2db9068, 0x14e56d3f1564853a},
fe{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000},
},
fe2{
fe{0xcd03c9e48671f071, 0x5dab22461fcda5d2, 0x587042afd3851b95, 0x8eb60ebe01bacb9e, 0x03f97d6e83d050d2, 0x18f0206554638741},
fe{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000},
},
fe2{
fe{0x43f5fffffffcaaae, 0x32b7fff2ed47fffd, 0x07e83a49a2e99d69, 0xeca8f3318332bb7a, 0xef148d1ea0f4c069, 0x040ab3263eff0206},
fe{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000},
},
fe2{
fe{0x30f1361b798a64e8, 0xf3b8ddab7ece5a2a, 0x16a8ca3ac61577f7, 0xc26a2ff874fd029b, 0x3636b76660701c6e, 0x051ba4ab241b6160},
fe{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000},
},
fe2{
fe{0xecfb361b798dba3a, 0xc100ddb891865a2c, 0x0ec08ff1232bda8e, 0xd5c13cc6f1ca4721, 0x47222a47bf7b5c04, 0x0110f184e51c5f59},
fe{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000},
},
}
var frobeniusCoeffs12 = [12]fe2{
fe2{
fe{0x760900000002fffd, 0xebf4000bc40c0002, 0x5f48985753c758ba, 0x77ce585370525745, 0x5c071a97a256ec6d, 0x15f65ec3fa80e493},
fe{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000},
},
fe2{
fe{0x07089552b319d465, 0xc6695f92b50a8313, 0x97e83cccd117228f, 0xa35baecab2dc29ee, 0x1ce393ea5daace4d, 0x08f2220fb0fb66eb},
fe{0xb2f66aad4ce5d646, 0x5842a06bfc497cec, 0xcf4895d42599d394, 0xc11b9cba40a8e8d0, 0x2e3813cbe5a0de89, 0x110eefda88847faf},
},
fe2{
fe{0xecfb361b798dba3a, 0xc100ddb891865a2c, 0x0ec08ff1232bda8e, 0xd5c13cc6f1ca4721, 0x47222a47bf7b5c04, 0x0110f184e51c5f59},
fe{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000},
},
fe2{
fe{0x3e2f585da55c9ad1, 0x4294213d86c18183, 0x382844c88b623732, 0x92ad2afd19103e18, 0x1d794e4fac7cf0b9, 0x0bd592fc7d825ec8},
fe{0x7bcfa7a25aa30fda, 0xdc17dec12a927e7c, 0x2f088dd86b4ebef1, 0xd1ca2087da74d4a7, 0x2da2596696cebc1d, 0x0e2b7eedbbfd87d2},
},
fe2{
fe{0x30f1361b798a64e8, 0xf3b8ddab7ece5a2a, 0x16a8ca3ac61577f7, 0xc26a2ff874fd029b, 0x3636b76660701c6e, 0x051ba4ab241b6160},
fe{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000},
},
fe2{
fe{0x3726c30af242c66c, 0x7c2ac1aad1b6fe70, 0xa04007fbba4b14a2, 0xef517c3266341429, 0x0095ba654ed2226b, 0x02e370eccc86f7dd},
fe{0x82d83cf50dbce43f, 0xa2813e53df9d018f, 0xc6f0caa53c65e181, 0x7525cf528d50fe95, 0x4a85ed50f4798a6b, 0x171da0fd6cf8eebd},
},
fe2{
fe{0x43f5fffffffcaaae, 0x32b7fff2ed47fffd, 0x07e83a49a2e99d69, 0xeca8f3318332bb7a, 0xef148d1ea0f4c069, 0x040ab3263eff0206},
fe{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000},
},
fe2{
fe{0xb2f66aad4ce5d646, 0x5842a06bfc497cec, 0xcf4895d42599d394, 0xc11b9cba40a8e8d0, 0x2e3813cbe5a0de89, 0x110eefda88847faf},
fe{0x07089552b319d465, 0xc6695f92b50a8313, 0x97e83cccd117228f, 0xa35baecab2dc29ee, 0x1ce393ea5daace4d, 0x08f2220fb0fb66eb},
},
fe2{
fe{0xcd03c9e48671f071, 0x5dab22461fcda5d2, 0x587042afd3851b95, 0x8eb60ebe01bacb9e, 0x03f97d6e83d050d2, 0x18f0206554638741},
fe{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000},
},
fe2{
fe{0x7bcfa7a25aa30fda, 0xdc17dec12a927e7c, 0x2f088dd86b4ebef1, 0xd1ca2087da74d4a7, 0x2da2596696cebc1d, 0x0e2b7eedbbfd87d2},
fe{0x3e2f585da55c9ad1, 0x4294213d86c18183, 0x382844c88b623732, 0x92ad2afd19103e18, 0x1d794e4fac7cf0b9, 0x0bd592fc7d825ec8},
},
fe2{
fe{0x890dc9e4867545c3, 0x2af322533285a5d5, 0x50880866309b7e2c, 0xa20d1b8c7e881024, 0x14e4f04fe2db9068, 0x14e56d3f1564853a},
fe{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000},
},
fe2{
fe{0x82d83cf50dbce43f, 0xa2813e53df9d018f, 0xc6f0caa53c65e181, 0x7525cf528d50fe95, 0x4a85ed50f4798a6b, 0x171da0fd6cf8eebd},
fe{0x3726c30af242c66c, 0x7c2ac1aad1b6fe70, 0xa04007fbba4b14a2, 0xef517c3266341429, 0x0095ba654ed2226b, 0x02e370eccc86f7dd},
},
}
/*
x
*/
var x = bigFromHex("0xd201000000010000")

View File

@ -0,0 +1,13 @@
package bls12381
import (
"crypto/rand"
"math/big"
)
var fuz = 10
func randScalar(max *big.Int) *big.Int {
a, _ := rand.Int(rand.Reader, max)
return a
}

View File

@ -0,0 +1,340 @@
// 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/>.
package bls12381
import (
"crypto/rand"
"encoding/hex"
"fmt"
"io"
"math/big"
)
// fe is base field element representation
type fe [6]uint64
// fe2 is element representation of 'fp2' which is quadratic extension 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 extension 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 extension of 'fp6'
// Representation follows c[0] + c[1] * w encoding order.
type fe12 [2]fe6
func (fe *fe) setBytes(in []byte) *fe {
size := 48
l := len(in)
if l >= size {
l = size
}
padded := make([]byte, size)
copy(padded[size-l:], in[:])
var a int
for i := 0; i < 6; i++ {
a = size - 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, 48)
var a int
for i := 0; i < 6; i++ {
a = 48 - 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 := 5; 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) < 0
}
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 := 5; 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) sign() bool {
r := new(fe)
fromMont(r, e)
return r[0]&1 == 0
}
func (fe *fe) div2(e uint64) {
fe[0] = fe[0]>>1 | fe[1]<<63
fe[1] = fe[1]>>1 | fe[2]<<63
fe[2] = fe[2]>>1 | fe[3]<<63
fe[3] = fe[3]>>1 | fe[4]<<63
fe[4] = fe[4]>>1 | fe[5]<<63
fe[5] = fe[5]>>1 | e<<63
}
func (fe *fe) mul2() uint64 {
e := fe[5] >> 63
fe[5] = fe[5]<<1 | fe[4]>>63
fe[4] = fe[4]<<1 | fe[3]>>63
fe[3] = fe[3]<<1 | fe[2]>>63
fe[2] = fe[2]<<1 | fe[1]>>63
fe[1] = fe[1]<<1 | fe[0]>>63
fe[0] = fe[0] << 1
return e
}
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) rand(r io.Reader) (*fe2, error) {
a0, err := new(fe).rand(r)
if err != nil {
return nil, err
}
a1, err := new(fe).rand(r)
if err != nil {
return nil, err
}
return &fe2{*a0, *a1}, 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) 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) rand(r io.Reader) (*fe6, error) {
a0, err := new(fe2).rand(r)
if err != nil {
return nil, err
}
a1, err := new(fe2).rand(r)
if err != nil {
return nil, err
}
a2, err := new(fe2).rand(r)
if err != nil {
return nil, err
}
return &fe6{*a0, *a1, *a2}, 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) rand(r io.Reader) (*fe12, error) {
a0, err := new(fe6).rand(r)
if err != nil {
return nil, err
}
a1, err := new(fe6).rand(r)
if err != nil {
return nil, err
}
return &fe12{*a0, *a1}, 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])
}

View File

@ -0,0 +1,251 @@
package bls12381
import (
"bytes"
"crypto/rand"
"math/big"
"testing"
)
func TestFieldElementValidation(t *testing.T) {
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)
fp2 := newFp2()
fp2.add(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)
fp6 := newFp6(fp2)
fp6.add(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)
fp12 := newFp12(fp6)
fp12.add(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, 48)
fe := new(fe).setBytes(in)
if !fe.isZero() {
t.Fatal("bad serialization")
}
if !bytes.Equal(in, fe.bytes()) {
t.Fatal("bad serialization")
}
})
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("bad serialization")
}
}
})
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("bad encoding or decoding")
}
}
})
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("bad encoding or decoding")
}
}
})
}
func TestFieldElementByteInputs(t *testing.T) {
zero := new(fe).zero()
in := make([]byte, 0)
a := new(fe).setBytes(in)
if !a.equal(zero) {
t.Fatal("bad serialization")
}
in = make([]byte, 48)
a = new(fe).setBytes(in)
if !a.equal(zero) {
t.Fatal("bad serialization")
}
in = make([]byte, 64)
a = new(fe).setBytes(in)
if !a.equal(zero) {
t.Fatal("bad serialization")
}
in = make([]byte, 49)
in[47] = 1
normalOne := &fe{1, 0, 0, 0, 0, 0}
a = new(fe).setBytes(in)
if !a.equal(normalOne) {
t.Fatal("bad serialization")
}
}
func TestFieldElementCopy(t *testing.T) {
a, _ := new(fe).rand(rand.Reader)
b := new(fe).set(a)
if !a.equal(b) {
t.Fatal("bad copy, 1")
}
a2, _ := new(fe2).rand(rand.Reader)
b2 := new(fe2).set(a2)
if !a2.equal(b2) {
t.Fatal("bad copy, 2")
}
a6, _ := new(fe6).rand(rand.Reader)
b6 := new(fe6).set(a6)
if !a6.equal(b6) {
t.Fatal("bad copy, 6")
}
a12, _ := new(fe12).rand(rand.Reader)
b12 := new(fe12).set(a12)
if !a12.equal(b12) {
t.Fatal("bad copy, 12")
}
}

View File

@ -0,0 +1,167 @@
// 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/>.
package bls12381
import (
"errors"
"math/big"
)
func fromBytes(in []byte) (*fe, error) {
fe := &fe{}
if len(in) != 48 {
return nil, errors.New("input string should 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 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 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 < 768; 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 < 381 || k > 381+384 {
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 < 384*2; i++ {
double(u, u)
}
inv.set(u)
}
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 isQuadraticNonResidue(elem *fe) bool {
result := new(fe)
exp(result, elem, pMinus1Over2)
return !result.isOne()
}

View File

@ -0,0 +1,279 @@
// 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/>.
package bls12381
import (
"errors"
"math/big"
)
type fp12 struct {
fp12temp
fp6 *fp6
}
type fp12temp struct {
t2 [9]*fe2
t6 [5]*fe6
t12 *fe12
}
func newFp12Temp() fp12temp {
t2 := [9]*fe2{}
t6 := [5]*fe6{}
for i := 0; i < len(t2); i++ {
t2[i] = &fe2{}
}
for i := 0; i < len(t6); i++ {
t6[i] = &fe6{}
}
return fp12temp{t2, t6, &fe12{}}
}
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 should be larger than 96 bytes")
}
fp6 := e.fp6
c1, err := fp6.fromBytes(in[:288])
if err != nil {
return nil, err
}
c0, err := fp6.fromBytes(in[288:])
if err != nil {
return nil, err
}
return &fe12{*c0, *c1}, nil
}
func (e *fp12) toBytes(a *fe12) []byte {
fp6 := e.fp6
out := make([]byte, 576)
copy(out[:288], fp6.toBytes(&a[1]))
copy(out[288:], 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 (e *fp12) add(c, a, b *fe12) {
fp6 := e.fp6
fp6.add(&c[0], &a[0], &b[0])
fp6.add(&c[1], &a[1], &b[1])
}
func (e *fp12) double(c, a *fe12) {
fp6 := e.fp6
fp6.double(&c[0], &a[0])
fp6.double(&c[1], &a[1])
}
func (e *fp12) sub(c, a, b *fe12) {
fp6 := e.fp6
fp6.sub(&c[0], &a[0], &b[0])
fp6.sub(&c[1], &a[1], &b[1])
}
func (e *fp12) neg(c, a *fe12) {
fp6 := e.fp6
fp6.neg(&c[0], &a[0])
fp6.neg(&c[1], &a[1])
}
func (e *fp12) conjugate(c, a *fe12) {
fp6 := e.fp6
c[0].set(&a[0])
fp6.neg(&c[1], &a[1])
}
func (e *fp12) square(c, a *fe12) {
fp6, t := e.fp6, e.t6
fp6.add(t[0], &a[0], &a[1])
fp6.mul(t[2], &a[0], &a[1])
fp6.mulByNonResidue(t[1], &a[1])
fp6.addAssign(t[1], &a[0])
fp6.mulByNonResidue(t[3], t[2])
fp6.mulAssign(t[0], t[1])
fp6.subAssign(t[0], t[2])
fp6.sub(&c[0], t[0], t[3])
fp6.double(&c[1], t[2])
}
func (e *fp12) cyclotomicSquare(c, a *fe12) {
t, fp2 := e.t2, e.fp2()
e.fp4Square(t[3], t[4], &a[0][0], &a[1][1])
fp2.sub(t[2], t[3], &a[0][0])
fp2.doubleAssign(t[2])
fp2.add(&c[0][0], t[2], t[3])
fp2.add(t[2], t[4], &a[1][1])
fp2.doubleAssign(t[2])
fp2.add(&c[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])
fp2.sub(t[2], t[3], &a[0][1])
fp2.doubleAssign(t[2])
fp2.add(&c[0][1], t[2], t[3])
fp2.add(t[2], t[4], &a[1][2])
fp2.doubleAssign(t[2])
fp2.add(&c[1][2], t[2], t[4])
fp2.mulByNonResidue(t[3], t[6])
fp2.add(t[2], t[3], &a[1][0])
fp2.doubleAssign(t[2])
fp2.add(&c[1][0], t[2], t[3])
fp2.sub(t[2], t[5], &a[0][2])
fp2.doubleAssign(t[2])
fp2.add(&c[0][2], t[2], t[5])
}
func (e *fp12) mul(c, a, b *fe12) {
t, fp6 := e.t6, e.fp6
fp6.mul(t[1], &a[0], &b[0])
fp6.mul(t[2], &a[1], &b[1])
fp6.add(t[0], t[1], t[2])
fp6.mulByNonResidue(t[2], t[2])
fp6.add(t[3], t[1], t[2])
fp6.add(t[1], &a[0], &a[1])
fp6.add(t[2], &b[0], &b[1])
fp6.mulAssign(t[1], t[2])
c[0].set(t[3])
fp6.sub(&c[1], t[1], t[0])
}
func (e *fp12) mulAssign(a, b *fe12) {
t, fp6 := e.t6, e.fp6
fp6.mul(t[1], &a[0], &b[0])
fp6.mul(t[2], &a[1], &b[1])
fp6.add(t[0], t[1], t[2])
fp6.mulByNonResidue(t[2], t[2])
fp6.add(t[3], t[1], t[2])
fp6.add(t[1], &a[0], &a[1])
fp6.add(t[2], &b[0], &b[1])
fp6.mulAssign(t[1], t[2])
a[0].set(t[3])
fp6.sub(&a[1], t[1], t[0])
}
func (e *fp12) fp4Square(c0, c1, a0, a1 *fe2) {
t, fp2 := e.t2, e.fp2()
fp2.square(t[0], a0)
fp2.square(t[1], a1)
fp2.mulByNonResidue(t[2], t[1])
fp2.add(c0, t[2], t[0])
fp2.add(t[2], a0, a1)
fp2.squareAssign(t[2])
fp2.subAssign(t[2], t[0])
fp2.sub(c1, t[2], t[1])
}
func (e *fp12) inverse(c, a *fe12) {
fp6, t := e.fp6, e.t6
fp6.square(t[0], &a[0])
fp6.square(t[1], &a[1])
fp6.mulByNonResidue(t[1], t[1])
fp6.sub(t[1], t[0], t[1])
fp6.inverse(t[0], t[1])
fp6.mul(&c[0], &a[0], t[0])
fp6.mulAssign(t[0], &a[1])
fp6.neg(&c[1], t[0])
}
func (e *fp12) mulBy014Assign(a *fe12, c0, c1, c4 *fe2) {
fp2, fp6, t, t2 := e.fp2(), e.fp6, e.t6, e.t2[0]
fp6.mulBy01(t[0], &a[0], c0, c1)
fp6.mulBy1(t[1], &a[1], c4)
fp2.add(t2, c1, c4)
fp6.add(t[2], &a[1], &a[0])
fp6.mulBy01Assign(t[2], c0, t2)
fp6.subAssign(t[2], t[0])
fp6.sub(&a[1], t[2], t[1])
fp6.mulByNonResidue(t[1], t[1])
fp6.add(&a[0], t[1], t[0])
}
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, z)
if s.Bit(i) == 1 {
e.mul(z, z, a)
}
}
c.set(z)
}
func (e *fp12) frobeniusMap(c, a *fe12, power uint) {
fp6 := e.fp6
fp6.frobeniusMap(&c[0], &a[0], power)
fp6.frobeniusMap(&c[1], &a[1], power)
switch power {
case 0:
return
case 6:
fp6.neg(&c[1], &c[1])
default:
fp6.mulByBaseField(&c[1], &c[1], &frobeniusCoeffs12[power])
}
}
func (e *fp12) frobeniusMapAssign(a *fe12, power uint) {
fp6 := e.fp6
fp6.frobeniusMapAssign(&a[0], power)
fp6.frobeniusMapAssign(&a[1], power)
switch power {
case 0:
return
case 6:
fp6.neg(&a[1], &a[1])
default:
fp6.mulByBaseField(&a[1], &a[1], &frobeniusCoeffs12[power])
}
}

View File

@ -0,0 +1,252 @@
// 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/>.
package bls12381
import (
"errors"
"math/big"
)
type fp2Temp struct {
t [4]*fe
}
type fp2 struct {
fp2Temp
}
func newFp2Temp() fp2Temp {
t := [4]*fe{}
for i := 0; i < len(t); i++ {
t[i] = &fe{}
}
return fp2Temp{t}
}
func newFp2() *fp2 {
t := newFp2Temp()
return &fp2{t}
}
func (e *fp2) fromBytes(in []byte) (*fe2, error) {
if len(in) != 96 {
return nil, errors.New("length of input string should be 96 bytes")
}
c1, err := fromBytes(in[:48])
if err != nil {
return nil, err
}
c0, err := fromBytes(in[48:])
if err != nil {
return nil, err
}
return &fe2{*c0, *c1}, nil
}
func (e *fp2) toBytes(a *fe2) []byte {
out := make([]byte, 96)
copy(out[:48], toBytes(&a[1]))
copy(out[48:], 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 (e *fp2) add(c, a, b *fe2) {
add(&c[0], &a[0], &b[0])
add(&c[1], &a[1], &b[1])
}
func (e *fp2) addAssign(a, b *fe2) {
addAssign(&a[0], &b[0])
addAssign(&a[1], &b[1])
}
func (e *fp2) ladd(c, a, b *fe2) {
ladd(&c[0], &a[0], &b[0])
ladd(&c[1], &a[1], &b[1])
}
func (e *fp2) double(c, a *fe2) {
double(&c[0], &a[0])
double(&c[1], &a[1])
}
func (e *fp2) doubleAssign(a *fe2) {
doubleAssign(&a[0])
doubleAssign(&a[1])
}
func (e *fp2) ldouble(c, a *fe2) {
ldouble(&c[0], &a[0])
ldouble(&c[1], &a[1])
}
func (e *fp2) sub(c, a, b *fe2) {
sub(&c[0], &a[0], &b[0])
sub(&c[1], &a[1], &b[1])
}
func (e *fp2) subAssign(c, a *fe2) {
subAssign(&c[0], &a[0])
subAssign(&c[1], &a[1])
}
func (e *fp2) neg(c, a *fe2) {
neg(&c[0], &a[0])
neg(&c[1], &a[1])
}
func (e *fp2) mul(c, a, b *fe2) {
t := e.t
mul(t[1], &a[0], &b[0])
mul(t[2], &a[1], &b[1])
add(t[0], &a[0], &a[1])
add(t[3], &b[0], &b[1])
sub(&c[0], t[1], t[2])
addAssign(t[1], t[2])
mul(t[0], t[0], t[3])
sub(&c[1], t[0], t[1])
}
func (e *fp2) mulAssign(a, b *fe2) {
t := e.t
mul(t[1], &a[0], &b[0])
mul(t[2], &a[1], &b[1])
add(t[0], &a[0], &a[1])
add(t[3], &b[0], &b[1])
sub(&a[0], t[1], t[2])
addAssign(t[1], t[2])
mul(t[0], t[0], t[3])
sub(&a[1], t[0], t[1])
}
func (e *fp2) square(c, 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(&c[0], t[0], t[1])
mul(&c[1], t[2], &a[1])
}
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) mulByNonResidue(c, a *fe2) {
t := e.t
sub(t[0], &a[0], &a[1])
add(&c[1], &a[0], &a[1])
c[0].set(t[0])
}
func (e *fp2) mulByB(c, a *fe2) {
t := e.t
double(t[0], &a[0])
double(t[1], &a[1])
doubleAssign(t[0])
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
square(t[0], &a[0])
square(t[1], &a[1])
addAssign(t[0], t[1])
inverse(t[0], t[0])
mul(&c[0], &a[0], t[0])
mul(t[0], t[0], &a[1])
neg(&c[1], t[0])
}
func (e *fp2) mulByFq(c, a *fe2, b *fe) {
mul(&c[0], &a[0], b)
mul(&c[1], &a[1], b)
}
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) frobeniusMap(c, a *fe2, power uint) {
c[0].set(&a[0])
if power%2 == 1 {
neg(&c[1], &a[1])
return
}
c[1].set(&a[1])
}
func (e *fp2) frobeniusMapAssign(a *fe2, power uint) {
if power%2 == 1 {
neg(&a[1], &a[1])
return
}
}
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
}
e.add(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 {
// https://github.com/leovt/constructible/wiki/Taking-Square-Roots-in-quadratic-extension-Fields
c0, c1 := new(fe), new(fe)
square(c0, &a[0])
square(c1, &a[1])
add(c1, c1, c0)
return isQuadraticNonResidue(c1)
}

View File

@ -0,0 +1,351 @@
// 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/>.
package bls12381
import (
"errors"
"math/big"
)
type fp6Temp struct {
t [6]*fe2
}
type fp6 struct {
fp2 *fp2
fp6Temp
}
func newFp6Temp() fp6Temp {
t := [6]*fe2{}
for i := 0; i < len(t); i++ {
t[i] = &fe2{}
}
return fp6Temp{t}
}
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 should be larger than 288 bytes")
}
fp2 := e.fp2
u2, err := fp2.fromBytes(b[:96])
if err != nil {
return nil, err
}
u1, err := fp2.fromBytes(b[96:192])
if err != nil {
return nil, err
}
u0, err := fp2.fromBytes(b[192:])
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, 288)
copy(out[:96], fp2.toBytes(&a[2]))
copy(out[96:192], fp2.toBytes(&a[1]))
copy(out[192:], 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 (e *fp6) add(c, a, b *fe6) {
fp2 := e.fp2
fp2.add(&c[0], &a[0], &b[0])
fp2.add(&c[1], &a[1], &b[1])
fp2.add(&c[2], &a[2], &b[2])
}
func (e *fp6) addAssign(a, b *fe6) {
fp2 := e.fp2
fp2.addAssign(&a[0], &b[0])
fp2.addAssign(&a[1], &b[1])
fp2.addAssign(&a[2], &b[2])
}
func (e *fp6) double(c, a *fe6) {
fp2 := e.fp2
fp2.double(&c[0], &a[0])
fp2.double(&c[1], &a[1])
fp2.double(&c[2], &a[2])
}
func (e *fp6) doubleAssign(a *fe6) {
fp2 := e.fp2
fp2.doubleAssign(&a[0])
fp2.doubleAssign(&a[1])
fp2.doubleAssign(&a[2])
}
func (e *fp6) sub(c, a, b *fe6) {
fp2 := e.fp2
fp2.sub(&c[0], &a[0], &b[0])
fp2.sub(&c[1], &a[1], &b[1])
fp2.sub(&c[2], &a[2], &b[2])
}
func (e *fp6) subAssign(a, b *fe6) {
fp2 := e.fp2
fp2.subAssign(&a[0], &b[0])
fp2.subAssign(&a[1], &b[1])
fp2.subAssign(&a[2], &b[2])
}
func (e *fp6) neg(c, a *fe6) {
fp2 := e.fp2
fp2.neg(&c[0], &a[0])
fp2.neg(&c[1], &a[1])
fp2.neg(&c[2], &a[2])
}
func (e *fp6) mul(c, a, b *fe6) {
fp2, t := e.fp2, e.t
fp2.mul(t[0], &a[0], &b[0])
fp2.mul(t[1], &a[1], &b[1])
fp2.mul(t[2], &a[2], &b[2])
fp2.add(t[3], &a[1], &a[2])
fp2.add(t[4], &b[1], &b[2])
fp2.mulAssign(t[3], t[4])
fp2.add(t[4], t[1], t[2])
fp2.subAssign(t[3], t[4])
fp2.mulByNonResidue(t[3], t[3])
fp2.add(t[5], t[0], t[3])
fp2.add(t[3], &a[0], &a[1])
fp2.add(t[4], &b[0], &b[1])
fp2.mulAssign(t[3], t[4])
fp2.add(t[4], t[0], t[1])
fp2.subAssign(t[3], t[4])
fp2.mulByNonResidue(t[4], t[2])
fp2.add(&c[1], t[3], t[4])
fp2.add(t[3], &a[0], &a[2])
fp2.add(t[4], &b[0], &b[2])
fp2.mulAssign(t[3], t[4])
fp2.add(t[4], t[0], t[2])
fp2.subAssign(t[3], t[4])
fp2.add(&c[2], t[1], t[3])
c[0].set(t[5])
}
func (e *fp6) mulAssign(a, b *fe6) {
fp2, t := e.fp2, e.t
fp2.mul(t[0], &a[0], &b[0])
fp2.mul(t[1], &a[1], &b[1])
fp2.mul(t[2], &a[2], &b[2])
fp2.add(t[3], &a[1], &a[2])
fp2.add(t[4], &b[1], &b[2])
fp2.mulAssign(t[3], t[4])
fp2.add(t[4], t[1], t[2])
fp2.subAssign(t[3], t[4])
fp2.mulByNonResidue(t[3], t[3])
fp2.add(t[5], t[0], t[3])
fp2.add(t[3], &a[0], &a[1])
fp2.add(t[4], &b[0], &b[1])
fp2.mulAssign(t[3], t[4])
fp2.add(t[4], t[0], t[1])
fp2.subAssign(t[3], t[4])
fp2.mulByNonResidue(t[4], t[2])
fp2.add(&a[1], t[3], t[4])
fp2.add(t[3], &a[0], &a[2])
fp2.add(t[4], &b[0], &b[2])
fp2.mulAssign(t[3], t[4])
fp2.add(t[4], t[0], t[2])
fp2.subAssign(t[3], t[4])
fp2.add(&a[2], t[1], t[3])
a[0].set(t[5])
}
func (e *fp6) square(c, a *fe6) {
fp2, t := e.fp2, e.t
fp2.square(t[0], &a[0])
fp2.mul(t[1], &a[0], &a[1])
fp2.doubleAssign(t[1])
fp2.sub(t[2], &a[0], &a[1])
fp2.addAssign(t[2], &a[2])
fp2.squareAssign(t[2])
fp2.mul(t[3], &a[1], &a[2])
fp2.doubleAssign(t[3])
fp2.square(t[4], &a[2])
fp2.mulByNonResidue(t[5], t[3])
fp2.add(&c[0], t[0], t[5])
fp2.mulByNonResidue(t[5], t[4])
fp2.add(&c[1], t[1], t[5])
fp2.addAssign(t[1], t[2])
fp2.addAssign(t[1], t[3])
fp2.addAssign(t[0], t[4])
fp2.sub(&c[2], t[1], t[0])
}
func (e *fp6) mulBy01Assign(a *fe6, b0, b1 *fe2) {
fp2, t := e.fp2, e.t
fp2.mul(t[0], &a[0], b0)
fp2.mul(t[1], &a[1], b1)
fp2.add(t[5], &a[1], &a[2])
fp2.mul(t[2], b1, t[5])
fp2.subAssign(t[2], t[1])
fp2.mulByNonResidue(t[2], t[2])
fp2.add(t[5], &a[0], &a[2])
fp2.mul(t[3], b0, t[5])
fp2.subAssign(t[3], t[0])
fp2.add(&a[2], t[3], t[1])
fp2.add(t[4], b0, b1)
fp2.add(t[5], &a[0], &a[1])
fp2.mulAssign(t[4], t[5])
fp2.subAssign(t[4], t[0])
fp2.sub(&a[1], t[4], t[1])
fp2.add(&a[0], t[2], t[0])
}
func (e *fp6) mulBy01(c, a *fe6, b0, b1 *fe2) {
fp2, t := e.fp2, e.t
fp2.mul(t[0], &a[0], b0)
fp2.mul(t[1], &a[1], b1)
fp2.add(t[2], &a[1], &a[2])
fp2.mulAssign(t[2], b1)
fp2.subAssign(t[2], t[1])
fp2.mulByNonResidue(t[2], t[2])
fp2.add(t[3], &a[0], &a[2])
fp2.mulAssign(t[3], b0)
fp2.subAssign(t[3], t[0])
fp2.add(&c[2], t[3], t[1])
fp2.add(t[4], b0, b1)
fp2.add(t[3], &a[0], &a[1])
fp2.mulAssign(t[4], t[3])
fp2.subAssign(t[4], t[0])
fp2.sub(&c[1], t[4], t[1])
fp2.add(&c[0], t[2], t[0])
}
func (e *fp6) mulBy1(c, a *fe6, b1 *fe2) {
fp2, t := e.fp2, e.t
fp2.mul(t[0], &a[2], b1)
fp2.mul(&c[2], &a[1], b1)
fp2.mul(&c[1], &a[0], b1)
fp2.mulByNonResidue(&c[0], t[0])
}
func (e *fp6) mulByNonResidue(c, a *fe6) {
fp2, t := e.fp2, e.t
t[0].set(&a[0])
fp2.mulByNonResidue(&c[0], &a[2])
c[2].set(&a[1])
c[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])
fp2.mulByNonResidue(t[1], t[1])
fp2.subAssign(t[0], t[1])
fp2.square(t[1], &a[1])
fp2.mul(t[2], &a[0], &a[2])
fp2.subAssign(t[1], t[2])
fp2.square(t[2], &a[2])
fp2.mulByNonResidue(t[2], t[2])
fp2.mul(t[3], &a[0], &a[1])
fp2.subAssign(t[2], t[3])
fp2.mul(t[3], &a[2], t[2])
fp2.mul(t[4], &a[1], t[1])
fp2.addAssign(t[3], t[4])
fp2.mulByNonResidue(t[3], t[3])
fp2.mul(t[4], &a[0], t[0])
fp2.addAssign(t[3], t[4])
fp2.inverse(t[3], t[3])
fp2.mul(&c[0], t[0], t[3])
fp2.mul(&c[1], t[2], t[3])
fp2.mul(&c[2], t[1], t[3])
}
func (e *fp6) frobeniusMap(c, a *fe6, power uint) {
fp2 := e.fp2
fp2.frobeniusMap(&c[0], &a[0], power)
fp2.frobeniusMap(&c[1], &a[1], power)
fp2.frobeniusMap(&c[2], &a[2], power)
switch power % 6 {
case 0:
return
case 3:
neg(&c[0][0], &a[1][1])
c[1][1].set(&a[1][0])
fp2.neg(&a[2], &a[2])
default:
fp2.mul(&c[1], &c[1], &frobeniusCoeffs61[power%6])
fp2.mul(&c[2], &c[2], &frobeniusCoeffs62[power%6])
}
}
func (e *fp6) frobeniusMapAssign(a *fe6, power uint) {
fp2 := e.fp2
fp2.frobeniusMapAssign(&a[0], power)
fp2.frobeniusMapAssign(&a[1], power)
fp2.frobeniusMapAssign(&a[2], power)
t := e.t
switch power % 6 {
case 0:
return
case 3:
neg(&t[0][0], &a[1][1])
a[1][1].set(&a[1][0])
a[1][0].set(&t[0][0])
fp2.neg(&a[2], &a[2])
default:
fp2.mulAssign(&a[1], &frobeniusCoeffs61[power%6])
fp2.mulAssign(&a[2], &frobeniusCoeffs62[power%6])
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,434 @@
// 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/>.
package bls12381
import (
"errors"
"math"
"math/big"
)
// PointG1 is type for point in G1.
// PointG1 is both used for Affine and Jacobian point representation.
// If z is equal to one the point is considered as in affine form.
type PointG1 [3]fe
func (p *PointG1) Set(p2 *PointG1) *PointG1 {
p[0].set(&p2[0])
p[1].set(&p2[1])
p[2].set(&p2[2])
return p
}
// Zero returns G1 point in point at infinity representation
func (p *PointG1) Zero() *PointG1 {
p[0].zero()
p[1].one()
p[2].zero()
return p
}
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(q)
}
func (g *G1) fromBytesUnchecked(in []byte) (*PointG1, error) {
p0, err := fromBytes(in[:48])
if err != nil {
return nil, err
}
p1, err := fromBytes(in[48:])
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.
// FromBytes does not take zcash flags into account.
// Byte input expected to be larger than 96 bytes.
// First 96 bytes should be concatenation of x and y values.
// Point (0, 0) is considered as infinity.
func (g *G1) FromBytes(in []byte) (*PointG1, error) {
if len(in) != 96 {
return nil, errors.New("input string should be equal or larger than 96")
}
p0, err := fromBytes(in[:48])
if err != nil {
return nil, err
}
p1, err := fromBytes(in[48:])
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
}
// DecodePoint given encoded (x, y) coordinates in 128 bytes returns a valid G1 Point.
func (g *G1) DecodePoint(in []byte) (*PointG1, error) {
if len(in) != 128 {
return nil, errors.New("invalid g1 point length")
}
pointBytes := make([]byte, 96)
// decode x
xBytes, err := decodeFieldElement(in[:64])
if err != nil {
return nil, err
}
// decode y
yBytes, err := decodeFieldElement(in[64:])
if err != nil {
return nil, err
}
copy(pointBytes[:48], xBytes)
copy(pointBytes[48:], yBytes)
return g.FromBytes(pointBytes)
}
// ToBytes serializes a point into bytes in uncompressed form.
// ToBytes does not take zcash flags into account.
// ToBytes returns (0, 0) if point is infinity.
func (g *G1) ToBytes(p *PointG1) []byte {
out := make([]byte, 96)
if g.IsZero(p) {
return out
}
g.Affine(p)
copy(out[:48], toBytes(&p[0]))
copy(out[48:], toBytes(&p[1]))
return out
}
// EncodePoint encodes a point into 128 bytes.
func (g *G1) EncodePoint(p *PointG1) []byte {
outRaw := g.ToBytes(p)
out := make([]byte, 128)
// encode x
copy(out[16:], outRaw[:48])
// encode y
copy(out[64+16:], outRaw[48:])
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 {
tmp := &PointG1{}
g.MulScalar(tmp, p, q)
return g.IsZero(tmp)
}
// 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])
square(t[1], &p[0])
mul(t[1], t[1], &p[0])
square(t[2], &p[2])
square(t[3], t[2])
mul(t[2], t[2], t[3])
mul(t[2], b, t[2])
add(t[1], t[1], t[2])
return t[0].equal(t[1])
}
// IsAffine checks a G1 point whether it is in affine form.
func (g *G1) IsAffine(p *PointG1) bool {
return p[2].isOne()
}
// Add adds two G1 points p1, p2 and assigns the result to point at first argument.
func (g *G1) Affine(p *PointG1) *PointG1 {
if g.IsZero(p) {
return p
}
if !g.IsAffine(p) {
t := g.t
inverse(t[0], &p[2])
square(t[1], t[0])
mul(&p[0], &p[0], t[1])
mul(t[0], t[0], t[1])
mul(&p[1], &p[1], t[0])
p[2].one()
}
return p
}
// 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)
}
t := g.t
square(t[7], &p1[2])
mul(t[1], &p2[0], t[7])
mul(t[2], &p1[2], t[7])
mul(t[0], &p2[1], t[2])
square(t[8], &p2[2])
mul(t[3], &p1[0], t[8])
mul(t[4], &p2[2], t[8])
mul(t[2], &p1[1], t[4])
if t[1].equal(t[3]) {
if t[0].equal(t[2]) {
return g.Double(r, p1)
}
return r.Zero()
}
sub(t[1], t[1], t[3])
double(t[4], t[1])
square(t[4], t[4])
mul(t[5], t[1], t[4])
sub(t[0], t[0], t[2])
double(t[0], t[0])
square(t[6], t[0])
sub(t[6], t[6], t[5])
mul(t[3], t[3], t[4])
double(t[4], t[3])
sub(&r[0], t[6], t[4])
sub(t[4], t[3], &r[0])
mul(t[6], t[2], t[5])
double(t[6], t[6])
mul(t[0], t[0], t[4])
sub(&r[1], t[0], t[6])
add(t[0], &p1[2], &p2[2])
square(t[0], t[0])
sub(t[0], t[0], t[7])
sub(t[0], t[0], t[8])
mul(&r[2], t[0], t[1])
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.Set(p)
}
t := g.t
square(t[0], &p[0])
square(t[1], &p[1])
square(t[2], t[1])
add(t[1], &p[0], t[1])
square(t[1], t[1])
sub(t[1], t[1], t[0])
sub(t[1], t[1], t[2])
double(t[1], t[1])
double(t[3], t[0])
add(t[0], t[3], t[0])
square(t[4], t[0])
double(t[3], t[1])
sub(&r[0], t[4], t[3])
sub(t[1], t[1], &r[0])
double(t[2], t[2])
double(t[2], t[2])
double(t[2], t[2])
mul(t[0], t[0], t[1])
sub(t[1], t[0], t[2])
mul(t[0], &p[1], &p[2])
r[1].set(t[1])
double(&r[2], t[0])
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 in big.Int and assigns the result to point at first argument.
func (g *G1) MulScalar(c, p *PointG1, e *big.Int) *PointG1 {
q, n := &PointG1{}, &PointG1{}
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)
}
// ClearCofactor maps given a G1 point to correct subgroup
func (g *G1) ClearCofactor(p *PointG1) {
g.MulScalar(p, p, cofactorEFFG1)
}
// 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, powers []*big.Int) (*PointG1, error) {
if len(points) != len(powers) {
return nil, errors.New("point and scalar vectors should be in same length")
}
var c uint32 = 3
if len(powers) >= 32 {
c = uint32(math.Ceil(math.Log10(float64(len(powers)))))
}
bucketSize, numBits := (1<<c)-1, uint32(g.Q().BitLen())
windows := make([]*PointG1, numBits/c+1)
bucket := make([]*PointG1, bucketSize)
acc, sum := g.New(), g.New()
for i := 0; i < bucketSize; i++ {
bucket[i] = g.New()
}
mask := (uint64(1) << c) - 1
j := 0
var cur uint32
for cur <= numBits {
acc.Zero()
bucket = make([]*PointG1, (1<<c)-1)
for i := 0; i < len(bucket); i++ {
bucket[i] = g.New()
}
for i := 0; i < len(powers); i++ {
s0 := powers[i].Uint64()
index := uint(s0 & mask)
if index != 0 {
g.Add(bucket[index-1], bucket[index-1], points[i])
}
powers[i] = new(big.Int).Rsh(powers[i], uint(c))
}
sum.Zero()
for i := len(bucket) - 1; i >= 0; i-- {
g.Add(sum, sum, bucket[i])
g.Add(acc, acc, sum)
}
windows[j] = g.New()
windows[j].Set(acc)
j++
cur += c
}
acc.Zero()
for i := len(windows) - 1; i >= 0; i-- {
for j := uint32(0); j < c; j++ {
g.Double(acc, acc)
}
g.Add(acc, acc, windows[i])
}
return r.Set(acc), nil
}
// 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
}

View File

@ -0,0 +1,283 @@
package bls12381
import (
"bytes"
"crypto/rand"
"math/big"
"testing"
"github.com/ethereum/go-ethereum/common"
)
func (g *G1) one() *PointG1 {
one, _ := g.fromBytesUnchecked(
common.FromHex("" +
"17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb" +
"08b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1",
),
)
return one
}
func (g *G1) rand() *PointG1 {
k, err := rand.Int(rand.Reader, q)
if err != nil {
panic(err)
}
return g.MulScalar(&PointG1{}, g.one(), k)
}
func TestG1Serialization(t *testing.T) {
g1 := NewG1()
for i := 0; i < fuz; i++ {
a := g1.rand()
buf := g1.ToBytes(a)
b, err := g1.FromBytes(buf)
if err != nil {
t.Fatal(err)
}
if !g1.Equal(a, b) {
t.Fatal("bad serialization from/to")
}
}
for i := 0; i < fuz; i++ {
a := g1.rand()
encoded := g1.EncodePoint(a)
b, err := g1.DecodePoint(encoded)
if err != nil {
t.Fatal(err)
}
if !g1.Equal(a, b) {
t.Fatal("bad serialization encode/decode")
}
}
}
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 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 TestG1MultiplicativeProperties(t *testing.T) {
g := NewG1()
t0, t1 := g.New(), g.New()
zero := g.Zero()
for i := 0; i < fuz; i++ {
a := g.rand()
s1, s2, s3 := randScalar(q), randScalar(q), randScalar(q)
sone := big.NewInt(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.Errorf(" (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.Errorf(" (a ^ s1) + (a ^ s2) == a ^ (s1 + s2)")
}
}
}
func TestG1MultiExpExpected(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.MulScalar(expected, one, big.NewInt(5))
_, _ = g.MultiExp(result, bases[:], scalars[:])
if !g.Equal(expected, result) {
t.Fatal("bad multi-exponentiation")
}
}
func TestG1MultiExpBatch(t *testing.T) {
g := NewG1()
one := g.one()
n := 1000
bases := make([]*PointG1, n)
scalars := make([]*big.Int, n)
// scalars: [s0,s1 ... s(n-1)]
// bases: [P0,P1,..P(n-1)] = [s(n-1)*G, s(n-2)*G ... s0*G]
for i, j := 0, n-1; i < n; i, j = i+1, j-1 {
scalars[j], _ = rand.Int(rand.Reader, big.NewInt(100000))
bases[i] = g.New()
g.MulScalar(bases[i], one, scalars[j])
}
// expected: s(n-1)*P0 + s(n-2)*P1 + s0*P(n-1)
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("bad multi-exponentiation")
}
}
func TestG1MapToCurve(t *testing.T) {
for i, v := range []struct {
u []byte
expected []byte
}{
{
u: make([]byte, 48),
expected: common.FromHex("11a9a0372b8f332d5c30de9ad14e50372a73fa4c45d5f2fa5097f2d6fb93bcac592f2e1711ac43db0519870c7d0ea415" + "092c0f994164a0719f51c24ba3788de240ff926b55f58c445116e8bc6a47cd63392fd4e8e22bdf9feaa96ee773222133"),
},
{
u: common.FromHex("07fdf49ea58e96015d61f6b5c9d1c8f277146a533ae7fbca2a8ef4c41055cd961fbc6e26979b5554e4b4f22330c0e16d"),
expected: common.FromHex("1223effdbb2d38152495a864d78eee14cb0992d89a241707abb03819a91a6d2fd65854ab9a69e9aacb0cbebfd490732c" + "0f925d61e0b235ecd945cbf0309291878df0d06e5d80d6b84aa4ff3e00633b26f9a7cb3523ef737d90e6d71e8b98b2d5"),
},
{
u: common.FromHex("1275ab3adbf824a169ed4b1fd669b49cf406d822f7fe90d6b2f8c601b5348436f89761bb1ad89a6fb1137cd91810e5d2"),
expected: common.FromHex("179d3fd0b4fb1da43aad06cea1fb3f828806ddb1b1fa9424b1e3944dfdbab6e763c42636404017da03099af0dcca0fd6" + "0d037cb1c6d495c0f5f22b061d23f1be3d7fe64d3c6820cfcd99b6b36fa69f7b4c1f4addba2ae7aa46fb25901ab483e4"),
},
{
u: common.FromHex("0e93d11d30de6d84b8578827856f5c05feef36083eef0b7b263e35ecb9b56e86299614a042e57d467fa20948e8564909"),
expected: common.FromHex("15aa66c77eded1209db694e8b1ba49daf8b686733afaa7b68c683d0b01788dfb0617a2e2d04c0856db4981921d3004af" + "0952bb2f61739dd1d201dd0a79d74cda3285403d47655ee886afe860593a8a4e51c5b77a22d2133e3a4280eaaaa8b788"),
},
{
u: common.FromHex("015a41481155d17074d20be6d8ec4d46632a51521cd9c916e265bd9b47343b3689979b50708c8546cbc2916b86cb1a3a"),
expected: common.FromHex("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 BenchmarkG1Add(t *testing.B) {
g1 := NewG1()
a, b, c := g1.rand(), g1.rand(), PointG1{}
t.ResetTimer()
for i := 0; i < t.N; i++ {
g1.Add(&c, a, b)
}
}
func BenchmarkG1Mul(t *testing.B) {
g1 := NewG1()
a, e, c := g1.rand(), q, PointG1{}
t.ResetTimer()
for i := 0; i < t.N; i++ {
g1.MulScalar(&c, a, e)
}
}
func BenchmarkG1MapToCurve(t *testing.B) {
a := make([]byte, 48)
g1 := NewG1()
t.ResetTimer()
for i := 0; i < t.N; i++ {
_, err := g1.MapToCurve(a)
if err != nil {
t.Fatal(err)
}
}
}

View File

@ -0,0 +1,456 @@
// 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/>.
package bls12381
import (
"errors"
"math"
"math/big"
)
// PointG2 is type for point in G2.
// PointG2 is both used for Affine and Jacobian point representation.
// If z is equal to one the point is considered as in affine form.
type PointG2 [3]fe2
// Set copies valeus 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
}
// Zero returns G2 point in point at infinity representation
func (p *PointG2) Zero() *PointG2 {
p[0].zero()
p[1].one()
p[2].zero()
return p
}
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(q)
}
func (g *G2) fromBytesUnchecked(in []byte) (*PointG2, error) {
p0, err := g.f.fromBytes(in[:96])
if err != nil {
return nil, err
}
p1, err := g.f.fromBytes(in[96:])
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.
// FromBytes does not take zcash flags into account.
// Byte input expected to be larger than 96 bytes.
// First 192 bytes should be concatenation of x and y values
// Point (0, 0) is considered as infinity.
func (g *G2) FromBytes(in []byte) (*PointG2, error) {
if len(in) != 192 {
return nil, errors.New("input string should be equal or larger than 192")
}
p0, err := g.f.fromBytes(in[:96])
if err != nil {
return nil, err
}
p1, err := g.f.fromBytes(in[96:])
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
}
// DecodePoint given encoded (x, y) coordinates in 256 bytes returns a valid G1 Point.
func (g *G2) DecodePoint(in []byte) (*PointG2, error) {
if len(in) != 256 {
return nil, errors.New("invalid g2 point length")
}
pointBytes := make([]byte, 192)
x0Bytes, err := decodeFieldElement(in[:64])
if err != nil {
return nil, err
}
x1Bytes, err := decodeFieldElement(in[64:128])
if err != nil {
return nil, err
}
y0Bytes, err := decodeFieldElement(in[128:192])
if err != nil {
return nil, err
}
y1Bytes, err := decodeFieldElement(in[192:])
if err != nil {
return nil, err
}
copy(pointBytes[:48], x1Bytes)
copy(pointBytes[48:96], x0Bytes)
copy(pointBytes[96:144], y1Bytes)
copy(pointBytes[144:192], y0Bytes)
return g.FromBytes(pointBytes)
}
// ToBytes serializes a point into bytes in uncompressed form,
// does not take zcash flags into account,
// returns (0, 0) if point is infinity.
func (g *G2) ToBytes(p *PointG2) []byte {
out := make([]byte, 192)
if g.IsZero(p) {
return out
}
g.Affine(p)
copy(out[:96], g.f.toBytes(&p[0]))
copy(out[96:], g.f.toBytes(&p[1]))
return out
}
// EncodePoint encodes a point into 256 bytes.
func (g *G2) EncodePoint(p *PointG2) []byte {
// outRaw is 96 bytes
outRaw := g.ToBytes(p)
out := make([]byte, 256)
// encode x
copy(out[16:16+48], outRaw[48:96])
copy(out[80:80+48], outRaw[:48])
// encode y
copy(out[144:144+48], outRaw[144:])
copy(out[208:208+48], outRaw[96:144])
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.mul(t[0], t[0], &p1[2])
g.f.mul(t[1], t[1], &p2[2])
g.f.mul(t[1], t[1], &p1[1])
g.f.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 *G2) InCorrectSubgroup(p *PointG2) bool {
tmp := &PointG2{}
g.MulScalar(tmp, p, q)
return g.IsZero(tmp)
}
// 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])
g.f.square(t[1], &p[0])
g.f.mul(t[1], t[1], &p[0])
g.f.square(t[2], &p[2])
g.f.square(t[3], t[2])
g.f.mul(t[2], t[2], t[3])
g.f.mul(t[2], b2, t[2])
g.f.add(t[1], t[1], t[2])
return t[0].equal(t[1])
}
// 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 {
if g.IsZero(p) {
return p
}
if !g.IsAffine(p) {
t := g.t
g.f.inverse(t[0], &p[2])
g.f.square(t[1], t[0])
g.f.mul(&p[0], &p[0], t[1])
g.f.mul(t[0], t[0], t[1])
g.f.mul(&p[1], &p[1], t[0])
p[2].one()
}
return p
}
// 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)
}
t := g.t
g.f.square(t[7], &p1[2])
g.f.mul(t[1], &p2[0], t[7])
g.f.mul(t[2], &p1[2], t[7])
g.f.mul(t[0], &p2[1], t[2])
g.f.square(t[8], &p2[2])
g.f.mul(t[3], &p1[0], t[8])
g.f.mul(t[4], &p2[2], t[8])
g.f.mul(t[2], &p1[1], t[4])
if t[1].equal(t[3]) {
if t[0].equal(t[2]) {
return g.Double(r, p1)
}
return r.Zero()
}
g.f.sub(t[1], t[1], t[3])
g.f.double(t[4], t[1])
g.f.square(t[4], t[4])
g.f.mul(t[5], t[1], t[4])
g.f.sub(t[0], t[0], t[2])
g.f.double(t[0], t[0])
g.f.square(t[6], t[0])
g.f.sub(t[6], t[6], t[5])
g.f.mul(t[3], t[3], t[4])
g.f.double(t[4], t[3])
g.f.sub(&r[0], t[6], t[4])
g.f.sub(t[4], t[3], &r[0])
g.f.mul(t[6], t[2], t[5])
g.f.double(t[6], t[6])
g.f.mul(t[0], t[0], t[4])
g.f.sub(&r[1], t[0], t[6])
g.f.add(t[0], &p1[2], &p2[2])
g.f.square(t[0], t[0])
g.f.sub(t[0], t[0], t[7])
g.f.sub(t[0], t[0], t[8])
g.f.mul(&r[2], t[0], t[1])
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])
g.f.square(t[1], &p[1])
g.f.square(t[2], t[1])
g.f.add(t[1], &p[0], t[1])
g.f.square(t[1], t[1])
g.f.sub(t[1], t[1], t[0])
g.f.sub(t[1], t[1], t[2])
g.f.double(t[1], t[1])
g.f.double(t[3], t[0])
g.f.add(t[0], t[3], t[0])
g.f.square(t[4], t[0])
g.f.double(t[3], t[1])
g.f.sub(&r[0], t[4], t[3])
g.f.sub(t[1], t[1], &r[0])
g.f.double(t[2], t[2])
g.f.double(t[2], t[2])
g.f.double(t[2], t[2])
g.f.mul(t[0], t[0], t[1])
g.f.sub(t[1], t[0], t[2])
g.f.mul(t[0], &p[1], &p[2])
r[1].set(t[1])
g.f.double(&r[2], t[0])
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])
g.f.neg(&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 in big.Int and assigns the result to point at first argument.
func (g *G2) MulScalar(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)
}
// ClearCofactor maps given a G2 point to correct subgroup
func (g *G2) ClearCofactor(p *PointG2) {
g.MulScalar(p, p, cofactorEFFG2)
}
// 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, powers []*big.Int) (*PointG2, error) {
if len(points) != len(powers) {
return nil, errors.New("point and scalar vectors should be in same length")
}
var c uint32 = 3
if len(powers) >= 32 {
c = uint32(math.Ceil(math.Log10(float64(len(powers)))))
}
bucketSize, numBits := (1<<c)-1, uint32(g.Q().BitLen())
windows := make([]*PointG2, numBits/c+1)
bucket := make([]*PointG2, bucketSize)
acc, sum := g.New(), g.New()
for i := 0; i < bucketSize; i++ {
bucket[i] = g.New()
}
mask := (uint64(1) << c) - 1
j := 0
var cur uint32
for cur <= numBits {
acc.Zero()
bucket = make([]*PointG2, (1<<c)-1)
for i := 0; i < len(bucket); i++ {
bucket[i] = g.New()
}
for i := 0; i < len(powers); i++ {
s0 := powers[i].Uint64()
index := uint(s0 & mask)
if index != 0 {
g.Add(bucket[index-1], bucket[index-1], points[i])
}
powers[i] = new(big.Int).Rsh(powers[i], uint(c))
}
sum.Zero()
for i := len(bucket) - 1; i >= 0; i-- {
g.Add(sum, sum, bucket[i])
g.Add(acc, acc, sum)
}
windows[j] = g.New()
windows[j].Set(acc)
j++
cur += c
}
acc.Zero()
for i := len(windows) - 1; i >= 0; i-- {
for j := uint32(0); j < c; j++ {
g.Double(acc, acc)
}
g.Add(acc, acc, windows[i])
}
return r.Set(acc), nil
}
// 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
}

View File

@ -0,0 +1,286 @@
package bls12381
import (
"bytes"
"crypto/rand"
"math/big"
"testing"
"github.com/ethereum/go-ethereum/common"
)
func (g *G2) one() *PointG2 {
one, _ := g.fromBytesUnchecked(
common.FromHex("" +
"13e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e" +
"024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8" +
"0606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be" +
"0ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801",
),
)
return one
}
func (g *G2) rand() *PointG2 {
k, err := rand.Int(rand.Reader, q)
if err != nil {
panic(err)
}
return g.MulScalar(&PointG2{}, g.one(), k)
}
func TestG2Serialization(t *testing.T) {
g2 := NewG2()
for i := 0; i < fuz; i++ {
a := g2.rand()
buf := g2.ToBytes(a)
b, err := g2.FromBytes(buf)
if err != nil {
t.Fatal(err)
}
if !g2.Equal(a, b) {
t.Fatal("bad serialization from/to")
}
}
for i := 0; i < fuz; i++ {
a := g2.rand()
encoded := g2.EncodePoint(a)
b, err := g2.DecodePoint(encoded)
if err != nil {
t.Fatal(err)
}
if !g2.Equal(a, b) {
t.Fatal("bad serialization encode/decode")
}
}
}
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 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 TestG2MultiplicativeProperties(t *testing.T) {
g := NewG2()
t0, t1 := g.New(), g.New()
zero := g.Zero()
for i := 0; i < fuz; i++ {
a := g.rand()
s1, s2, s3 := randScalar(q), randScalar(q), randScalar(q)
sone := big.NewInt(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.Errorf(" (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.Errorf(" (a ^ s1) + (a ^ s2) == a ^ (s1 + s2)")
}
}
}
func TestG2MultiExpExpected(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.MulScalar(expected, one, big.NewInt(5))
_, _ = g.MultiExp(result, bases[:], scalars[:])
if !g.Equal(expected, result) {
t.Fatal("bad multi-exponentiation")
}
}
func TestG2MultiExpBatch(t *testing.T) {
g := NewG2()
one := g.one()
n := 1000
bases := make([]*PointG2, n)
scalars := make([]*big.Int, n)
// scalars: [s0,s1 ... s(n-1)]
// bases: [P0,P1,..P(n-1)] = [s(n-1)*G, s(n-2)*G ... s0*G]
for i, j := 0, n-1; i < n; i, j = i+1, j-1 {
scalars[j], _ = rand.Int(rand.Reader, big.NewInt(100000))
bases[i] = g.New()
g.MulScalar(bases[i], one, scalars[j])
}
// expected: s(n-1)*P0 + s(n-2)*P1 + s0*P(n-1)
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("bad multi-exponentiation")
}
}
func TestG2MapToCurve(t *testing.T) {
for i, v := range []struct {
u []byte
expected []byte
}{
{
u: make([]byte, 96),
expected: common.FromHex("0a67d12118b5a35bb02d2e86b3ebfa7e23410db93de39fb06d7025fa95e96ffa428a7a27c3ae4dd4b40bd251ac658892" + "018320896ec9eef9d5e619848dc29ce266f413d02dd31d9b9d44ec0c79cd61f18b075ddba6d7bd20b7ff27a4b324bfce" + "04c69777a43f0bda07679d5805e63f18cf4e0e7c6112ac7f70266d199b4f76ae27c6269a3ceebdae30806e9a76aadf5c" + "0260e03644d1a2c321256b3246bad2b895cad13890cbe6f85df55106a0d334604fb143c7a042d878006271865bc35941"),
},
{
u: common.FromHex("025fbc07711ba267b7e70c82caa70a16fbb1d470ae24ceef307f5e2000751677820b7013ad4e25492dcf30052d3e5eca" + "0e775d7827adf385b83e20e4445bd3fab21d7b4498426daf3c1d608b9d41e9edb5eda0df022e753b8bb4bc3bb7db4914"),
expected: common.FromHex("0d4333b77becbf9f9dfa3ca928002233d1ecc854b1447e5a71f751c9042d000f42db91c1d6649a5e0ad22bd7bf7398b8" + "027e4bfada0b47f9f07e04aec463c7371e68f2fd0c738cd517932ea3801a35acf09db018deda57387b0f270f7a219e4d" + "0cc76dc777ea0d447e02a41004f37a0a7b1fafb6746884e8d9fc276716ccf47e4e0899548a2ec71c2bdf1a2a50e876db" + "053674cba9ef516ddc218fedb37324e6c47de27f88ab7ef123b006127d738293c0277187f7e2f80a299a24d84ed03da7"),
},
{
u: common.FromHex("1870a7dbfd2a1deb74015a3546b20f598041bf5d5202997956a94a368d30d3f70f18cdaa1d33ce970a4e16af961cbdcb" + "045ab31ce4b5a8ba7c4b2851b64f063a66cd1223d3c85005b78e1beee65e33c90ceef0244e45fc45a5e1d6eab6644fdb"),
expected: common.FromHex("18f0f87b40af67c056915dbaf48534c592524e82c1c2b50c3734d02c0172c80df780a60b5683759298a3303c5d942778" + "09349f1cb5b2e55489dcd45a38545343451cc30a1681c57acd4fb0a6db125f8352c09f4a67eb7d1d8242cb7d3405f97b" + "10a2ba341bc689ab947b7941ce6ef39be17acaab067bd32bd652b471ab0792c53a2bd03bdac47f96aaafe96e441f63c0" + "02f2d9deb2c7742512f5b8230bf0fd83ea42279d7d39779543c1a43b61c885982b611f6a7a24b514995e8a098496b811"),
},
{
u: common.FromHex("088fe329b054db8a6474f21a7fbfdf17b4c18044db299d9007af582c3d5f17d00e56d99921d4b5640fce44b05219b5de" + "0b6e6135a4cd31ba980ddbd115ac48abef7ec60e226f264d7befe002c165f3a496f36f76dd524efd75d17422558d10b4"),
expected: common.FromHex("19808ec5930a53c7cf5912ccce1cc33f1b3dcff24a53ce1cc4cba41fd6996dbed4843ccdd2eaf6a0cd801e562718d163" + "149fe43777d34f0d25430dea463889bd9393bdfb4932946db23671727081c629ebb98a89604f3433fba1c67d356a4af7" + "04783e391c30c83f805ca271e353582fdf19d159f6a4c39b73acbb637a9b8ac820cfbe2738d683368a7c07ad020e3e33" + "04c0d6793a766233b2982087b5f4a254f261003ccb3262ea7c50903eecef3e871d1502c293f9e063d7d293f6384f4551"),
},
{
u: common.FromHex("03df16a66a05e4c1188c234788f43896e0565bfb64ac49b9639e6b284cc47dad73c47bb4ea7e677db8d496beb907fbb6" + "0f45b50647d67485295aa9eb2d91a877b44813677c67c8d35b2173ff3ba95f7bd0806f9ca8a1436b8b9d14ee81da4d7e"),
expected: common.FromHex("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 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 BenchmarkG2Mul(t *testing.B) {
g2 := NewG2()
a, e, c := g2.rand(), q, PointG2{}
t.ResetTimer()
for i := 0; i < t.N; i++ {
g2.MulScalar(&c, a, e)
}
}
func BenchmarkG2SWUMap(t *testing.B) {
a := make([]byte, 96)
g2 := NewG2()
t.ResetTimer()
for i := 0; i < t.N; i++ {
_, err := g2.MapToCurve(a)
if err != nil {
t.Fatal(err)
}
}
}

View File

@ -0,0 +1,121 @@
// 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/>.
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
}
func (e *E) Set(e2 *E) *E {
return e.set(e2)
}
// One sets a new target group element to one
func (e *E) One() *E {
e = new(fe12).one()
return e
}
// IsOne returns true if given element equals to one
func (e *E) IsOne() bool {
return e.isOne()
}
// Equal returns true if given two element is equal, otherwise returns false
func (g *E) Equal(g2 *E) bool {
return g.equal(g2)
}
// NewGT constructs new target group instance.
func NewGT() *GT {
fp12 := newFp12(nil)
return &GT{fp12}
}
// Q returns group order in big.Int.
func (g *GT) Q() *big.Int {
return new(big.Int).Set(q)
}
// 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, q)
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) {
g.fp12.add(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) {
g.fp12.sub(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) {
g.fp12.cyclotomicSquare(c, a)
}
// Exp exponents an element `a` by a scalar `s` and assigns the result to the element in first argument.
func (g *GT) Exp(c, a *E, s *big.Int) {
g.fp12.cyclotomicExp(c, a, s)
}
// Inverse inverses an element `a` and assigns the result to the element in first argument.
func (g *GT) Inverse(c, a *E) {
g.fp12.inverse(c, a)
}

View File

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

View File

@ -0,0 +1,282 @@
// 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/>.
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
}
// NewPairingEngine creates new pairing engine instance.
func NewPairingEngine() *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 [10]*fe2
t12 [9]fe12
}
func newEngineTemp() pairingEngineTemp {
t2 := [10]*fe2{}
for i := 0; i < 10; i++ {
t2[i] = &fe2{}
}
t12 := [9]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.isZero(p) {
e.affine(p)
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 {
e.G1.Neg(g1, g1)
e.AddPair(g1, g2)
return e
}
// Reset deletes added pairs.
func (e *Engine) Reset() *Engine {
e.pairs = []pair{}
return e
}
func (e *Engine) isZero(p pair) bool {
return e.G1.IsZero(p.g1) || e.G2.IsZero(p.g2)
}
func (e *Engine) affine(p pair) {
e.G1.Affine(p.g1)
e.G2.Affine(p.g2)
}
func (e *Engine) doublingStep(coeff *[3]fe2, r *PointG2) {
// Adaptation of Formula 3 in https://eprint.iacr.org/2010/526.pdf
fp2 := e.fp2
t := e.t2
fp2.mul(t[0], &r[0], &r[1])
fp2.mulByFq(t[0], t[0], twoInv)
fp2.square(t[1], &r[1])
fp2.square(t[2], &r[2])
fp2.double(t[7], t[2])
fp2.add(t[7], t[7], t[2])
fp2.mulByB(t[3], t[7])
fp2.double(t[4], t[3])
fp2.add(t[4], t[4], t[3])
fp2.add(t[5], t[1], t[4])
fp2.mulByFq(t[5], t[5], twoInv)
fp2.add(t[6], &r[1], &r[2])
fp2.square(t[6], t[6])
fp2.add(t[7], t[2], t[1])
fp2.sub(t[6], t[6], t[7])
fp2.sub(&coeff[0], t[3], t[1])
fp2.square(t[7], &r[0])
fp2.sub(t[4], t[1], t[4])
fp2.mul(&r[0], t[4], t[0])
fp2.square(t[2], t[3])
fp2.double(t[3], t[2])
fp2.add(t[3], t[3], t[2])
fp2.square(t[5], t[5])
fp2.sub(&r[1], t[5], t[3])
fp2.mul(&r[2], t[1], t[6])
fp2.double(t[0], t[7])
fp2.add(&coeff[1], t[0], t[7])
fp2.neg(&coeff[2], t[6])
}
func (e *Engine) additionStep(coeff *[3]fe2, r, q *PointG2) {
// Algorithm 12 in https://eprint.iacr.org/2010/526.pdf
fp2 := e.fp2
t := e.t2
fp2.mul(t[0], &q[1], &r[2])
fp2.neg(t[0], t[0])
fp2.add(t[0], t[0], &r[1])
fp2.mul(t[1], &q[0], &r[2])
fp2.neg(t[1], t[1])
fp2.add(t[1], 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.mul(t[3], &r[0], t[3])
fp2.double(t[5], t[3])
fp2.sub(t[5], t[4], t[5])
fp2.add(t[5], t[5], t[2])
fp2.mul(&r[0], t[1], t[5])
fp2.sub(t[2], t[3], t[5])
fp2.mul(t[2], t[2], t[0])
fp2.mul(t[3], &r[1], t[4])
fp2.sub(&r[1], t[2], t[3])
fp2.mul(&r[2], &r[2], t[4])
fp2.mul(t[2], t[1], &q[1])
fp2.mul(t[3], t[0], &q[0])
fp2.sub(&coeff[0], t[3], t[2])
fp2.neg(&coeff[1], t[0])
coeff[2].set(t[1])
}
func (e *Engine) preCompute(ellCoeffs *[68][3]fe2, twistPoint *PointG2) {
// Algorithm 5 in https://eprint.iacr.org/2019/077.pdf
if e.G2.IsZero(twistPoint) {
return
}
r := new(PointG2).Set(twistPoint)
j := 0
for i := x.BitLen() - 2; i >= 0; i-- {
e.doublingStep(&ellCoeffs[j], r)
if x.Bit(i) != 0 {
j++
ellCoeffs[j] = fe6{}
e.additionStep(&ellCoeffs[j], r, twistPoint)
}
j++
}
}
func (e *Engine) millerLoop(f *fe12) {
pairs := e.pairs
ellCoeffs := make([][68][3]fe2, len(pairs))
for i := 0; i < len(pairs); i++ {
e.preCompute(&ellCoeffs[i], pairs[i].g2)
}
fp12, fp2 := e.fp12, e.fp2
t := e.t2
f.one()
j := 0
for i := 62; /* x.BitLen() - 2 */ i >= 0; i-- {
if i != 62 {
fp12.square(f, f)
}
for i := 0; i <= len(pairs)-1; i++ {
fp2.mulByFq(t[0], &ellCoeffs[i][j][2], &pairs[i].g1[1])
fp2.mulByFq(t[1], &ellCoeffs[i][j][1], &pairs[i].g1[0])
fp12.mulBy014Assign(f, &ellCoeffs[i][j][0], t[1], t[0])
}
if x.Bit(i) != 0 {
j++
for i := 0; i <= len(pairs)-1; i++ {
fp2.mulByFq(t[0], &ellCoeffs[i][j][2], &pairs[i].g1[1])
fp2.mulByFq(t[1], &ellCoeffs[i][j][1], &pairs[i].g1[0])
fp12.mulBy014Assign(f, &ellCoeffs[i][j][0], t[1], t[0])
}
}
j++
}
fp12.conjugate(f, f)
}
func (e *Engine) exp(c, a *fe12) {
fp12 := e.fp12
fp12.cyclotomicExp(c, a, x)
fp12.conjugate(c, c)
}
func (e *Engine) finalExp(f *fe12) {
fp12 := e.fp12
t := e.t12
// easy part
fp12.frobeniusMap(&t[0], f, 6)
fp12.inverse(&t[1], f)
fp12.mul(&t[2], &t[0], &t[1])
t[1].set(&t[2])
fp12.frobeniusMapAssign(&t[2], 2)
fp12.mulAssign(&t[2], &t[1])
fp12.cyclotomicSquare(&t[1], &t[2])
fp12.conjugate(&t[1], &t[1])
// hard part
e.exp(&t[3], &t[2])
fp12.cyclotomicSquare(&t[4], &t[3])
fp12.mul(&t[5], &t[1], &t[3])
e.exp(&t[1], &t[5])
e.exp(&t[0], &t[1])
e.exp(&t[6], &t[0])
fp12.mulAssign(&t[6], &t[4])
e.exp(&t[4], &t[6])
fp12.conjugate(&t[5], &t[5])
fp12.mulAssign(&t[4], &t[5])
fp12.mulAssign(&t[4], &t[2])
fp12.conjugate(&t[5], &t[2])
fp12.mulAssign(&t[1], &t[2])
fp12.frobeniusMapAssign(&t[1], 3)
fp12.mulAssign(&t[6], &t[5])
fp12.frobeniusMapAssign(&t[6], 1)
fp12.mulAssign(&t[3], &t[0])
fp12.frobeniusMapAssign(&t[3], 2)
fp12.mulAssign(&t[3], &t[1])
fp12.mulAssign(&t[3], &t[6])
fp12.mul(f, &t[3], &t[4])
}
func (e *Engine) calculate() *fe12 {
f := e.fp12.one()
if len(e.pairs) == 0 {
return f
}
e.millerLoop(f)
e.finalExp(f)
return f
}
// Check computes pairing and checks if result is equal to one
func (e *Engine) Check() bool {
return e.calculate().isOne()
}
// Result computes pairing and returns target group element as result.
func (e *Engine) Result() *E {
r := e.calculate()
e.Reset()
return r
}
// GT returns target group instance.
func (e *Engine) GT() *GT {
return NewGT()
}

View File

@ -0,0 +1,230 @@
package bls12381
import (
"math/big"
"testing"
"github.com/ethereum/go-ethereum/common"
)
func TestPairingExpected(t *testing.T) {
bls := NewPairingEngine()
G1, G2 := bls.G1, bls.G2
GT := bls.GT()
expected, err := GT.FromBytes(
common.FromHex("" +
"0f41e58663bf08cf068672cbd01a7ec73baca4d72ca93544deff686bfd6df543d48eaa24afe47e1efde449383b676631" +
"04c581234d086a9902249b64728ffd21a189e87935a954051c7cdba7b3872629a4fafc05066245cb9108f0242d0fe3ef" +
"03350f55a7aefcd3c31b4fcb6ce5771cc6a0e9786ab5973320c806ad360829107ba810c5a09ffdd9be2291a0c25a99a2" +
"11b8b424cd48bf38fcef68083b0b0ec5c81a93b330ee1a677d0d15ff7b984e8978ef48881e32fac91b93b47333e2ba57" +
"06fba23eb7c5af0d9f80940ca771b6ffd5857baaf222eb95a7d2809d61bfe02e1bfd1b68ff02f0b8102ae1c2d5d5ab1a" +
"19f26337d205fb469cd6bd15c3d5a04dc88784fbb3d0b2dbdea54d43b2b73f2cbb12d58386a8703e0f948226e47ee89d" +
"018107154f25a764bd3c79937a45b84546da634b8f6be14a8061e55cceba478b23f7dacaa35c8ca78beae9624045b4b6" +
"01b2f522473d171391125ba84dc4007cfbf2f8da752f7c74185203fcca589ac719c34dffbbaad8431dad1c1fb597aaa5" +
"193502b86edb8857c273fa075a50512937e0794e1e65a7617c90d8bd66065b1fffe51d7a579973b1315021ec3c19934f" +
"1368bb445c7c2d209703f239689ce34c0378a68e72a6b3b216da0e22a5031b54ddff57309396b38c881c4c849ec23e87" +
"089a1c5b46e5110b86750ec6a532348868a84045483c92b7af5af689452eafabf1a8943e50439f1d59882a98eaa0170f" +
"1250ebd871fc0a92a7b2d83168d0d727272d441befa15c503dd8e90ce98db3e7b6d194f60839c508a84305aaca1789b6",
),
)
if err != nil {
t.Fatal(err)
}
r := bls.AddPair(G1.One(), G2.One()).Result()
if !r.Equal(expected) {
t.Fatal("bad pairing")
}
if !GT.IsValid(r) {
t.Fatal("element is not in correct subgroup")
}
}
func TestPairingNonDegeneracy(t *testing.T) {
bls := NewPairingEngine()
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(
common.FromHex("" +
"0f41e58663bf08cf068672cbd01a7ec73baca4d72ca93544deff686bfd6df543d48eaa24afe47e1efde449383b676631" +
"04c581234d086a9902249b64728ffd21a189e87935a954051c7cdba7b3872629a4fafc05066245cb9108f0242d0fe3ef" +
"03350f55a7aefcd3c31b4fcb6ce5771cc6a0e9786ab5973320c806ad360829107ba810c5a09ffdd9be2291a0c25a99a2" +
"11b8b424cd48bf38fcef68083b0b0ec5c81a93b330ee1a677d0d15ff7b984e8978ef48881e32fac91b93b47333e2ba57" +
"06fba23eb7c5af0d9f80940ca771b6ffd5857baaf222eb95a7d2809d61bfe02e1bfd1b68ff02f0b8102ae1c2d5d5ab1a" +
"19f26337d205fb469cd6bd15c3d5a04dc88784fbb3d0b2dbdea54d43b2b73f2cbb12d58386a8703e0f948226e47ee89d" +
"018107154f25a764bd3c79937a45b84546da634b8f6be14a8061e55cceba478b23f7dacaa35c8ca78beae9624045b4b6" +
"01b2f522473d171391125ba84dc4007cfbf2f8da752f7c74185203fcca589ac719c34dffbbaad8431dad1c1fb597aaa5" +
"193502b86edb8857c273fa075a50512937e0794e1e65a7617c90d8bd66065b1fffe51d7a579973b1315021ec3c19934f" +
"1368bb445c7c2d209703f239689ce34c0378a68e72a6b3b216da0e22a5031b54ddff57309396b38c881c4c849ec23e87" +
"089a1c5b46e5110b86750ec6a532348868a84045483c92b7af5af689452eafabf1a8943e50439f1d59882a98eaa0170f" +
"1250ebd871fc0a92a7b2d83168d0d727272d441befa15c503dd8e90ce98db3e7b6d194f60839c508a84305aaca1789b6",
),
)
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("bad pairing")
}
}
}
func TestPairingBilinearity(t *testing.T) {
bls := NewPairingEngine()
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.MulScalar(P1, G1, a)
g2.MulScalar(P2, G2, b)
e1 := bls.AddPair(P1, P2).Result()
gt.Exp(e0, e0, c)
if !e0.Equal(e1) {
t.Fatal("bad pairing, 1")
}
}
// 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.MulScalar(G1, G1, c)
bls.AddPair(G1, G2)
// RHS
P1, P2 := g1.One(), g2.One()
g1.MulScalar(P1, P1, a)
g2.MulScalar(P2, P2, b)
bls.AddPairInv(P1, P2)
// should be one
if !bls.Check() {
t.Fatal("bad pairing, 2")
}
}
// 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()
g2.MulScalar(G2, G2, c)
bls.AddPair(G1, G2)
// RHS
H1, H2 := g1.One(), g2.One()
g1.MulScalar(H1, H1, a)
g2.MulScalar(H2, H2, b)
bls.AddPairInv(H1, H2)
// should be one
if !bls.Check() {
t.Fatal("bad pairing, 3")
}
}
}
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 := NewPairingEngine()
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(q), randScalar(q)
P1, P2 := g1.One(), g2.One()
g1.MulScalar(P1, P1, a1)
g2.MulScalar(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.MulScalar(T1, T1, targetExp)
bls.AddPairInv(T1, T2)
if !bls.Check() {
t.Fatal("fail multi pairing")
}
}
func TestPairingEmpty(t *testing.T) {
bls := NewPairingEngine()
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 := NewPairingEngine()
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
}

View File

@ -0,0 +1,158 @@
// 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/>.
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()
e.add(x1, tv[0], tv[1])
e.inverse(x1, x1)
e1 := x1.isZero()
e.add(x1, x1, e.one())
if e1 {
x1.set(params.zInv)
}
e.mul(x1, x1, params.minusBOverA)
gx1 := e.new()
e.square(gx1, x1)
e.add(gx1, gx1, params.a)
e.mul(gx1, gx1, x1)
e.add(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.sqrt(y, y2)
if y.sign() != u.sign() {
e.neg(y, y)
}
return x, y
}
var swuParamsForG1 = struct {
z *fe
zInv *fe
a *fe
b *fe
minusBOverA *fe
}{
a: &fe{0x2f65aa0e9af5aa51, 0x86464c2d1e8416c3, 0xb85ce591b7bd31e2, 0x27e11c91b5f24e7c, 0x28376eda6bfc1835, 0x155455c3e5071d85},
b: &fe{0xfb996971fe22a1e0, 0x9aa93eb35b742d6f, 0x8c476013de99c5c4, 0x873e27c3a221e571, 0xca72b5e45a52d888, 0x06824061418a386b},
z: &fe{0x886c00000023ffdc, 0x0f70008d3090001d, 0x77672417ed5828c3, 0x9dac23e943dc1740, 0x50553f1b9c131521, 0x078c712fbe0ab6e8},
zInv: &fe{0x0e8a2e8ba2e83e10, 0x5b28ba2ca4d745d1, 0x678cd5473847377a, 0x4c506dd8a8076116, 0x9bcb227d79284139, 0x0e8d3154b0ba099a},
minusBOverA: &fe{0x052583c93555a7fe, 0x3b40d72430f93c82, 0x1b75faa0105ec983, 0x2527e7dc63851767, 0x99fffd1f34fc181d, 0x097cab54770ca0d3},
}
var swuParamsForG2 = struct {
z *fe2
zInv *fe2
a *fe2
b *fe2
minusBOverA *fe2
}{
a: &fe2{
fe{0, 0, 0, 0, 0, 0},
fe{0xe53a000003135242, 0x01080c0fdef80285, 0xe7889edbe340f6bd, 0x0b51375126310601, 0x02d6985717c744ab, 0x1220b4e979ea5467},
},
b: &fe2{
fe{0x22ea00000cf89db2, 0x6ec832df71380aa4, 0x6e1b94403db5a66e, 0x75bf3c53a79473ba, 0x3dd3a569412c0a34, 0x125cdb5e74dc4fd1},
fe{0x22ea00000cf89db2, 0x6ec832df71380aa4, 0x6e1b94403db5a66e, 0x75bf3c53a79473ba, 0x3dd3a569412c0a34, 0x125cdb5e74dc4fd1},
},
z: &fe2{
fe{0x87ebfffffff9555c, 0x656fffe5da8ffffa, 0x0fd0749345d33ad2, 0xd951e663066576f4, 0xde291a3d41e980d3, 0x0815664c7dfe040d},
fe{0x43f5fffffffcaaae, 0x32b7fff2ed47fffd, 0x07e83a49a2e99d69, 0xeca8f3318332bb7a, 0xef148d1ea0f4c069, 0x040ab3263eff0206},
},
zInv: &fe2{
fe{0xacd0000000011110, 0x9dd9999dc88ccccd, 0xb5ca2ac9b76352bf, 0xf1b574bcf4bc90ce, 0x42dab41f28a77081, 0x132fc6ac14cd1e12},
fe{0xe396ffffffff2223, 0x4fbf332fcd0d9998, 0x0c4bbd3c1aff4cc4, 0x6b9c91267926ca58, 0x29ae4da6aef7f496, 0x10692e942f195791},
},
minusBOverA: &fe2{
fe{0x903c555555474fb3, 0x5f98cc95ce451105, 0x9f8e582eefe0fade, 0xc68946b6aebbd062, 0x467a4ad10ee6de53, 0x0e7146f483e23a05},
fe{0x29c2aaaaaab85af8, 0xbf133368e30eeefa, 0xc7a27a7206cffb45, 0x9dee04ce44c9425c, 0x04a15ce53464ce83, 0x0b8fcaf5b59dac95},
},
}

View File

@ -0,0 +1,45 @@
// 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/>.
package bls12381
import (
"errors"
"math/big"
"github.com/ethereum/go-ethereum/common"
)
func bigFromHex(hex string) *big.Int {
return new(big.Int).SetBytes(common.FromHex(hex))
}
// decodeFieldElement expects 64 byte input with zero top 16 bytes,
// returns lower 48 bytes.
func decodeFieldElement(in []byte) ([]byte, error) {
if len(in) != 64 {
return nil, errors.New("invalid field element length")
}
// check top bytes
for i := 0; i < 16; i++ {
if in[i] != byte(0x00) {
return nil, errors.New("invalid field element top bytes")
}
}
out := make([]byte, 48)
copy(out[:], in[16:])
return out, nil
}

View File

@ -0,0 +1,28 @@
Copyright (c) 2012 The Go Authors. All rights reserved.
Copyright (c) 2018 Péter Szilágyi. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -0,0 +1,25 @@
// Copyright 2018 Péter Szilágyi. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be found
// in the LICENSE file.
// +build amd64 arm64
// Package bn256 implements the Optimal Ate pairing over a 256-bit Barreto-Naehrig curve.
package bn256
import (
bn256cf "github.com/ethereum/go-ethereum/crypto/bn256/cloudflare"
)
// G1 is an abstract cyclic group. The zero value is suitable for use as the
// output of an operation, but cannot be used as an input.
type G1 = bn256cf.G1
// G2 is an abstract cyclic group. The zero value is suitable for use as the
// output of an operation, but cannot be used as an input.
type G2 = bn256cf.G2
// PairingCheck calculates the Optimal Ate pairing for a set of points.
func PairingCheck(a []*G1, b []*G2) bool {
return bn256cf.PairingCheck(a, b)
}

View File

@ -0,0 +1,23 @@
// Copyright 2018 Péter Szilágyi. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be found
// in the LICENSE file.
// +build !amd64,!arm64
// Package bn256 implements the Optimal Ate pairing over a 256-bit Barreto-Naehrig curve.
package bn256
import bn256 "github.com/ethereum/go-ethereum/crypto/bn256/google"
// G1 is an abstract cyclic group. The zero value is suitable for use as the
// output of an operation, but cannot be used as an input.
type G1 = bn256.G1
// G2 is an abstract cyclic group. The zero value is suitable for use as the
// output of an operation, but cannot be used as an input.
type G2 = bn256.G2
// PairingCheck calculates the Optimal Ate pairing for a set of points.
func PairingCheck(a []*G1, b []*G2) bool {
return bn256.PairingCheck(a, b)
}

View File

@ -0,0 +1,27 @@
Copyright (c) 2009 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -0,0 +1,495 @@
// Package bn256 implements a particular bilinear group at the 128-bit security
// level.
//
// Bilinear groups are the basis of many of the new cryptographic protocols that
// have been proposed over the past decade. They consist of a triplet of groups
// (G₁, G₂ and GT) such that there exists a function e(g₁ˣ,g₂ʸ)=gTˣʸ (where gₓ
// is a generator of the respective group). That function is called a pairing
// function.
//
// This package specifically implements the Optimal Ate pairing over a 256-bit
// Barreto-Naehrig curve as described in
// http://cryptojedi.org/papers/dclxvi-20100714.pdf. Its output is not
// compatible with the implementation described in that paper, as different
// parameters are chosen.
//
// (This package previously claimed to operate at a 128-bit security level.
// However, recent improvements in attacks mean that is no longer true. See
// https://moderncrypto.org/mail-archive/curves/2016/000740.html.)
package bn256
import (
"crypto/rand"
"errors"
"io"
"math/big"
)
func randomK(r io.Reader) (k *big.Int, err error) {
for {
k, err = rand.Int(r, Order)
if err != nil || k.Sign() > 0 {
return
}
}
}
// G1 is an abstract cyclic group. The zero value is suitable for use as the
// output of an operation, but cannot be used as an input.
type G1 struct {
p *curvePoint
}
// RandomG1 returns x and g₁ˣ where x is a random, non-zero number read from r.
func RandomG1(r io.Reader) (*big.Int, *G1, error) {
k, err := randomK(r)
if err != nil {
return nil, nil, err
}
return k, new(G1).ScalarBaseMult(k), nil
}
func (g *G1) String() string {
return "bn256.G1" + g.p.String()
}
// ScalarBaseMult sets e to g*k where g is the generator of the group and then
// returns e.
func (e *G1) ScalarBaseMult(k *big.Int) *G1 {
if e.p == nil {
e.p = &curvePoint{}
}
e.p.Mul(curveGen, k)
return e
}
// ScalarMult sets e to a*k and then returns e.
func (e *G1) ScalarMult(a *G1, k *big.Int) *G1 {
if e.p == nil {
e.p = &curvePoint{}
}
e.p.Mul(a.p, k)
return e
}
// Add sets e to a+b and then returns e.
func (e *G1) Add(a, b *G1) *G1 {
if e.p == nil {
e.p = &curvePoint{}
}
e.p.Add(a.p, b.p)
return e
}
// Neg sets e to -a and then returns e.
func (e *G1) Neg(a *G1) *G1 {
if e.p == nil {
e.p = &curvePoint{}
}
e.p.Neg(a.p)
return e
}
// Set sets e to a and then returns e.
func (e *G1) Set(a *G1) *G1 {
if e.p == nil {
e.p = &curvePoint{}
}
e.p.Set(a.p)
return e
}
// Marshal converts e to a byte slice.
func (e *G1) Marshal() []byte {
// Each value is a 256-bit number.
const numBytes = 256 / 8
if e.p == nil {
e.p = &curvePoint{}
}
e.p.MakeAffine()
ret := make([]byte, numBytes*2)
if e.p.IsInfinity() {
return ret
}
temp := &gfP{}
montDecode(temp, &e.p.x)
temp.Marshal(ret)
montDecode(temp, &e.p.y)
temp.Marshal(ret[numBytes:])
return ret
}
// Unmarshal sets e to the result of converting the output of Marshal back into
// a group element and then returns e.
func (e *G1) Unmarshal(m []byte) ([]byte, error) {
// Each value is a 256-bit number.
const numBytes = 256 / 8
if len(m) < 2*numBytes {
return nil, errors.New("bn256: not enough data")
}
// Unmarshal the points and check their caps
if e.p == nil {
e.p = &curvePoint{}
} else {
e.p.x, e.p.y = gfP{0}, gfP{0}
}
var err error
if err = e.p.x.Unmarshal(m); err != nil {
return nil, err
}
if err = e.p.y.Unmarshal(m[numBytes:]); err != nil {
return nil, err
}
// Encode into Montgomery form and ensure it's on the curve
montEncode(&e.p.x, &e.p.x)
montEncode(&e.p.y, &e.p.y)
zero := gfP{0}
if e.p.x == zero && e.p.y == zero {
// This is the point at infinity.
e.p.y = *newGFp(1)
e.p.z = gfP{0}
e.p.t = gfP{0}
} else {
e.p.z = *newGFp(1)
e.p.t = *newGFp(1)
if !e.p.IsOnCurve() {
return nil, errors.New("bn256: malformed point")
}
}
return m[2*numBytes:], nil
}
// G2 is an abstract cyclic group. The zero value is suitable for use as the
// output of an operation, but cannot be used as an input.
type G2 struct {
p *twistPoint
}
// RandomG2 returns x and g₂ˣ where x is a random, non-zero number read from r.
func RandomG2(r io.Reader) (*big.Int, *G2, error) {
k, err := randomK(r)
if err != nil {
return nil, nil, err
}
return k, new(G2).ScalarBaseMult(k), nil
}
func (e *G2) String() string {
return "bn256.G2" + e.p.String()
}
// ScalarBaseMult sets e to g*k where g is the generator of the group and then
// returns out.
func (e *G2) ScalarBaseMult(k *big.Int) *G2 {
if e.p == nil {
e.p = &twistPoint{}
}
e.p.Mul(twistGen, k)
return e
}
// ScalarMult sets e to a*k and then returns e.
func (e *G2) ScalarMult(a *G2, k *big.Int) *G2 {
if e.p == nil {
e.p = &twistPoint{}
}
e.p.Mul(a.p, k)
return e
}
// Add sets e to a+b and then returns e.
func (e *G2) Add(a, b *G2) *G2 {
if e.p == nil {
e.p = &twistPoint{}
}
e.p.Add(a.p, b.p)
return e
}
// Neg sets e to -a and then returns e.
func (e *G2) Neg(a *G2) *G2 {
if e.p == nil {
e.p = &twistPoint{}
}
e.p.Neg(a.p)
return e
}
// Set sets e to a and then returns e.
func (e *G2) Set(a *G2) *G2 {
if e.p == nil {
e.p = &twistPoint{}
}
e.p.Set(a.p)
return e
}
// Marshal converts e into a byte slice.
func (e *G2) Marshal() []byte {
// Each value is a 256-bit number.
const numBytes = 256 / 8
if e.p == nil {
e.p = &twistPoint{}
}
e.p.MakeAffine()
ret := make([]byte, numBytes*4)
if e.p.IsInfinity() {
return ret
}
temp := &gfP{}
montDecode(temp, &e.p.x.x)
temp.Marshal(ret)
montDecode(temp, &e.p.x.y)
temp.Marshal(ret[numBytes:])
montDecode(temp, &e.p.y.x)
temp.Marshal(ret[2*numBytes:])
montDecode(temp, &e.p.y.y)
temp.Marshal(ret[3*numBytes:])
return ret
}
// Unmarshal sets e to the result of converting the output of Marshal back into
// a group element and then returns e.
func (e *G2) Unmarshal(m []byte) ([]byte, error) {
// Each value is a 256-bit number.
const numBytes = 256 / 8
if len(m) < 4*numBytes {
return nil, errors.New("bn256: not enough data")
}
// Unmarshal the points and check their caps
if e.p == nil {
e.p = &twistPoint{}
}
var err error
if err = e.p.x.x.Unmarshal(m); err != nil {
return nil, err
}
if err = e.p.x.y.Unmarshal(m[numBytes:]); err != nil {
return nil, err
}
if err = e.p.y.x.Unmarshal(m[2*numBytes:]); err != nil {
return nil, err
}
if err = e.p.y.y.Unmarshal(m[3*numBytes:]); err != nil {
return nil, err
}
// Encode into Montgomery form and ensure it's on the curve
montEncode(&e.p.x.x, &e.p.x.x)
montEncode(&e.p.x.y, &e.p.x.y)
montEncode(&e.p.y.x, &e.p.y.x)
montEncode(&e.p.y.y, &e.p.y.y)
if e.p.x.IsZero() && e.p.y.IsZero() {
// This is the point at infinity.
e.p.y.SetOne()
e.p.z.SetZero()
e.p.t.SetZero()
} else {
e.p.z.SetOne()
e.p.t.SetOne()
if !e.p.IsOnCurve() {
return nil, errors.New("bn256: malformed point")
}
}
return m[4*numBytes:], nil
}
// GT is an abstract cyclic group. The zero value is suitable for use as the
// output of an operation, but cannot be used as an input.
type GT struct {
p *gfP12
}
// Pair calculates an Optimal Ate pairing.
func Pair(g1 *G1, g2 *G2) *GT {
return &GT{optimalAte(g2.p, g1.p)}
}
// PairingCheck calculates the Optimal Ate pairing for a set of points.
func PairingCheck(a []*G1, b []*G2) bool {
acc := new(gfP12)
acc.SetOne()
for i := 0; i < len(a); i++ {
if a[i].p.IsInfinity() || b[i].p.IsInfinity() {
continue
}
acc.Mul(acc, miller(b[i].p, a[i].p))
}
return finalExponentiation(acc).IsOne()
}
// Miller applies Miller's algorithm, which is a bilinear function from the
// source groups to F_p^12. Miller(g1, g2).Finalize() is equivalent to Pair(g1,
// g2).
func Miller(g1 *G1, g2 *G2) *GT {
return &GT{miller(g2.p, g1.p)}
}
func (g *GT) String() string {
return "bn256.GT" + g.p.String()
}
// ScalarMult sets e to a*k and then returns e.
func (e *GT) ScalarMult(a *GT, k *big.Int) *GT {
if e.p == nil {
e.p = &gfP12{}
}
e.p.Exp(a.p, k)
return e
}
// Add sets e to a+b and then returns e.
func (e *GT) Add(a, b *GT) *GT {
if e.p == nil {
e.p = &gfP12{}
}
e.p.Mul(a.p, b.p)
return e
}
// Neg sets e to -a and then returns e.
func (e *GT) Neg(a *GT) *GT {
if e.p == nil {
e.p = &gfP12{}
}
e.p.Conjugate(a.p)
return e
}
// Set sets e to a and then returns e.
func (e *GT) Set(a *GT) *GT {
if e.p == nil {
e.p = &gfP12{}
}
e.p.Set(a.p)
return e
}
// Finalize is a linear function from F_p^12 to GT.
func (e *GT) Finalize() *GT {
ret := finalExponentiation(e.p)
e.p.Set(ret)
return e
}
// Marshal converts e into a byte slice.
func (e *GT) Marshal() []byte {
// Each value is a 256-bit number.
const numBytes = 256 / 8
if e.p == nil {
e.p = &gfP12{}
e.p.SetOne()
}
ret := make([]byte, numBytes*12)
temp := &gfP{}
montDecode(temp, &e.p.x.x.x)
temp.Marshal(ret)
montDecode(temp, &e.p.x.x.y)
temp.Marshal(ret[numBytes:])
montDecode(temp, &e.p.x.y.x)
temp.Marshal(ret[2*numBytes:])
montDecode(temp, &e.p.x.y.y)
temp.Marshal(ret[3*numBytes:])
montDecode(temp, &e.p.x.z.x)
temp.Marshal(ret[4*numBytes:])
montDecode(temp, &e.p.x.z.y)
temp.Marshal(ret[5*numBytes:])
montDecode(temp, &e.p.y.x.x)
temp.Marshal(ret[6*numBytes:])
montDecode(temp, &e.p.y.x.y)
temp.Marshal(ret[7*numBytes:])
montDecode(temp, &e.p.y.y.x)
temp.Marshal(ret[8*numBytes:])
montDecode(temp, &e.p.y.y.y)
temp.Marshal(ret[9*numBytes:])
montDecode(temp, &e.p.y.z.x)
temp.Marshal(ret[10*numBytes:])
montDecode(temp, &e.p.y.z.y)
temp.Marshal(ret[11*numBytes:])
return ret
}
// Unmarshal sets e to the result of converting the output of Marshal back into
// a group element and then returns e.
func (e *GT) Unmarshal(m []byte) ([]byte, error) {
// Each value is a 256-bit number.
const numBytes = 256 / 8
if len(m) < 12*numBytes {
return nil, errors.New("bn256: not enough data")
}
if e.p == nil {
e.p = &gfP12{}
}
var err error
if err = e.p.x.x.x.Unmarshal(m); err != nil {
return nil, err
}
if err = e.p.x.x.y.Unmarshal(m[numBytes:]); err != nil {
return nil, err
}
if err = e.p.x.y.x.Unmarshal(m[2*numBytes:]); err != nil {
return nil, err
}
if err = e.p.x.y.y.Unmarshal(m[3*numBytes:]); err != nil {
return nil, err
}
if err = e.p.x.z.x.Unmarshal(m[4*numBytes:]); err != nil {
return nil, err
}
if err = e.p.x.z.y.Unmarshal(m[5*numBytes:]); err != nil {
return nil, err
}
if err = e.p.y.x.x.Unmarshal(m[6*numBytes:]); err != nil {
return nil, err
}
if err = e.p.y.x.y.Unmarshal(m[7*numBytes:]); err != nil {
return nil, err
}
if err = e.p.y.y.x.Unmarshal(m[8*numBytes:]); err != nil {
return nil, err
}
if err = e.p.y.y.y.Unmarshal(m[9*numBytes:]); err != nil {
return nil, err
}
if err = e.p.y.z.x.Unmarshal(m[10*numBytes:]); err != nil {
return nil, err
}
if err = e.p.y.z.y.Unmarshal(m[11*numBytes:]); err != nil {
return nil, err
}
montEncode(&e.p.x.x.x, &e.p.x.x.x)
montEncode(&e.p.x.x.y, &e.p.x.x.y)
montEncode(&e.p.x.y.x, &e.p.x.y.x)
montEncode(&e.p.x.y.y, &e.p.x.y.y)
montEncode(&e.p.x.z.x, &e.p.x.z.x)
montEncode(&e.p.x.z.y, &e.p.x.z.y)
montEncode(&e.p.y.x.x, &e.p.y.x.x)
montEncode(&e.p.y.x.y, &e.p.y.x.y)
montEncode(&e.p.y.y.x, &e.p.y.y.x)
montEncode(&e.p.y.y.y, &e.p.y.y.y)
montEncode(&e.p.y.z.x, &e.p.y.z.x)
montEncode(&e.p.y.z.y, &e.p.y.z.y)
return m[12*numBytes:], nil
}

View File

@ -0,0 +1,116 @@
package bn256
import (
"bytes"
"crypto/rand"
"testing"
)
func TestG1Marshal(t *testing.T) {
_, Ga, err := RandomG1(rand.Reader)
if err != nil {
t.Fatal(err)
}
ma := Ga.Marshal()
Gb := new(G1)
_, err = Gb.Unmarshal(ma)
if err != nil {
t.Fatal(err)
}
mb := Gb.Marshal()
if !bytes.Equal(ma, mb) {
t.Fatal("bytes are different")
}
}
func TestG2Marshal(t *testing.T) {
_, Ga, err := RandomG2(rand.Reader)
if err != nil {
t.Fatal(err)
}
ma := Ga.Marshal()
Gb := new(G2)
_, err = Gb.Unmarshal(ma)
if err != nil {
t.Fatal(err)
}
mb := Gb.Marshal()
if !bytes.Equal(ma, mb) {
t.Fatal("bytes are different")
}
}
func TestBilinearity(t *testing.T) {
for i := 0; i < 2; i++ {
a, p1, _ := RandomG1(rand.Reader)
b, p2, _ := RandomG2(rand.Reader)
e1 := Pair(p1, p2)
e2 := Pair(&G1{curveGen}, &G2{twistGen})
e2.ScalarMult(e2, a)
e2.ScalarMult(e2, b)
if *e1.p != *e2.p {
t.Fatalf("bad pairing result: %s", e1)
}
}
}
func TestTripartiteDiffieHellman(t *testing.T) {
a, _ := rand.Int(rand.Reader, Order)
b, _ := rand.Int(rand.Reader, Order)
c, _ := rand.Int(rand.Reader, Order)
pa, pb, pc := new(G1), new(G1), new(G1)
qa, qb, qc := new(G2), new(G2), new(G2)
pa.Unmarshal(new(G1).ScalarBaseMult(a).Marshal())
qa.Unmarshal(new(G2).ScalarBaseMult(a).Marshal())
pb.Unmarshal(new(G1).ScalarBaseMult(b).Marshal())
qb.Unmarshal(new(G2).ScalarBaseMult(b).Marshal())
pc.Unmarshal(new(G1).ScalarBaseMult(c).Marshal())
qc.Unmarshal(new(G2).ScalarBaseMult(c).Marshal())
k1 := Pair(pb, qc)
k1.ScalarMult(k1, a)
k1Bytes := k1.Marshal()
k2 := Pair(pc, qa)
k2.ScalarMult(k2, b)
k2Bytes := k2.Marshal()
k3 := Pair(pa, qb)
k3.ScalarMult(k3, c)
k3Bytes := k3.Marshal()
if !bytes.Equal(k1Bytes, k2Bytes) || !bytes.Equal(k2Bytes, k3Bytes) {
t.Errorf("keys didn't agree")
}
}
func BenchmarkG1(b *testing.B) {
x, _ := rand.Int(rand.Reader, Order)
b.ResetTimer()
for i := 0; i < b.N; i++ {
new(G1).ScalarBaseMult(x)
}
}
func BenchmarkG2(b *testing.B) {
x, _ := rand.Int(rand.Reader, Order)
b.ResetTimer()
for i := 0; i < b.N; i++ {
new(G2).ScalarBaseMult(x)
}
}
func BenchmarkPairing(b *testing.B) {
for i := 0; i < b.N; i++ {
Pair(&G1{curveGen}, &G2{twistGen})
}
}

View File

@ -0,0 +1,62 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package bn256
import (
"math/big"
)
func bigFromBase10(s string) *big.Int {
n, _ := new(big.Int).SetString(s, 10)
return n
}
// u is the BN parameter.
var u = bigFromBase10("4965661367192848881")
// Order is the number of elements in both G₁ and G₂: 36u⁴+36u³+18u²+6u+1.
// Needs to be highly 2-adic for efficient SNARK key and proof generation.
// Order - 1 = 2^28 * 3^2 * 13 * 29 * 983 * 11003 * 237073 * 405928799 * 1670836401704629 * 13818364434197438864469338081.
// Refer to https://eprint.iacr.org/2013/879.pdf and https://eprint.iacr.org/2013/507.pdf for more information on these parameters.
var Order = bigFromBase10("21888242871839275222246405745257275088548364400416034343698204186575808495617")
// P is a prime over which we form a basic field: 36u⁴+36u³+24u²+6u+1.
var P = bigFromBase10("21888242871839275222246405745257275088696311157297823662689037894645226208583")
// p2 is p, represented as little-endian 64-bit words.
var p2 = [4]uint64{0x3c208c16d87cfd47, 0x97816a916871ca8d, 0xb85045b68181585d, 0x30644e72e131a029}
// np is the negative inverse of p, mod 2^256.
var np = [4]uint64{0x87d20782e4866389, 0x9ede7d651eca6ac9, 0xd8afcbd01833da80, 0xf57a22b791888c6b}
// rN1 is R^-1 where R = 2^256 mod p.
var rN1 = &gfP{0xed84884a014afa37, 0xeb2022850278edf8, 0xcf63e9cfb74492d9, 0x2e67157159e5c639}
// r2 is R^2 where R = 2^256 mod p.
var r2 = &gfP{0xf32cfc5b538afa89, 0xb5e71911d44501fb, 0x47ab1eff0a417ff6, 0x06d89f71cab8351f}
// r3 is R^3 where R = 2^256 mod p.
var r3 = &gfP{0xb1cd6dafda1530df, 0x62f210e6a7283db6, 0xef7f0b0c0ada0afb, 0x20fd6e902d592544}
// xiToPMinus1Over6 is ξ^((p-1)/6) where ξ = i+9.
var xiToPMinus1Over6 = &gfP2{gfP{0xa222ae234c492d72, 0xd00f02a4565de15b, 0xdc2ff3a253dfc926, 0x10a75716b3899551}, gfP{0xaf9ba69633144907, 0xca6b1d7387afb78a, 0x11bded5ef08a2087, 0x02f34d751a1f3a7c}}
// xiToPMinus1Over3 is ξ^((p-1)/3) where ξ = i+9.
var xiToPMinus1Over3 = &gfP2{gfP{0x6e849f1ea0aa4757, 0xaa1c7b6d89f89141, 0xb6e713cdfae0ca3a, 0x26694fbb4e82ebc3}, gfP{0xb5773b104563ab30, 0x347f91c8a9aa6454, 0x7a007127242e0991, 0x1956bcd8118214ec}}
// xiToPMinus1Over2 is ξ^((p-1)/2) where ξ = i+9.
var xiToPMinus1Over2 = &gfP2{gfP{0xa1d77ce45ffe77c7, 0x07affd117826d1db, 0x6d16bd27bb7edc6b, 0x2c87200285defecc}, gfP{0xe4bbdd0c2936b629, 0xbb30f162e133bacb, 0x31a9d1b6f9645366, 0x253570bea500f8dd}}
// xiToPSquaredMinus1Over3 is ξ^((p²-1)/3) where ξ = i+9.
var xiToPSquaredMinus1Over3 = &gfP{0x3350c88e13e80b9c, 0x7dce557cdb5e56b9, 0x6001b4b8b615564a, 0x2682e617020217e0}
// xiTo2PSquaredMinus2Over3 is ξ^((2p²-2)/3) where ξ = i+9 (a cubic root of unity, mod p).
var xiTo2PSquaredMinus2Over3 = &gfP{0x71930c11d782e155, 0xa6bb947cffbe3323, 0xaa303344d4741444, 0x2c3b3f0d26594943}
// xiToPSquaredMinus1Over6 is ξ^((1p²-1)/6) where ξ = i+9 (a cubic root of -1, mod p).
var xiToPSquaredMinus1Over6 = &gfP{0xca8d800500fa1bf2, 0xf0c5d61468b39769, 0x0e201271ad0d4418, 0x04290f65bad856e6}
// xiTo2PMinus2Over3 is ξ^((2p-2)/3) where ξ = i+9.
var xiTo2PMinus2Over3 = &gfP2{gfP{0x5dddfd154bd8c949, 0x62cb29a5a4445b60, 0x37bc870a0c7dd2b9, 0x24830a9d3171f0fd}, gfP{0x7361d77f843abe92, 0xa5bb2bd3273411fb, 0x9c941f314b3e2399, 0x15df9cddbb9fd3ec}}

View File

@ -0,0 +1,238 @@
package bn256
import (
"math/big"
)
// curvePoint implements the elliptic curve y²=x³+3. Points are kept in Jacobian
// form and t=z² when valid. G₁ is the set of points of this curve on GF(p).
type curvePoint struct {
x, y, z, t gfP
}
var curveB = newGFp(3)
// curveGen is the generator of G₁.
var curveGen = &curvePoint{
x: *newGFp(1),
y: *newGFp(2),
z: *newGFp(1),
t: *newGFp(1),
}
func (c *curvePoint) String() string {
c.MakeAffine()
x, y := &gfP{}, &gfP{}
montDecode(x, &c.x)
montDecode(y, &c.y)
return "(" + x.String() + ", " + y.String() + ")"
}
func (c *curvePoint) Set(a *curvePoint) {
c.x.Set(&a.x)
c.y.Set(&a.y)
c.z.Set(&a.z)
c.t.Set(&a.t)
}
// IsOnCurve returns true iff c is on the curve.
func (c *curvePoint) IsOnCurve() bool {
c.MakeAffine()
if c.IsInfinity() {
return true
}
y2, x3 := &gfP{}, &gfP{}
gfpMul(y2, &c.y, &c.y)
gfpMul(x3, &c.x, &c.x)
gfpMul(x3, x3, &c.x)
gfpAdd(x3, x3, curveB)
return *y2 == *x3
}
func (c *curvePoint) SetInfinity() {
c.x = gfP{0}
c.y = *newGFp(1)
c.z = gfP{0}
c.t = gfP{0}
}
func (c *curvePoint) IsInfinity() bool {
return c.z == gfP{0}
}
func (c *curvePoint) Add(a, b *curvePoint) {
if a.IsInfinity() {
c.Set(b)
return
}
if b.IsInfinity() {
c.Set(a)
return
}
// See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/addition/add-2007-bl.op3
// Normalize the points by replacing a = [x1:y1:z1] and b = [x2:y2:z2]
// by [u1:s1:z1·z2] and [u2:s2:z1·z2]
// where u1 = x1·z2², s1 = y1·z2³ and u1 = x2·z1², s2 = y2·z1³
z12, z22 := &gfP{}, &gfP{}
gfpMul(z12, &a.z, &a.z)
gfpMul(z22, &b.z, &b.z)
u1, u2 := &gfP{}, &gfP{}
gfpMul(u1, &a.x, z22)
gfpMul(u2, &b.x, z12)
t, s1 := &gfP{}, &gfP{}
gfpMul(t, &b.z, z22)
gfpMul(s1, &a.y, t)
s2 := &gfP{}
gfpMul(t, &a.z, z12)
gfpMul(s2, &b.y, t)
// Compute x = (2h)²(s²-u1-u2)
// where s = (s2-s1)/(u2-u1) is the slope of the line through
// (u1,s1) and (u2,s2). The extra factor 2h = 2(u2-u1) comes from the value of z below.
// This is also:
// 4(s2-s1)² - 4h²(u1+u2) = 4(s2-s1)² - 4h³ - 4h²(2u1)
// = r² - j - 2v
// with the notations below.
h := &gfP{}
gfpSub(h, u2, u1)
xEqual := *h == gfP{0}
gfpAdd(t, h, h)
// i = 4h²
i := &gfP{}
gfpMul(i, t, t)
// j = 4h³
j := &gfP{}
gfpMul(j, h, i)
gfpSub(t, s2, s1)
yEqual := *t == gfP{0}
if xEqual && yEqual {
c.Double(a)
return
}
r := &gfP{}
gfpAdd(r, t, t)
v := &gfP{}
gfpMul(v, u1, i)
// t4 = 4(s2-s1)²
t4, t6 := &gfP{}, &gfP{}
gfpMul(t4, r, r)
gfpAdd(t, v, v)
gfpSub(t6, t4, j)
gfpSub(&c.x, t6, t)
// Set y = -(2h)³(s1 + s*(x/4h²-u1))
// This is also
// y = - 2·s1·j - (s2-s1)(2x - 2i·u1) = r(v-x) - 2·s1·j
gfpSub(t, v, &c.x) // t7
gfpMul(t4, s1, j) // t8
gfpAdd(t6, t4, t4) // t9
gfpMul(t4, r, t) // t10
gfpSub(&c.y, t4, t6)
// Set z = 2(u2-u1)·z1·z2 = 2h·z1·z2
gfpAdd(t, &a.z, &b.z) // t11
gfpMul(t4, t, t) // t12
gfpSub(t, t4, z12) // t13
gfpSub(t4, t, z22) // t14
gfpMul(&c.z, t4, h)
}
func (c *curvePoint) Double(a *curvePoint) {
// See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/doubling/dbl-2009-l.op3
A, B, C := &gfP{}, &gfP{}, &gfP{}
gfpMul(A, &a.x, &a.x)
gfpMul(B, &a.y, &a.y)
gfpMul(C, B, B)
t, t2 := &gfP{}, &gfP{}
gfpAdd(t, &a.x, B)
gfpMul(t2, t, t)
gfpSub(t, t2, A)
gfpSub(t2, t, C)
d, e, f := &gfP{}, &gfP{}, &gfP{}
gfpAdd(d, t2, t2)
gfpAdd(t, A, A)
gfpAdd(e, t, A)
gfpMul(f, e, e)
gfpAdd(t, d, d)
gfpSub(&c.x, f, t)
gfpAdd(t, C, C)
gfpAdd(t2, t, t)
gfpAdd(t, t2, t2)
gfpSub(&c.y, d, &c.x)
gfpMul(t2, e, &c.y)
gfpSub(&c.y, t2, t)
gfpMul(t, &a.y, &a.z)
gfpAdd(&c.z, t, t)
}
func (c *curvePoint) Mul(a *curvePoint, scalar *big.Int) {
precomp := [1 << 2]*curvePoint{nil, {}, {}, {}}
precomp[1].Set(a)
precomp[2].Set(a)
gfpMul(&precomp[2].x, &precomp[2].x, xiTo2PSquaredMinus2Over3)
precomp[3].Add(precomp[1], precomp[2])
multiScalar := curveLattice.Multi(scalar)
sum := &curvePoint{}
sum.SetInfinity()
t := &curvePoint{}
for i := len(multiScalar) - 1; i >= 0; i-- {
t.Double(sum)
if multiScalar[i] == 0 {
sum.Set(t)
} else {
sum.Add(t, precomp[multiScalar[i]])
}
}
c.Set(sum)
}
func (c *curvePoint) MakeAffine() {
if c.z == *newGFp(1) {
return
} else if c.z == *newGFp(0) {
c.x = gfP{0}
c.y = *newGFp(1)
c.t = gfP{0}
return
}
zInv := &gfP{}
zInv.Invert(&c.z)
t, zInv2 := &gfP{}, &gfP{}
gfpMul(t, &c.y, zInv)
gfpMul(zInv2, zInv, zInv)
gfpMul(&c.x, &c.x, zInv2)
gfpMul(&c.y, t, zInv2)
c.z = *newGFp(1)
c.t = *newGFp(1)
}
func (c *curvePoint) Neg(a *curvePoint) {
c.x.Set(&a.x)
gfpNeg(&c.y, &a.y)
c.z.Set(&a.z)
c.t = gfP{0}
}

View File

@ -0,0 +1,51 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package bn256
import (
"crypto/rand"
"testing"
"github.com/stretchr/testify/require"
)
func TestExamplePair(t *testing.T) {
// This implements the tripartite Diffie-Hellman algorithm from "A One
// Round Protocol for Tripartite Diffie-Hellman", A. Joux.
// http://www.springerlink.com/content/cddc57yyva0hburb/fulltext.pdf
// Each of three parties, a, b and c, generate a private value.
a, _ := rand.Int(rand.Reader, Order)
b, _ := rand.Int(rand.Reader, Order)
c, _ := rand.Int(rand.Reader, Order)
// Then each party calculates g₁ and g₂ times their private value.
pa := new(G1).ScalarBaseMult(a)
qa := new(G2).ScalarBaseMult(a)
pb := new(G1).ScalarBaseMult(b)
qb := new(G2).ScalarBaseMult(b)
pc := new(G1).ScalarBaseMult(c)
qc := new(G2).ScalarBaseMult(c)
// Now each party exchanges its public values with the other two and
// all parties can calculate the shared key.
k1 := Pair(pb, qc)
k1.ScalarMult(k1, a)
k2 := Pair(pc, qa)
k2.ScalarMult(k2, b)
k3 := Pair(pa, qb)
k3.ScalarMult(k3, c)
// k1, k2 and k3 will all be equal.
require.Equal(t, k1, k2)
require.Equal(t, k1, k3)
require.Equal(t, len(np), 4) //Avoid gometalinter varcheck err on np
}

View File

@ -0,0 +1,81 @@
package bn256
import (
"errors"
"fmt"
)
type gfP [4]uint64
func newGFp(x int64) (out *gfP) {
if x >= 0 {
out = &gfP{uint64(x)}
} else {
out = &gfP{uint64(-x)}
gfpNeg(out, out)
}
montEncode(out, out)
return out
}
func (e *gfP) String() string {
return fmt.Sprintf("%16.16x%16.16x%16.16x%16.16x", e[3], e[2], e[1], e[0])
}
func (e *gfP) Set(f *gfP) {
e[0] = f[0]
e[1] = f[1]
e[2] = f[2]
e[3] = f[3]
}
func (e *gfP) Invert(f *gfP) {
bits := [4]uint64{0x3c208c16d87cfd45, 0x97816a916871ca8d, 0xb85045b68181585d, 0x30644e72e131a029}
sum, power := &gfP{}, &gfP{}
sum.Set(rN1)
power.Set(f)
for word := 0; word < 4; word++ {
for bit := uint(0); bit < 64; bit++ {
if (bits[word]>>bit)&1 == 1 {
gfpMul(sum, sum, power)
}
gfpMul(power, power, power)
}
}
gfpMul(sum, sum, r3)
e.Set(sum)
}
func (e *gfP) Marshal(out []byte) {
for w := uint(0); w < 4; w++ {
for b := uint(0); b < 8; b++ {
out[8*w+b] = byte(e[3-w] >> (56 - 8*b))
}
}
}
func (e *gfP) Unmarshal(in []byte) error {
// Unmarshal the bytes into little endian form
for w := uint(0); w < 4; w++ {
for b := uint(0); b < 8; b++ {
e[3-w] += uint64(in[8*w+b]) << (56 - 8*b)
}
}
// Ensure the point respects the curve modulus
for i := 3; i >= 0; i-- {
if e[i] < p2[i] {
return nil
}
if e[i] > p2[i] {
return errors.New("bn256: coordinate exceeds modulus")
}
}
return errors.New("bn256: coordinate equals modulus")
}
func montEncode(c, a *gfP) { gfpMul(c, a, r2) }
func montDecode(c, a *gfP) { gfpMul(c, a, &gfP{1}) }

View File

@ -0,0 +1,160 @@
package bn256
// For details of the algorithms used, see "Multiplication and Squaring on
// Pairing-Friendly Fields, Devegili et al.
// http://eprint.iacr.org/2006/471.pdf.
import (
"math/big"
)
// gfP12 implements the field of size p¹² as a quadratic extension of gfP6
// where ω²=τ.
type gfP12 struct {
x, y gfP6 // value is xω + y
}
func (e *gfP12) String() string {
return "(" + e.x.String() + "," + e.y.String() + ")"
}
func (e *gfP12) Set(a *gfP12) *gfP12 {
e.x.Set(&a.x)
e.y.Set(&a.y)
return e
}
func (e *gfP12) SetZero() *gfP12 {
e.x.SetZero()
e.y.SetZero()
return e
}
func (e *gfP12) SetOne() *gfP12 {
e.x.SetZero()
e.y.SetOne()
return e
}
func (e *gfP12) IsZero() bool {
return e.x.IsZero() && e.y.IsZero()
}
func (e *gfP12) IsOne() bool {
return e.x.IsZero() && e.y.IsOne()
}
func (e *gfP12) Conjugate(a *gfP12) *gfP12 {
e.x.Neg(&a.x)
e.y.Set(&a.y)
return e
}
func (e *gfP12) Neg(a *gfP12) *gfP12 {
e.x.Neg(&a.x)
e.y.Neg(&a.y)
return e
}
// Frobenius computes (xω+y)^p = x^p ω·ξ^((p-1)/6) + y^p
func (e *gfP12) Frobenius(a *gfP12) *gfP12 {
e.x.Frobenius(&a.x)
e.y.Frobenius(&a.y)
e.x.MulScalar(&e.x, xiToPMinus1Over6)
return e
}
// FrobeniusP2 computes (xω+y)^p² = x^p² ω·ξ^((p²-1)/6) + y^p²
func (e *gfP12) FrobeniusP2(a *gfP12) *gfP12 {
e.x.FrobeniusP2(&a.x)
e.x.MulGFP(&e.x, xiToPSquaredMinus1Over6)
e.y.FrobeniusP2(&a.y)
return e
}
func (e *gfP12) FrobeniusP4(a *gfP12) *gfP12 {
e.x.FrobeniusP4(&a.x)
e.x.MulGFP(&e.x, xiToPSquaredMinus1Over3)
e.y.FrobeniusP4(&a.y)
return e
}
func (e *gfP12) Add(a, b *gfP12) *gfP12 {
e.x.Add(&a.x, &b.x)
e.y.Add(&a.y, &b.y)
return e
}
func (e *gfP12) Sub(a, b *gfP12) *gfP12 {
e.x.Sub(&a.x, &b.x)
e.y.Sub(&a.y, &b.y)
return e
}
func (e *gfP12) Mul(a, b *gfP12) *gfP12 {
tx := (&gfP6{}).Mul(&a.x, &b.y)
t := (&gfP6{}).Mul(&b.x, &a.y)
tx.Add(tx, t)
ty := (&gfP6{}).Mul(&a.y, &b.y)
t.Mul(&a.x, &b.x).MulTau(t)
e.x.Set(tx)
e.y.Add(ty, t)
return e
}
func (e *gfP12) MulScalar(a *gfP12, b *gfP6) *gfP12 {
e.x.Mul(&e.x, b)
e.y.Mul(&e.y, b)
return e
}
func (c *gfP12) Exp(a *gfP12, power *big.Int) *gfP12 {
sum := (&gfP12{}).SetOne()
t := &gfP12{}
for i := power.BitLen() - 1; i >= 0; i-- {
t.Square(sum)
if power.Bit(i) != 0 {
sum.Mul(t, a)
} else {
sum.Set(t)
}
}
c.Set(sum)
return c
}
func (e *gfP12) Square(a *gfP12) *gfP12 {
// Complex squaring algorithm
v0 := (&gfP6{}).Mul(&a.x, &a.y)
t := (&gfP6{}).MulTau(&a.x)
t.Add(&a.y, t)
ty := (&gfP6{}).Add(&a.x, &a.y)
ty.Mul(ty, t).Sub(ty, v0)
t.MulTau(v0)
ty.Sub(ty, t)
e.x.Add(v0, v0)
e.y.Set(ty)
return e
}
func (e *gfP12) Invert(a *gfP12) *gfP12 {
// See "Implementing cryptographic pairings", M. Scott, section 3.2.
// ftp://136.206.11.249/pub/crypto/pairings.pdf
t1, t2 := &gfP6{}, &gfP6{}
t1.Square(&a.x)
t2.Square(&a.y)
t1.MulTau(t1).Sub(t2, t1)
t2.Invert(t1)
e.x.Neg(&a.x)
e.y.Set(&a.y)
e.MulScalar(e, t2)
return e
}

View File

@ -0,0 +1,156 @@
package bn256
// For details of the algorithms used, see "Multiplication and Squaring on
// Pairing-Friendly Fields, Devegili et al.
// http://eprint.iacr.org/2006/471.pdf.
// gfP2 implements a field of size p² as a quadratic extension of the base field
// where i²=-1.
type gfP2 struct {
x, y gfP // value is xi+y.
}
func gfP2Decode(in *gfP2) *gfP2 {
out := &gfP2{}
montDecode(&out.x, &in.x)
montDecode(&out.y, &in.y)
return out
}
func (e *gfP2) String() string {
return "(" + e.x.String() + ", " + e.y.String() + ")"
}
func (e *gfP2) Set(a *gfP2) *gfP2 {
e.x.Set(&a.x)
e.y.Set(&a.y)
return e
}
func (e *gfP2) SetZero() *gfP2 {
e.x = gfP{0}
e.y = gfP{0}
return e
}
func (e *gfP2) SetOne() *gfP2 {
e.x = gfP{0}
e.y = *newGFp(1)
return e
}
func (e *gfP2) IsZero() bool {
zero := gfP{0}
return e.x == zero && e.y == zero
}
func (e *gfP2) IsOne() bool {
zero, one := gfP{0}, *newGFp(1)
return e.x == zero && e.y == one
}
func (e *gfP2) Conjugate(a *gfP2) *gfP2 {
e.y.Set(&a.y)
gfpNeg(&e.x, &a.x)
return e
}
func (e *gfP2) Neg(a *gfP2) *gfP2 {
gfpNeg(&e.x, &a.x)
gfpNeg(&e.y, &a.y)
return e
}
func (e *gfP2) Add(a, b *gfP2) *gfP2 {
gfpAdd(&e.x, &a.x, &b.x)
gfpAdd(&e.y, &a.y, &b.y)
return e
}
func (e *gfP2) Sub(a, b *gfP2) *gfP2 {
gfpSub(&e.x, &a.x, &b.x)
gfpSub(&e.y, &a.y, &b.y)
return e
}
// See "Multiplication and Squaring in Pairing-Friendly Fields",
// http://eprint.iacr.org/2006/471.pdf
func (e *gfP2) Mul(a, b *gfP2) *gfP2 {
tx, t := &gfP{}, &gfP{}
gfpMul(tx, &a.x, &b.y)
gfpMul(t, &b.x, &a.y)
gfpAdd(tx, tx, t)
ty := &gfP{}
gfpMul(ty, &a.y, &b.y)
gfpMul(t, &a.x, &b.x)
gfpSub(ty, ty, t)
e.x.Set(tx)
e.y.Set(ty)
return e
}
func (e *gfP2) MulScalar(a *gfP2, b *gfP) *gfP2 {
gfpMul(&e.x, &a.x, b)
gfpMul(&e.y, &a.y, b)
return e
}
// MulXi sets e=ξa where ξ=i+9 and then returns e.
func (e *gfP2) MulXi(a *gfP2) *gfP2 {
// (xi+y)(i+9) = (9x+y)i+(9y-x)
tx := &gfP{}
gfpAdd(tx, &a.x, &a.x)
gfpAdd(tx, tx, tx)
gfpAdd(tx, tx, tx)
gfpAdd(tx, tx, &a.x)
gfpAdd(tx, tx, &a.y)
ty := &gfP{}
gfpAdd(ty, &a.y, &a.y)
gfpAdd(ty, ty, ty)
gfpAdd(ty, ty, ty)
gfpAdd(ty, ty, &a.y)
gfpSub(ty, ty, &a.x)
e.x.Set(tx)
e.y.Set(ty)
return e
}
func (e *gfP2) Square(a *gfP2) *gfP2 {
// Complex squaring algorithm:
// (xi+y)² = (x+y)(y-x) + 2*i*x*y
tx, ty := &gfP{}, &gfP{}
gfpSub(tx, &a.y, &a.x)
gfpAdd(ty, &a.x, &a.y)
gfpMul(ty, tx, ty)
gfpMul(tx, &a.x, &a.y)
gfpAdd(tx, tx, tx)
e.x.Set(tx)
e.y.Set(ty)
return e
}
func (e *gfP2) Invert(a *gfP2) *gfP2 {
// See "Implementing cryptographic pairings", M. Scott, section 3.2.
// ftp://136.206.11.249/pub/crypto/pairings.pdf
t1, t2 := &gfP{}, &gfP{}
gfpMul(t1, &a.x, &a.x)
gfpMul(t2, &a.y, &a.y)
gfpAdd(t1, t1, t2)
inv := &gfP{}
inv.Invert(t1)
gfpNeg(t1, &a.x)
gfpMul(&e.x, t1, inv)
gfpMul(&e.y, &a.y, inv)
return e
}

View File

@ -0,0 +1,213 @@
package bn256
// For details of the algorithms used, see "Multiplication and Squaring on
// Pairing-Friendly Fields, Devegili et al.
// http://eprint.iacr.org/2006/471.pdf.
// gfP6 implements the field of size p⁶ as a cubic extension of gfP2 where τ³=ξ
// and ξ=i+9.
type gfP6 struct {
x, y, z gfP2 // value is xτ² + yτ + z
}
func (e *gfP6) String() string {
return "(" + e.x.String() + ", " + e.y.String() + ", " + e.z.String() + ")"
}
func (e *gfP6) Set(a *gfP6) *gfP6 {
e.x.Set(&a.x)
e.y.Set(&a.y)
e.z.Set(&a.z)
return e
}
func (e *gfP6) SetZero() *gfP6 {
e.x.SetZero()
e.y.SetZero()
e.z.SetZero()
return e
}
func (e *gfP6) SetOne() *gfP6 {
e.x.SetZero()
e.y.SetZero()
e.z.SetOne()
return e
}
func (e *gfP6) IsZero() bool {
return e.x.IsZero() && e.y.IsZero() && e.z.IsZero()
}
func (e *gfP6) IsOne() bool {
return e.x.IsZero() && e.y.IsZero() && e.z.IsOne()
}
func (e *gfP6) Neg(a *gfP6) *gfP6 {
e.x.Neg(&a.x)
e.y.Neg(&a.y)
e.z.Neg(&a.z)
return e
}
func (e *gfP6) Frobenius(a *gfP6) *gfP6 {
e.x.Conjugate(&a.x)
e.y.Conjugate(&a.y)
e.z.Conjugate(&a.z)
e.x.Mul(&e.x, xiTo2PMinus2Over3)
e.y.Mul(&e.y, xiToPMinus1Over3)
return e
}
// FrobeniusP2 computes (xτ²+yτ+z)^(p²) = xτ^(2p²) + yτ^(p²) + z
func (e *gfP6) FrobeniusP2(a *gfP6) *gfP6 {
// τ^(2p²) = τ²τ^(2p²-2) = τ²ξ^((2p²-2)/3)
e.x.MulScalar(&a.x, xiTo2PSquaredMinus2Over3)
// τ^(p²) = ττ^(p²-1) = τξ^((p²-1)/3)
e.y.MulScalar(&a.y, xiToPSquaredMinus1Over3)
e.z.Set(&a.z)
return e
}
func (e *gfP6) FrobeniusP4(a *gfP6) *gfP6 {
e.x.MulScalar(&a.x, xiToPSquaredMinus1Over3)
e.y.MulScalar(&a.y, xiTo2PSquaredMinus2Over3)
e.z.Set(&a.z)
return e
}
func (e *gfP6) Add(a, b *gfP6) *gfP6 {
e.x.Add(&a.x, &b.x)
e.y.Add(&a.y, &b.y)
e.z.Add(&a.z, &b.z)
return e
}
func (e *gfP6) Sub(a, b *gfP6) *gfP6 {
e.x.Sub(&a.x, &b.x)
e.y.Sub(&a.y, &b.y)
e.z.Sub(&a.z, &b.z)
return e
}
func (e *gfP6) Mul(a, b *gfP6) *gfP6 {
// "Multiplication and Squaring on Pairing-Friendly Fields"
// Section 4, Karatsuba method.
// http://eprint.iacr.org/2006/471.pdf
v0 := (&gfP2{}).Mul(&a.z, &b.z)
v1 := (&gfP2{}).Mul(&a.y, &b.y)
v2 := (&gfP2{}).Mul(&a.x, &b.x)
t0 := (&gfP2{}).Add(&a.x, &a.y)
t1 := (&gfP2{}).Add(&b.x, &b.y)
tz := (&gfP2{}).Mul(t0, t1)
tz.Sub(tz, v1).Sub(tz, v2).MulXi(tz).Add(tz, v0)
t0.Add(&a.y, &a.z)
t1.Add(&b.y, &b.z)
ty := (&gfP2{}).Mul(t0, t1)
t0.MulXi(v2)
ty.Sub(ty, v0).Sub(ty, v1).Add(ty, t0)
t0.Add(&a.x, &a.z)
t1.Add(&b.x, &b.z)
tx := (&gfP2{}).Mul(t0, t1)
tx.Sub(tx, v0).Add(tx, v1).Sub(tx, v2)
e.x.Set(tx)
e.y.Set(ty)
e.z.Set(tz)
return e
}
func (e *gfP6) MulScalar(a *gfP6, b *gfP2) *gfP6 {
e.x.Mul(&a.x, b)
e.y.Mul(&a.y, b)
e.z.Mul(&a.z, b)
return e
}
func (e *gfP6) MulGFP(a *gfP6, b *gfP) *gfP6 {
e.x.MulScalar(&a.x, b)
e.y.MulScalar(&a.y, b)
e.z.MulScalar(&a.z, b)
return e
}
// MulTau computes τ·(aτ²+bτ+c) = bτ²+cτ+aξ
func (e *gfP6) MulTau(a *gfP6) *gfP6 {
tz := (&gfP2{}).MulXi(&a.x)
ty := (&gfP2{}).Set(&a.y)
e.y.Set(&a.z)
e.x.Set(ty)
e.z.Set(tz)
return e
}
func (e *gfP6) Square(a *gfP6) *gfP6 {
v0 := (&gfP2{}).Square(&a.z)
v1 := (&gfP2{}).Square(&a.y)
v2 := (&gfP2{}).Square(&a.x)
c0 := (&gfP2{}).Add(&a.x, &a.y)
c0.Square(c0).Sub(c0, v1).Sub(c0, v2).MulXi(c0).Add(c0, v0)
c1 := (&gfP2{}).Add(&a.y, &a.z)
c1.Square(c1).Sub(c1, v0).Sub(c1, v1)
xiV2 := (&gfP2{}).MulXi(v2)
c1.Add(c1, xiV2)
c2 := (&gfP2{}).Add(&a.x, &a.z)
c2.Square(c2).Sub(c2, v0).Add(c2, v1).Sub(c2, v2)
e.x.Set(c2)
e.y.Set(c1)
e.z.Set(c0)
return e
}
func (e *gfP6) Invert(a *gfP6) *gfP6 {
// See "Implementing cryptographic pairings", M. Scott, section 3.2.
// ftp://136.206.11.249/pub/crypto/pairings.pdf
// Here we can give a short explanation of how it works: let j be a cubic root of
// unity in GF(p²) so that 1+j+j²=0.
// Then (xτ² + yτ + z)(xj²τ² + yjτ + z)(xjτ² + yj²τ + z)
// = (xτ² + yτ + z)(Cτ²+Bτ+A)
// = (x³ξ²+y³ξ+z³-3ξxyz) = F is an element of the base field (the norm).
//
// On the other hand (xj²τ² + yjτ + z)(xjτ² + yj²τ + z)
// = τ²(y²-ξxz) + τ(ξx²-yz) + (z²-ξxy)
//
// So that's why A = (z²-ξxy), B = (ξx²-yz), C = (y²-ξxz)
t1 := (&gfP2{}).Mul(&a.x, &a.y)
t1.MulXi(t1)
A := (&gfP2{}).Square(&a.z)
A.Sub(A, t1)
B := (&gfP2{}).Square(&a.x)
B.MulXi(B)
t1.Mul(&a.y, &a.z)
B.Sub(B, t1)
C := (&gfP2{}).Square(&a.y)
t1.Mul(&a.x, &a.z)
C.Sub(C, t1)
F := (&gfP2{}).Mul(C, &a.y)
F.MulXi(F)
t1.Mul(A, &a.z)
F.Add(F, t1)
t1.Mul(B, &a.x).MulXi(t1)
F.Add(F, t1)
F.Invert(F)
e.x.Mul(C, F)
e.y.Mul(B, F)
e.z.Mul(A, F)
return e
}

View File

@ -0,0 +1,129 @@
// +build amd64,!generic
#define storeBlock(a0,a1,a2,a3, r) \
MOVQ a0, 0+r \
MOVQ a1, 8+r \
MOVQ a2, 16+r \
MOVQ a3, 24+r
#define loadBlock(r, a0,a1,a2,a3) \
MOVQ 0+r, a0 \
MOVQ 8+r, a1 \
MOVQ 16+r, a2 \
MOVQ 24+r, a3
#define gfpCarry(a0,a1,a2,a3,a4, b0,b1,b2,b3,b4) \
\ // b = a-p
MOVQ a0, b0 \
MOVQ a1, b1 \
MOVQ a2, b2 \
MOVQ a3, b3 \
MOVQ a4, b4 \
\
SUBQ ·p2+0(SB), b0 \
SBBQ ·p2+8(SB), b1 \
SBBQ ·p2+16(SB), b2 \
SBBQ ·p2+24(SB), b3 \
SBBQ $0, b4 \
\
\ // if b is negative then return a
\ // else return b
CMOVQCC b0, a0 \
CMOVQCC b1, a1 \
CMOVQCC b2, a2 \
CMOVQCC b3, a3
#include "mul_amd64.h"
#include "mul_bmi2_amd64.h"
TEXT ·gfpNeg(SB),0,$0-16
MOVQ ·p2+0(SB), R8
MOVQ ·p2+8(SB), R9
MOVQ ·p2+16(SB), R10
MOVQ ·p2+24(SB), R11
MOVQ a+8(FP), DI
SUBQ 0(DI), R8
SBBQ 8(DI), R9
SBBQ 16(DI), R10
SBBQ 24(DI), R11
MOVQ $0, AX
gfpCarry(R8,R9,R10,R11,AX, R12,R13,R14,R15,BX)
MOVQ c+0(FP), DI
storeBlock(R8,R9,R10,R11, 0(DI))
RET
TEXT ·gfpAdd(SB),0,$0-24
MOVQ a+8(FP), DI
MOVQ b+16(FP), SI
loadBlock(0(DI), R8,R9,R10,R11)
MOVQ $0, R12
ADDQ 0(SI), R8
ADCQ 8(SI), R9
ADCQ 16(SI), R10
ADCQ 24(SI), R11
ADCQ $0, R12
gfpCarry(R8,R9,R10,R11,R12, R13,R14,R15,AX,BX)
MOVQ c+0(FP), DI
storeBlock(R8,R9,R10,R11, 0(DI))
RET
TEXT ·gfpSub(SB),0,$0-24
MOVQ a+8(FP), DI
MOVQ b+16(FP), SI
loadBlock(0(DI), R8,R9,R10,R11)
MOVQ ·p2+0(SB), R12
MOVQ ·p2+8(SB), R13
MOVQ ·p2+16(SB), R14
MOVQ ·p2+24(SB), R15
MOVQ $0, AX
SUBQ 0(SI), R8
SBBQ 8(SI), R9
SBBQ 16(SI), R10
SBBQ 24(SI), R11
CMOVQCC AX, R12
CMOVQCC AX, R13
CMOVQCC AX, R14
CMOVQCC AX, R15
ADDQ R12, R8
ADCQ R13, R9
ADCQ R14, R10
ADCQ R15, R11
MOVQ c+0(FP), DI
storeBlock(R8,R9,R10,R11, 0(DI))
RET
TEXT ·gfpMul(SB),0,$160-24
MOVQ a+8(FP), DI
MOVQ b+16(FP), SI
// Jump to a slightly different implementation if MULX isn't supported.
CMPB ·hasBMI2(SB), $0
JE nobmi2Mul
mulBMI2(0(DI),8(DI),16(DI),24(DI), 0(SI))
storeBlock( R8, R9,R10,R11, 0(SP))
storeBlock(R12,R13,R14,R15, 32(SP))
gfpReduceBMI2()
JMP end
nobmi2Mul:
mul(0(DI),8(DI),16(DI),24(DI), 0(SI), 0(SP))
gfpReduce(0(SP))
end:
MOVQ c+0(FP), DI
storeBlock(R12,R13,R14,R15, 0(DI))
RET

View File

@ -0,0 +1,113 @@
// +build arm64,!generic
#define storeBlock(a0,a1,a2,a3, r) \
MOVD a0, 0+r \
MOVD a1, 8+r \
MOVD a2, 16+r \
MOVD a3, 24+r
#define loadBlock(r, a0,a1,a2,a3) \
MOVD 0+r, a0 \
MOVD 8+r, a1 \
MOVD 16+r, a2 \
MOVD 24+r, a3
#define loadModulus(p0,p1,p2,p3) \
MOVD ·p2+0(SB), p0 \
MOVD ·p2+8(SB), p1 \
MOVD ·p2+16(SB), p2 \
MOVD ·p2+24(SB), p3
#include "mul_arm64.h"
TEXT ·gfpNeg(SB),0,$0-16
MOVD a+8(FP), R0
loadBlock(0(R0), R1,R2,R3,R4)
loadModulus(R5,R6,R7,R8)
SUBS R1, R5, R1
SBCS R2, R6, R2
SBCS R3, R7, R3
SBCS R4, R8, R4
SUBS R5, R1, R5
SBCS R6, R2, R6
SBCS R7, R3, R7
SBCS R8, R4, R8
CSEL CS, R5, R1, R1
CSEL CS, R6, R2, R2
CSEL CS, R7, R3, R3
CSEL CS, R8, R4, R4
MOVD c+0(FP), R0
storeBlock(R1,R2,R3,R4, 0(R0))
RET
TEXT ·gfpAdd(SB),0,$0-24
MOVD a+8(FP), R0
loadBlock(0(R0), R1,R2,R3,R4)
MOVD b+16(FP), R0
loadBlock(0(R0), R5,R6,R7,R8)
loadModulus(R9,R10,R11,R12)
MOVD ZR, R0
ADDS R5, R1
ADCS R6, R2
ADCS R7, R3
ADCS R8, R4
ADCS ZR, R0
SUBS R9, R1, R5
SBCS R10, R2, R6
SBCS R11, R3, R7
SBCS R12, R4, R8
SBCS ZR, R0, R0
CSEL CS, R5, R1, R1
CSEL CS, R6, R2, R2
CSEL CS, R7, R3, R3
CSEL CS, R8, R4, R4
MOVD c+0(FP), R0
storeBlock(R1,R2,R3,R4, 0(R0))
RET
TEXT ·gfpSub(SB),0,$0-24
MOVD a+8(FP), R0
loadBlock(0(R0), R1,R2,R3,R4)
MOVD b+16(FP), R0
loadBlock(0(R0), R5,R6,R7,R8)
loadModulus(R9,R10,R11,R12)
SUBS R5, R1
SBCS R6, R2
SBCS R7, R3
SBCS R8, R4
CSEL CS, ZR, R9, R9
CSEL CS, ZR, R10, R10
CSEL CS, ZR, R11, R11
CSEL CS, ZR, R12, R12
ADDS R9, R1
ADCS R10, R2
ADCS R11, R3
ADCS R12, R4
MOVD c+0(FP), R0
storeBlock(R1,R2,R3,R4, 0(R0))
RET
TEXT ·gfpMul(SB),0,$0-24
MOVD a+8(FP), R0
loadBlock(0(R0), R1,R2,R3,R4)
MOVD b+16(FP), R0
loadBlock(0(R0), R5,R6,R7,R8)
mul(R9,R10,R11,R12,R13,R14,R15,R16)
gfpReduce()
MOVD c+0(FP), R0
storeBlock(R1,R2,R3,R4, 0(R0))
RET

View File

@ -0,0 +1,25 @@
// +build amd64,!generic arm64,!generic
package bn256
// This file contains forward declarations for the architecture-specific
// assembly implementations of these functions, provided that they exist.
import (
"golang.org/x/sys/cpu"
)
//nolint:varcheck
var hasBMI2 = cpu.X86.HasBMI2
// go:noescape
func gfpNeg(c, a *gfP)
//go:noescape
func gfpAdd(c, a, b *gfP)
//go:noescape
func gfpSub(c, a, b *gfP)
//go:noescape
func gfpMul(c, a, b *gfP)

View File

@ -0,0 +1,173 @@
// +build !amd64,!arm64 generic
package bn256
func gfpCarry(a *gfP, head uint64) {
b := &gfP{}
var carry uint64
for i, pi := range p2 {
ai := a[i]
bi := ai - pi - carry
b[i] = bi
carry = (pi&^ai | (pi|^ai)&bi) >> 63
}
carry = carry &^ head
// If b is negative, then return a.
// Else return b.
carry = -carry
ncarry := ^carry
for i := 0; i < 4; i++ {
a[i] = (a[i] & carry) | (b[i] & ncarry)
}
}
func gfpNeg(c, a *gfP) {
var carry uint64
for i, pi := range p2 {
ai := a[i]
ci := pi - ai - carry
c[i] = ci
carry = (ai&^pi | (ai|^pi)&ci) >> 63
}
gfpCarry(c, 0)
}
func gfpAdd(c, a, b *gfP) {
var carry uint64
for i, ai := range a {
bi := b[i]
ci := ai + bi + carry
c[i] = ci
carry = (ai&bi | (ai|bi)&^ci) >> 63
}
gfpCarry(c, carry)
}
func gfpSub(c, a, b *gfP) {
t := &gfP{}
var carry uint64
for i, pi := range p2 {
bi := b[i]
ti := pi - bi - carry
t[i] = ti
carry = (bi&^pi | (bi|^pi)&ti) >> 63
}
carry = 0
for i, ai := range a {
ti := t[i]
ci := ai + ti + carry
c[i] = ci
carry = (ai&ti | (ai|ti)&^ci) >> 63
}
gfpCarry(c, carry)
}
func mul(a, b [4]uint64) [8]uint64 {
const (
mask16 uint64 = 0x0000ffff
mask32 uint64 = 0xffffffff
)
var buff [32]uint64
for i, ai := range a {
a0, a1, a2, a3 := ai&mask16, (ai>>16)&mask16, (ai>>32)&mask16, ai>>48
for j, bj := range b {
b0, b2 := bj&mask32, bj>>32
off := 4 * (i + j)
buff[off+0] += a0 * b0
buff[off+1] += a1 * b0
buff[off+2] += a2*b0 + a0*b2
buff[off+3] += a3*b0 + a1*b2
buff[off+4] += a2 * b2
buff[off+5] += a3 * b2
}
}
for i := uint(1); i < 4; i++ {
shift := 16 * i
var head, carry uint64
for j := uint(0); j < 8; j++ {
block := 4 * j
xi := buff[block]
yi := (buff[block+i] << shift) + head
zi := xi + yi + carry
buff[block] = zi
carry = (xi&yi | (xi|yi)&^zi) >> 63
head = buff[block+i] >> (64 - shift)
}
}
return [8]uint64{buff[0], buff[4], buff[8], buff[12], buff[16], buff[20], buff[24], buff[28]}
}
func halfMul(a, b [4]uint64) [4]uint64 {
const (
mask16 uint64 = 0x0000ffff
mask32 uint64 = 0xffffffff
)
var buff [18]uint64
for i, ai := range a {
a0, a1, a2, a3 := ai&mask16, (ai>>16)&mask16, (ai>>32)&mask16, ai>>48
for j, bj := range b {
if i+j > 3 {
break
}
b0, b2 := bj&mask32, bj>>32
off := 4 * (i + j)
buff[off+0] += a0 * b0
buff[off+1] += a1 * b0
buff[off+2] += a2*b0 + a0*b2
buff[off+3] += a3*b0 + a1*b2
buff[off+4] += a2 * b2
buff[off+5] += a3 * b2
}
}
for i := uint(1); i < 4; i++ {
shift := 16 * i
var head, carry uint64
for j := uint(0); j < 4; j++ {
block := 4 * j
xi := buff[block]
yi := (buff[block+i] << shift) + head
zi := xi + yi + carry
buff[block] = zi
carry = (xi&yi | (xi|yi)&^zi) >> 63
head = buff[block+i] >> (64 - shift)
}
}
return [4]uint64{buff[0], buff[4], buff[8], buff[12]}
}
func gfpMul(c, a, b *gfP) {
T := mul(*a, *b)
m := halfMul([4]uint64{T[0], T[1], T[2], T[3]}, np)
t := mul([4]uint64{m[0], m[1], m[2], m[3]}, p2)
var carry uint64
for i, Ti := range T {
ti := t[i]
zi := Ti + ti + carry
T[i] = zi
carry = (Ti&ti | (Ti|ti)&^zi) >> 63
}
*c = gfP{T[4], T[5], T[6], T[7]}
gfpCarry(c, carry)
}

View File

@ -0,0 +1,60 @@
package bn256
import (
"testing"
)
// Tests that negation works the same way on both assembly-optimized and pure Go
// implementation.
func TestGFpNeg(t *testing.T) {
n := &gfP{0x0123456789abcdef, 0xfedcba9876543210, 0xdeadbeefdeadbeef, 0xfeebdaedfeebdaed}
w := &gfP{0xfedcba9876543211, 0x0123456789abcdef, 0x2152411021524110, 0x0114251201142512}
h := &gfP{}
gfpNeg(h, n)
if *h != *w {
t.Errorf("negation mismatch: have %#x, want %#x", *h, *w)
}
}
// Tests that addition works the same way on both assembly-optimized and pure Go
// implementation.
func TestGFpAdd(t *testing.T) {
a := &gfP{0x0123456789abcdef, 0xfedcba9876543210, 0xdeadbeefdeadbeef, 0xfeebdaedfeebdaed}
b := &gfP{0xfedcba9876543210, 0x0123456789abcdef, 0xfeebdaedfeebdaed, 0xdeadbeefdeadbeef}
w := &gfP{0xc3df73e9278302b8, 0x687e956e978e3572, 0x254954275c18417f, 0xad354b6afc67f9b4}
h := &gfP{}
gfpAdd(h, a, b)
if *h != *w {
t.Errorf("addition mismatch: have %#x, want %#x", *h, *w)
}
}
// Tests that subtraction works the same way on both assembly-optimized and pure Go
// implementation.
func TestGFpSub(t *testing.T) {
a := &gfP{0x0123456789abcdef, 0xfedcba9876543210, 0xdeadbeefdeadbeef, 0xfeebdaedfeebdaed}
b := &gfP{0xfedcba9876543210, 0x0123456789abcdef, 0xfeebdaedfeebdaed, 0xdeadbeefdeadbeef}
w := &gfP{0x02468acf13579bdf, 0xfdb97530eca86420, 0xdfc1e401dfc1e402, 0x203e1bfe203e1bfd}
h := &gfP{}
gfpSub(h, a, b)
if *h != *w {
t.Errorf("subtraction mismatch: have %#x, want %#x", *h, *w)
}
}
// Tests that multiplication works the same way on both assembly-optimized and pure Go
// implementation.
func TestGFpMul(t *testing.T) {
a := &gfP{0x0123456789abcdef, 0xfedcba9876543210, 0xdeadbeefdeadbeef, 0xfeebdaedfeebdaed}
b := &gfP{0xfedcba9876543210, 0x0123456789abcdef, 0xfeebdaedfeebdaed, 0xdeadbeefdeadbeef}
w := &gfP{0xcbcbd377f7ad22d3, 0x3b89ba5d849379bf, 0x87b61627bd38b6d2, 0xc44052a2a0e654b2}
h := &gfP{}
gfpMul(h, a, b)
if *h != *w {
t.Errorf("multiplication mismatch: have %#x, want %#x", *h, *w)
}
}

View File

@ -0,0 +1,115 @@
package bn256
import (
"math/big"
)
var half = new(big.Int).Rsh(Order, 1)
var curveLattice = &lattice{
vectors: [][]*big.Int{
{bigFromBase10("147946756881789319000765030803803410728"), bigFromBase10("147946756881789319010696353538189108491")},
{bigFromBase10("147946756881789319020627676272574806254"), bigFromBase10("-147946756881789318990833708069417712965")},
},
inverse: []*big.Int{
bigFromBase10("147946756881789318990833708069417712965"),
bigFromBase10("147946756881789319010696353538189108491"),
},
det: bigFromBase10("43776485743678550444492811490514550177096728800832068687396408373151616991234"),
}
var targetLattice = &lattice{
vectors: [][]*big.Int{
{bigFromBase10("9931322734385697761"), bigFromBase10("9931322734385697761"), bigFromBase10("9931322734385697763"), bigFromBase10("9931322734385697764")},
{bigFromBase10("4965661367192848881"), bigFromBase10("4965661367192848881"), bigFromBase10("4965661367192848882"), bigFromBase10("-9931322734385697762")},
{bigFromBase10("-9931322734385697762"), bigFromBase10("-4965661367192848881"), bigFromBase10("4965661367192848881"), bigFromBase10("-4965661367192848882")},
{bigFromBase10("9931322734385697763"), bigFromBase10("-4965661367192848881"), bigFromBase10("-4965661367192848881"), bigFromBase10("-4965661367192848881")},
},
inverse: []*big.Int{
bigFromBase10("734653495049373973658254490726798021314063399421879442165"),
bigFromBase10("147946756881789319000765030803803410728"),
bigFromBase10("-147946756881789319005730692170996259609"),
bigFromBase10("1469306990098747947464455738335385361643788813749140841702"),
},
det: new(big.Int).Set(Order),
}
type lattice struct {
vectors [][]*big.Int
inverse []*big.Int
det *big.Int
}
// decompose takes a scalar mod Order as input and finds a short, positive decomposition of it wrt to the lattice basis.
func (l *lattice) decompose(k *big.Int) []*big.Int {
n := len(l.inverse)
// Calculate closest vector in lattice to <k,0,0,...> with Babai's rounding.
c := make([]*big.Int, n)
for i := 0; i < n; i++ {
c[i] = new(big.Int).Mul(k, l.inverse[i])
round(c[i], l.det)
}
// Transform vectors according to c and subtract <k,0,0,...>.
out := make([]*big.Int, n)
temp := new(big.Int)
for i := 0; i < n; i++ {
out[i] = new(big.Int)
for j := 0; j < n; j++ {
temp.Mul(c[j], l.vectors[j][i])
out[i].Add(out[i], temp)
}
out[i].Neg(out[i])
out[i].Add(out[i], l.vectors[0][i]).Add(out[i], l.vectors[0][i])
}
out[0].Add(out[0], k)
return out
}
func (l *lattice) Precompute(add func(i, j uint)) {
n := uint(len(l.vectors))
total := uint(1) << n
for i := uint(0); i < n; i++ {
for j := uint(0); j < total; j++ {
if (j>>i)&1 == 1 {
add(i, j)
}
}
}
}
func (l *lattice) Multi(scalar *big.Int) []uint8 {
decomp := l.decompose(scalar)
maxLen := 0
for _, x := range decomp {
if x.BitLen() > maxLen {
maxLen = x.BitLen()
}
}
out := make([]uint8, maxLen)
for j, x := range decomp {
for i := 0; i < maxLen; i++ {
out[i] += uint8(x.Bit(i)) << uint(j)
}
}
return out
}
// round sets num to num/denom rounded to the nearest integer.
func round(num, denom *big.Int) {
r := new(big.Int)
num.DivMod(num, denom, r)
if r.Cmp(half) == 1 {
num.Add(num, big.NewInt(1))
}
}

View File

@ -0,0 +1,29 @@
package bn256
import (
"crypto/rand"
"testing"
)
func TestLatticeReduceCurve(t *testing.T) {
k, _ := rand.Int(rand.Reader, Order)
ks := curveLattice.decompose(k)
if ks[0].BitLen() > 130 || ks[1].BitLen() > 130 {
t.Fatal("reduction too large")
} else if ks[0].Sign() < 0 || ks[1].Sign() < 0 {
t.Fatal("reduction must be positive")
}
}
func TestLatticeReduceTarget(t *testing.T) {
k, _ := rand.Int(rand.Reader, Order)
ks := targetLattice.decompose(k)
if ks[0].BitLen() > 66 || ks[1].BitLen() > 66 || ks[2].BitLen() > 66 || ks[3].BitLen() > 66 {
t.Fatal("reduction too large")
} else if ks[0].Sign() < 0 || ks[1].Sign() < 0 || ks[2].Sign() < 0 || ks[3].Sign() < 0 {
t.Fatal("reduction must be positive")
}
}

View File

@ -0,0 +1,71 @@
package bn256
import (
"testing"
"crypto/rand"
)
func TestRandomG2Marshal(t *testing.T) {
for i := 0; i < 10; i++ {
n, g2, err := RandomG2(rand.Reader)
if err != nil {
t.Error(err)
continue
}
t.Logf("%v: %x\n", n, g2.Marshal())
}
}
func TestPairings(t *testing.T) {
a1 := new(G1).ScalarBaseMult(bigFromBase10("1"))
a2 := new(G1).ScalarBaseMult(bigFromBase10("2"))
a37 := new(G1).ScalarBaseMult(bigFromBase10("37"))
an1 := new(G1).ScalarBaseMult(bigFromBase10("21888242871839275222246405745257275088548364400416034343698204186575808495616"))
b0 := new(G2).ScalarBaseMult(bigFromBase10("0"))
b1 := new(G2).ScalarBaseMult(bigFromBase10("1"))
b2 := new(G2).ScalarBaseMult(bigFromBase10("2"))
b27 := new(G2).ScalarBaseMult(bigFromBase10("27"))
b999 := new(G2).ScalarBaseMult(bigFromBase10("999"))
bn1 := new(G2).ScalarBaseMult(bigFromBase10("21888242871839275222246405745257275088548364400416034343698204186575808495616"))
p1 := Pair(a1, b1)
pn1 := Pair(a1, bn1)
np1 := Pair(an1, b1)
if pn1.String() != np1.String() {
t.Error("Pairing mismatch: e(a, -b) != e(-a, b)")
}
if !PairingCheck([]*G1{a1, an1}, []*G2{b1, b1}) {
t.Error("MultiAte check gave false negative!")
}
p0 := new(GT).Add(p1, pn1)
p0_2 := Pair(a1, b0)
if p0.String() != p0_2.String() {
t.Error("Pairing mismatch: e(a, b) * e(a, -b) != 1")
}
p0_3 := new(GT).ScalarMult(p1, bigFromBase10("21888242871839275222246405745257275088548364400416034343698204186575808495617"))
if p0.String() != p0_3.String() {
t.Error("Pairing mismatch: e(a, b) has wrong order")
}
p2 := Pair(a2, b1)
p2_2 := Pair(a1, b2)
p2_3 := new(GT).ScalarMult(p1, bigFromBase10("2"))
if p2.String() != p2_2.String() {
t.Error("Pairing mismatch: e(a, b * 2) != e(a * 2, b)")
}
if p2.String() != p2_3.String() {
t.Error("Pairing mismatch: e(a, b * 2) != e(a, b) ** 2")
}
if p2.String() == p1.String() {
t.Error("Pairing is degenerate!")
}
if PairingCheck([]*G1{a1, a1}, []*G2{b1, b1}) {
t.Error("MultiAte check gave false positive!")
}
p999 := Pair(a37, b27)
p999_2 := Pair(a1, b999)
if p999.String() != p999_2.String() {
t.Error("Pairing mismatch: e(a * 37, b * 27) != e(a, b * 999)")
}
}

View File

@ -0,0 +1,181 @@
#define mul(a0,a1,a2,a3, rb, stack) \
MOVQ a0, AX \
MULQ 0+rb \
MOVQ AX, R8 \
MOVQ DX, R9 \
MOVQ a0, AX \
MULQ 8+rb \
ADDQ AX, R9 \
ADCQ $0, DX \
MOVQ DX, R10 \
MOVQ a0, AX \
MULQ 16+rb \
ADDQ AX, R10 \
ADCQ $0, DX \
MOVQ DX, R11 \
MOVQ a0, AX \
MULQ 24+rb \
ADDQ AX, R11 \
ADCQ $0, DX \
MOVQ DX, R12 \
\
storeBlock(R8,R9,R10,R11, 0+stack) \
MOVQ R12, 32+stack \
\
MOVQ a1, AX \
MULQ 0+rb \
MOVQ AX, R8 \
MOVQ DX, R9 \
MOVQ a1, AX \
MULQ 8+rb \
ADDQ AX, R9 \
ADCQ $0, DX \
MOVQ DX, R10 \
MOVQ a1, AX \
MULQ 16+rb \
ADDQ AX, R10 \
ADCQ $0, DX \
MOVQ DX, R11 \
MOVQ a1, AX \
MULQ 24+rb \
ADDQ AX, R11 \
ADCQ $0, DX \
MOVQ DX, R12 \
\
ADDQ 8+stack, R8 \
ADCQ 16+stack, R9 \
ADCQ 24+stack, R10 \
ADCQ 32+stack, R11 \
ADCQ $0, R12 \
storeBlock(R8,R9,R10,R11, 8+stack) \
MOVQ R12, 40+stack \
\
MOVQ a2, AX \
MULQ 0+rb \
MOVQ AX, R8 \
MOVQ DX, R9 \
MOVQ a2, AX \
MULQ 8+rb \
ADDQ AX, R9 \
ADCQ $0, DX \
MOVQ DX, R10 \
MOVQ a2, AX \
MULQ 16+rb \
ADDQ AX, R10 \
ADCQ $0, DX \
MOVQ DX, R11 \
MOVQ a2, AX \
MULQ 24+rb \
ADDQ AX, R11 \
ADCQ $0, DX \
MOVQ DX, R12 \
\
ADDQ 16+stack, R8 \
ADCQ 24+stack, R9 \
ADCQ 32+stack, R10 \
ADCQ 40+stack, R11 \
ADCQ $0, R12 \
storeBlock(R8,R9,R10,R11, 16+stack) \
MOVQ R12, 48+stack \
\
MOVQ a3, AX \
MULQ 0+rb \
MOVQ AX, R8 \
MOVQ DX, R9 \
MOVQ a3, AX \
MULQ 8+rb \
ADDQ AX, R9 \
ADCQ $0, DX \
MOVQ DX, R10 \
MOVQ a3, AX \
MULQ 16+rb \
ADDQ AX, R10 \
ADCQ $0, DX \
MOVQ DX, R11 \
MOVQ a3, AX \
MULQ 24+rb \
ADDQ AX, R11 \
ADCQ $0, DX \
MOVQ DX, R12 \
\
ADDQ 24+stack, R8 \
ADCQ 32+stack, R9 \
ADCQ 40+stack, R10 \
ADCQ 48+stack, R11 \
ADCQ $0, R12 \
storeBlock(R8,R9,R10,R11, 24+stack) \
MOVQ R12, 56+stack
#define gfpReduce(stack) \
\ // m = (T * N') mod R, store m in R8:R9:R10:R11
MOVQ ·np+0(SB), AX \
MULQ 0+stack \
MOVQ AX, R8 \
MOVQ DX, R9 \
MOVQ ·np+0(SB), AX \
MULQ 8+stack \
ADDQ AX, R9 \
ADCQ $0, DX \
MOVQ DX, R10 \
MOVQ ·np+0(SB), AX \
MULQ 16+stack \
ADDQ AX, R10 \
ADCQ $0, DX \
MOVQ DX, R11 \
MOVQ ·np+0(SB), AX \
MULQ 24+stack \
ADDQ AX, R11 \
\
MOVQ ·np+8(SB), AX \
MULQ 0+stack \
MOVQ AX, R12 \
MOVQ DX, R13 \
MOVQ ·np+8(SB), AX \
MULQ 8+stack \
ADDQ AX, R13 \
ADCQ $0, DX \
MOVQ DX, R14 \
MOVQ ·np+8(SB), AX \
MULQ 16+stack \
ADDQ AX, R14 \
\
ADDQ R12, R9 \
ADCQ R13, R10 \
ADCQ R14, R11 \
\
MOVQ ·np+16(SB), AX \
MULQ 0+stack \
MOVQ AX, R12 \
MOVQ DX, R13 \
MOVQ ·np+16(SB), AX \
MULQ 8+stack \
ADDQ AX, R13 \
\
ADDQ R12, R10 \
ADCQ R13, R11 \
\
MOVQ ·np+24(SB), AX \
MULQ 0+stack \
ADDQ AX, R11 \
\
storeBlock(R8,R9,R10,R11, 64+stack) \
\
\ // m * N
mul(·p2+0(SB),·p2+8(SB),·p2+16(SB),·p2+24(SB), 64+stack, 96+stack) \
\
\ // Add the 512-bit intermediate to m*N
loadBlock(96+stack, R8,R9,R10,R11) \
loadBlock(128+stack, R12,R13,R14,R15) \
\
MOVQ $0, AX \
ADDQ 0+stack, R8 \
ADCQ 8+stack, R9 \
ADCQ 16+stack, R10 \
ADCQ 24+stack, R11 \
ADCQ 32+stack, R12 \
ADCQ 40+stack, R13 \
ADCQ 48+stack, R14 \
ADCQ 56+stack, R15 \
ADCQ $0, AX \
\
gfpCarry(R12,R13,R14,R15,AX, R8,R9,R10,R11,BX)

View File

@ -0,0 +1,133 @@
#define mul(c0,c1,c2,c3,c4,c5,c6,c7) \
MUL R1, R5, c0 \
UMULH R1, R5, c1 \
MUL R1, R6, R0 \
ADDS R0, c1 \
UMULH R1, R6, c2 \
MUL R1, R7, R0 \
ADCS R0, c2 \
UMULH R1, R7, c3 \
MUL R1, R8, R0 \
ADCS R0, c3 \
UMULH R1, R8, c4 \
ADCS ZR, c4 \
\
MUL R2, R5, R1 \
UMULH R2, R5, R26 \
MUL R2, R6, R0 \
ADDS R0, R26 \
UMULH R2, R6, R27 \
MUL R2, R7, R0 \
ADCS R0, R27 \
UMULH R2, R7, R29 \
MUL R2, R8, R0 \
ADCS R0, R29 \
UMULH R2, R8, c5 \
ADCS ZR, c5 \
ADDS R1, c1 \
ADCS R26, c2 \
ADCS R27, c3 \
ADCS R29, c4 \
ADCS ZR, c5 \
\
MUL R3, R5, R1 \
UMULH R3, R5, R26 \
MUL R3, R6, R0 \
ADDS R0, R26 \
UMULH R3, R6, R27 \
MUL R3, R7, R0 \
ADCS R0, R27 \
UMULH R3, R7, R29 \
MUL R3, R8, R0 \
ADCS R0, R29 \
UMULH R3, R8, c6 \
ADCS ZR, c6 \
ADDS R1, c2 \
ADCS R26, c3 \
ADCS R27, c4 \
ADCS R29, c5 \
ADCS ZR, c6 \
\
MUL R4, R5, R1 \
UMULH R4, R5, R26 \
MUL R4, R6, R0 \
ADDS R0, R26 \
UMULH R4, R6, R27 \
MUL R4, R7, R0 \
ADCS R0, R27 \
UMULH R4, R7, R29 \
MUL R4, R8, R0 \
ADCS R0, R29 \
UMULH R4, R8, c7 \
ADCS ZR, c7 \
ADDS R1, c3 \
ADCS R26, c4 \
ADCS R27, c5 \
ADCS R29, c6 \
ADCS ZR, c7
#define gfpReduce() \
\ // m = (T * N') mod R, store m in R1:R2:R3:R4
MOVD ·np+0(SB), R17 \
MOVD ·np+8(SB), R25 \
MOVD ·np+16(SB), R19 \
MOVD ·np+24(SB), R20 \
\
MUL R9, R17, R1 \
UMULH R9, R17, R2 \
MUL R9, R25, R0 \
ADDS R0, R2 \
UMULH R9, R25, R3 \
MUL R9, R19, R0 \
ADCS R0, R3 \
UMULH R9, R19, R4 \
MUL R9, R20, R0 \
ADCS R0, R4 \
\
MUL R10, R17, R21 \
UMULH R10, R17, R22 \
MUL R10, R25, R0 \
ADDS R0, R22 \
UMULH R10, R25, R23 \
MUL R10, R19, R0 \
ADCS R0, R23 \
ADDS R21, R2 \
ADCS R22, R3 \
ADCS R23, R4 \
\
MUL R11, R17, R21 \
UMULH R11, R17, R22 \
MUL R11, R25, R0 \
ADDS R0, R22 \
ADDS R21, R3 \
ADCS R22, R4 \
\
MUL R12, R17, R21 \
ADDS R21, R4 \
\
\ // m * N
loadModulus(R5,R6,R7,R8) \
mul(R17,R25,R19,R20,R21,R22,R23,R24) \
\
\ // Add the 512-bit intermediate to m*N
MOVD ZR, R0 \
ADDS R9, R17 \
ADCS R10, R25 \
ADCS R11, R19 \
ADCS R12, R20 \
ADCS R13, R21 \
ADCS R14, R22 \
ADCS R15, R23 \
ADCS R16, R24 \
ADCS ZR, R0 \
\
\ // Our output is R21:R22:R23:R24. Reduce mod p if necessary.
SUBS R5, R21, R10 \
SBCS R6, R22, R11 \
SBCS R7, R23, R12 \
SBCS R8, R24, R13 \
\
CSEL CS, R10, R21, R1 \
CSEL CS, R11, R22, R2 \
CSEL CS, R12, R23, R3 \
CSEL CS, R13, R24, R4

View File

@ -0,0 +1,112 @@
#define mulBMI2(a0,a1,a2,a3, rb) \
MOVQ a0, DX \
MOVQ $0, R13 \
MULXQ 0+rb, R8, R9 \
MULXQ 8+rb, AX, R10 \
ADDQ AX, R9 \
MULXQ 16+rb, AX, R11 \
ADCQ AX, R10 \
MULXQ 24+rb, AX, R12 \
ADCQ AX, R11 \
ADCQ $0, R12 \
ADCQ $0, R13 \
\
MOVQ a1, DX \
MOVQ $0, R14 \
MULXQ 0+rb, AX, BX \
ADDQ AX, R9 \
ADCQ BX, R10 \
MULXQ 16+rb, AX, BX \
ADCQ AX, R11 \
ADCQ BX, R12 \
ADCQ $0, R13 \
MULXQ 8+rb, AX, BX \
ADDQ AX, R10 \
ADCQ BX, R11 \
MULXQ 24+rb, AX, BX \
ADCQ AX, R12 \
ADCQ BX, R13 \
ADCQ $0, R14 \
\
MOVQ a2, DX \
MOVQ $0, R15 \
MULXQ 0+rb, AX, BX \
ADDQ AX, R10 \
ADCQ BX, R11 \
MULXQ 16+rb, AX, BX \
ADCQ AX, R12 \
ADCQ BX, R13 \
ADCQ $0, R14 \
MULXQ 8+rb, AX, BX \
ADDQ AX, R11 \
ADCQ BX, R12 \
MULXQ 24+rb, AX, BX \
ADCQ AX, R13 \
ADCQ BX, R14 \
ADCQ $0, R15 \
\
MOVQ a3, DX \
MULXQ 0+rb, AX, BX \
ADDQ AX, R11 \
ADCQ BX, R12 \
MULXQ 16+rb, AX, BX \
ADCQ AX, R13 \
ADCQ BX, R14 \
ADCQ $0, R15 \
MULXQ 8+rb, AX, BX \
ADDQ AX, R12 \
ADCQ BX, R13 \
MULXQ 24+rb, AX, BX \
ADCQ AX, R14 \
ADCQ BX, R15
#define gfpReduceBMI2() \
\ // m = (T * N') mod R, store m in R8:R9:R10:R11
MOVQ ·np+0(SB), DX \
MULXQ 0(SP), R8, R9 \
MULXQ 8(SP), AX, R10 \
ADDQ AX, R9 \
MULXQ 16(SP), AX, R11 \
ADCQ AX, R10 \
MULXQ 24(SP), AX, BX \
ADCQ AX, R11 \
\
MOVQ ·np+8(SB), DX \
MULXQ 0(SP), AX, BX \
ADDQ AX, R9 \
ADCQ BX, R10 \
MULXQ 16(SP), AX, BX \
ADCQ AX, R11 \
MULXQ 8(SP), AX, BX \
ADDQ AX, R10 \
ADCQ BX, R11 \
\
MOVQ ·np+16(SB), DX \
MULXQ 0(SP), AX, BX \
ADDQ AX, R10 \
ADCQ BX, R11 \
MULXQ 8(SP), AX, BX \
ADDQ AX, R11 \
\
MOVQ ·np+24(SB), DX \
MULXQ 0(SP), AX, BX \
ADDQ AX, R11 \
\
storeBlock(R8,R9,R10,R11, 64(SP)) \
\
\ // m * N
mulBMI2(·p2+0(SB),·p2+8(SB),·p2+16(SB),·p2+24(SB), 64(SP)) \
\
\ // Add the 512-bit intermediate to m*N
MOVQ $0, AX \
ADDQ 0(SP), R8 \
ADCQ 8(SP), R9 \
ADCQ 16(SP), R10 \
ADCQ 24(SP), R11 \
ADCQ 32(SP), R12 \
ADCQ 40(SP), R13 \
ADCQ 48(SP), R14 \
ADCQ 56(SP), R15 \
ADCQ $0, AX \
\
gfpCarry(R12,R13,R14,R15,AX, R8,R9,R10,R11,BX)

View File

@ -0,0 +1,271 @@
package bn256
func lineFunctionAdd(r, p *twistPoint, q *curvePoint, r2 *gfP2) (a, b, c *gfP2, rOut *twistPoint) {
// See the mixed addition algorithm from "Faster Computation of the
// Tate Pairing", http://arxiv.org/pdf/0904.0854v3.pdf
B := (&gfP2{}).Mul(&p.x, &r.t)
D := (&gfP2{}).Add(&p.y, &r.z)
D.Square(D).Sub(D, r2).Sub(D, &r.t).Mul(D, &r.t)
H := (&gfP2{}).Sub(B, &r.x)
I := (&gfP2{}).Square(H)
E := (&gfP2{}).Add(I, I)
E.Add(E, E)
J := (&gfP2{}).Mul(H, E)
L1 := (&gfP2{}).Sub(D, &r.y)
L1.Sub(L1, &r.y)
V := (&gfP2{}).Mul(&r.x, E)
rOut = &twistPoint{}
rOut.x.Square(L1).Sub(&rOut.x, J).Sub(&rOut.x, V).Sub(&rOut.x, V)
rOut.z.Add(&r.z, H).Square(&rOut.z).Sub(&rOut.z, &r.t).Sub(&rOut.z, I)
t := (&gfP2{}).Sub(V, &rOut.x)
t.Mul(t, L1)
t2 := (&gfP2{}).Mul(&r.y, J)
t2.Add(t2, t2)
rOut.y.Sub(t, t2)
rOut.t.Square(&rOut.z)
t.Add(&p.y, &rOut.z).Square(t).Sub(t, r2).Sub(t, &rOut.t)
t2.Mul(L1, &p.x)
t2.Add(t2, t2)
a = (&gfP2{}).Sub(t2, t)
c = (&gfP2{}).MulScalar(&rOut.z, &q.y)
c.Add(c, c)
b = (&gfP2{}).Neg(L1)
b.MulScalar(b, &q.x).Add(b, b)
return
}
func lineFunctionDouble(r *twistPoint, q *curvePoint) (a, b, c *gfP2, rOut *twistPoint) {
// See the doubling algorithm for a=0 from "Faster Computation of the
// Tate Pairing", http://arxiv.org/pdf/0904.0854v3.pdf
A := (&gfP2{}).Square(&r.x)
B := (&gfP2{}).Square(&r.y)
C := (&gfP2{}).Square(B)
D := (&gfP2{}).Add(&r.x, B)
D.Square(D).Sub(D, A).Sub(D, C).Add(D, D)
E := (&gfP2{}).Add(A, A)
E.Add(E, A)
G := (&gfP2{}).Square(E)
rOut = &twistPoint{}
rOut.x.Sub(G, D).Sub(&rOut.x, D)
rOut.z.Add(&r.y, &r.z).Square(&rOut.z).Sub(&rOut.z, B).Sub(&rOut.z, &r.t)
rOut.y.Sub(D, &rOut.x).Mul(&rOut.y, E)
t := (&gfP2{}).Add(C, C)
t.Add(t, t).Add(t, t)
rOut.y.Sub(&rOut.y, t)
rOut.t.Square(&rOut.z)
t.Mul(E, &r.t).Add(t, t)
b = (&gfP2{}).Neg(t)
b.MulScalar(b, &q.x)
a = (&gfP2{}).Add(&r.x, E)
a.Square(a).Sub(a, A).Sub(a, G)
t.Add(B, B).Add(t, t)
a.Sub(a, t)
c = (&gfP2{}).Mul(&rOut.z, &r.t)
c.Add(c, c).MulScalar(c, &q.y)
return
}
func mulLine(ret *gfP12, a, b, c *gfP2) {
a2 := &gfP6{}
a2.y.Set(a)
a2.z.Set(b)
a2.Mul(a2, &ret.x)
t3 := (&gfP6{}).MulScalar(&ret.y, c)
t := (&gfP2{}).Add(b, c)
t2 := &gfP6{}
t2.y.Set(a)
t2.z.Set(t)
ret.x.Add(&ret.x, &ret.y)
ret.y.Set(t3)
ret.x.Mul(&ret.x, t2).Sub(&ret.x, a2).Sub(&ret.x, &ret.y)
a2.MulTau(a2)
ret.y.Add(&ret.y, a2)
}
// sixuPlus2NAF is 6u+2 in non-adjacent form.
var sixuPlus2NAF = []int8{0, 0, 0, 1, 0, 1, 0, -1, 0, 0, 1, -1, 0, 0, 1, 0,
0, 1, 1, 0, -1, 0, 0, 1, 0, -1, 0, 0, 0, 0, 1, 1,
1, 0, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, -1, 0, 0, 1,
1, 0, 0, -1, 0, 0, 0, 1, 1, 0, -1, 0, 0, 1, 0, 1, 1}
// miller implements the Miller loop for calculating the Optimal Ate pairing.
// See algorithm 1 from http://cryptojedi.org/papers/dclxvi-20100714.pdf
func miller(q *twistPoint, p *curvePoint) *gfP12 {
ret := (&gfP12{}).SetOne()
aAffine := &twistPoint{}
aAffine.Set(q)
aAffine.MakeAffine()
bAffine := &curvePoint{}
bAffine.Set(p)
bAffine.MakeAffine()
minusA := &twistPoint{}
minusA.Neg(aAffine)
r := &twistPoint{}
r.Set(aAffine)
r2 := (&gfP2{}).Square(&aAffine.y)
for i := len(sixuPlus2NAF) - 1; i > 0; i-- {
a, b, c, newR := lineFunctionDouble(r, bAffine)
if i != len(sixuPlus2NAF)-1 {
ret.Square(ret)
}
mulLine(ret, a, b, c)
r = newR
switch sixuPlus2NAF[i-1] {
case 1:
a, b, c, newR = lineFunctionAdd(r, aAffine, bAffine, r2)
case -1:
a, b, c, newR = lineFunctionAdd(r, minusA, bAffine, r2)
default:
continue
}
mulLine(ret, a, b, c)
r = newR
}
// In order to calculate Q1 we have to convert q from the sextic twist
// to the full GF(p^12) group, apply the Frobenius there, and convert
// back.
//
// The twist isomorphism is (x', y') -> (xω², yω³). If we consider just
// x for a moment, then after applying the Frobenius, we have x̄ω^(2p)
// where x̄ is the conjugate of x. If we are going to apply the inverse
// isomorphism we need a value with a single coefficient of ω² so we
// rewrite this as x̄ω^(2p-2)ω². ξ⁶ = ω and, due to the construction of
// p, 2p-2 is a multiple of six. Therefore we can rewrite as
// x̄ξ^((p-1)/3)ω² and applying the inverse isomorphism eliminates the
// ω².
//
// A similar argument can be made for the y value.
q1 := &twistPoint{}
q1.x.Conjugate(&aAffine.x).Mul(&q1.x, xiToPMinus1Over3)
q1.y.Conjugate(&aAffine.y).Mul(&q1.y, xiToPMinus1Over2)
q1.z.SetOne()
q1.t.SetOne()
// For Q2 we are applying the p² Frobenius. The two conjugations cancel
// out and we are left only with the factors from the isomorphism. In
// the case of x, we end up with a pure number which is why
// xiToPSquaredMinus1Over3 is ∈ GF(p). With y we get a factor of -1. We
// ignore this to end up with -Q2.
minusQ2 := &twistPoint{}
minusQ2.x.MulScalar(&aAffine.x, xiToPSquaredMinus1Over3)
minusQ2.y.Set(&aAffine.y)
minusQ2.z.SetOne()
minusQ2.t.SetOne()
r2.Square(&q1.y)
a, b, c, newR := lineFunctionAdd(r, q1, bAffine, r2)
mulLine(ret, a, b, c)
r = newR
r2.Square(&minusQ2.y)
a, b, c, newR = lineFunctionAdd(r, minusQ2, bAffine, r2)
mulLine(ret, a, b, c)
r = newR
return ret
}
// finalExponentiation computes the (p¹²-1)/Order-th power of an element of
// GF(p¹²) to obtain an element of GT (steps 13-15 of algorithm 1 from
// http://cryptojedi.org/papers/dclxvi-20100714.pdf)
func finalExponentiation(in *gfP12) *gfP12 {
t1 := &gfP12{}
// This is the p^6-Frobenius
t1.x.Neg(&in.x)
t1.y.Set(&in.y)
inv := &gfP12{}
inv.Invert(in)
t1.Mul(t1, inv)
t2 := (&gfP12{}).FrobeniusP2(t1)
t1.Mul(t1, t2)
fp := (&gfP12{}).Frobenius(t1)
fp2 := (&gfP12{}).FrobeniusP2(t1)
fp3 := (&gfP12{}).Frobenius(fp2)
fu := (&gfP12{}).Exp(t1, u)
fu2 := (&gfP12{}).Exp(fu, u)
fu3 := (&gfP12{}).Exp(fu2, u)
y3 := (&gfP12{}).Frobenius(fu)
fu2p := (&gfP12{}).Frobenius(fu2)
fu3p := (&gfP12{}).Frobenius(fu3)
y2 := (&gfP12{}).FrobeniusP2(fu2)
y0 := &gfP12{}
y0.Mul(fp, fp2).Mul(y0, fp3)
y1 := (&gfP12{}).Conjugate(t1)
y5 := (&gfP12{}).Conjugate(fu2)
y3.Conjugate(y3)
y4 := (&gfP12{}).Mul(fu, fu2p)
y4.Conjugate(y4)
y6 := (&gfP12{}).Mul(fu3, fu3p)
y6.Conjugate(y6)
t0 := (&gfP12{}).Square(y6)
t0.Mul(t0, y4).Mul(t0, y5)
t1.Mul(y3, y5).Mul(t1, t0)
t0.Mul(t0, y2)
t1.Square(t1).Mul(t1, t0).Square(t1)
t0.Mul(t1, y1)
t1.Mul(t1, y0)
t0.Square(t0).Mul(t0, t1)
return t0
}
func optimalAte(a *twistPoint, b *curvePoint) *gfP12 {
e := miller(a, b)
ret := finalExponentiation(e)
if a.IsInfinity() || b.IsInfinity() {
ret.SetOne()
}
return ret
}

View File

@ -0,0 +1,204 @@
package bn256
import (
"math/big"
)
// twistPoint implements the elliptic curve y²=x³+3/ξ over GF(p²). Points are
// kept in Jacobian form and t=z² when valid. The group G₂ is the set of
// n-torsion points of this curve over GF(p²) (where n = Order)
type twistPoint struct {
x, y, z, t gfP2
}
var twistB = &gfP2{
gfP{0x38e7ecccd1dcff67, 0x65f0b37d93ce0d3e, 0xd749d0dd22ac00aa, 0x0141b9ce4a688d4d},
gfP{0x3bf938e377b802a8, 0x020b1b273633535d, 0x26b7edf049755260, 0x2514c6324384a86d},
}
// twistGen is the generator of group G₂.
var twistGen = &twistPoint{
gfP2{
gfP{0xafb4737da84c6140, 0x6043dd5a5802d8c4, 0x09e950fc52a02f86, 0x14fef0833aea7b6b},
gfP{0x8e83b5d102bc2026, 0xdceb1935497b0172, 0xfbb8264797811adf, 0x19573841af96503b},
},
gfP2{
gfP{0x64095b56c71856ee, 0xdc57f922327d3cbb, 0x55f935be33351076, 0x0da4a0e693fd6482},
gfP{0x619dfa9d886be9f6, 0xfe7fd297f59e9b78, 0xff9e1a62231b7dfe, 0x28fd7eebae9e4206},
},
gfP2{*newGFp(0), *newGFp(1)},
gfP2{*newGFp(0), *newGFp(1)},
}
func (c *twistPoint) String() string {
c.MakeAffine()
x, y := gfP2Decode(&c.x), gfP2Decode(&c.y)
return "(" + x.String() + ", " + y.String() + ")"
}
func (c *twistPoint) Set(a *twistPoint) {
c.x.Set(&a.x)
c.y.Set(&a.y)
c.z.Set(&a.z)
c.t.Set(&a.t)
}
// IsOnCurve returns true iff c is on the curve.
func (c *twistPoint) IsOnCurve() bool {
c.MakeAffine()
if c.IsInfinity() {
return true
}
y2, x3 := &gfP2{}, &gfP2{}
y2.Square(&c.y)
x3.Square(&c.x).Mul(x3, &c.x).Add(x3, twistB)
if *y2 != *x3 {
return false
}
cneg := &twistPoint{}
cneg.Mul(c, Order)
return cneg.z.IsZero()
}
func (c *twistPoint) SetInfinity() {
c.x.SetZero()
c.y.SetOne()
c.z.SetZero()
c.t.SetZero()
}
func (c *twistPoint) IsInfinity() bool {
return c.z.IsZero()
}
func (c *twistPoint) Add(a, b *twistPoint) {
// For additional comments, see the same function in curve.go.
if a.IsInfinity() {
c.Set(b)
return
}
if b.IsInfinity() {
c.Set(a)
return
}
// See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/addition/add-2007-bl.op3
z12 := (&gfP2{}).Square(&a.z)
z22 := (&gfP2{}).Square(&b.z)
u1 := (&gfP2{}).Mul(&a.x, z22)
u2 := (&gfP2{}).Mul(&b.x, z12)
t := (&gfP2{}).Mul(&b.z, z22)
s1 := (&gfP2{}).Mul(&a.y, t)
t.Mul(&a.z, z12)
s2 := (&gfP2{}).Mul(&b.y, t)
h := (&gfP2{}).Sub(u2, u1)
xEqual := h.IsZero()
t.Add(h, h)
i := (&gfP2{}).Square(t)
j := (&gfP2{}).Mul(h, i)
t.Sub(s2, s1)
yEqual := t.IsZero()
if xEqual && yEqual {
c.Double(a)
return
}
r := (&gfP2{}).Add(t, t)
v := (&gfP2{}).Mul(u1, i)
t4 := (&gfP2{}).Square(r)
t.Add(v, v)
t6 := (&gfP2{}).Sub(t4, j)
c.x.Sub(t6, t)
t.Sub(v, &c.x) // t7
t4.Mul(s1, j) // t8
t6.Add(t4, t4) // t9
t4.Mul(r, t) // t10
c.y.Sub(t4, t6)
t.Add(&a.z, &b.z) // t11
t4.Square(t) // t12
t.Sub(t4, z12) // t13
t4.Sub(t, z22) // t14
c.z.Mul(t4, h)
}
func (c *twistPoint) Double(a *twistPoint) {
// See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/doubling/dbl-2009-l.op3
A := (&gfP2{}).Square(&a.x)
B := (&gfP2{}).Square(&a.y)
C := (&gfP2{}).Square(B)
t := (&gfP2{}).Add(&a.x, B)
t2 := (&gfP2{}).Square(t)
t.Sub(t2, A)
t2.Sub(t, C)
d := (&gfP2{}).Add(t2, t2)
t.Add(A, A)
e := (&gfP2{}).Add(t, A)
f := (&gfP2{}).Square(e)
t.Add(d, d)
c.x.Sub(f, t)
t.Add(C, C)
t2.Add(t, t)
t.Add(t2, t2)
c.y.Sub(d, &c.x)
t2.Mul(e, &c.y)
c.y.Sub(t2, t)
t.Mul(&a.y, &a.z)
c.z.Add(t, t)
}
func (c *twistPoint) Mul(a *twistPoint, scalar *big.Int) {
sum, t := &twistPoint{}, &twistPoint{}
for i := scalar.BitLen(); i >= 0; i-- {
t.Double(sum)
if scalar.Bit(i) != 0 {
sum.Add(t, a)
} else {
sum.Set(t)
}
}
c.Set(sum)
}
func (c *twistPoint) MakeAffine() {
if c.z.IsOne() {
return
} else if c.z.IsZero() {
c.x.SetZero()
c.y.SetOne()
c.t.SetZero()
return
}
zInv := (&gfP2{}).Invert(&c.z)
t := (&gfP2{}).Mul(&c.y, zInv)
zInv2 := (&gfP2{}).Square(zInv)
c.y.Mul(t, zInv2)
t.Mul(&c.x, zInv2)
c.x.Set(t)
c.z.SetOne()
c.t.SetOne()
}
func (c *twistPoint) Neg(a *twistPoint) {
c.x.Set(&a.x)
c.y.Neg(&a.y)
c.z.Set(&a.z)
c.t.SetZero()
}

View File

@ -0,0 +1,460 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package bn256 implements a particular bilinear group.
//
// Bilinear groups are the basis of many of the new cryptographic protocols
// that have been proposed over the past decade. They consist of a triplet of
// groups (G₁, G₂ and GT) such that there exists a function e(g₁ˣ,g₂ʸ)=gTˣʸ
// (where gₓ is a generator of the respective group). That function is called
// a pairing function.
//
// This package specifically implements the Optimal Ate pairing over a 256-bit
// Barreto-Naehrig curve as described in
// http://cryptojedi.org/papers/dclxvi-20100714.pdf. Its output is not
// compatible with the implementation described in that paper, as different
// parameters are chosen.
//
// (This package previously claimed to operate at a 128-bit security level.
// However, recent improvements in attacks mean that is no longer true. See
// https://moderncrypto.org/mail-archive/curves/2016/000740.html.)
package bn256
import (
"crypto/rand"
"errors"
"io"
"math/big"
)
// BUG(agl): this implementation is not constant time.
// TODO(agl): keep GF(p²) elements in Mongomery form.
// G1 is an abstract cyclic group. The zero value is suitable for use as the
// output of an operation, but cannot be used as an input.
type G1 struct {
p *curvePoint
}
// RandomG1 returns x and g₁ˣ where x is a random, non-zero number read from r.
func RandomG1(r io.Reader) (*big.Int, *G1, error) {
var k *big.Int
var err error
for {
k, err = rand.Int(r, Order)
if err != nil {
return nil, nil, err
}
if k.Sign() > 0 {
break
}
}
return k, new(G1).ScalarBaseMult(k), nil
}
func (e *G1) String() string {
return "bn256.G1" + e.p.String()
}
// CurvePoints returns p's curve points in big integer
func (e *G1) CurvePoints() (*big.Int, *big.Int, *big.Int, *big.Int) {
return e.p.x, e.p.y, e.p.z, e.p.t
}
// ScalarBaseMult sets e to g*k where g is the generator of the group and
// then returns e.
func (e *G1) ScalarBaseMult(k *big.Int) *G1 {
if e.p == nil {
e.p = newCurvePoint(nil)
}
e.p.Mul(curveGen, k, new(bnPool))
return e
}
// ScalarMult sets e to a*k and then returns e.
func (e *G1) ScalarMult(a *G1, k *big.Int) *G1 {
if e.p == nil {
e.p = newCurvePoint(nil)
}
e.p.Mul(a.p, k, new(bnPool))
return e
}
// Add sets e to a+b and then returns e.
// BUG(agl): this function is not complete: a==b fails.
func (e *G1) Add(a, b *G1) *G1 {
if e.p == nil {
e.p = newCurvePoint(nil)
}
e.p.Add(a.p, b.p, new(bnPool))
return e
}
// Neg sets e to -a and then returns e.
func (e *G1) Neg(a *G1) *G1 {
if e.p == nil {
e.p = newCurvePoint(nil)
}
e.p.Negative(a.p)
return e
}
// Marshal converts n to a byte slice.
func (e *G1) Marshal() []byte {
// Each value is a 256-bit number.
const numBytes = 256 / 8
if e.p.IsInfinity() {
return make([]byte, numBytes*2)
}
e.p.MakeAffine(nil)
xBytes := new(big.Int).Mod(e.p.x, P).Bytes()
yBytes := new(big.Int).Mod(e.p.y, P).Bytes()
ret := make([]byte, numBytes*2)
copy(ret[1*numBytes-len(xBytes):], xBytes)
copy(ret[2*numBytes-len(yBytes):], yBytes)
return ret
}
// Unmarshal sets e to the result of converting the output of Marshal back into
// a group element and then returns e.
func (e *G1) Unmarshal(m []byte) ([]byte, error) {
// Each value is a 256-bit number.
const numBytes = 256 / 8
if len(m) != 2*numBytes {
return nil, errors.New("bn256: not enough data")
}
// Unmarshal the points and check their caps
if e.p == nil {
e.p = newCurvePoint(nil)
}
e.p.x.SetBytes(m[0*numBytes : 1*numBytes])
if e.p.x.Cmp(P) >= 0 {
return nil, errors.New("bn256: coordinate exceeds modulus")
}
e.p.y.SetBytes(m[1*numBytes : 2*numBytes])
if e.p.y.Cmp(P) >= 0 {
return nil, errors.New("bn256: coordinate exceeds modulus")
}
// Ensure the point is on the curve
if e.p.x.Sign() == 0 && e.p.y.Sign() == 0 {
// This is the point at infinity.
e.p.y.SetInt64(1)
e.p.z.SetInt64(0)
e.p.t.SetInt64(0)
} else {
e.p.z.SetInt64(1)
e.p.t.SetInt64(1)
if !e.p.IsOnCurve() {
return nil, errors.New("bn256: malformed point")
}
}
return m[2*numBytes:], nil
}
// G2 is an abstract cyclic group. The zero value is suitable for use as the
// output of an operation, but cannot be used as an input.
type G2 struct {
p *twistPoint
}
// RandomG1 returns x and g₂ˣ where x is a random, non-zero number read from r.
func RandomG2(r io.Reader) (*big.Int, *G2, error) {
var k *big.Int
var err error
for {
k, err = rand.Int(r, Order)
if err != nil {
return nil, nil, err
}
if k.Sign() > 0 {
break
}
}
return k, new(G2).ScalarBaseMult(k), nil
}
func (e *G2) String() string {
return "bn256.G2" + e.p.String()
}
// CurvePoints returns the curve points of p which includes the real
// and imaginary parts of the curve point.
func (e *G2) CurvePoints() (*gfP2, *gfP2, *gfP2, *gfP2) {
return e.p.x, e.p.y, e.p.z, e.p.t
}
// ScalarBaseMult sets e to g*k where g is the generator of the group and
// then returns out.
func (e *G2) ScalarBaseMult(k *big.Int) *G2 {
if e.p == nil {
e.p = newTwistPoint(nil)
}
e.p.Mul(twistGen, k, new(bnPool))
return e
}
// ScalarMult sets e to a*k and then returns e.
func (e *G2) ScalarMult(a *G2, k *big.Int) *G2 {
if e.p == nil {
e.p = newTwistPoint(nil)
}
e.p.Mul(a.p, k, new(bnPool))
return e
}
// Add sets e to a+b and then returns e.
// BUG(agl): this function is not complete: a==b fails.
func (e *G2) Add(a, b *G2) *G2 {
if e.p == nil {
e.p = newTwistPoint(nil)
}
e.p.Add(a.p, b.p, new(bnPool))
return e
}
// Marshal converts n into a byte slice.
func (n *G2) Marshal() []byte {
// Each value is a 256-bit number.
const numBytes = 256 / 8
if n.p.IsInfinity() {
return make([]byte, numBytes*4)
}
n.p.MakeAffine(nil)
xxBytes := new(big.Int).Mod(n.p.x.x, P).Bytes()
xyBytes := new(big.Int).Mod(n.p.x.y, P).Bytes()
yxBytes := new(big.Int).Mod(n.p.y.x, P).Bytes()
yyBytes := new(big.Int).Mod(n.p.y.y, P).Bytes()
ret := make([]byte, numBytes*4)
copy(ret[1*numBytes-len(xxBytes):], xxBytes)
copy(ret[2*numBytes-len(xyBytes):], xyBytes)
copy(ret[3*numBytes-len(yxBytes):], yxBytes)
copy(ret[4*numBytes-len(yyBytes):], yyBytes)
return ret
}
// Unmarshal sets e to the result of converting the output of Marshal back into
// a group element and then returns e.
func (e *G2) Unmarshal(m []byte) ([]byte, error) {
// Each value is a 256-bit number.
const numBytes = 256 / 8
if len(m) != 4*numBytes {
return nil, errors.New("bn256: not enough data")
}
// Unmarshal the points and check their caps
if e.p == nil {
e.p = newTwistPoint(nil)
}
e.p.x.x.SetBytes(m[0*numBytes : 1*numBytes])
if e.p.x.x.Cmp(P) >= 0 {
return nil, errors.New("bn256: coordinate exceeds modulus")
}
e.p.x.y.SetBytes(m[1*numBytes : 2*numBytes])
if e.p.x.y.Cmp(P) >= 0 {
return nil, errors.New("bn256: coordinate exceeds modulus")
}
e.p.y.x.SetBytes(m[2*numBytes : 3*numBytes])
if e.p.y.x.Cmp(P) >= 0 {
return nil, errors.New("bn256: coordinate exceeds modulus")
}
e.p.y.y.SetBytes(m[3*numBytes : 4*numBytes])
if e.p.y.y.Cmp(P) >= 0 {
return nil, errors.New("bn256: coordinate exceeds modulus")
}
// Ensure the point is on the curve
if e.p.x.x.Sign() == 0 &&
e.p.x.y.Sign() == 0 &&
e.p.y.x.Sign() == 0 &&
e.p.y.y.Sign() == 0 {
// This is the point at infinity.
e.p.y.SetOne()
e.p.z.SetZero()
e.p.t.SetZero()
} else {
e.p.z.SetOne()
e.p.t.SetOne()
if !e.p.IsOnCurve() {
return nil, errors.New("bn256: malformed point")
}
}
return m[4*numBytes:], nil
}
// GT is an abstract cyclic group. The zero value is suitable for use as the
// output of an operation, but cannot be used as an input.
type GT struct {
p *gfP12
}
func (g *GT) String() string {
return "bn256.GT" + g.p.String()
}
// ScalarMult sets e to a*k and then returns e.
func (e *GT) ScalarMult(a *GT, k *big.Int) *GT {
if e.p == nil {
e.p = newGFp12(nil)
}
e.p.Exp(a.p, k, new(bnPool))
return e
}
// Add sets e to a+b and then returns e.
func (e *GT) Add(a, b *GT) *GT {
if e.p == nil {
e.p = newGFp12(nil)
}
e.p.Mul(a.p, b.p, new(bnPool))
return e
}
// Neg sets e to -a and then returns e.
func (e *GT) Neg(a *GT) *GT {
if e.p == nil {
e.p = newGFp12(nil)
}
e.p.Invert(a.p, new(bnPool))
return e
}
// Marshal converts n into a byte slice.
func (n *GT) Marshal() []byte {
n.p.Minimal()
xxxBytes := n.p.x.x.x.Bytes()
xxyBytes := n.p.x.x.y.Bytes()
xyxBytes := n.p.x.y.x.Bytes()
xyyBytes := n.p.x.y.y.Bytes()
xzxBytes := n.p.x.z.x.Bytes()
xzyBytes := n.p.x.z.y.Bytes()
yxxBytes := n.p.y.x.x.Bytes()
yxyBytes := n.p.y.x.y.Bytes()
yyxBytes := n.p.y.y.x.Bytes()
yyyBytes := n.p.y.y.y.Bytes()
yzxBytes := n.p.y.z.x.Bytes()
yzyBytes := n.p.y.z.y.Bytes()
// Each value is a 256-bit number.
const numBytes = 256 / 8
ret := make([]byte, numBytes*12)
copy(ret[1*numBytes-len(xxxBytes):], xxxBytes)
copy(ret[2*numBytes-len(xxyBytes):], xxyBytes)
copy(ret[3*numBytes-len(xyxBytes):], xyxBytes)
copy(ret[4*numBytes-len(xyyBytes):], xyyBytes)
copy(ret[5*numBytes-len(xzxBytes):], xzxBytes)
copy(ret[6*numBytes-len(xzyBytes):], xzyBytes)
copy(ret[7*numBytes-len(yxxBytes):], yxxBytes)
copy(ret[8*numBytes-len(yxyBytes):], yxyBytes)
copy(ret[9*numBytes-len(yyxBytes):], yyxBytes)
copy(ret[10*numBytes-len(yyyBytes):], yyyBytes)
copy(ret[11*numBytes-len(yzxBytes):], yzxBytes)
copy(ret[12*numBytes-len(yzyBytes):], yzyBytes)
return ret
}
// Unmarshal sets e to the result of converting the output of Marshal back into
// a group element and then returns e.
func (e *GT) Unmarshal(m []byte) (*GT, bool) {
// Each value is a 256-bit number.
const numBytes = 256 / 8
if len(m) != 12*numBytes {
return nil, false
}
if e.p == nil {
e.p = newGFp12(nil)
}
e.p.x.x.x.SetBytes(m[0*numBytes : 1*numBytes])
e.p.x.x.y.SetBytes(m[1*numBytes : 2*numBytes])
e.p.x.y.x.SetBytes(m[2*numBytes : 3*numBytes])
e.p.x.y.y.SetBytes(m[3*numBytes : 4*numBytes])
e.p.x.z.x.SetBytes(m[4*numBytes : 5*numBytes])
e.p.x.z.y.SetBytes(m[5*numBytes : 6*numBytes])
e.p.y.x.x.SetBytes(m[6*numBytes : 7*numBytes])
e.p.y.x.y.SetBytes(m[7*numBytes : 8*numBytes])
e.p.y.y.x.SetBytes(m[8*numBytes : 9*numBytes])
e.p.y.y.y.SetBytes(m[9*numBytes : 10*numBytes])
e.p.y.z.x.SetBytes(m[10*numBytes : 11*numBytes])
e.p.y.z.y.SetBytes(m[11*numBytes : 12*numBytes])
return e, true
}
// Pair calculates an Optimal Ate pairing.
func Pair(g1 *G1, g2 *G2) *GT {
return &GT{optimalAte(g2.p, g1.p, new(bnPool))}
}
// PairingCheck calculates the Optimal Ate pairing for a set of points.
func PairingCheck(a []*G1, b []*G2) bool {
pool := new(bnPool)
acc := newGFp12(pool)
acc.SetOne()
for i := 0; i < len(a); i++ {
if a[i].p.IsInfinity() || b[i].p.IsInfinity() {
continue
}
acc.Mul(acc, miller(b[i].p, a[i].p, pool), pool)
}
ret := finalExponentiation(acc, pool)
acc.Put(pool)
return ret.IsOne()
}
// bnPool implements a tiny cache of *big.Int objects that's used to reduce the
// number of allocations made during processing.
type bnPool struct {
bns []*big.Int
count int
}
func (pool *bnPool) Get() *big.Int {
if pool == nil {
return new(big.Int)
}
pool.count++
l := len(pool.bns)
if l == 0 {
return new(big.Int)
}
bn := pool.bns[l-1]
pool.bns = pool.bns[:l-1]
return bn
}
func (pool *bnPool) Put(bn *big.Int) {
if pool == nil {
return
}
pool.bns = append(pool.bns, bn)
pool.count--
}
func (pool *bnPool) Count() int {
return pool.count
}

View File

@ -0,0 +1,311 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package bn256
import (
"bytes"
"crypto/rand"
"math/big"
"testing"
)
func TestGFp2Invert(t *testing.T) {
pool := new(bnPool)
a := newGFp2(pool)
a.x.SetString("23423492374", 10)
a.y.SetString("12934872398472394827398470", 10)
inv := newGFp2(pool)
inv.Invert(a, pool)
b := newGFp2(pool).Mul(inv, a, pool)
if b.x.Int64() != 0 || b.y.Int64() != 1 {
t.Fatalf("bad result for a^-1*a: %s %s", b.x, b.y)
}
a.Put(pool)
b.Put(pool)
inv.Put(pool)
if c := pool.Count(); c > 0 {
t.Errorf("Pool count non-zero: %d\n", c)
}
}
func isZero(n *big.Int) bool {
return new(big.Int).Mod(n, P).Int64() == 0
}
func isOne(n *big.Int) bool {
return new(big.Int).Mod(n, P).Int64() == 1
}
func TestGFp6Invert(t *testing.T) {
pool := new(bnPool)
a := newGFp6(pool)
a.x.x.SetString("239487238491", 10)
a.x.y.SetString("2356249827341", 10)
a.y.x.SetString("082659782", 10)
a.y.y.SetString("182703523765", 10)
a.z.x.SetString("978236549263", 10)
a.z.y.SetString("64893242", 10)
inv := newGFp6(pool)
inv.Invert(a, pool)
b := newGFp6(pool).Mul(inv, a, pool)
if !isZero(b.x.x) ||
!isZero(b.x.y) ||
!isZero(b.y.x) ||
!isZero(b.y.y) ||
!isZero(b.z.x) ||
!isOne(b.z.y) {
t.Fatalf("bad result for a^-1*a: %s", b)
}
a.Put(pool)
b.Put(pool)
inv.Put(pool)
if c := pool.Count(); c > 0 {
t.Errorf("Pool count non-zero: %d\n", c)
}
}
func TestGFp12Invert(t *testing.T) {
pool := new(bnPool)
a := newGFp12(pool)
a.x.x.x.SetString("239846234862342323958623", 10)
a.x.x.y.SetString("2359862352529835623", 10)
a.x.y.x.SetString("928836523", 10)
a.x.y.y.SetString("9856234", 10)
a.x.z.x.SetString("235635286", 10)
a.x.z.y.SetString("5628392833", 10)
a.y.x.x.SetString("252936598265329856238956532167968", 10)
a.y.x.y.SetString("23596239865236954178968", 10)
a.y.y.x.SetString("95421692834", 10)
a.y.y.y.SetString("236548", 10)
a.y.z.x.SetString("924523", 10)
a.y.z.y.SetString("12954623", 10)
inv := newGFp12(pool)
inv.Invert(a, pool)
b := newGFp12(pool).Mul(inv, a, pool)
if !isZero(b.x.x.x) ||
!isZero(b.x.x.y) ||
!isZero(b.x.y.x) ||
!isZero(b.x.y.y) ||
!isZero(b.x.z.x) ||
!isZero(b.x.z.y) ||
!isZero(b.y.x.x) ||
!isZero(b.y.x.y) ||
!isZero(b.y.y.x) ||
!isZero(b.y.y.y) ||
!isZero(b.y.z.x) ||
!isOne(b.y.z.y) {
t.Fatalf("bad result for a^-1*a: %s", b)
}
a.Put(pool)
b.Put(pool)
inv.Put(pool)
if c := pool.Count(); c > 0 {
t.Errorf("Pool count non-zero: %d\n", c)
}
}
func TestCurveImpl(t *testing.T) {
pool := new(bnPool)
g := &curvePoint{
pool.Get().SetInt64(1),
pool.Get().SetInt64(-2),
pool.Get().SetInt64(1),
pool.Get().SetInt64(0),
}
x := pool.Get().SetInt64(32498273234)
X := newCurvePoint(pool).Mul(g, x, pool)
y := pool.Get().SetInt64(98732423523)
Y := newCurvePoint(pool).Mul(g, y, pool)
s1 := newCurvePoint(pool).Mul(X, y, pool).MakeAffine(pool)
s2 := newCurvePoint(pool).Mul(Y, x, pool).MakeAffine(pool)
if s1.x.Cmp(s2.x) != 0 ||
s2.x.Cmp(s1.x) != 0 {
t.Errorf("DH points don't match: (%s, %s) (%s, %s)", s1.x, s1.y, s2.x, s2.y)
}
pool.Put(x)
X.Put(pool)
pool.Put(y)
Y.Put(pool)
s1.Put(pool)
s2.Put(pool)
g.Put(pool)
if c := pool.Count(); c > 0 {
t.Errorf("Pool count non-zero: %d\n", c)
}
}
func TestOrderG1(t *testing.T) {
g := new(G1).ScalarBaseMult(Order)
if !g.p.IsInfinity() {
t.Error("G1 has incorrect order")
}
one := new(G1).ScalarBaseMult(new(big.Int).SetInt64(1))
g.Add(g, one)
g.p.MakeAffine(nil)
if g.p.x.Cmp(one.p.x) != 0 || g.p.y.Cmp(one.p.y) != 0 {
t.Errorf("1+0 != 1 in G1")
}
}
func TestOrderG2(t *testing.T) {
g := new(G2).ScalarBaseMult(Order)
if !g.p.IsInfinity() {
t.Error("G2 has incorrect order")
}
one := new(G2).ScalarBaseMult(new(big.Int).SetInt64(1))
g.Add(g, one)
g.p.MakeAffine(nil)
if g.p.x.x.Cmp(one.p.x.x) != 0 ||
g.p.x.y.Cmp(one.p.x.y) != 0 ||
g.p.y.x.Cmp(one.p.y.x) != 0 ||
g.p.y.y.Cmp(one.p.y.y) != 0 {
t.Errorf("1+0 != 1 in G2")
}
}
func TestOrderGT(t *testing.T) {
gt := Pair(&G1{curveGen}, &G2{twistGen})
g := new(GT).ScalarMult(gt, Order)
if !g.p.IsOne() {
t.Error("GT has incorrect order")
}
}
func TestBilinearity(t *testing.T) {
for i := 0; i < 2; i++ {
a, p1, _ := RandomG1(rand.Reader)
b, p2, _ := RandomG2(rand.Reader)
e1 := Pair(p1, p2)
e2 := Pair(&G1{curveGen}, &G2{twistGen})
e2.ScalarMult(e2, a)
e2.ScalarMult(e2, b)
minusE2 := new(GT).Neg(e2)
e1.Add(e1, minusE2)
if !e1.p.IsOne() {
t.Fatalf("bad pairing result: %s", e1)
}
}
}
func TestG1Marshal(t *testing.T) {
g := new(G1).ScalarBaseMult(new(big.Int).SetInt64(1))
form := g.Marshal()
_, err := new(G1).Unmarshal(form)
if err != nil {
t.Fatalf("failed to unmarshal")
}
g.ScalarBaseMult(Order)
form = g.Marshal()
g2 := new(G1)
if _, err = g2.Unmarshal(form); err != nil {
t.Fatalf("failed to unmarshal ∞")
}
if !g2.p.IsInfinity() {
t.Fatalf("∞ unmarshaled incorrectly")
}
}
func TestG2Marshal(t *testing.T) {
g := new(G2).ScalarBaseMult(new(big.Int).SetInt64(1))
form := g.Marshal()
_, err := new(G2).Unmarshal(form)
if err != nil {
t.Fatalf("failed to unmarshal")
}
g.ScalarBaseMult(Order)
form = g.Marshal()
g2 := new(G2)
if _, err = g2.Unmarshal(form); err != nil {
t.Fatalf("failed to unmarshal ∞")
}
if !g2.p.IsInfinity() {
t.Fatalf("∞ unmarshaled incorrectly")
}
}
func TestG1Identity(t *testing.T) {
g := new(G1).ScalarBaseMult(new(big.Int).SetInt64(0))
if !g.p.IsInfinity() {
t.Error("failure")
}
}
func TestG2Identity(t *testing.T) {
g := new(G2).ScalarBaseMult(new(big.Int).SetInt64(0))
if !g.p.IsInfinity() {
t.Error("failure")
}
}
func TestTripartiteDiffieHellman(t *testing.T) {
a, _ := rand.Int(rand.Reader, Order)
b, _ := rand.Int(rand.Reader, Order)
c, _ := rand.Int(rand.Reader, Order)
pa := new(G1)
pa.Unmarshal(new(G1).ScalarBaseMult(a).Marshal())
qa := new(G2)
qa.Unmarshal(new(G2).ScalarBaseMult(a).Marshal())
pb := new(G1)
pb.Unmarshal(new(G1).ScalarBaseMult(b).Marshal())
qb := new(G2)
qb.Unmarshal(new(G2).ScalarBaseMult(b).Marshal())
pc := new(G1)
pc.Unmarshal(new(G1).ScalarBaseMult(c).Marshal())
qc := new(G2)
qc.Unmarshal(new(G2).ScalarBaseMult(c).Marshal())
k1 := Pair(pb, qc)
k1.ScalarMult(k1, a)
k1Bytes := k1.Marshal()
k2 := Pair(pc, qa)
k2.ScalarMult(k2, b)
k2Bytes := k2.Marshal()
k3 := Pair(pa, qb)
k3.ScalarMult(k3, c)
k3Bytes := k3.Marshal()
if !bytes.Equal(k1Bytes, k2Bytes) || !bytes.Equal(k2Bytes, k3Bytes) {
t.Errorf("keys didn't agree")
}
}
func BenchmarkPairing(b *testing.B) {
for i := 0; i < b.N; i++ {
Pair(&G1{curveGen}, &G2{twistGen})
}
}

View File

@ -0,0 +1,47 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package bn256
import (
"math/big"
)
func bigFromBase10(s string) *big.Int {
n, _ := new(big.Int).SetString(s, 10)
return n
}
// u is the BN parameter that determines the prime.
var u = bigFromBase10("4965661367192848881")
// P is a prime over which we form a basic field: 36u⁴+36u³+24u²+6u+1.
var P = bigFromBase10("21888242871839275222246405745257275088696311157297823662689037894645226208583")
// Order is the number of elements in both G₁ and G₂: 36u⁴+36u³+18u²+6u+1.
// Needs to be highly 2-adic for efficient SNARK key and proof generation.
// Order - 1 = 2^28 * 3^2 * 13 * 29 * 983 * 11003 * 237073 * 405928799 * 1670836401704629 * 13818364434197438864469338081.
// Refer to https://eprint.iacr.org/2013/879.pdf and https://eprint.iacr.org/2013/507.pdf for more information on these parameters.
var Order = bigFromBase10("21888242871839275222246405745257275088548364400416034343698204186575808495617")
// xiToPMinus1Over6 is ξ^((p-1)/6) where ξ = i+9.
var xiToPMinus1Over6 = &gfP2{bigFromBase10("16469823323077808223889137241176536799009286646108169935659301613961712198316"), bigFromBase10("8376118865763821496583973867626364092589906065868298776909617916018768340080")}
// xiToPMinus1Over3 is ξ^((p-1)/3) where ξ = i+9.
var xiToPMinus1Over3 = &gfP2{bigFromBase10("10307601595873709700152284273816112264069230130616436755625194854815875713954"), bigFromBase10("21575463638280843010398324269430826099269044274347216827212613867836435027261")}
// xiToPMinus1Over2 is ξ^((p-1)/2) where ξ = i+9.
var xiToPMinus1Over2 = &gfP2{bigFromBase10("3505843767911556378687030309984248845540243509899259641013678093033130930403"), bigFromBase10("2821565182194536844548159561693502659359617185244120367078079554186484126554")}
// xiToPSquaredMinus1Over3 is ξ^((p²-1)/3) where ξ = i+9.
var xiToPSquaredMinus1Over3 = bigFromBase10("21888242871839275220042445260109153167277707414472061641714758635765020556616")
// xiTo2PSquaredMinus2Over3 is ξ^((2p²-2)/3) where ξ = i+9 (a cubic root of unity, mod p).
var xiTo2PSquaredMinus2Over3 = bigFromBase10("2203960485148121921418603742825762020974279258880205651966")
// xiToPSquaredMinus1Over6 is ξ^((1p²-1)/6) where ξ = i+9 (a cubic root of -1, mod p).
var xiToPSquaredMinus1Over6 = bigFromBase10("21888242871839275220042445260109153167277707414472061641714758635765020556617")
// xiTo2PMinus2Over3 is ξ^((2p-2)/3) where ξ = i+9.
var xiTo2PMinus2Over3 = &gfP2{bigFromBase10("19937756971775647987995932169929341994314640652964949448313374472400716661030"), bigFromBase10("2581911344467009335267311115468803099551665605076196740867805258568234346338")}

View File

@ -0,0 +1,286 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package bn256
import (
"math/big"
)
// curvePoint implements the elliptic curve y²=x³+3. Points are kept in
// Jacobian form and t=z² when valid. G₁ is the set of points of this curve on
// GF(p).
type curvePoint struct {
x, y, z, t *big.Int
}
var curveB = new(big.Int).SetInt64(3)
// curveGen is the generator of G₁.
var curveGen = &curvePoint{
new(big.Int).SetInt64(1),
new(big.Int).SetInt64(2),
new(big.Int).SetInt64(1),
new(big.Int).SetInt64(1),
}
func newCurvePoint(pool *bnPool) *curvePoint {
return &curvePoint{
pool.Get(),
pool.Get(),
pool.Get(),
pool.Get(),
}
}
func (c *curvePoint) String() string {
c.MakeAffine(new(bnPool))
return "(" + c.x.String() + ", " + c.y.String() + ")"
}
func (c *curvePoint) Put(pool *bnPool) {
pool.Put(c.x)
pool.Put(c.y)
pool.Put(c.z)
pool.Put(c.t)
}
func (c *curvePoint) Set(a *curvePoint) {
c.x.Set(a.x)
c.y.Set(a.y)
c.z.Set(a.z)
c.t.Set(a.t)
}
// IsOnCurve returns true iff c is on the curve where c must be in affine form.
func (c *curvePoint) IsOnCurve() bool {
yy := new(big.Int).Mul(c.y, c.y)
xxx := new(big.Int).Mul(c.x, c.x)
xxx.Mul(xxx, c.x)
yy.Sub(yy, xxx)
yy.Sub(yy, curveB)
if yy.Sign() < 0 || yy.Cmp(P) >= 0 {
yy.Mod(yy, P)
}
return yy.Sign() == 0
}
func (c *curvePoint) SetInfinity() {
c.z.SetInt64(0)
}
func (c *curvePoint) IsInfinity() bool {
return c.z.Sign() == 0
}
func (c *curvePoint) Add(a, b *curvePoint, pool *bnPool) {
if a.IsInfinity() {
c.Set(b)
return
}
if b.IsInfinity() {
c.Set(a)
return
}
// See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/addition/add-2007-bl.op3
// Normalize the points by replacing a = [x1:y1:z1] and b = [x2:y2:z2]
// by [u1:s1:z1·z2] and [u2:s2:z1·z2]
// where u1 = x1·z2², s1 = y1·z2³ and u1 = x2·z1², s2 = y2·z1³
z1z1 := pool.Get().Mul(a.z, a.z)
z1z1.Mod(z1z1, P)
z2z2 := pool.Get().Mul(b.z, b.z)
z2z2.Mod(z2z2, P)
u1 := pool.Get().Mul(a.x, z2z2)
u1.Mod(u1, P)
u2 := pool.Get().Mul(b.x, z1z1)
u2.Mod(u2, P)
t := pool.Get().Mul(b.z, z2z2)
t.Mod(t, P)
s1 := pool.Get().Mul(a.y, t)
s1.Mod(s1, P)
t.Mul(a.z, z1z1)
t.Mod(t, P)
s2 := pool.Get().Mul(b.y, t)
s2.Mod(s2, P)
// Compute x = (2h)²(s²-u1-u2)
// where s = (s2-s1)/(u2-u1) is the slope of the line through
// (u1,s1) and (u2,s2). The extra factor 2h = 2(u2-u1) comes from the value of z below.
// This is also:
// 4(s2-s1)² - 4h²(u1+u2) = 4(s2-s1)² - 4h³ - 4h²(2u1)
// = r² - j - 2v
// with the notations below.
h := pool.Get().Sub(u2, u1)
xEqual := h.Sign() == 0
t.Add(h, h)
// i = 4h²
i := pool.Get().Mul(t, t)
i.Mod(i, P)
// j = 4h³
j := pool.Get().Mul(h, i)
j.Mod(j, P)
t.Sub(s2, s1)
yEqual := t.Sign() == 0
if xEqual && yEqual {
c.Double(a, pool)
return
}
r := pool.Get().Add(t, t)
v := pool.Get().Mul(u1, i)
v.Mod(v, P)
// t4 = 4(s2-s1)²
t4 := pool.Get().Mul(r, r)
t4.Mod(t4, P)
t.Add(v, v)
t6 := pool.Get().Sub(t4, j)
c.x.Sub(t6, t)
// Set y = -(2h)³(s1 + s*(x/4h²-u1))
// This is also
// y = - 2·s1·j - (s2-s1)(2x - 2i·u1) = r(v-x) - 2·s1·j
t.Sub(v, c.x) // t7
t4.Mul(s1, j) // t8
t4.Mod(t4, P)
t6.Add(t4, t4) // t9
t4.Mul(r, t) // t10
t4.Mod(t4, P)
c.y.Sub(t4, t6)
// Set z = 2(u2-u1)·z1·z2 = 2h·z1·z2
t.Add(a.z, b.z) // t11
t4.Mul(t, t) // t12
t4.Mod(t4, P)
t.Sub(t4, z1z1) // t13
t4.Sub(t, z2z2) // t14
c.z.Mul(t4, h)
c.z.Mod(c.z, P)
pool.Put(z1z1)
pool.Put(z2z2)
pool.Put(u1)
pool.Put(u2)
pool.Put(t)
pool.Put(s1)
pool.Put(s2)
pool.Put(h)
pool.Put(i)
pool.Put(j)
pool.Put(r)
pool.Put(v)
pool.Put(t4)
pool.Put(t6)
}
func (c *curvePoint) Double(a *curvePoint, pool *bnPool) {
// See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/doubling/dbl-2009-l.op3
A := pool.Get().Mul(a.x, a.x)
A.Mod(A, P)
B := pool.Get().Mul(a.y, a.y)
B.Mod(B, P)
C_ := pool.Get().Mul(B, B)
C_.Mod(C_, P)
t := pool.Get().Add(a.x, B)
t2 := pool.Get().Mul(t, t)
t2.Mod(t2, P)
t.Sub(t2, A)
t2.Sub(t, C_)
d := pool.Get().Add(t2, t2)
t.Add(A, A)
e := pool.Get().Add(t, A)
f := pool.Get().Mul(e, e)
f.Mod(f, P)
t.Add(d, d)
c.x.Sub(f, t)
t.Add(C_, C_)
t2.Add(t, t)
t.Add(t2, t2)
c.y.Sub(d, c.x)
t2.Mul(e, c.y)
t2.Mod(t2, P)
c.y.Sub(t2, t)
t.Mul(a.y, a.z)
t.Mod(t, P)
c.z.Add(t, t)
pool.Put(A)
pool.Put(B)
pool.Put(C_)
pool.Put(t)
pool.Put(t2)
pool.Put(d)
pool.Put(e)
pool.Put(f)
}
func (c *curvePoint) Mul(a *curvePoint, scalar *big.Int, pool *bnPool) *curvePoint {
sum := newCurvePoint(pool)
sum.SetInfinity()
t := newCurvePoint(pool)
for i := scalar.BitLen(); i >= 0; i-- {
t.Double(sum, pool)
if scalar.Bit(i) != 0 {
sum.Add(t, a, pool)
} else {
sum.Set(t)
}
}
c.Set(sum)
sum.Put(pool)
t.Put(pool)
return c
}
// MakeAffine converts c to affine form and returns c. If c is ∞, then it sets
// c to 0 : 1 : 0.
func (c *curvePoint) MakeAffine(pool *bnPool) *curvePoint {
if words := c.z.Bits(); len(words) == 1 && words[0] == 1 {
return c
}
if c.IsInfinity() {
c.x.SetInt64(0)
c.y.SetInt64(1)
c.z.SetInt64(0)
c.t.SetInt64(0)
return c
}
zInv := pool.Get().ModInverse(c.z, P)
t := pool.Get().Mul(c.y, zInv)
t.Mod(t, P)
zInv2 := pool.Get().Mul(zInv, zInv)
zInv2.Mod(zInv2, P)
c.y.Mul(t, zInv2)
c.y.Mod(c.y, P)
t.Mul(c.x, zInv2)
t.Mod(t, P)
c.x.Set(t)
c.z.SetInt64(1)
c.t.SetInt64(1)
pool.Put(zInv)
pool.Put(t)
pool.Put(zInv2)
return c
}
func (c *curvePoint) Negative(a *curvePoint) {
c.x.Set(a.x)
c.y.Neg(a.y)
c.z.Set(a.z)
c.t.SetInt64(0)
}

View File

@ -0,0 +1,43 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package bn256
import (
"crypto/rand"
)
func ExamplePair() {
// This implements the tripartite Diffie-Hellman algorithm from "A One
// Round Protocol for Tripartite Diffie-Hellman", A. Joux.
// http://www.springerlink.com/content/cddc57yyva0hburb/fulltext.pdf
// Each of three parties, a, b and c, generate a private value.
a, _ := rand.Int(rand.Reader, Order)
b, _ := rand.Int(rand.Reader, Order)
c, _ := rand.Int(rand.Reader, Order)
// Then each party calculates g₁ and g₂ times their private value.
pa := new(G1).ScalarBaseMult(a)
qa := new(G2).ScalarBaseMult(a)
pb := new(G1).ScalarBaseMult(b)
qb := new(G2).ScalarBaseMult(b)
pc := new(G1).ScalarBaseMult(c)
qc := new(G2).ScalarBaseMult(c)
// Now each party exchanges its public values with the other two and
// all parties can calculate the shared key.
k1 := Pair(pb, qc)
k1.ScalarMult(k1, a)
k2 := Pair(pc, qa)
k2.ScalarMult(k2, b)
k3 := Pair(pa, qb)
k3.ScalarMult(k3, c)
// k1, k2 and k3 will all be equal.
}

View File

@ -0,0 +1,200 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package bn256
// For details of the algorithms used, see "Multiplication and Squaring on
// Pairing-Friendly Fields, Devegili et al.
// http://eprint.iacr.org/2006/471.pdf.
import (
"math/big"
)
// gfP12 implements the field of size p¹² as a quadratic extension of gfP6
// where ω²=τ.
type gfP12 struct {
x, y *gfP6 // value is xω + y
}
func newGFp12(pool *bnPool) *gfP12 {
return &gfP12{newGFp6(pool), newGFp6(pool)}
}
func (e *gfP12) String() string {
return "(" + e.x.String() + "," + e.y.String() + ")"
}
func (e *gfP12) Put(pool *bnPool) {
e.x.Put(pool)
e.y.Put(pool)
}
func (e *gfP12) Set(a *gfP12) *gfP12 {
e.x.Set(a.x)
e.y.Set(a.y)
return e
}
func (e *gfP12) SetZero() *gfP12 {
e.x.SetZero()
e.y.SetZero()
return e
}
func (e *gfP12) SetOne() *gfP12 {
e.x.SetZero()
e.y.SetOne()
return e
}
func (e *gfP12) Minimal() {
e.x.Minimal()
e.y.Minimal()
}
func (e *gfP12) IsZero() bool {
e.Minimal()
return e.x.IsZero() && e.y.IsZero()
}
func (e *gfP12) IsOne() bool {
e.Minimal()
return e.x.IsZero() && e.y.IsOne()
}
func (e *gfP12) Conjugate(a *gfP12) *gfP12 {
e.x.Negative(a.x)
e.y.Set(a.y)
return a
}
func (e *gfP12) Negative(a *gfP12) *gfP12 {
e.x.Negative(a.x)
e.y.Negative(a.y)
return e
}
// Frobenius computes (xω+y)^p = x^p ω·ξ^((p-1)/6) + y^p
func (e *gfP12) Frobenius(a *gfP12, pool *bnPool) *gfP12 {
e.x.Frobenius(a.x, pool)
e.y.Frobenius(a.y, pool)
e.x.MulScalar(e.x, xiToPMinus1Over6, pool)
return e
}
// FrobeniusP2 computes (xω+y)^p² = x^p² ω·ξ^((p²-1)/6) + y^p²
func (e *gfP12) FrobeniusP2(a *gfP12, pool *bnPool) *gfP12 {
e.x.FrobeniusP2(a.x)
e.x.MulGFP(e.x, xiToPSquaredMinus1Over6)
e.y.FrobeniusP2(a.y)
return e
}
func (e *gfP12) Add(a, b *gfP12) *gfP12 {
e.x.Add(a.x, b.x)
e.y.Add(a.y, b.y)
return e
}
func (e *gfP12) Sub(a, b *gfP12) *gfP12 {
e.x.Sub(a.x, b.x)
e.y.Sub(a.y, b.y)
return e
}
func (e *gfP12) Mul(a, b *gfP12, pool *bnPool) *gfP12 {
tx := newGFp6(pool)
tx.Mul(a.x, b.y, pool)
t := newGFp6(pool)
t.Mul(b.x, a.y, pool)
tx.Add(tx, t)
ty := newGFp6(pool)
ty.Mul(a.y, b.y, pool)
t.Mul(a.x, b.x, pool)
t.MulTau(t, pool)
e.y.Add(ty, t)
e.x.Set(tx)
tx.Put(pool)
ty.Put(pool)
t.Put(pool)
return e
}
func (e *gfP12) MulScalar(a *gfP12, b *gfP6, pool *bnPool) *gfP12 {
e.x.Mul(e.x, b, pool)
e.y.Mul(e.y, b, pool)
return e
}
func (c *gfP12) Exp(a *gfP12, power *big.Int, pool *bnPool) *gfP12 {
sum := newGFp12(pool)
sum.SetOne()
t := newGFp12(pool)
for i := power.BitLen() - 1; i >= 0; i-- {
t.Square(sum, pool)
if power.Bit(i) != 0 {
sum.Mul(t, a, pool)
} else {
sum.Set(t)
}
}
c.Set(sum)
sum.Put(pool)
t.Put(pool)
return c
}
func (e *gfP12) Square(a *gfP12, pool *bnPool) *gfP12 {
// Complex squaring algorithm
v0 := newGFp6(pool)
v0.Mul(a.x, a.y, pool)
t := newGFp6(pool)
t.MulTau(a.x, pool)
t.Add(a.y, t)
ty := newGFp6(pool)
ty.Add(a.x, a.y)
ty.Mul(ty, t, pool)
ty.Sub(ty, v0)
t.MulTau(v0, pool)
ty.Sub(ty, t)
e.y.Set(ty)
e.x.Double(v0)
v0.Put(pool)
t.Put(pool)
ty.Put(pool)
return e
}
func (e *gfP12) Invert(a *gfP12, pool *bnPool) *gfP12 {
// See "Implementing cryptographic pairings", M. Scott, section 3.2.
// ftp://136.206.11.249/pub/crypto/pairings.pdf
t1 := newGFp6(pool)
t2 := newGFp6(pool)
t1.Square(a.x, pool)
t2.Square(a.y, pool)
t1.MulTau(t1, pool)
t1.Sub(t2, t1)
t2.Invert(t1, pool)
e.x.Negative(a.x)
e.y.Set(a.y)
e.MulScalar(e, t2, pool)
t1.Put(pool)
t2.Put(pool)
return e
}

View File

@ -0,0 +1,227 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package bn256
// For details of the algorithms used, see "Multiplication and Squaring on
// Pairing-Friendly Fields, Devegili et al.
// http://eprint.iacr.org/2006/471.pdf.
import (
"math/big"
)
// gfP2 implements a field of size p² as a quadratic extension of the base
// field where i²=-1.
type gfP2 struct {
x, y *big.Int // value is xi+y.
}
func newGFp2(pool *bnPool) *gfP2 {
return &gfP2{pool.Get(), pool.Get()}
}
func (e *gfP2) String() string {
x := new(big.Int).Mod(e.x, P)
y := new(big.Int).Mod(e.y, P)
return "(" + x.String() + "," + y.String() + ")"
}
func (e *gfP2) Put(pool *bnPool) {
pool.Put(e.x)
pool.Put(e.y)
}
func (e *gfP2) Set(a *gfP2) *gfP2 {
e.x.Set(a.x)
e.y.Set(a.y)
return e
}
func (e *gfP2) SetZero() *gfP2 {
e.x.SetInt64(0)
e.y.SetInt64(0)
return e
}
func (e *gfP2) SetOne() *gfP2 {
e.x.SetInt64(0)
e.y.SetInt64(1)
return e
}
func (e *gfP2) Minimal() {
if e.x.Sign() < 0 || e.x.Cmp(P) >= 0 {
e.x.Mod(e.x, P)
}
if e.y.Sign() < 0 || e.y.Cmp(P) >= 0 {
e.y.Mod(e.y, P)
}
}
func (e *gfP2) IsZero() bool {
return e.x.Sign() == 0 && e.y.Sign() == 0
}
func (e *gfP2) IsOne() bool {
if e.x.Sign() != 0 {
return false
}
words := e.y.Bits()
return len(words) == 1 && words[0] == 1
}
func (e *gfP2) Conjugate(a *gfP2) *gfP2 {
e.y.Set(a.y)
e.x.Neg(a.x)
return e
}
func (e *gfP2) Negative(a *gfP2) *gfP2 {
e.x.Neg(a.x)
e.y.Neg(a.y)
return e
}
func (e *gfP2) Add(a, b *gfP2) *gfP2 {
e.x.Add(a.x, b.x)
e.y.Add(a.y, b.y)
return e
}
func (e *gfP2) Sub(a, b *gfP2) *gfP2 {
e.x.Sub(a.x, b.x)
e.y.Sub(a.y, b.y)
return e
}
func (e *gfP2) Double(a *gfP2) *gfP2 {
e.x.Lsh(a.x, 1)
e.y.Lsh(a.y, 1)
return e
}
func (c *gfP2) Exp(a *gfP2, power *big.Int, pool *bnPool) *gfP2 {
sum := newGFp2(pool)
sum.SetOne()
t := newGFp2(pool)
for i := power.BitLen() - 1; i >= 0; i-- {
t.Square(sum, pool)
if power.Bit(i) != 0 {
sum.Mul(t, a, pool)
} else {
sum.Set(t)
}
}
c.Set(sum)
sum.Put(pool)
t.Put(pool)
return c
}
// See "Multiplication and Squaring in Pairing-Friendly Fields",
// http://eprint.iacr.org/2006/471.pdf
func (e *gfP2) Mul(a, b *gfP2, pool *bnPool) *gfP2 {
tx := pool.Get().Mul(a.x, b.y)
t := pool.Get().Mul(b.x, a.y)
tx.Add(tx, t)
tx.Mod(tx, P)
ty := pool.Get().Mul(a.y, b.y)
t.Mul(a.x, b.x)
ty.Sub(ty, t)
e.y.Mod(ty, P)
e.x.Set(tx)
pool.Put(tx)
pool.Put(ty)
pool.Put(t)
return e
}
func (e *gfP2) MulScalar(a *gfP2, b *big.Int) *gfP2 {
e.x.Mul(a.x, b)
e.y.Mul(a.y, b)
return e
}
// MulXi sets e=ξa where ξ=i+9 and then returns e.
func (e *gfP2) MulXi(a *gfP2, pool *bnPool) *gfP2 {
// (xi+y)(i+3) = (9x+y)i+(9y-x)
tx := pool.Get().Lsh(a.x, 3)
tx.Add(tx, a.x)
tx.Add(tx, a.y)
ty := pool.Get().Lsh(a.y, 3)
ty.Add(ty, a.y)
ty.Sub(ty, a.x)
e.x.Set(tx)
e.y.Set(ty)
pool.Put(tx)
pool.Put(ty)
return e
}
func (e *gfP2) Square(a *gfP2, pool *bnPool) *gfP2 {
// Complex squaring algorithm:
// (xi+b)² = (x+y)(y-x) + 2*i*x*y
t1 := pool.Get().Sub(a.y, a.x)
t2 := pool.Get().Add(a.x, a.y)
ty := pool.Get().Mul(t1, t2)
ty.Mod(ty, P)
t1.Mul(a.x, a.y)
t1.Lsh(t1, 1)
e.x.Mod(t1, P)
e.y.Set(ty)
pool.Put(t1)
pool.Put(t2)
pool.Put(ty)
return e
}
func (e *gfP2) Invert(a *gfP2, pool *bnPool) *gfP2 {
// See "Implementing cryptographic pairings", M. Scott, section 3.2.
// ftp://136.206.11.249/pub/crypto/pairings.pdf
t := pool.Get()
t.Mul(a.y, a.y)
t2 := pool.Get()
t2.Mul(a.x, a.x)
t.Add(t, t2)
inv := pool.Get()
inv.ModInverse(t, P)
e.x.Neg(a.x)
e.x.Mul(e.x, inv)
e.x.Mod(e.x, P)
e.y.Mul(a.y, inv)
e.y.Mod(e.y, P)
pool.Put(t)
pool.Put(t2)
pool.Put(inv)
return e
}
func (e *gfP2) Real() *big.Int {
return e.x
}
func (e *gfP2) Imag() *big.Int {
return e.y
}

View File

@ -0,0 +1,296 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package bn256
// For details of the algorithms used, see "Multiplication and Squaring on
// Pairing-Friendly Fields, Devegili et al.
// http://eprint.iacr.org/2006/471.pdf.
import (
"math/big"
)
// gfP6 implements the field of size p⁶ as a cubic extension of gfP2 where τ³=ξ
// and ξ=i+9.
type gfP6 struct {
x, y, z *gfP2 // value is xτ² + yτ + z
}
func newGFp6(pool *bnPool) *gfP6 {
return &gfP6{newGFp2(pool), newGFp2(pool), newGFp2(pool)}
}
func (e *gfP6) String() string {
return "(" + e.x.String() + "," + e.y.String() + "," + e.z.String() + ")"
}
func (e *gfP6) Put(pool *bnPool) {
e.x.Put(pool)
e.y.Put(pool)
e.z.Put(pool)
}
func (e *gfP6) Set(a *gfP6) *gfP6 {
e.x.Set(a.x)
e.y.Set(a.y)
e.z.Set(a.z)
return e
}
func (e *gfP6) SetZero() *gfP6 {
e.x.SetZero()
e.y.SetZero()
e.z.SetZero()
return e
}
func (e *gfP6) SetOne() *gfP6 {
e.x.SetZero()
e.y.SetZero()
e.z.SetOne()
return e
}
func (e *gfP6) Minimal() {
e.x.Minimal()
e.y.Minimal()
e.z.Minimal()
}
func (e *gfP6) IsZero() bool {
return e.x.IsZero() && e.y.IsZero() && e.z.IsZero()
}
func (e *gfP6) IsOne() bool {
return e.x.IsZero() && e.y.IsZero() && e.z.IsOne()
}
func (e *gfP6) Negative(a *gfP6) *gfP6 {
e.x.Negative(a.x)
e.y.Negative(a.y)
e.z.Negative(a.z)
return e
}
func (e *gfP6) Frobenius(a *gfP6, pool *bnPool) *gfP6 {
e.x.Conjugate(a.x)
e.y.Conjugate(a.y)
e.z.Conjugate(a.z)
e.x.Mul(e.x, xiTo2PMinus2Over3, pool)
e.y.Mul(e.y, xiToPMinus1Over3, pool)
return e
}
// FrobeniusP2 computes (xτ²+yτ+z)^(p²) = xτ^(2p²) + yτ^(p²) + z
func (e *gfP6) FrobeniusP2(a *gfP6) *gfP6 {
// τ^(2p²) = τ²τ^(2p²-2) = τ²ξ^((2p²-2)/3)
e.x.MulScalar(a.x, xiTo2PSquaredMinus2Over3)
// τ^(p²) = ττ^(p²-1) = τξ^((p²-1)/3)
e.y.MulScalar(a.y, xiToPSquaredMinus1Over3)
e.z.Set(a.z)
return e
}
func (e *gfP6) Add(a, b *gfP6) *gfP6 {
e.x.Add(a.x, b.x)
e.y.Add(a.y, b.y)
e.z.Add(a.z, b.z)
return e
}
func (e *gfP6) Sub(a, b *gfP6) *gfP6 {
e.x.Sub(a.x, b.x)
e.y.Sub(a.y, b.y)
e.z.Sub(a.z, b.z)
return e
}
func (e *gfP6) Double(a *gfP6) *gfP6 {
e.x.Double(a.x)
e.y.Double(a.y)
e.z.Double(a.z)
return e
}
func (e *gfP6) Mul(a, b *gfP6, pool *bnPool) *gfP6 {
// "Multiplication and Squaring on Pairing-Friendly Fields"
// Section 4, Karatsuba method.
// http://eprint.iacr.org/2006/471.pdf
v0 := newGFp2(pool)
v0.Mul(a.z, b.z, pool)
v1 := newGFp2(pool)
v1.Mul(a.y, b.y, pool)
v2 := newGFp2(pool)
v2.Mul(a.x, b.x, pool)
t0 := newGFp2(pool)
t0.Add(a.x, a.y)
t1 := newGFp2(pool)
t1.Add(b.x, b.y)
tz := newGFp2(pool)
tz.Mul(t0, t1, pool)
tz.Sub(tz, v1)
tz.Sub(tz, v2)
tz.MulXi(tz, pool)
tz.Add(tz, v0)
t0.Add(a.y, a.z)
t1.Add(b.y, b.z)
ty := newGFp2(pool)
ty.Mul(t0, t1, pool)
ty.Sub(ty, v0)
ty.Sub(ty, v1)
t0.MulXi(v2, pool)
ty.Add(ty, t0)
t0.Add(a.x, a.z)
t1.Add(b.x, b.z)
tx := newGFp2(pool)
tx.Mul(t0, t1, pool)
tx.Sub(tx, v0)
tx.Add(tx, v1)
tx.Sub(tx, v2)
e.x.Set(tx)
e.y.Set(ty)
e.z.Set(tz)
t0.Put(pool)
t1.Put(pool)
tx.Put(pool)
ty.Put(pool)
tz.Put(pool)
v0.Put(pool)
v1.Put(pool)
v2.Put(pool)
return e
}
func (e *gfP6) MulScalar(a *gfP6, b *gfP2, pool *bnPool) *gfP6 {
e.x.Mul(a.x, b, pool)
e.y.Mul(a.y, b, pool)
e.z.Mul(a.z, b, pool)
return e
}
func (e *gfP6) MulGFP(a *gfP6, b *big.Int) *gfP6 {
e.x.MulScalar(a.x, b)
e.y.MulScalar(a.y, b)
e.z.MulScalar(a.z, b)
return e
}
// MulTau computes τ·(aτ²+bτ+c) = bτ²+cτ+aξ
func (e *gfP6) MulTau(a *gfP6, pool *bnPool) {
tz := newGFp2(pool)
tz.MulXi(a.x, pool)
ty := newGFp2(pool)
ty.Set(a.y)
e.y.Set(a.z)
e.x.Set(ty)
e.z.Set(tz)
tz.Put(pool)
ty.Put(pool)
}
func (e *gfP6) Square(a *gfP6, pool *bnPool) *gfP6 {
v0 := newGFp2(pool).Square(a.z, pool)
v1 := newGFp2(pool).Square(a.y, pool)
v2 := newGFp2(pool).Square(a.x, pool)
c0 := newGFp2(pool).Add(a.x, a.y)
c0.Square(c0, pool)
c0.Sub(c0, v1)
c0.Sub(c0, v2)
c0.MulXi(c0, pool)
c0.Add(c0, v0)
c1 := newGFp2(pool).Add(a.y, a.z)
c1.Square(c1, pool)
c1.Sub(c1, v0)
c1.Sub(c1, v1)
xiV2 := newGFp2(pool).MulXi(v2, pool)
c1.Add(c1, xiV2)
c2 := newGFp2(pool).Add(a.x, a.z)
c2.Square(c2, pool)
c2.Sub(c2, v0)
c2.Add(c2, v1)
c2.Sub(c2, v2)
e.x.Set(c2)
e.y.Set(c1)
e.z.Set(c0)
v0.Put(pool)
v1.Put(pool)
v2.Put(pool)
c0.Put(pool)
c1.Put(pool)
c2.Put(pool)
xiV2.Put(pool)
return e
}
func (e *gfP6) Invert(a *gfP6, pool *bnPool) *gfP6 {
// See "Implementing cryptographic pairings", M. Scott, section 3.2.
// ftp://136.206.11.249/pub/crypto/pairings.pdf
// Here we can give a short explanation of how it works: let j be a cubic root of
// unity in GF(p²) so that 1+j+j²=0.
// Then (xτ² + yτ + z)(xj²τ² + yjτ + z)(xjτ² + yj²τ + z)
// = (xτ² + yτ + z)(Cτ²+Bτ+A)
// = (x³ξ²+y³ξ+z³-3ξxyz) = F is an element of the base field (the norm).
//
// On the other hand (xj²τ² + yjτ + z)(xjτ² + yj²τ + z)
// = τ²(y²-ξxz) + τ(ξx²-yz) + (z²-ξxy)
//
// So that's why A = (z²-ξxy), B = (ξx²-yz), C = (y²-ξxz)
t1 := newGFp2(pool)
A := newGFp2(pool)
A.Square(a.z, pool)
t1.Mul(a.x, a.y, pool)
t1.MulXi(t1, pool)
A.Sub(A, t1)
B := newGFp2(pool)
B.Square(a.x, pool)
B.MulXi(B, pool)
t1.Mul(a.y, a.z, pool)
B.Sub(B, t1)
C_ := newGFp2(pool)
C_.Square(a.y, pool)
t1.Mul(a.x, a.z, pool)
C_.Sub(C_, t1)
F := newGFp2(pool)
F.Mul(C_, a.y, pool)
F.MulXi(F, pool)
t1.Mul(A, a.z, pool)
F.Add(F, t1)
t1.Mul(B, a.x, pool)
t1.MulXi(t1, pool)
F.Add(F, t1)
F.Invert(F, pool)
e.x.Mul(C_, F, pool)
e.y.Mul(B, F, pool)
e.z.Mul(A, F, pool)
t1.Put(pool)
A.Put(pool)
B.Put(pool)
C_.Put(pool)
F.Put(pool)
return e
}

View File

@ -0,0 +1,71 @@
package bn256
import (
"testing"
"crypto/rand"
)
func TestRandomG2Marshal(t *testing.T) {
for i := 0; i < 10; i++ {
n, g2, err := RandomG2(rand.Reader)
if err != nil {
t.Error(err)
continue
}
t.Logf("%v: %x\n", n, g2.Marshal())
}
}
func TestPairings(t *testing.T) {
a1 := new(G1).ScalarBaseMult(bigFromBase10("1"))
a2 := new(G1).ScalarBaseMult(bigFromBase10("2"))
a37 := new(G1).ScalarBaseMult(bigFromBase10("37"))
an1 := new(G1).ScalarBaseMult(bigFromBase10("21888242871839275222246405745257275088548364400416034343698204186575808495616"))
b0 := new(G2).ScalarBaseMult(bigFromBase10("0"))
b1 := new(G2).ScalarBaseMult(bigFromBase10("1"))
b2 := new(G2).ScalarBaseMult(bigFromBase10("2"))
b27 := new(G2).ScalarBaseMult(bigFromBase10("27"))
b999 := new(G2).ScalarBaseMult(bigFromBase10("999"))
bn1 := new(G2).ScalarBaseMult(bigFromBase10("21888242871839275222246405745257275088548364400416034343698204186575808495616"))
p1 := Pair(a1, b1)
pn1 := Pair(a1, bn1)
np1 := Pair(an1, b1)
if pn1.String() != np1.String() {
t.Error("Pairing mismatch: e(a, -b) != e(-a, b)")
}
if !PairingCheck([]*G1{a1, an1}, []*G2{b1, b1}) {
t.Error("MultiAte check gave false negative!")
}
p0 := new(GT).Add(p1, pn1)
p0_2 := Pair(a1, b0)
if p0.String() != p0_2.String() {
t.Error("Pairing mismatch: e(a, b) * e(a, -b) != 1")
}
p0_3 := new(GT).ScalarMult(p1, bigFromBase10("21888242871839275222246405745257275088548364400416034343698204186575808495617"))
if p0.String() != p0_3.String() {
t.Error("Pairing mismatch: e(a, b) has wrong order")
}
p2 := Pair(a2, b1)
p2_2 := Pair(a1, b2)
p2_3 := new(GT).ScalarMult(p1, bigFromBase10("2"))
if p2.String() != p2_2.String() {
t.Error("Pairing mismatch: e(a, b * 2) != e(a * 2, b)")
}
if p2.String() != p2_3.String() {
t.Error("Pairing mismatch: e(a, b * 2) != e(a, b) ** 2")
}
if p2.String() == p1.String() {
t.Error("Pairing is degenerate!")
}
if PairingCheck([]*G1{a1, a1}, []*G2{b1, b1}) {
t.Error("MultiAte check gave false positive!")
}
p999 := Pair(a37, b27)
p999_2 := Pair(a1, b999)
if p999.String() != p999_2.String() {
t.Error("Pairing mismatch: e(a * 37, b * 27) != e(a, b * 999)")
}
}

View File

@ -0,0 +1,397 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package bn256
func lineFunctionAdd(r, p *twistPoint, q *curvePoint, r2 *gfP2, pool *bnPool) (a, b, c *gfP2, rOut *twistPoint) {
// See the mixed addition algorithm from "Faster Computation of the
// Tate Pairing", http://arxiv.org/pdf/0904.0854v3.pdf
B := newGFp2(pool).Mul(p.x, r.t, pool)
D := newGFp2(pool).Add(p.y, r.z)
D.Square(D, pool)
D.Sub(D, r2)
D.Sub(D, r.t)
D.Mul(D, r.t, pool)
H := newGFp2(pool).Sub(B, r.x)
I := newGFp2(pool).Square(H, pool)
E := newGFp2(pool).Add(I, I)
E.Add(E, E)
J := newGFp2(pool).Mul(H, E, pool)
L1 := newGFp2(pool).Sub(D, r.y)
L1.Sub(L1, r.y)
V := newGFp2(pool).Mul(r.x, E, pool)
rOut = newTwistPoint(pool)
rOut.x.Square(L1, pool)
rOut.x.Sub(rOut.x, J)
rOut.x.Sub(rOut.x, V)
rOut.x.Sub(rOut.x, V)
rOut.z.Add(r.z, H)
rOut.z.Square(rOut.z, pool)
rOut.z.Sub(rOut.z, r.t)
rOut.z.Sub(rOut.z, I)
t := newGFp2(pool).Sub(V, rOut.x)
t.Mul(t, L1, pool)
t2 := newGFp2(pool).Mul(r.y, J, pool)
t2.Add(t2, t2)
rOut.y.Sub(t, t2)
rOut.t.Square(rOut.z, pool)
t.Add(p.y, rOut.z)
t.Square(t, pool)
t.Sub(t, r2)
t.Sub(t, rOut.t)
t2.Mul(L1, p.x, pool)
t2.Add(t2, t2)
a = newGFp2(pool)
a.Sub(t2, t)
c = newGFp2(pool)
c.MulScalar(rOut.z, q.y)
c.Add(c, c)
b = newGFp2(pool)
b.SetZero()
b.Sub(b, L1)
b.MulScalar(b, q.x)
b.Add(b, b)
B.Put(pool)
D.Put(pool)
H.Put(pool)
I.Put(pool)
E.Put(pool)
J.Put(pool)
L1.Put(pool)
V.Put(pool)
t.Put(pool)
t2.Put(pool)
return
}
func lineFunctionDouble(r *twistPoint, q *curvePoint, pool *bnPool) (a, b, c *gfP2, rOut *twistPoint) {
// See the doubling algorithm for a=0 from "Faster Computation of the
// Tate Pairing", http://arxiv.org/pdf/0904.0854v3.pdf
A := newGFp2(pool).Square(r.x, pool)
B := newGFp2(pool).Square(r.y, pool)
C_ := newGFp2(pool).Square(B, pool)
D := newGFp2(pool).Add(r.x, B)
D.Square(D, pool)
D.Sub(D, A)
D.Sub(D, C_)
D.Add(D, D)
E := newGFp2(pool).Add(A, A)
E.Add(E, A)
G := newGFp2(pool).Square(E, pool)
rOut = newTwistPoint(pool)
rOut.x.Sub(G, D)
rOut.x.Sub(rOut.x, D)
rOut.z.Add(r.y, r.z)
rOut.z.Square(rOut.z, pool)
rOut.z.Sub(rOut.z, B)
rOut.z.Sub(rOut.z, r.t)
rOut.y.Sub(D, rOut.x)
rOut.y.Mul(rOut.y, E, pool)
t := newGFp2(pool).Add(C_, C_)
t.Add(t, t)
t.Add(t, t)
rOut.y.Sub(rOut.y, t)
rOut.t.Square(rOut.z, pool)
t.Mul(E, r.t, pool)
t.Add(t, t)
b = newGFp2(pool)
b.SetZero()
b.Sub(b, t)
b.MulScalar(b, q.x)
a = newGFp2(pool)
a.Add(r.x, E)
a.Square(a, pool)
a.Sub(a, A)
a.Sub(a, G)
t.Add(B, B)
t.Add(t, t)
a.Sub(a, t)
c = newGFp2(pool)
c.Mul(rOut.z, r.t, pool)
c.Add(c, c)
c.MulScalar(c, q.y)
A.Put(pool)
B.Put(pool)
C_.Put(pool)
D.Put(pool)
E.Put(pool)
G.Put(pool)
t.Put(pool)
return
}
func mulLine(ret *gfP12, a, b, c *gfP2, pool *bnPool) {
a2 := newGFp6(pool)
a2.x.SetZero()
a2.y.Set(a)
a2.z.Set(b)
a2.Mul(a2, ret.x, pool)
t3 := newGFp6(pool).MulScalar(ret.y, c, pool)
t := newGFp2(pool)
t.Add(b, c)
t2 := newGFp6(pool)
t2.x.SetZero()
t2.y.Set(a)
t2.z.Set(t)
ret.x.Add(ret.x, ret.y)
ret.y.Set(t3)
ret.x.Mul(ret.x, t2, pool)
ret.x.Sub(ret.x, a2)
ret.x.Sub(ret.x, ret.y)
a2.MulTau(a2, pool)
ret.y.Add(ret.y, a2)
a2.Put(pool)
t3.Put(pool)
t2.Put(pool)
t.Put(pool)
}
// sixuPlus2NAF is 6u+2 in non-adjacent form.
var sixuPlus2NAF = []int8{0, 0, 0, 1, 0, 1, 0, -1, 0, 0, 1, -1, 0, 0, 1, 0,
0, 1, 1, 0, -1, 0, 0, 1, 0, -1, 0, 0, 0, 0, 1, 1,
1, 0, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, -1, 0, 0, 1,
1, 0, 0, -1, 0, 0, 0, 1, 1, 0, -1, 0, 0, 1, 0, 1, 1}
// miller implements the Miller loop for calculating the Optimal Ate pairing.
// See algorithm 1 from http://cryptojedi.org/papers/dclxvi-20100714.pdf
func miller(q *twistPoint, p *curvePoint, pool *bnPool) *gfP12 {
ret := newGFp12(pool)
ret.SetOne()
aAffine := newTwistPoint(pool)
aAffine.Set(q)
aAffine.MakeAffine(pool)
bAffine := newCurvePoint(pool)
bAffine.Set(p)
bAffine.MakeAffine(pool)
minusA := newTwistPoint(pool)
minusA.Negative(aAffine, pool)
r := newTwistPoint(pool)
r.Set(aAffine)
r2 := newGFp2(pool)
r2.Square(aAffine.y, pool)
for i := len(sixuPlus2NAF) - 1; i > 0; i-- {
a, b, c, newR := lineFunctionDouble(r, bAffine, pool)
if i != len(sixuPlus2NAF)-1 {
ret.Square(ret, pool)
}
mulLine(ret, a, b, c, pool)
a.Put(pool)
b.Put(pool)
c.Put(pool)
r.Put(pool)
r = newR
switch sixuPlus2NAF[i-1] {
case 1:
a, b, c, newR = lineFunctionAdd(r, aAffine, bAffine, r2, pool)
case -1:
a, b, c, newR = lineFunctionAdd(r, minusA, bAffine, r2, pool)
default:
continue
}
mulLine(ret, a, b, c, pool)
a.Put(pool)
b.Put(pool)
c.Put(pool)
r.Put(pool)
r = newR
}
// In order to calculate Q1 we have to convert q from the sextic twist
// to the full GF(p^12) group, apply the Frobenius there, and convert
// back.
//
// The twist isomorphism is (x', y') -> (xω², yω³). If we consider just
// x for a moment, then after applying the Frobenius, we have x̄ω^(2p)
// where x̄ is the conjugate of x. If we are going to apply the inverse
// isomorphism we need a value with a single coefficient of ω² so we
// rewrite this as x̄ω^(2p-2)ω². ξ⁶ = ω and, due to the construction of
// p, 2p-2 is a multiple of six. Therefore we can rewrite as
// x̄ξ^((p-1)/3)ω² and applying the inverse isomorphism eliminates the
// ω².
//
// A similar argument can be made for the y value.
q1 := newTwistPoint(pool)
q1.x.Conjugate(aAffine.x)
q1.x.Mul(q1.x, xiToPMinus1Over3, pool)
q1.y.Conjugate(aAffine.y)
q1.y.Mul(q1.y, xiToPMinus1Over2, pool)
q1.z.SetOne()
q1.t.SetOne()
// For Q2 we are applying the p² Frobenius. The two conjugations cancel
// out and we are left only with the factors from the isomorphism. In
// the case of x, we end up with a pure number which is why
// xiToPSquaredMinus1Over3 is ∈ GF(p). With y we get a factor of -1. We
// ignore this to end up with -Q2.
minusQ2 := newTwistPoint(pool)
minusQ2.x.MulScalar(aAffine.x, xiToPSquaredMinus1Over3)
minusQ2.y.Set(aAffine.y)
minusQ2.z.SetOne()
minusQ2.t.SetOne()
r2.Square(q1.y, pool)
a, b, c, newR := lineFunctionAdd(r, q1, bAffine, r2, pool)
mulLine(ret, a, b, c, pool)
a.Put(pool)
b.Put(pool)
c.Put(pool)
r.Put(pool)
r = newR
r2.Square(minusQ2.y, pool)
a, b, c, newR = lineFunctionAdd(r, minusQ2, bAffine, r2, pool)
mulLine(ret, a, b, c, pool)
a.Put(pool)
b.Put(pool)
c.Put(pool)
r.Put(pool)
r = newR
aAffine.Put(pool)
bAffine.Put(pool)
minusA.Put(pool)
r.Put(pool)
r2.Put(pool)
return ret
}
// finalExponentiation computes the (p¹²-1)/Order-th power of an element of
// GF(p¹²) to obtain an element of GT (steps 13-15 of algorithm 1 from
// http://cryptojedi.org/papers/dclxvi-20100714.pdf)
func finalExponentiation(in *gfP12, pool *bnPool) *gfP12 {
t1 := newGFp12(pool)
// This is the p^6-Frobenius
t1.x.Negative(in.x)
t1.y.Set(in.y)
inv := newGFp12(pool)
inv.Invert(in, pool)
t1.Mul(t1, inv, pool)
t2 := newGFp12(pool).FrobeniusP2(t1, pool)
t1.Mul(t1, t2, pool)
fp := newGFp12(pool).Frobenius(t1, pool)
fp2 := newGFp12(pool).FrobeniusP2(t1, pool)
fp3 := newGFp12(pool).Frobenius(fp2, pool)
fu, fu2, fu3 := newGFp12(pool), newGFp12(pool), newGFp12(pool)
fu.Exp(t1, u, pool)
fu2.Exp(fu, u, pool)
fu3.Exp(fu2, u, pool)
y3 := newGFp12(pool).Frobenius(fu, pool)
fu2p := newGFp12(pool).Frobenius(fu2, pool)
fu3p := newGFp12(pool).Frobenius(fu3, pool)
y2 := newGFp12(pool).FrobeniusP2(fu2, pool)
y0 := newGFp12(pool)
y0.Mul(fp, fp2, pool)
y0.Mul(y0, fp3, pool)
y1, y4, y5 := newGFp12(pool), newGFp12(pool), newGFp12(pool)
y1.Conjugate(t1)
y5.Conjugate(fu2)
y3.Conjugate(y3)
y4.Mul(fu, fu2p, pool)
y4.Conjugate(y4)
y6 := newGFp12(pool)
y6.Mul(fu3, fu3p, pool)
y6.Conjugate(y6)
t0 := newGFp12(pool)
t0.Square(y6, pool)
t0.Mul(t0, y4, pool)
t0.Mul(t0, y5, pool)
t1.Mul(y3, y5, pool)
t1.Mul(t1, t0, pool)
t0.Mul(t0, y2, pool)
t1.Square(t1, pool)
t1.Mul(t1, t0, pool)
t1.Square(t1, pool)
t0.Mul(t1, y1, pool)
t1.Mul(t1, y0, pool)
t0.Square(t0, pool)
t0.Mul(t0, t1, pool)
inv.Put(pool)
t1.Put(pool)
t2.Put(pool)
fp.Put(pool)
fp2.Put(pool)
fp3.Put(pool)
fu.Put(pool)
fu2.Put(pool)
fu3.Put(pool)
fu2p.Put(pool)
fu3p.Put(pool)
y0.Put(pool)
y1.Put(pool)
y2.Put(pool)
y3.Put(pool)
y4.Put(pool)
y5.Put(pool)
y6.Put(pool)
return t0
}
func optimalAte(a *twistPoint, b *curvePoint, pool *bnPool) *gfP12 {
e := miller(a, b, pool)
ret := finalExponentiation(e, pool)
e.Put(pool)
if a.IsInfinity() || b.IsInfinity() {
ret.SetOne()
}
return ret
}

View File

@ -0,0 +1,263 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package bn256
import (
"math/big"
)
// twistPoint implements the elliptic curve y²=x³+3/ξ over GF(p²). Points are
// kept in Jacobian form and t=z² when valid. The group G₂ is the set of
// n-torsion points of this curve over GF(p²) (where n = Order)
type twistPoint struct {
x, y, z, t *gfP2
}
var twistB = &gfP2{
bigFromBase10("266929791119991161246907387137283842545076965332900288569378510910307636690"),
bigFromBase10("19485874751759354771024239261021720505790618469301721065564631296452457478373"),
}
// twistGen is the generator of group G₂.
var twistGen = &twistPoint{
&gfP2{
bigFromBase10("11559732032986387107991004021392285783925812861821192530917403151452391805634"),
bigFromBase10("10857046999023057135944570762232829481370756359578518086990519993285655852781"),
},
&gfP2{
bigFromBase10("4082367875863433681332203403145435568316851327593401208105741076214120093531"),
bigFromBase10("8495653923123431417604973247489272438418190587263600148770280649306958101930"),
},
&gfP2{
bigFromBase10("0"),
bigFromBase10("1"),
},
&gfP2{
bigFromBase10("0"),
bigFromBase10("1"),
},
}
func newTwistPoint(pool *bnPool) *twistPoint {
return &twistPoint{
newGFp2(pool),
newGFp2(pool),
newGFp2(pool),
newGFp2(pool),
}
}
func (c *twistPoint) String() string {
return "(" + c.x.String() + ", " + c.y.String() + ", " + c.z.String() + ")"
}
func (c *twistPoint) Put(pool *bnPool) {
c.x.Put(pool)
c.y.Put(pool)
c.z.Put(pool)
c.t.Put(pool)
}
func (c *twistPoint) Set(a *twistPoint) {
c.x.Set(a.x)
c.y.Set(a.y)
c.z.Set(a.z)
c.t.Set(a.t)
}
// IsOnCurve returns true iff c is on the curve where c must be in affine form.
func (c *twistPoint) IsOnCurve() bool {
pool := new(bnPool)
yy := newGFp2(pool).Square(c.y, pool)
xxx := newGFp2(pool).Square(c.x, pool)
xxx.Mul(xxx, c.x, pool)
yy.Sub(yy, xxx)
yy.Sub(yy, twistB)
yy.Minimal()
if yy.x.Sign() != 0 || yy.y.Sign() != 0 {
return false
}
cneg := newTwistPoint(pool)
cneg.Mul(c, Order, pool)
return cneg.z.IsZero()
}
func (c *twistPoint) SetInfinity() {
c.z.SetZero()
}
func (c *twistPoint) IsInfinity() bool {
return c.z.IsZero()
}
func (c *twistPoint) Add(a, b *twistPoint, pool *bnPool) {
// For additional comments, see the same function in curve.go.
if a.IsInfinity() {
c.Set(b)
return
}
if b.IsInfinity() {
c.Set(a)
return
}
// See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/addition/add-2007-bl.op3
z1z1 := newGFp2(pool).Square(a.z, pool)
z2z2 := newGFp2(pool).Square(b.z, pool)
u1 := newGFp2(pool).Mul(a.x, z2z2, pool)
u2 := newGFp2(pool).Mul(b.x, z1z1, pool)
t := newGFp2(pool).Mul(b.z, z2z2, pool)
s1 := newGFp2(pool).Mul(a.y, t, pool)
t.Mul(a.z, z1z1, pool)
s2 := newGFp2(pool).Mul(b.y, t, pool)
h := newGFp2(pool).Sub(u2, u1)
xEqual := h.IsZero()
t.Add(h, h)
i := newGFp2(pool).Square(t, pool)
j := newGFp2(pool).Mul(h, i, pool)
t.Sub(s2, s1)
yEqual := t.IsZero()
if xEqual && yEqual {
c.Double(a, pool)
return
}
r := newGFp2(pool).Add(t, t)
v := newGFp2(pool).Mul(u1, i, pool)
t4 := newGFp2(pool).Square(r, pool)
t.Add(v, v)
t6 := newGFp2(pool).Sub(t4, j)
c.x.Sub(t6, t)
t.Sub(v, c.x) // t7
t4.Mul(s1, j, pool) // t8
t6.Add(t4, t4) // t9
t4.Mul(r, t, pool) // t10
c.y.Sub(t4, t6)
t.Add(a.z, b.z) // t11
t4.Square(t, pool) // t12
t.Sub(t4, z1z1) // t13
t4.Sub(t, z2z2) // t14
c.z.Mul(t4, h, pool)
z1z1.Put(pool)
z2z2.Put(pool)
u1.Put(pool)
u2.Put(pool)
t.Put(pool)
s1.Put(pool)
s2.Put(pool)
h.Put(pool)
i.Put(pool)
j.Put(pool)
r.Put(pool)
v.Put(pool)
t4.Put(pool)
t6.Put(pool)
}
func (c *twistPoint) Double(a *twistPoint, pool *bnPool) {
// See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/doubling/dbl-2009-l.op3
A := newGFp2(pool).Square(a.x, pool)
B := newGFp2(pool).Square(a.y, pool)
C_ := newGFp2(pool).Square(B, pool)
t := newGFp2(pool).Add(a.x, B)
t2 := newGFp2(pool).Square(t, pool)
t.Sub(t2, A)
t2.Sub(t, C_)
d := newGFp2(pool).Add(t2, t2)
t.Add(A, A)
e := newGFp2(pool).Add(t, A)
f := newGFp2(pool).Square(e, pool)
t.Add(d, d)
c.x.Sub(f, t)
t.Add(C_, C_)
t2.Add(t, t)
t.Add(t2, t2)
c.y.Sub(d, c.x)
t2.Mul(e, c.y, pool)
c.y.Sub(t2, t)
t.Mul(a.y, a.z, pool)
c.z.Add(t, t)
A.Put(pool)
B.Put(pool)
C_.Put(pool)
t.Put(pool)
t2.Put(pool)
d.Put(pool)
e.Put(pool)
f.Put(pool)
}
func (c *twistPoint) Mul(a *twistPoint, scalar *big.Int, pool *bnPool) *twistPoint {
sum := newTwistPoint(pool)
sum.SetInfinity()
t := newTwistPoint(pool)
for i := scalar.BitLen(); i >= 0; i-- {
t.Double(sum, pool)
if scalar.Bit(i) != 0 {
sum.Add(t, a, pool)
} else {
sum.Set(t)
}
}
c.Set(sum)
sum.Put(pool)
t.Put(pool)
return c
}
// MakeAffine converts c to affine form and returns c. If c is ∞, then it sets
// c to 0 : 1 : 0.
func (c *twistPoint) MakeAffine(pool *bnPool) *twistPoint {
if c.z.IsOne() {
return c
}
if c.IsInfinity() {
c.x.SetZero()
c.y.SetOne()
c.z.SetZero()
c.t.SetZero()
return c
}
zInv := newGFp2(pool).Invert(c.z, pool)
t := newGFp2(pool).Mul(c.y, zInv, pool)
zInv2 := newGFp2(pool).Square(zInv, pool)
c.y.Mul(t, zInv2, pool)
t.Mul(c.x, zInv2, pool)
c.x.Set(t)
c.z.SetOne()
c.t.SetOne()
zInv.Put(pool)
t.Put(pool)
zInv2.Put(pool)
return c
}
func (c *twistPoint) Negative(a *twistPoint, pool *bnPool) {
c.x.Set(a.x)
c.y.SetZero()
c.y.Sub(c.y, a.y)
c.z.Set(a.z)
c.t.SetZero()
}

317
restricted/crypto/crypto.go Normal file
View File

@ -0,0 +1,317 @@
// Copyright 2014 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/>.
package crypto
import (
"bufio"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"encoding/hex"
"errors"
"fmt"
"hash"
"io"
"io/ioutil"
"math/big"
"os"
"github.com/openrelayxyz/plugeth-utils/core"
"github.com/openrelayxyz/plugeth-utils/restricted/rlp"
"golang.org/x/crypto/sha3"
)
//SignatureLength indicates the byte length required to carry a signature with recovery id.
const SignatureLength = 64 + 1 // 64 bytes ECDSA signature + 1 byte recovery id
// RecoveryIDOffset points to the byte offset within the signature that contains the recovery id.
const RecoveryIDOffset = 64
// DigestLength sets the signature digest exact length
const DigestLength = 32
var (
secp256k1N, _ = new(big.Int).SetString("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", 16)
secp256k1halfN = new(big.Int).Div(secp256k1N, big.NewInt(2))
)
const (
// number of bits in a big.Word
wordBits = 32 << (uint64(^big.Word(0)) >> 63)
// number of bytes in a big.Word
wordBytes = wordBits / 8
)
var Big1 = new(big.Int).SetInt64(1)
var errInvalidPubkey = errors.New("invalid secp256k1 public key")
// KeccakState wraps sha3.state. In addition to the usual hash methods, it also supports
// Read to get a variable amount of data from the hash state. Read is faster than Sum
// because it doesn't copy the internal state, but also modifies the internal state.
type KeccakState interface {
hash.Hash
Read([]byte) (int, error)
}
// NewKeccakState creates a new KeccakState
func NewKeccakState() KeccakState {
return sha3.NewLegacyKeccak256().(KeccakState)
}
// HashData hashes the provided data using the KeccakState and returns a 32 byte hash
func HashData(kh KeccakState, data []byte) (h core.Hash) {
kh.Reset()
kh.Write(data)
kh.Read(h[:])
return h
}
// Keccak256 calculates and returns the Keccak256 hash of the input data.
func Keccak256(data ...[]byte) []byte {
b := make([]byte, 32)
d := NewKeccakState()
for _, b := range data {
d.Write(b)
}
d.Read(b)
return b
}
// Keccak256Hash calculates and returns the Keccak256 hash of the input data,
// converting it to an internal Hash data structure.
func Keccak256Hash(data ...[]byte) (h core.Hash) {
d := NewKeccakState()
for _, b := range data {
d.Write(b)
}
d.Read(h[:])
return h
}
// Keccak512 calculates and returns the Keccak512 hash of the input data.
func Keccak512(data ...[]byte) []byte {
d := sha3.NewLegacyKeccak512()
for _, b := range data {
d.Write(b)
}
return d.Sum(nil)
}
// CreateAddress creates an ethereum address given the bytes and the nonce
func CreateAddress(b core.Address, nonce uint64) core.Address {
data, _ := rlp.EncodeToBytes([]interface{}{b, nonce})
return core.BytesToAddress(Keccak256(data)[12:])
}
// CreateAddress2 creates an ethereum address given the address bytes, initial
// contract code hash and a salt.
func CreateAddress2(b core.Address, salt [32]byte, inithash []byte) core.Address {
return core.BytesToAddress(Keccak256([]byte{0xff}, b[:], salt[:], inithash)[12:])
}
// ToECDSA creates a private key with the given D value.
func ToECDSA(d []byte) (*ecdsa.PrivateKey, error) {
return toECDSA(d, true)
}
// ToECDSAUnsafe blindly converts a binary blob to a private key. It should almost
// never be used unless you are sure the input is valid and want to avoid hitting
// errors due to bad origin encoding (0 prefixes cut off).
func ToECDSAUnsafe(d []byte) *ecdsa.PrivateKey {
priv, _ := toECDSA(d, false)
return priv
}
// toECDSA creates a private key with the given D value. The strict parameter
// controls whether the key's length should be enforced at the curve size or
// it can also accept legacy encodings (0 prefixes).
func toECDSA(d []byte, strict bool) (*ecdsa.PrivateKey, error) {
priv := new(ecdsa.PrivateKey)
priv.PublicKey.Curve = S256()
if strict && 8*len(d) != priv.Params().BitSize {
return nil, fmt.Errorf("invalid length, need %d bits", priv.Params().BitSize)
}
priv.D = new(big.Int).SetBytes(d)
// The priv.D must < N
if priv.D.Cmp(secp256k1N) >= 0 {
return nil, fmt.Errorf("invalid private key, >=N")
}
// The priv.D must not be zero or negative.
if priv.D.Sign() <= 0 {
return nil, fmt.Errorf("invalid private key, zero or negative")
}
priv.PublicKey.X, priv.PublicKey.Y = priv.PublicKey.Curve.ScalarBaseMult(d)
if priv.PublicKey.X == nil {
return nil, errors.New("invalid private key")
}
return priv, nil
}
// ReadBits encodes the absolute value of bigint as big-endian bytes. Callers must ensure
// that buf has enough space. If buf is too short the result will be incomplete.
func ReadBits(bigint *big.Int, buf []byte) {
i := len(buf)
for _, d := range bigint.Bits() {
for j := 0; j < wordBytes && i > 0; j++ {
i--
buf[i] = byte(d)
d >>= 8
}
}
}
// PaddedBigBytes encodes a big integer as a big-endian byte slice. The length
// of the slice is at least n bytes.
func PaddedBigBytes(bigint *big.Int, n int) []byte {
if bigint.BitLen()/8 >= n {
return bigint.Bytes()
}
ret := make([]byte, n)
ReadBits(bigint, ret)
return ret
}
// FromECDSA exports a private key into a binary dump.
func FromECDSA(priv *ecdsa.PrivateKey) []byte {
if priv == nil {
return nil
}
return PaddedBigBytes(priv.D, priv.Params().BitSize/8)
}
// UnmarshalPubkey converts bytes to a secp256k1 public key.
func UnmarshalPubkey(pub []byte) (*ecdsa.PublicKey, error) {
x, y := elliptic.Unmarshal(S256(), pub)
if x == nil {
return nil, errInvalidPubkey
}
return &ecdsa.PublicKey{Curve: S256(), X: x, Y: y}, nil
}
func FromECDSAPub(pub *ecdsa.PublicKey) []byte {
if pub == nil || pub.X == nil || pub.Y == nil {
return nil
}
return elliptic.Marshal(S256(), pub.X, pub.Y)
}
// HexToECDSA parses a secp256k1 private key.
func HexToECDSA(hexkey string) (*ecdsa.PrivateKey, error) {
b, err := hex.DecodeString(hexkey)
if byteErr, ok := err.(hex.InvalidByteError); ok {
return nil, fmt.Errorf("invalid hex character %q in private key", byte(byteErr))
} else if err != nil {
return nil, errors.New("invalid hex data for private key")
}
return ToECDSA(b)
}
// LoadECDSA loads a secp256k1 private key from the given file.
func LoadECDSA(file string) (*ecdsa.PrivateKey, error) {
fd, err := os.Open(file)
if err != nil {
return nil, err
}
defer fd.Close()
r := bufio.NewReader(fd)
buf := make([]byte, 64)
n, err := readASCII(buf, r)
if err != nil {
return nil, err
} else if n != len(buf) {
return nil, fmt.Errorf("key file too short, want 64 hex characters")
}
if err := checkKeyFileEnd(r); err != nil {
return nil, err
}
return HexToECDSA(string(buf))
}
// readASCII reads into 'buf', stopping when the buffer is full or
// when a non-printable control character is encountered.
func readASCII(buf []byte, r *bufio.Reader) (n int, err error) {
for ; n < len(buf); n++ {
buf[n], err = r.ReadByte()
switch {
case err == io.EOF || buf[n] < '!':
return n, nil
case err != nil:
return n, err
}
}
return n, nil
}
// checkKeyFileEnd skips over additional newlines at the end of a key file.
func checkKeyFileEnd(r *bufio.Reader) error {
for i := 0; ; i++ {
b, err := r.ReadByte()
switch {
case err == io.EOF:
return nil
case err != nil:
return err
case b != '\n' && b != '\r':
return fmt.Errorf("invalid character %q at end of key file", b)
case i >= 2:
return errors.New("key file too long, want 64 hex characters")
}
}
}
// SaveECDSA saves a secp256k1 private key to the given file with
// restrictive permissions. The key data is saved hex-encoded.
func SaveECDSA(file string, key *ecdsa.PrivateKey) error {
k := hex.EncodeToString(FromECDSA(key))
return ioutil.WriteFile(file, []byte(k), 0600)
}
// GenerateKey generates a new private key.
func GenerateKey() (*ecdsa.PrivateKey, error) {
return ecdsa.GenerateKey(S256(), rand.Reader)
}
// ValidateSignatureValues verifies whether the signature values are valid with
// the given chain rules. The v value is assumed to be either 0 or 1.
func ValidateSignatureValues(v byte, r, s *big.Int, homestead bool) bool {
if r.Cmp(Big1) < 0 || s.Cmp(Big1) < 0 {
return false
}
// reject upper range of s values (ECDSA malleability)
// see discussion in secp256k1/libsecp256k1/include/secp256k1.h
if homestead && s.Cmp(secp256k1halfN) > 0 {
return false
}
// Frontier: allow s to be in full N range
return r.Cmp(secp256k1N) < 0 && s.Cmp(secp256k1N) < 0 && (v == 0 || v == 1)
}
func PubkeyToAddress(p ecdsa.PublicKey) core.Address {
pubBytes := FromECDSAPub(&p)
return core.BytesToAddress(Keccak256(pubBytes[1:])[12:])
}
func zeroBytes(bytes []byte) {
for i := range bytes {
bytes[i] = 0
}
}

View File

@ -0,0 +1,284 @@
// Copyright 2014 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/>.
package crypto
import (
"bytes"
"crypto/ecdsa"
"encoding/hex"
"io/ioutil"
"math/big"
"os"
"reflect"
"testing"
"github.com/openrelayxyz/plugeth-utils/core"
"github.com/openrelayxyz/plugeth-utils/restricted/hexutil"
)
var testAddrHex = "970e8128ab834e8eac17ab8e3812f010678cf791"
var testPrivHex = "289c2857d4598e37fb9647507e47a309d6133539bf21a8b9cb6df88fd5232032"
// These tests are sanity checks.
// They should ensure that we don't e.g. use Sha3-224 instead of Sha3-256
// and that the sha3 library uses keccak-f permutation.
func TestKeccak256Hash(t *testing.T) {
msg := []byte("abc")
exp, _ := hex.DecodeString("4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45")
checkhash(t, "Sha3-256-array", func(in []byte) []byte { h := Keccak256Hash(in); return h[:] }, msg, exp)
}
func TestKeccak256Hasher(t *testing.T) {
msg := []byte("abc")
exp, _ := hex.DecodeString("4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45")
hasher := NewKeccakState()
checkhash(t, "Sha3-256-array", func(in []byte) []byte { h := HashData(hasher, in); return h[:] }, msg, exp)
}
func TestToECDSAErrors(t *testing.T) {
if _, err := HexToECDSA("0000000000000000000000000000000000000000000000000000000000000000"); err == nil {
t.Fatal("HexToECDSA should've returned error")
}
if _, err := HexToECDSA("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); err == nil {
t.Fatal("HexToECDSA should've returned error")
}
}
func BenchmarkSha3(b *testing.B) {
a := []byte("hello world")
for i := 0; i < b.N; i++ {
Keccak256(a)
}
}
func TestUnmarshalPubkey(t *testing.T) {
key, err := UnmarshalPubkey(nil)
if err != errInvalidPubkey || key != nil {
t.Fatalf("expected error, got %v, %v", err, key)
}
key, err = UnmarshalPubkey([]byte{1, 2, 3})
if err != errInvalidPubkey || key != nil {
t.Fatalf("expected error, got %v, %v", err, key)
}
var (
enc, _ = hex.DecodeString("04760c4460e5336ac9bbd87952a3c7ec4363fc0a97bd31c86430806e287b437fd1b01abc6e1db640cf3106b520344af1d58b00b57823db3e1407cbc433e1b6d04d")
dec = &ecdsa.PublicKey{
Curve: S256(),
X: hexutil.MustDecodeBig("0x760c4460e5336ac9bbd87952a3c7ec4363fc0a97bd31c86430806e287b437fd1"),
Y: hexutil.MustDecodeBig("0xb01abc6e1db640cf3106b520344af1d58b00b57823db3e1407cbc433e1b6d04d"),
}
)
key, err = UnmarshalPubkey(enc)
if err != nil {
t.Fatalf("expected no error, got %v", err)
}
if !reflect.DeepEqual(key, dec) {
t.Fatal("wrong result")
}
}
func TestSign(t *testing.T) {
key, _ := HexToECDSA(testPrivHex)
addr := core.HexToAddress(testAddrHex)
msg := Keccak256([]byte("foo"))
sig, err := Sign(msg, key)
if err != nil {
t.Errorf("Sign error: %s", err)
}
recoveredPub, err := Ecrecover(msg, sig)
if err != nil {
t.Errorf("ECRecover error: %s", err)
}
pubKey, _ := UnmarshalPubkey(recoveredPub)
recoveredAddr := PubkeyToAddress(*pubKey)
if addr != recoveredAddr {
t.Errorf("Address mismatch: want: %x have: %x", addr, recoveredAddr)
}
// should be equal to SigToPub
recoveredPub2, err := SigToPub(msg, sig)
if err != nil {
t.Errorf("ECRecover error: %s", err)
}
recoveredAddr2 := PubkeyToAddress(*recoveredPub2)
if addr != recoveredAddr2 {
t.Errorf("Address mismatch: want: %x have: %x", addr, recoveredAddr2)
}
}
func TestInvalidSign(t *testing.T) {
if _, err := Sign(make([]byte, 1), nil); err == nil {
t.Errorf("expected sign with hash 1 byte to error")
}
if _, err := Sign(make([]byte, 33), nil); err == nil {
t.Errorf("expected sign with hash 33 byte to error")
}
}
func TestNewContractAddress(t *testing.T) {
key, _ := HexToECDSA(testPrivHex)
addr := core.HexToAddress(testAddrHex)
genAddr := PubkeyToAddress(key.PublicKey)
// sanity check before using addr to create contract address
checkAddr(t, genAddr, addr)
caddr0 := CreateAddress(addr, 0)
caddr1 := CreateAddress(addr, 1)
caddr2 := CreateAddress(addr, 2)
checkAddr(t, core.HexToAddress("333c3310824b7c685133f2bedb2ca4b8b4df633d"), caddr0)
checkAddr(t, core.HexToAddress("8bda78331c916a08481428e4b07c96d3e916d165"), caddr1)
checkAddr(t, core.HexToAddress("c9ddedf451bc62ce88bf9292afb13df35b670699"), caddr2)
}
func TestLoadECDSA(t *testing.T) {
tests := []struct {
input string
err string
}{
// good
{input: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"},
{input: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\n"},
{input: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\n\r"},
{input: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"},
{input: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\n\n"},
{input: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\n\r"},
// bad
{
input: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcde",
err: "key file too short, want 64 hex characters",
},
{
input: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcde\n",
err: "key file too short, want 64 hex characters",
},
{
input: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdeX",
err: "invalid hex character 'X' in private key",
},
{
input: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdefX",
err: "invalid character 'X' at end of key file",
},
{
input: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\n\n\n",
err: "key file too long, want 64 hex characters",
},
}
for _, test := range tests {
f, err := ioutil.TempFile("", "loadecdsa_test.*.txt")
if err != nil {
t.Fatal(err)
}
filename := f.Name()
f.WriteString(test.input)
f.Close()
_, err = LoadECDSA(filename)
switch {
case err != nil && test.err == "":
t.Fatalf("unexpected error for input %q:\n %v", test.input, err)
case err != nil && err.Error() != test.err:
t.Fatalf("wrong error for input %q:\n %v", test.input, err)
case err == nil && test.err != "":
t.Fatalf("LoadECDSA did not return error for input %q", test.input)
}
}
}
func TestSaveECDSA(t *testing.T) {
f, err := ioutil.TempFile("", "saveecdsa_test.*.txt")
if err != nil {
t.Fatal(err)
}
file := f.Name()
f.Close()
defer os.Remove(file)
key, _ := HexToECDSA(testPrivHex)
if err := SaveECDSA(file, key); err != nil {
t.Fatal(err)
}
loaded, err := LoadECDSA(file)
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(key, loaded) {
t.Fatal("loaded key not equal to saved key")
}
}
func TestValidateSignatureValues(t *testing.T) {
check := func(expected bool, v byte, r, s *big.Int) {
if ValidateSignatureValues(v, r, s, false) != expected {
t.Errorf("mismatch for v: %d r: %d s: %d want: %v", v, r, s, expected)
}
}
minusOne := big.NewInt(-1)
one := Big1
zero := new(big.Int)
secp256k1nMinus1 := new(big.Int).Sub(secp256k1N, Big1)
// correct v,r,s
check(true, 0, one, one)
check(true, 1, one, one)
// incorrect v, correct r,s,
check(false, 2, one, one)
check(false, 3, one, one)
// incorrect v, combinations of incorrect/correct r,s at lower limit
check(false, 2, zero, zero)
check(false, 2, zero, one)
check(false, 2, one, zero)
check(false, 2, one, one)
// correct v for any combination of incorrect r,s
check(false, 0, zero, zero)
check(false, 0, zero, one)
check(false, 0, one, zero)
check(false, 1, zero, zero)
check(false, 1, zero, one)
check(false, 1, one, zero)
// correct sig with max r,s
check(true, 0, secp256k1nMinus1, secp256k1nMinus1)
// correct v, combinations of incorrect r,s at upper limit
check(false, 0, secp256k1N, secp256k1nMinus1)
check(false, 0, secp256k1nMinus1, secp256k1N)
check(false, 0, secp256k1N, secp256k1N)
// current callers ensures r,s cannot be negative, but let's test for that too
// as crypto package could be used stand-alone
check(false, 0, minusOne, one)
check(false, 0, one, minusOne)
}
func checkhash(t *testing.T, name string, f func([]byte) []byte, msg, exp []byte) {
sum := f(msg)
if !bytes.Equal(exp, sum) {
t.Fatalf("hash %s mismatch: want: %x have: %x", name, exp, sum)
}
}
func checkAddr(t *testing.T, addr0, addr1 core.Address) {
if addr0 != addr1 {
t.Fatalf("address mismatch: want: %x have: %x", addr0, addr1)
}
}

24
restricted/crypto/ecies/.gitignore vendored Normal file
View File

@ -0,0 +1,24 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*~

View File

@ -0,0 +1,28 @@
Copyright (c) 2013 Kyle Isom <kyle@tyrfingr.is>
Copyright (c) 2012 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -0,0 +1,94 @@
# NOTE
This implementation is direct fork of Kylom's implementation. I claim no authorship over this code apart from some minor modifications.
Please be aware this code **has not yet been reviewed**.
ecies implements the Elliptic Curve Integrated Encryption Scheme.
The package is designed to be compliant with the appropriate NIST
standards, and therefore doesn't support the full SEC 1 algorithm set.
STATUS:
ecies should be ready for use. The ASN.1 support is only complete so
far as to supported the listed algorithms before.
CAVEATS
1. CMAC support is currently not present.
SUPPORTED ALGORITHMS
SYMMETRIC CIPHERS HASH FUNCTIONS
AES128 SHA-1
AES192 SHA-224
AES256 SHA-256
SHA-384
ELLIPTIC CURVE SHA-512
P256
P384 KEY DERIVATION FUNCTION
P521 NIST SP 800-65a Concatenation KDF
Curve P224 isn't supported because it does not provide a minimum security
level of AES128 with HMAC-SHA1. According to NIST SP 800-57, the security
level of P224 is 112 bits of security. Symmetric ciphers use CTR-mode;
message tags are computed using HMAC-<HASH> function.
CURVE SELECTION
According to NIST SP 800-57, the following curves should be selected:
+----------------+-------+
| SYMMETRIC SIZE | CURVE |
+----------------+-------+
| 128-bit | P256 |
+----------------+-------+
| 192-bit | P384 |
+----------------+-------+
| 256-bit | P521 |
+----------------+-------+
TODO
1. Look at serialising the parameters with the SEC 1 ASN.1 module.
2. Validate ASN.1 formats with SEC 1.
TEST VECTORS
The only test vectors I've found so far date from 1993, predating AES
and including only 163-bit curves. Therefore, there are no published
test vectors to compare to.
LICENSE
ecies is released under the same license as the Go source code. See the
LICENSE file for details.
REFERENCES
* SEC (Standard for Efficient Cryptography) 1, version 2.0: Elliptic
Curve Cryptography; Certicom, May 2009.
http://www.secg.org/sec1-v2.pdf
* GEC (Guidelines for Efficient Cryptography) 2, version 0.3: Test
Vectors for SEC 1; Certicom, September 1999.
http://read.pudn.com/downloads168/doc/772358/TestVectorsforSEC%201-gec2.pdf
* NIST SP 800-56a: Recommendation for Pair-Wise Key Establishment Schemes
Using Discrete Logarithm Cryptography. National Institute of Standards
and Technology, May 2007.
http://csrc.nist.gov/publications/nistpubs/800-56A/SP800-56A_Revision1_Mar08-2007.pdf
* Suite B Implementers Guide to NIST SP 800-56A. National Security
Agency, July 28, 2009.
http://www.nsa.gov/ia/_files/SuiteB_Implementer_G-113808.pdf
* NIST SP 800-57: Recommendation for Key Management Part 1: General
(Revision 3). National Institute of Standards and Technology, July
2012.
http://csrc.nist.gov/publications/nistpubs/800-57/sp800-57_part1_rev3_general.pdf

View File

@ -0,0 +1,317 @@
// Copyright (c) 2013 Kyle Isom <kyle@tyrfingr.is>
// Copyright (c) 2012 The Go Authors. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package ecies
import (
"crypto/cipher"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/hmac"
"crypto/subtle"
"encoding/binary"
"fmt"
"hash"
"io"
"math/big"
)
var (
ErrImport = fmt.Errorf("ecies: failed to import key")
ErrInvalidCurve = fmt.Errorf("ecies: invalid elliptic curve")
ErrInvalidPublicKey = fmt.Errorf("ecies: invalid public key")
ErrSharedKeyIsPointAtInfinity = fmt.Errorf("ecies: shared key is point at infinity")
ErrSharedKeyTooBig = fmt.Errorf("ecies: shared key params are too big")
)
// PublicKey is a representation of an elliptic curve public key.
type PublicKey struct {
X *big.Int
Y *big.Int
elliptic.Curve
Params *ECIESParams
}
// Export an ECIES public key as an ECDSA public key.
func (pub *PublicKey) ExportECDSA() *ecdsa.PublicKey {
return &ecdsa.PublicKey{Curve: pub.Curve, X: pub.X, Y: pub.Y}
}
// Import an ECDSA public key as an ECIES public key.
func ImportECDSAPublic(pub *ecdsa.PublicKey) *PublicKey {
return &PublicKey{
X: pub.X,
Y: pub.Y,
Curve: pub.Curve,
Params: ParamsFromCurve(pub.Curve),
}
}
// PrivateKey is a representation of an elliptic curve private key.
type PrivateKey struct {
PublicKey
D *big.Int
}
// Export an ECIES private key as an ECDSA private key.
func (prv *PrivateKey) ExportECDSA() *ecdsa.PrivateKey {
pub := &prv.PublicKey
pubECDSA := pub.ExportECDSA()
return &ecdsa.PrivateKey{PublicKey: *pubECDSA, D: prv.D}
}
// Import an ECDSA private key as an ECIES private key.
func ImportECDSA(prv *ecdsa.PrivateKey) *PrivateKey {
pub := ImportECDSAPublic(&prv.PublicKey)
return &PrivateKey{*pub, prv.D}
}
// Generate an elliptic curve public / private keypair. If params is nil,
// the recommended default parameters for the key will be chosen.
func GenerateKey(rand io.Reader, curve elliptic.Curve, params *ECIESParams) (prv *PrivateKey, err error) {
pb, x, y, err := elliptic.GenerateKey(curve, rand)
if err != nil {
return
}
prv = new(PrivateKey)
prv.PublicKey.X = x
prv.PublicKey.Y = y
prv.PublicKey.Curve = curve
prv.D = new(big.Int).SetBytes(pb)
if params == nil {
params = ParamsFromCurve(curve)
}
prv.PublicKey.Params = params
return
}
// MaxSharedKeyLength returns the maximum length of the shared key the
// public key can produce.
func MaxSharedKeyLength(pub *PublicKey) int {
return (pub.Curve.Params().BitSize + 7) / 8
}
// ECDH key agreement method used to establish secret keys for encryption.
func (prv *PrivateKey) GenerateShared(pub *PublicKey, skLen, macLen int) (sk []byte, err error) {
if prv.PublicKey.Curve != pub.Curve {
return nil, ErrInvalidCurve
}
if skLen+macLen > MaxSharedKeyLength(pub) {
return nil, ErrSharedKeyTooBig
}
x, _ := pub.Curve.ScalarMult(pub.X, pub.Y, prv.D.Bytes())
if x == nil {
return nil, ErrSharedKeyIsPointAtInfinity
}
sk = make([]byte, skLen+macLen)
skBytes := x.Bytes()
copy(sk[len(sk)-len(skBytes):], skBytes)
return sk, nil
}
var (
ErrSharedTooLong = fmt.Errorf("ecies: shared secret is too long")
ErrInvalidMessage = fmt.Errorf("ecies: invalid message")
)
// NIST SP 800-56 Concatenation Key Derivation Function (see section 5.8.1).
func concatKDF(hash hash.Hash, z, s1 []byte, kdLen int) []byte {
counterBytes := make([]byte, 4)
k := make([]byte, 0, roundup(kdLen, hash.Size()))
for counter := uint32(1); len(k) < kdLen; counter++ {
binary.BigEndian.PutUint32(counterBytes, counter)
hash.Reset()
hash.Write(counterBytes)
hash.Write(z)
hash.Write(s1)
k = hash.Sum(k)
}
return k[:kdLen]
}
// roundup rounds size up to the next multiple of blocksize.
func roundup(size, blocksize int) int {
return size + blocksize - (size % blocksize)
}
// deriveKeys creates the encryption and MAC keys using concatKDF.
func deriveKeys(hash hash.Hash, z, s1 []byte, keyLen int) (Ke, Km []byte) {
K := concatKDF(hash, z, s1, 2*keyLen)
Ke = K[:keyLen]
Km = K[keyLen:]
hash.Reset()
hash.Write(Km)
Km = hash.Sum(Km[:0])
return Ke, Km
}
// messageTag computes the MAC of a message (called the tag) as per
// SEC 1, 3.5.
func messageTag(hash func() hash.Hash, km, msg, shared []byte) []byte {
mac := hmac.New(hash, km)
mac.Write(msg)
mac.Write(shared)
tag := mac.Sum(nil)
return tag
}
// Generate an initialisation vector for CTR mode.
func generateIV(params *ECIESParams, rand io.Reader) (iv []byte, err error) {
iv = make([]byte, params.BlockSize)
_, err = io.ReadFull(rand, iv)
return
}
// symEncrypt carries out CTR encryption using the block cipher specified in the
func symEncrypt(rand io.Reader, params *ECIESParams, key, m []byte) (ct []byte, err error) {
c, err := params.Cipher(key)
if err != nil {
return
}
iv, err := generateIV(params, rand)
if err != nil {
return
}
ctr := cipher.NewCTR(c, iv)
ct = make([]byte, len(m)+params.BlockSize)
copy(ct, iv)
ctr.XORKeyStream(ct[params.BlockSize:], m)
return
}
// symDecrypt carries out CTR decryption using the block cipher specified in
// the parameters
func symDecrypt(params *ECIESParams, key, ct []byte) (m []byte, err error) {
c, err := params.Cipher(key)
if err != nil {
return
}
ctr := cipher.NewCTR(c, ct[:params.BlockSize])
m = make([]byte, len(ct)-params.BlockSize)
ctr.XORKeyStream(m, ct[params.BlockSize:])
return
}
// Encrypt encrypts a message using ECIES as specified in SEC 1, 5.1.
//
// s1 and s2 contain shared information that is not part of the resulting
// ciphertext. s1 is fed into key derivation, s2 is fed into the MAC. If the
// shared information parameters aren't being used, they should be nil.
func Encrypt(rand io.Reader, pub *PublicKey, m, s1, s2 []byte) (ct []byte, err error) {
params, err := pubkeyParams(pub)
if err != nil {
return nil, err
}
R, err := GenerateKey(rand, pub.Curve, params)
if err != nil {
return nil, err
}
z, err := R.GenerateShared(pub, params.KeyLen, params.KeyLen)
if err != nil {
return nil, err
}
hash := params.Hash()
Ke, Km := deriveKeys(hash, z, s1, params.KeyLen)
em, err := symEncrypt(rand, params, Ke, m)
if err != nil || len(em) <= params.BlockSize {
return nil, err
}
d := messageTag(params.Hash, Km, em, s2)
Rb := elliptic.Marshal(pub.Curve, R.PublicKey.X, R.PublicKey.Y)
ct = make([]byte, len(Rb)+len(em)+len(d))
copy(ct, Rb)
copy(ct[len(Rb):], em)
copy(ct[len(Rb)+len(em):], d)
return ct, nil
}
// Decrypt decrypts an ECIES ciphertext.
func (prv *PrivateKey) Decrypt(c, s1, s2 []byte) (m []byte, err error) {
if len(c) == 0 {
return nil, ErrInvalidMessage
}
params, err := pubkeyParams(&prv.PublicKey)
if err != nil {
return nil, err
}
hash := params.Hash()
var (
rLen int
hLen int = hash.Size()
mStart int
mEnd int
)
switch c[0] {
case 2, 3, 4:
rLen = (prv.PublicKey.Curve.Params().BitSize + 7) / 4
if len(c) < (rLen + hLen + 1) {
return nil, ErrInvalidMessage
}
default:
return nil, ErrInvalidPublicKey
}
mStart = rLen
mEnd = len(c) - hLen
R := new(PublicKey)
R.Curve = prv.PublicKey.Curve
R.X, R.Y = elliptic.Unmarshal(R.Curve, c[:rLen])
if R.X == nil {
return nil, ErrInvalidPublicKey
}
z, err := prv.GenerateShared(R, params.KeyLen, params.KeyLen)
if err != nil {
return nil, err
}
Ke, Km := deriveKeys(hash, z, s1, params.KeyLen)
d := messageTag(params.Hash, Km, c[mStart:mEnd], s2)
if subtle.ConstantTimeCompare(c[mEnd:], d) != 1 {
return nil, ErrInvalidMessage
}
return symDecrypt(params, Ke, c[mStart:mEnd])
}

View File

@ -0,0 +1,430 @@
// Copyright (c) 2013 Kyle Isom <kyle@tyrfingr.is>
// Copyright (c) 2012 The Go Authors. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package ecies
import (
"bytes"
"crypto/elliptic"
"crypto/rand"
"crypto/sha256"
"encoding/hex"
"fmt"
"math/big"
"testing"
"github.com/ethereum/go-ethereum/crypto"
)
func TestKDF(t *testing.T) {
tests := []struct {
length int
output []byte
}{
{6, decode("858b192fa2ed")},
{32, decode("858b192fa2ed4395e2bf88dd8d5770d67dc284ee539f12da8bceaa45d06ebae0")},
{48, decode("858b192fa2ed4395e2bf88dd8d5770d67dc284ee539f12da8bceaa45d06ebae0700f1ab918a5f0413b8140f9940d6955")},
{64, decode("858b192fa2ed4395e2bf88dd8d5770d67dc284ee539f12da8bceaa45d06ebae0700f1ab918a5f0413b8140f9940d6955f3467fd6672cce1024c5b1effccc0f61")},
}
for _, test := range tests {
h := sha256.New()
k := concatKDF(h, []byte("input"), nil, test.length)
if !bytes.Equal(k, test.output) {
t.Fatalf("KDF: generated key %x does not match expected output %x", k, test.output)
}
}
}
var ErrBadSharedKeys = fmt.Errorf("ecies: shared keys don't match")
// cmpParams compares a set of ECIES parameters. We assume, as per the
// docs, that AES is the only supported symmetric encryption algorithm.
func cmpParams(p1, p2 *ECIESParams) bool {
return p1.hashAlgo == p2.hashAlgo &&
p1.KeyLen == p2.KeyLen &&
p1.BlockSize == p2.BlockSize
}
// Validate the ECDH component.
func TestSharedKey(t *testing.T) {
prv1, err := GenerateKey(rand.Reader, DefaultCurve, nil)
if err != nil {
t.Fatal(err)
}
skLen := MaxSharedKeyLength(&prv1.PublicKey) / 2
prv2, err := GenerateKey(rand.Reader, DefaultCurve, nil)
if err != nil {
t.Fatal(err)
}
sk1, err := prv1.GenerateShared(&prv2.PublicKey, skLen, skLen)
if err != nil {
t.Fatal(err)
}
sk2, err := prv2.GenerateShared(&prv1.PublicKey, skLen, skLen)
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(sk1, sk2) {
t.Fatal(ErrBadSharedKeys)
}
}
func TestSharedKeyPadding(t *testing.T) {
// sanity checks
prv0 := hexKey("1adf5c18167d96a1f9a0b1ef63be8aa27eaf6032c233b2b38f7850cf5b859fd9")
prv1 := hexKey("0097a076fc7fcd9208240668e31c9abee952cbb6e375d1b8febc7499d6e16f1a")
x0, _ := new(big.Int).SetString("1a8ed022ff7aec59dc1b440446bdda5ff6bcb3509a8b109077282b361efffbd8", 16)
x1, _ := new(big.Int).SetString("6ab3ac374251f638d0abb3ef596d1dc67955b507c104e5f2009724812dc027b8", 16)
y0, _ := new(big.Int).SetString("e040bd480b1deccc3bc40bd5b1fdcb7bfd352500b477cb9471366dbd4493f923", 16)
y1, _ := new(big.Int).SetString("8ad915f2b503a8be6facab6588731fefeb584fd2dfa9a77a5e0bba1ec439e4fa", 16)
if prv0.PublicKey.X.Cmp(x0) != 0 {
t.Errorf("mismatched prv0.X:\nhave: %x\nwant: %x\n", prv0.PublicKey.X.Bytes(), x0.Bytes())
}
if prv0.PublicKey.Y.Cmp(y0) != 0 {
t.Errorf("mismatched prv0.Y:\nhave: %x\nwant: %x\n", prv0.PublicKey.Y.Bytes(), y0.Bytes())
}
if prv1.PublicKey.X.Cmp(x1) != 0 {
t.Errorf("mismatched prv1.X:\nhave: %x\nwant: %x\n", prv1.PublicKey.X.Bytes(), x1.Bytes())
}
if prv1.PublicKey.Y.Cmp(y1) != 0 {
t.Errorf("mismatched prv1.Y:\nhave: %x\nwant: %x\n", prv1.PublicKey.Y.Bytes(), y1.Bytes())
}
// test shared secret generation
sk1, err := prv0.GenerateShared(&prv1.PublicKey, 16, 16)
if err != nil {
t.Log(err.Error())
}
sk2, err := prv1.GenerateShared(&prv0.PublicKey, 16, 16)
if err != nil {
t.Fatal(err.Error())
}
if !bytes.Equal(sk1, sk2) {
t.Fatal(ErrBadSharedKeys.Error())
}
}
// Verify that the key generation code fails when too much key data is
// requested.
func TestTooBigSharedKey(t *testing.T) {
prv1, err := GenerateKey(rand.Reader, DefaultCurve, nil)
if err != nil {
t.Fatal(err)
}
prv2, err := GenerateKey(rand.Reader, DefaultCurve, nil)
if err != nil {
t.Fatal(err)
}
_, err = prv1.GenerateShared(&prv2.PublicKey, 32, 32)
if err != ErrSharedKeyTooBig {
t.Fatal("ecdh: shared key should be too large for curve")
}
_, err = prv2.GenerateShared(&prv1.PublicKey, 32, 32)
if err != ErrSharedKeyTooBig {
t.Fatal("ecdh: shared key should be too large for curve")
}
}
// Benchmark the generation of P256 keys.
func BenchmarkGenerateKeyP256(b *testing.B) {
for i := 0; i < b.N; i++ {
if _, err := GenerateKey(rand.Reader, elliptic.P256(), nil); err != nil {
b.Fatal(err)
}
}
}
// Benchmark the generation of P256 shared keys.
func BenchmarkGenSharedKeyP256(b *testing.B) {
prv, err := GenerateKey(rand.Reader, elliptic.P256(), nil)
if err != nil {
b.Fatal(err)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, err := prv.GenerateShared(&prv.PublicKey, 16, 16)
if err != nil {
b.Fatal(err)
}
}
}
// Benchmark the generation of S256 shared keys.
func BenchmarkGenSharedKeyS256(b *testing.B) {
prv, err := GenerateKey(rand.Reader, crypto.S256(), nil)
if err != nil {
b.Fatal(err)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, err := prv.GenerateShared(&prv.PublicKey, 16, 16)
if err != nil {
b.Fatal(err)
}
}
}
// Verify that an encrypted message can be successfully decrypted.
func TestEncryptDecrypt(t *testing.T) {
prv1, err := GenerateKey(rand.Reader, DefaultCurve, nil)
if err != nil {
t.Fatal(err)
}
prv2, err := GenerateKey(rand.Reader, DefaultCurve, nil)
if err != nil {
t.Fatal(err)
}
message := []byte("Hello, world.")
ct, err := Encrypt(rand.Reader, &prv2.PublicKey, message, nil, nil)
if err != nil {
t.Fatal(err)
}
pt, err := prv2.Decrypt(ct, nil, nil)
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(pt, message) {
t.Fatal("ecies: plaintext doesn't match message")
}
_, err = prv1.Decrypt(ct, nil, nil)
if err == nil {
t.Fatal("ecies: encryption should not have succeeded")
}
}
func TestDecryptShared2(t *testing.T) {
prv, err := GenerateKey(rand.Reader, DefaultCurve, nil)
if err != nil {
t.Fatal(err)
}
message := []byte("Hello, world.")
shared2 := []byte("shared data 2")
ct, err := Encrypt(rand.Reader, &prv.PublicKey, message, nil, shared2)
if err != nil {
t.Fatal(err)
}
// Check that decrypting with correct shared data works.
pt, err := prv.Decrypt(ct, nil, shared2)
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(pt, message) {
t.Fatal("ecies: plaintext doesn't match message")
}
// Decrypting without shared data or incorrect shared data fails.
if _, err = prv.Decrypt(ct, nil, nil); err == nil {
t.Fatal("ecies: decrypting without shared data didn't fail")
}
if _, err = prv.Decrypt(ct, nil, []byte("garbage")); err == nil {
t.Fatal("ecies: decrypting with incorrect shared data didn't fail")
}
}
type testCase struct {
Curve elliptic.Curve
Name string
Expected *ECIESParams
}
var testCases = []testCase{
{
Curve: elliptic.P256(),
Name: "P256",
Expected: ECIES_AES128_SHA256,
},
{
Curve: elliptic.P384(),
Name: "P384",
Expected: ECIES_AES256_SHA384,
},
{
Curve: elliptic.P521(),
Name: "P521",
Expected: ECIES_AES256_SHA512,
},
}
// Test parameter selection for each curve, and that P224 fails automatic
// parameter selection (see README for a discussion of P224). Ensures that
// selecting a set of parameters automatically for the given curve works.
func TestParamSelection(t *testing.T) {
for _, c := range testCases {
testParamSelection(t, c)
}
}
func testParamSelection(t *testing.T, c testCase) {
params := ParamsFromCurve(c.Curve)
if params == nil {
t.Fatal("ParamsFromCurve returned nil")
} else if params != nil && !cmpParams(params, c.Expected) {
t.Fatalf("ecies: parameters should be invalid (%s)\n", c.Name)
}
prv1, err := GenerateKey(rand.Reader, DefaultCurve, nil)
if err != nil {
t.Fatalf("%s (%s)\n", err.Error(), c.Name)
}
prv2, err := GenerateKey(rand.Reader, DefaultCurve, nil)
if err != nil {
t.Fatalf("%s (%s)\n", err.Error(), c.Name)
}
message := []byte("Hello, world.")
ct, err := Encrypt(rand.Reader, &prv2.PublicKey, message, nil, nil)
if err != nil {
t.Fatalf("%s (%s)\n", err.Error(), c.Name)
}
pt, err := prv2.Decrypt(ct, nil, nil)
if err != nil {
t.Fatalf("%s (%s)\n", err.Error(), c.Name)
}
if !bytes.Equal(pt, message) {
t.Fatalf("ecies: plaintext doesn't match message (%s)\n", c.Name)
}
_, err = prv1.Decrypt(ct, nil, nil)
if err == nil {
t.Fatalf("ecies: encryption should not have succeeded (%s)\n", c.Name)
}
}
// Ensure that the basic public key validation in the decryption operation
// works.
func TestBasicKeyValidation(t *testing.T) {
badBytes := []byte{0, 1, 5, 6, 7, 8, 9}
prv, err := GenerateKey(rand.Reader, DefaultCurve, nil)
if err != nil {
t.Fatal(err)
}
message := []byte("Hello, world.")
ct, err := Encrypt(rand.Reader, &prv.PublicKey, message, nil, nil)
if err != nil {
t.Fatal(err)
}
for _, b := range badBytes {
ct[0] = b
_, err := prv.Decrypt(ct, nil, nil)
if err != ErrInvalidPublicKey {
t.Fatal("ecies: validated an invalid key")
}
}
}
func TestBox(t *testing.T) {
prv1 := hexKey("4b50fa71f5c3eeb8fdc452224b2395af2fcc3d125e06c32c82e048c0559db03f")
prv2 := hexKey("d0b043b4c5d657670778242d82d68a29d25d7d711127d17b8e299f156dad361a")
pub2 := &prv2.PublicKey
message := []byte("Hello, world.")
ct, err := Encrypt(rand.Reader, pub2, message, nil, nil)
if err != nil {
t.Fatal(err)
}
pt, err := prv2.Decrypt(ct, nil, nil)
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(pt, message) {
t.Fatal("ecies: plaintext doesn't match message")
}
if _, err = prv1.Decrypt(ct, nil, nil); err == nil {
t.Fatal("ecies: encryption should not have succeeded")
}
}
// Verify GenerateShared against static values - useful when
// debugging changes in underlying libs
func TestSharedKeyStatic(t *testing.T) {
prv1 := hexKey("7ebbc6a8358bc76dd73ebc557056702c8cfc34e5cfcd90eb83af0347575fd2ad")
prv2 := hexKey("6a3d6396903245bba5837752b9e0348874e72db0c4e11e9c485a81b4ea4353b9")
skLen := MaxSharedKeyLength(&prv1.PublicKey) / 2
sk1, err := prv1.GenerateShared(&prv2.PublicKey, skLen, skLen)
if err != nil {
t.Fatal(err)
}
sk2, err := prv2.GenerateShared(&prv1.PublicKey, skLen, skLen)
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(sk1, sk2) {
t.Fatal(ErrBadSharedKeys)
}
sk := decode("167ccc13ac5e8a26b131c3446030c60fbfac6aa8e31149d0869f93626a4cdf62")
if !bytes.Equal(sk1, sk) {
t.Fatalf("shared secret mismatch: want: %x have: %x", sk, sk1)
}
}
func hexKey(prv string) *PrivateKey {
key, err := crypto.HexToECDSA(prv)
if err != nil {
panic(err)
}
return ImportECDSA(key)
}
func decode(s string) []byte {
bytes, err := hex.DecodeString(s)
if err != nil {
panic(err)
}
return bytes
}

View File

@ -0,0 +1,136 @@
// Copyright (c) 2013 Kyle Isom <kyle@tyrfingr.is>
// Copyright (c) 2012 The Go Authors. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package ecies
// This file contains parameters for ECIES encryption, specifying the
// symmetric encryption and HMAC parameters.
import (
"crypto"
"crypto/aes"
"crypto/cipher"
"crypto/elliptic"
"crypto/sha256"
"crypto/sha512"
"fmt"
"hash"
ethcrypto "github.com/ethereum/go-ethereum/crypto"
)
var (
DefaultCurve = ethcrypto.S256()
ErrUnsupportedECDHAlgorithm = fmt.Errorf("ecies: unsupported ECDH algorithm")
ErrUnsupportedECIESParameters = fmt.Errorf("ecies: unsupported ECIES parameters")
ErrInvalidKeyLen = fmt.Errorf("ecies: invalid key size (> %d) in ECIESParams", maxKeyLen)
)
// KeyLen is limited to prevent overflow of the counter
// in concatKDF. While the theoretical limit is much higher,
// no known cipher uses keys larger than 512 bytes.
const maxKeyLen = 512
type ECIESParams struct {
Hash func() hash.Hash // hash function
hashAlgo crypto.Hash
Cipher func([]byte) (cipher.Block, error) // symmetric cipher
BlockSize int // block size of symmetric cipher
KeyLen int // length of symmetric key
}
// Standard ECIES parameters:
// * ECIES using AES128 and HMAC-SHA-256-16
// * ECIES using AES256 and HMAC-SHA-256-32
// * ECIES using AES256 and HMAC-SHA-384-48
// * ECIES using AES256 and HMAC-SHA-512-64
var (
ECIES_AES128_SHA256 = &ECIESParams{
Hash: sha256.New,
hashAlgo: crypto.SHA256,
Cipher: aes.NewCipher,
BlockSize: aes.BlockSize,
KeyLen: 16,
}
ECIES_AES256_SHA256 = &ECIESParams{
Hash: sha256.New,
hashAlgo: crypto.SHA256,
Cipher: aes.NewCipher,
BlockSize: aes.BlockSize,
KeyLen: 32,
}
ECIES_AES256_SHA384 = &ECIESParams{
Hash: sha512.New384,
hashAlgo: crypto.SHA384,
Cipher: aes.NewCipher,
BlockSize: aes.BlockSize,
KeyLen: 32,
}
ECIES_AES256_SHA512 = &ECIESParams{
Hash: sha512.New,
hashAlgo: crypto.SHA512,
Cipher: aes.NewCipher,
BlockSize: aes.BlockSize,
KeyLen: 32,
}
)
var paramsFromCurve = map[elliptic.Curve]*ECIESParams{
ethcrypto.S256(): ECIES_AES128_SHA256,
elliptic.P256(): ECIES_AES128_SHA256,
elliptic.P384(): ECIES_AES256_SHA384,
elliptic.P521(): ECIES_AES256_SHA512,
}
func AddParamsForCurve(curve elliptic.Curve, params *ECIESParams) {
paramsFromCurve[curve] = params
}
// ParamsFromCurve selects parameters optimal for the selected elliptic curve.
// Only the curves P256, P384, and P512 are supported.
func ParamsFromCurve(curve elliptic.Curve) (params *ECIESParams) {
return paramsFromCurve[curve]
}
func pubkeyParams(key *PublicKey) (*ECIESParams, error) {
params := key.Params
if params == nil {
if params = ParamsFromCurve(key.Curve); params == nil {
return nil, ErrUnsupportedECIESParameters
}
}
if params.KeyLen > maxKeyLen {
return nil, ErrInvalidKeyLen
}
return params, nil
}

24
restricted/crypto/secp256k1/.gitignore vendored Normal file
View File

@ -0,0 +1,24 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*~

View File

@ -0,0 +1,31 @@
Copyright (c) 2010 The Go Authors. All rights reserved.
Copyright (c) 2011 ThePiachu. All rights reserved.
Copyright (c) 2015 Jeffrey Wilcke. All rights reserved.
Copyright (c) 2015 Felix Lange. All rights reserved.
Copyright (c) 2015 Gustav Simonsson. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of the copyright holder. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -0,0 +1,298 @@
// Copyright 2010 The Go Authors. All rights reserved.
// Copyright 2011 ThePiachu. All rights reserved.
// Copyright 2015 Jeffrey Wilcke, Felix Lange, Gustav Simonsson. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
// * The name of ThePiachu may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package secp256k1
import (
"crypto/elliptic"
"math/big"
)
const (
// number of bits in a big.Word
wordBits = 32 << (uint64(^big.Word(0)) >> 63)
// number of bytes in a big.Word
wordBytes = wordBits / 8
)
// readBits encodes the absolute value of bigint as big-endian bytes. Callers
// must ensure that buf has enough space. If buf is too short the result will
// be incomplete.
func readBits(bigint *big.Int, buf []byte) {
i := len(buf)
for _, d := range bigint.Bits() {
for j := 0; j < wordBytes && i > 0; j++ {
i--
buf[i] = byte(d)
d >>= 8
}
}
}
// This code is from https://github.com/ThePiachu/GoBit and implements
// several Koblitz elliptic curves over prime fields.
//
// The curve methods, internally, on Jacobian coordinates. For a given
// (x, y) position on the curve, the Jacobian coordinates are (x1, y1,
// z1) where x = x1/z1² and y = y1/z1³. The greatest speedups come
// when the whole calculation can be performed within the transform
// (as in ScalarMult and ScalarBaseMult). But even for Add and Double,
// it's faster to apply and reverse the transform than to operate in
// affine coordinates.
// A BitCurve represents a Koblitz Curve with a=0.
// See http://www.hyperelliptic.org/EFD/g1p/auto-shortw.html
type BitCurve struct {
P *big.Int // the order of the underlying field
N *big.Int // the order of the base point
B *big.Int // the constant of the BitCurve equation
Gx, Gy *big.Int // (x,y) of the base point
BitSize int // the size of the underlying field
}
func (BitCurve *BitCurve) Params() *elliptic.CurveParams {
return &elliptic.CurveParams{
P: BitCurve.P,
N: BitCurve.N,
B: BitCurve.B,
Gx: BitCurve.Gx,
Gy: BitCurve.Gy,
BitSize: BitCurve.BitSize,
}
}
// IsOnCurve returns true if the given (x,y) lies on the BitCurve.
func (BitCurve *BitCurve) IsOnCurve(x, y *big.Int) bool {
// y² = x³ + b
y2 := new(big.Int).Mul(y, y) //y²
y2.Mod(y2, BitCurve.P) //y²%P
x3 := new(big.Int).Mul(x, x) //x²
x3.Mul(x3, x) //x³
x3.Add(x3, BitCurve.B) //x³+B
x3.Mod(x3, BitCurve.P) //(x³+B)%P
return x3.Cmp(y2) == 0
}
//TODO: double check if the function is okay
// affineFromJacobian reverses the Jacobian transform. See the comment at the
// top of the file.
func (BitCurve *BitCurve) affineFromJacobian(x, y, z *big.Int) (xOut, yOut *big.Int) {
if z.Sign() == 0 {
return new(big.Int), new(big.Int)
}
zinv := new(big.Int).ModInverse(z, BitCurve.P)
zinvsq := new(big.Int).Mul(zinv, zinv)
xOut = new(big.Int).Mul(x, zinvsq)
xOut.Mod(xOut, BitCurve.P)
zinvsq.Mul(zinvsq, zinv)
yOut = new(big.Int).Mul(y, zinvsq)
yOut.Mod(yOut, BitCurve.P)
return
}
// Add returns the sum of (x1,y1) and (x2,y2)
func (BitCurve *BitCurve) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) {
// If one point is at infinity, return the other point.
// Adding the point at infinity to any point will preserve the other point.
if x1.Sign() == 0 && y1.Sign() == 0 {
return x2, y2
}
if x2.Sign() == 0 && y2.Sign() == 0 {
return x1, y1
}
z := new(big.Int).SetInt64(1)
if x1.Cmp(x2) == 0 && y1.Cmp(y2) == 0 {
return BitCurve.affineFromJacobian(BitCurve.doubleJacobian(x1, y1, z))
}
return BitCurve.affineFromJacobian(BitCurve.addJacobian(x1, y1, z, x2, y2, z))
}
// addJacobian takes two points in Jacobian coordinates, (x1, y1, z1) and
// (x2, y2, z2) and returns their sum, also in Jacobian form.
func (BitCurve *BitCurve) addJacobian(x1, y1, z1, x2, y2, z2 *big.Int) (*big.Int, *big.Int, *big.Int) {
// See http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl
z1z1 := new(big.Int).Mul(z1, z1)
z1z1.Mod(z1z1, BitCurve.P)
z2z2 := new(big.Int).Mul(z2, z2)
z2z2.Mod(z2z2, BitCurve.P)
u1 := new(big.Int).Mul(x1, z2z2)
u1.Mod(u1, BitCurve.P)
u2 := new(big.Int).Mul(x2, z1z1)
u2.Mod(u2, BitCurve.P)
h := new(big.Int).Sub(u2, u1)
if h.Sign() == -1 {
h.Add(h, BitCurve.P)
}
i := new(big.Int).Lsh(h, 1)
i.Mul(i, i)
j := new(big.Int).Mul(h, i)
s1 := new(big.Int).Mul(y1, z2)
s1.Mul(s1, z2z2)
s1.Mod(s1, BitCurve.P)
s2 := new(big.Int).Mul(y2, z1)
s2.Mul(s2, z1z1)
s2.Mod(s2, BitCurve.P)
r := new(big.Int).Sub(s2, s1)
if r.Sign() == -1 {
r.Add(r, BitCurve.P)
}
r.Lsh(r, 1)
v := new(big.Int).Mul(u1, i)
x3 := new(big.Int).Set(r)
x3.Mul(x3, x3)
x3.Sub(x3, j)
x3.Sub(x3, v)
x3.Sub(x3, v)
x3.Mod(x3, BitCurve.P)
y3 := new(big.Int).Set(r)
v.Sub(v, x3)
y3.Mul(y3, v)
s1.Mul(s1, j)
s1.Lsh(s1, 1)
y3.Sub(y3, s1)
y3.Mod(y3, BitCurve.P)
z3 := new(big.Int).Add(z1, z2)
z3.Mul(z3, z3)
z3.Sub(z3, z1z1)
if z3.Sign() == -1 {
z3.Add(z3, BitCurve.P)
}
z3.Sub(z3, z2z2)
if z3.Sign() == -1 {
z3.Add(z3, BitCurve.P)
}
z3.Mul(z3, h)
z3.Mod(z3, BitCurve.P)
return x3, y3, z3
}
// Double returns 2*(x,y)
func (BitCurve *BitCurve) Double(x1, y1 *big.Int) (*big.Int, *big.Int) {
z1 := new(big.Int).SetInt64(1)
return BitCurve.affineFromJacobian(BitCurve.doubleJacobian(x1, y1, z1))
}
// doubleJacobian takes a point in Jacobian coordinates, (x, y, z), and
// returns its double, also in Jacobian form.
func (BitCurve *BitCurve) doubleJacobian(x, y, z *big.Int) (*big.Int, *big.Int, *big.Int) {
// See http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l
a := new(big.Int).Mul(x, x) //X1²
b := new(big.Int).Mul(y, y) //Y1²
c := new(big.Int).Mul(b, b) //B²
d := new(big.Int).Add(x, b) //X1+B
d.Mul(d, d) //(X1+B)²
d.Sub(d, a) //(X1+B)²-A
d.Sub(d, c) //(X1+B)²-A-C
d.Mul(d, big.NewInt(2)) //2*((X1+B)²-A-C)
e := new(big.Int).Mul(big.NewInt(3), a) //3*A
f := new(big.Int).Mul(e, e) //E²
x3 := new(big.Int).Mul(big.NewInt(2), d) //2*D
x3.Sub(f, x3) //F-2*D
x3.Mod(x3, BitCurve.P)
y3 := new(big.Int).Sub(d, x3) //D-X3
y3.Mul(e, y3) //E*(D-X3)
y3.Sub(y3, new(big.Int).Mul(big.NewInt(8), c)) //E*(D-X3)-8*C
y3.Mod(y3, BitCurve.P)
z3 := new(big.Int).Mul(y, z) //Y1*Z1
z3.Mul(big.NewInt(2), z3) //3*Y1*Z1
z3.Mod(z3, BitCurve.P)
return x3, y3, z3
}
// ScalarBaseMult returns k*G, where G is the base point of the group and k is
// an integer in big-endian form.
func (BitCurve *BitCurve) ScalarBaseMult(k []byte) (*big.Int, *big.Int) {
return BitCurve.ScalarMult(BitCurve.Gx, BitCurve.Gy, k)
}
// Marshal converts a point into the form specified in section 4.3.6 of ANSI
// X9.62.
func (BitCurve *BitCurve) Marshal(x, y *big.Int) []byte {
byteLen := (BitCurve.BitSize + 7) >> 3
ret := make([]byte, 1+2*byteLen)
ret[0] = 4 // uncompressed point flag
readBits(x, ret[1:1+byteLen])
readBits(y, ret[1+byteLen:])
return ret
}
// Unmarshal converts a point, serialised by Marshal, into an x, y pair. On
// error, x = nil.
func (BitCurve *BitCurve) Unmarshal(data []byte) (x, y *big.Int) {
byteLen := (BitCurve.BitSize + 7) >> 3
if len(data) != 1+2*byteLen {
return
}
if data[0] != 4 { // uncompressed form
return
}
x = new(big.Int).SetBytes(data[1 : 1+byteLen])
y = new(big.Int).SetBytes(data[1+byteLen:])
return
}
var theCurve = new(BitCurve)
func init() {
// See SEC 2 section 2.7.1
// curve parameters taken from:
// http://www.secg.org/sec2-v2.pdf
theCurve.P, _ = new(big.Int).SetString("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", 0)
theCurve.N, _ = new(big.Int).SetString("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", 0)
theCurve.B, _ = new(big.Int).SetString("0x0000000000000000000000000000000000000000000000000000000000000007", 0)
theCurve.Gx, _ = new(big.Int).SetString("0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", 0)
theCurve.Gy, _ = new(big.Int).SetString("0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8", 0)
theCurve.BitSize = 256
}
// S256 returns a BitCurve which implements secp256k1.
func S256() *BitCurve {
return theCurve
}

View File

@ -0,0 +1,20 @@
// +build dummy
// This file is part of a workaround for `go mod vendor` which won't vendor
// C files if there's no Go file in the same directory.
// This would prevent the crypto/secp256k1/libsecp256k1/include/secp256k1.h file to be vendored.
//
// This Go file imports the c directory where there is another dummy.go file which
// is the second part of this workaround.
//
// These two files combined make it so `go mod vendor` behaves correctly.
//
// See this issue for reference: https://github.com/golang/go/issues/26366
package secp256k1
import (
_ "github.com/ethereum/go-ethereum/crypto/secp256k1/libsecp256k1/include"
_ "github.com/ethereum/go-ethereum/crypto/secp256k1/libsecp256k1/src"
_ "github.com/ethereum/go-ethereum/crypto/secp256k1/libsecp256k1/src/modules/recovery"
)

View File

@ -0,0 +1,130 @@
// Copyright 2015 Jeffrey Wilcke, Felix Lange, Gustav Simonsson. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be found in
// the LICENSE file.
// secp256k1_context_create_sign_verify creates a context for signing and signature verification.
static secp256k1_context* secp256k1_context_create_sign_verify() {
return secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
}
// secp256k1_ext_ecdsa_recover recovers the public key of an encoded compact signature.
//
// Returns: 1: recovery was successful
// 0: recovery was not successful
// Args: ctx: pointer to a context object (cannot be NULL)
// Out: pubkey_out: the serialized 65-byte public key of the signer (cannot be NULL)
// In: sigdata: pointer to a 65-byte signature with the recovery id at the end (cannot be NULL)
// msgdata: pointer to a 32-byte message (cannot be NULL)
static int secp256k1_ext_ecdsa_recover(
const secp256k1_context* ctx,
unsigned char *pubkey_out,
const unsigned char *sigdata,
const unsigned char *msgdata
) {
secp256k1_ecdsa_recoverable_signature sig;
secp256k1_pubkey pubkey;
if (!secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &sig, sigdata, (int)sigdata[64])) {
return 0;
}
if (!secp256k1_ecdsa_recover(ctx, &pubkey, &sig, msgdata)) {
return 0;
}
size_t outputlen = 65;
return secp256k1_ec_pubkey_serialize(ctx, pubkey_out, &outputlen, &pubkey, SECP256K1_EC_UNCOMPRESSED);
}
// secp256k1_ext_ecdsa_verify verifies an encoded compact signature.
//
// Returns: 1: signature is valid
// 0: signature is invalid
// Args: ctx: pointer to a context object (cannot be NULL)
// In: sigdata: pointer to a 64-byte signature (cannot be NULL)
// msgdata: pointer to a 32-byte message (cannot be NULL)
// pubkeydata: pointer to public key data (cannot be NULL)
// pubkeylen: length of pubkeydata
static int secp256k1_ext_ecdsa_verify(
const secp256k1_context* ctx,
const unsigned char *sigdata,
const unsigned char *msgdata,
const unsigned char *pubkeydata,
size_t pubkeylen
) {
secp256k1_ecdsa_signature sig;
secp256k1_pubkey pubkey;
if (!secp256k1_ecdsa_signature_parse_compact(ctx, &sig, sigdata)) {
return 0;
}
if (!secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeydata, pubkeylen)) {
return 0;
}
return secp256k1_ecdsa_verify(ctx, &sig, msgdata, &pubkey);
}
// secp256k1_ext_reencode_pubkey decodes then encodes a public key. It can be used to
// convert between public key formats. The input/output formats are chosen depending on the
// length of the input/output buffers.
//
// Returns: 1: conversion successful
// 0: conversion unsuccessful
// Args: ctx: pointer to a context object (cannot be NULL)
// Out: out: output buffer that will contain the reencoded key (cannot be NULL)
// In: outlen: length of out (33 for compressed keys, 65 for uncompressed keys)
// pubkeydata: the input public key (cannot be NULL)
// pubkeylen: length of pubkeydata
static int secp256k1_ext_reencode_pubkey(
const secp256k1_context* ctx,
unsigned char *out,
size_t outlen,
const unsigned char *pubkeydata,
size_t pubkeylen
) {
secp256k1_pubkey pubkey;
if (!secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeydata, pubkeylen)) {
return 0;
}
unsigned int flag = (outlen == 33) ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED;
return secp256k1_ec_pubkey_serialize(ctx, out, &outlen, &pubkey, flag);
}
// secp256k1_ext_scalar_mul multiplies a point by a scalar in constant time.
//
// Returns: 1: multiplication was successful
// 0: scalar was invalid (zero or overflow)
// Args: ctx: pointer to a context object (cannot be NULL)
// Out: point: the multiplied point (usually secret)
// In: point: pointer to a 64-byte public point,
// encoded as two 256bit big-endian numbers.
// scalar: a 32-byte scalar with which to multiply the point
int secp256k1_ext_scalar_mul(const secp256k1_context* ctx, unsigned char *point, const unsigned char *scalar) {
int ret = 0;
int overflow = 0;
secp256k1_fe feX, feY;
secp256k1_gej res;
secp256k1_ge ge;
secp256k1_scalar s;
ARG_CHECK(point != NULL);
ARG_CHECK(scalar != NULL);
(void)ctx;
secp256k1_fe_set_b32(&feX, point);
secp256k1_fe_set_b32(&feY, point+32);
secp256k1_ge_set_xy(&ge, &feX, &feY);
secp256k1_scalar_set_b32(&s, scalar, &overflow);
if (overflow || secp256k1_scalar_is_zero(&s)) {
ret = 0;
} else {
secp256k1_ecmult_const(&res, &ge, &s);
secp256k1_ge_set_gej(&ge, &res);
/* Note: can't use secp256k1_pubkey_save here because it is not constant time. */
secp256k1_fe_normalize(&ge.x);
secp256k1_fe_normalize(&ge.y);
secp256k1_fe_get_b32(point, &ge.x);
secp256k1_fe_get_b32(point+32, &ge.y);
ret = 1;
}
secp256k1_scalar_clear(&s);
return ret;
}

View File

@ -0,0 +1,49 @@
bench_inv
bench_ecdh
bench_sign
bench_verify
bench_schnorr_verify
bench_recover
bench_internal
tests
exhaustive_tests
gen_context
*.exe
*.so
*.a
!.gitignore
Makefile
configure
.libs/
Makefile.in
aclocal.m4
autom4te.cache/
config.log
config.status
*.tar.gz
*.la
libtool
.deps/
.dirstamp
*.lo
*.o
*~
src/libsecp256k1-config.h
src/libsecp256k1-config.h.in
src/ecmult_static_context.h
build-aux/config.guess
build-aux/config.sub
build-aux/depcomp
build-aux/install-sh
build-aux/ltmain.sh
build-aux/m4/libtool.m4
build-aux/m4/lt~obsolete.m4
build-aux/m4/ltoptions.m4
build-aux/m4/ltsugar.m4
build-aux/m4/ltversion.m4
build-aux/missing
build-aux/compile
build-aux/test-driver
src/stamp-h1
libsecp256k1.pc

View File

@ -0,0 +1,69 @@
language: c
sudo: false
addons:
apt:
packages: libgmp-dev
compiler:
- clang
- gcc
cache:
directories:
- src/java/guava/
env:
global:
- FIELD=auto BIGNUM=auto SCALAR=auto ENDOMORPHISM=no STATICPRECOMPUTATION=yes ASM=no BUILD=check EXTRAFLAGS= HOST= ECDH=no RECOVERY=no EXPERIMENTAL=no
- GUAVA_URL=https://search.maven.org/remotecontent?filepath=com/google/guava/guava/18.0/guava-18.0.jar GUAVA_JAR=src/java/guava/guava-18.0.jar
matrix:
- SCALAR=32bit RECOVERY=yes
- SCALAR=32bit FIELD=32bit ECDH=yes EXPERIMENTAL=yes
- SCALAR=64bit
- FIELD=64bit RECOVERY=yes
- FIELD=64bit ENDOMORPHISM=yes
- FIELD=64bit ENDOMORPHISM=yes ECDH=yes EXPERIMENTAL=yes
- FIELD=64bit ASM=x86_64
- FIELD=64bit ENDOMORPHISM=yes ASM=x86_64
- FIELD=32bit ENDOMORPHISM=yes
- BIGNUM=no
- BIGNUM=no ENDOMORPHISM=yes RECOVERY=yes EXPERIMENTAL=yes
- BIGNUM=no STATICPRECOMPUTATION=no
- BUILD=distcheck
- EXTRAFLAGS=CPPFLAGS=-DDETERMINISTIC
- EXTRAFLAGS=CFLAGS=-O0
- BUILD=check-java ECDH=yes EXPERIMENTAL=yes
matrix:
fast_finish: true
include:
- compiler: clang
env: HOST=i686-linux-gnu ENDOMORPHISM=yes
addons:
apt:
packages:
- gcc-multilib
- libgmp-dev:i386
- compiler: clang
env: HOST=i686-linux-gnu
addons:
apt:
packages:
- gcc-multilib
- compiler: gcc
env: HOST=i686-linux-gnu ENDOMORPHISM=yes
addons:
apt:
packages:
- gcc-multilib
- compiler: gcc
env: HOST=i686-linux-gnu
addons:
apt:
packages:
- gcc-multilib
- libgmp-dev:i386
before_install: mkdir -p `dirname $GUAVA_JAR`
install: if [ ! -f $GUAVA_JAR ]; then wget $GUAVA_URL -O $GUAVA_JAR; fi
before_script: ./autogen.sh
script:
- if [ -n "$HOST" ]; then export USE_HOST="--host=$HOST"; fi
- if [ "x$HOST" = "xi686-linux-gnu" ]; then export CC="$CC -m32"; fi
- ./configure --enable-experimental=$EXPERIMENTAL --enable-endomorphism=$ENDOMORPHISM --with-field=$FIELD --with-bignum=$BIGNUM --with-scalar=$SCALAR --enable-ecmult-static-precomputation=$STATICPRECOMPUTATION --enable-module-ecdh=$ECDH --enable-module-recovery=$RECOVERY $EXTRAFLAGS $USE_HOST && make -j2 $BUILD
os: linux

View File

@ -0,0 +1,19 @@
Copyright (c) 2013 Pieter Wuille
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -0,0 +1,177 @@
ACLOCAL_AMFLAGS = -I build-aux/m4
lib_LTLIBRARIES = libsecp256k1.la
if USE_JNI
JNI_LIB = libsecp256k1_jni.la
noinst_LTLIBRARIES = $(JNI_LIB)
else
JNI_LIB =
endif
include_HEADERS = include/secp256k1.h
noinst_HEADERS =
noinst_HEADERS += src/scalar.h
noinst_HEADERS += src/scalar_4x64.h
noinst_HEADERS += src/scalar_8x32.h
noinst_HEADERS += src/scalar_low.h
noinst_HEADERS += src/scalar_impl.h
noinst_HEADERS += src/scalar_4x64_impl.h
noinst_HEADERS += src/scalar_8x32_impl.h
noinst_HEADERS += src/scalar_low_impl.h
noinst_HEADERS += src/group.h
noinst_HEADERS += src/group_impl.h
noinst_HEADERS += src/num_gmp.h
noinst_HEADERS += src/num_gmp_impl.h
noinst_HEADERS += src/ecdsa.h
noinst_HEADERS += src/ecdsa_impl.h
noinst_HEADERS += src/eckey.h
noinst_HEADERS += src/eckey_impl.h
noinst_HEADERS += src/ecmult.h
noinst_HEADERS += src/ecmult_impl.h
noinst_HEADERS += src/ecmult_const.h
noinst_HEADERS += src/ecmult_const_impl.h
noinst_HEADERS += src/ecmult_gen.h
noinst_HEADERS += src/ecmult_gen_impl.h
noinst_HEADERS += src/num.h
noinst_HEADERS += src/num_impl.h
noinst_HEADERS += src/field_10x26.h
noinst_HEADERS += src/field_10x26_impl.h
noinst_HEADERS += src/field_5x52.h
noinst_HEADERS += src/field_5x52_impl.h
noinst_HEADERS += src/field_5x52_int128_impl.h
noinst_HEADERS += src/field_5x52_asm_impl.h
noinst_HEADERS += src/java/org_bitcoin_NativeSecp256k1.h
noinst_HEADERS += src/java/org_bitcoin_Secp256k1Context.h
noinst_HEADERS += src/util.h
noinst_HEADERS += src/testrand.h
noinst_HEADERS += src/testrand_impl.h
noinst_HEADERS += src/hash.h
noinst_HEADERS += src/hash_impl.h
noinst_HEADERS += src/field.h
noinst_HEADERS += src/field_impl.h
noinst_HEADERS += src/bench.h
noinst_HEADERS += contrib/lax_der_parsing.h
noinst_HEADERS += contrib/lax_der_parsing.c
noinst_HEADERS += contrib/lax_der_privatekey_parsing.h
noinst_HEADERS += contrib/lax_der_privatekey_parsing.c
if USE_EXTERNAL_ASM
COMMON_LIB = libsecp256k1_common.la
noinst_LTLIBRARIES = $(COMMON_LIB)
else
COMMON_LIB =
endif
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libsecp256k1.pc
if USE_EXTERNAL_ASM
if USE_ASM_ARM
libsecp256k1_common_la_SOURCES = src/asm/field_10x26_arm.s
endif
endif
libsecp256k1_la_SOURCES = src/secp256k1.c
libsecp256k1_la_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/include -I$(top_srcdir)/src $(SECP_INCLUDES)
libsecp256k1_la_LIBADD = $(JNI_LIB) $(SECP_LIBS) $(COMMON_LIB)
libsecp256k1_jni_la_SOURCES = src/java/org_bitcoin_NativeSecp256k1.c src/java/org_bitcoin_Secp256k1Context.c
libsecp256k1_jni_la_CPPFLAGS = -DSECP256K1_BUILD $(JNI_INCLUDES)
noinst_PROGRAMS =
if USE_BENCHMARK
noinst_PROGRAMS += bench_verify bench_sign bench_internal
bench_verify_SOURCES = src/bench_verify.c
bench_verify_LDADD = libsecp256k1.la $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB)
bench_sign_SOURCES = src/bench_sign.c
bench_sign_LDADD = libsecp256k1.la $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB)
bench_internal_SOURCES = src/bench_internal.c
bench_internal_LDADD = $(SECP_LIBS) $(COMMON_LIB)
bench_internal_CPPFLAGS = -DSECP256K1_BUILD $(SECP_INCLUDES)
endif
TESTS =
if USE_TESTS
noinst_PROGRAMS += tests
tests_SOURCES = src/tests.c
tests_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/src -I$(top_srcdir)/include $(SECP_INCLUDES) $(SECP_TEST_INCLUDES)
if !ENABLE_COVERAGE
tests_CPPFLAGS += -DVERIFY
endif
tests_LDADD = $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB)
tests_LDFLAGS = -static
TESTS += tests
endif
if USE_EXHAUSTIVE_TESTS
noinst_PROGRAMS += exhaustive_tests
exhaustive_tests_SOURCES = src/tests_exhaustive.c
exhaustive_tests_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/src $(SECP_INCLUDES)
if !ENABLE_COVERAGE
exhaustive_tests_CPPFLAGS += -DVERIFY
endif
exhaustive_tests_LDADD = $(SECP_LIBS)
exhaustive_tests_LDFLAGS = -static
TESTS += exhaustive_tests
endif
JAVAROOT=src/java
JAVAORG=org/bitcoin
JAVA_GUAVA=$(srcdir)/$(JAVAROOT)/guava/guava-18.0.jar
CLASSPATH_ENV=CLASSPATH=$(JAVA_GUAVA)
JAVA_FILES= \
$(JAVAROOT)/$(JAVAORG)/NativeSecp256k1.java \
$(JAVAROOT)/$(JAVAORG)/NativeSecp256k1Test.java \
$(JAVAROOT)/$(JAVAORG)/NativeSecp256k1Util.java \
$(JAVAROOT)/$(JAVAORG)/Secp256k1Context.java
if USE_JNI
$(JAVA_GUAVA):
@echo Guava is missing. Fetch it via: \
wget https://search.maven.org/remotecontent?filepath=com/google/guava/guava/18.0/guava-18.0.jar -O $(@)
@false
.stamp-java: $(JAVA_FILES)
@echo Compiling $^
$(AM_V_at)$(CLASSPATH_ENV) javac $^
@touch $@
if USE_TESTS
check-java: libsecp256k1.la $(JAVA_GUAVA) .stamp-java
$(AM_V_at)java -Djava.library.path="./:./src:./src/.libs:.libs/" -cp "$(JAVA_GUAVA):$(JAVAROOT)" $(JAVAORG)/NativeSecp256k1Test
endif
endif
if USE_ECMULT_STATIC_PRECOMPUTATION
CPPFLAGS_FOR_BUILD +=-I$(top_srcdir)
CFLAGS_FOR_BUILD += -Wall -Wextra -Wno-unused-function
gen_context_OBJECTS = gen_context.o
gen_context_BIN = gen_context$(BUILD_EXEEXT)
gen_%.o: src/gen_%.c
$(CC_FOR_BUILD) $(CPPFLAGS_FOR_BUILD) $(CFLAGS_FOR_BUILD) -c $< -o $@
$(gen_context_BIN): $(gen_context_OBJECTS)
$(CC_FOR_BUILD) $^ -o $@
$(libsecp256k1_la_OBJECTS): src/ecmult_static_context.h
$(tests_OBJECTS): src/ecmult_static_context.h
$(bench_internal_OBJECTS): src/ecmult_static_context.h
src/ecmult_static_context.h: $(gen_context_BIN)
./$(gen_context_BIN)
CLEANFILES = $(gen_context_BIN) src/ecmult_static_context.h $(JAVAROOT)/$(JAVAORG)/*.class .stamp-java
endif
EXTRA_DIST = autogen.sh src/gen_context.c src/basic-config.h $(JAVA_FILES)
if ENABLE_MODULE_ECDH
include src/modules/ecdh/Makefile.am.include
endif
if ENABLE_MODULE_RECOVERY
include src/modules/recovery/Makefile.am.include
endif

View File

@ -0,0 +1,61 @@
libsecp256k1
============
[![Build Status](https://travis-ci.org/bitcoin-core/secp256k1.svg?branch=master)](https://travis-ci.org/bitcoin-core/secp256k1)
Optimized C library for EC operations on curve secp256k1.
This library is a work in progress and is being used to research best practices. Use at your own risk.
Features:
* secp256k1 ECDSA signing/verification and key generation.
* Adding/multiplying private/public keys.
* Serialization/parsing of private keys, public keys, signatures.
* Constant time, constant memory access signing and pubkey generation.
* Derandomized DSA (via RFC6979 or with a caller provided function.)
* Very efficient implementation.
Implementation details
----------------------
* General
* No runtime heap allocation.
* Extensive testing infrastructure.
* Structured to facilitate review and analysis.
* Intended to be portable to any system with a C89 compiler and uint64_t support.
* Expose only higher level interfaces to minimize the API surface and improve application security. ("Be difficult to use insecurely.")
* Field operations
* Optimized implementation of arithmetic modulo the curve's field size (2^256 - 0x1000003D1).
* Using 5 52-bit limbs (including hand-optimized assembly for x86_64, by Diederik Huys).
* Using 10 26-bit limbs.
* Field inverses and square roots using a sliding window over blocks of 1s (by Peter Dettman).
* Scalar operations
* Optimized implementation without data-dependent branches of arithmetic modulo the curve's order.
* Using 4 64-bit limbs (relying on __int128 support in the compiler).
* Using 8 32-bit limbs.
* Group operations
* Point addition formula specifically simplified for the curve equation (y^2 = x^3 + 7).
* Use addition between points in Jacobian and affine coordinates where possible.
* Use a unified addition/doubling formula where necessary to avoid data-dependent branches.
* Point/x comparison without a field inversion by comparison in the Jacobian coordinate space.
* Point multiplication for verification (a*P + b*G).
* Use wNAF notation for point multiplicands.
* Use a much larger window for multiples of G, using precomputed multiples.
* Use Shamir's trick to do the multiplication with the public key and the generator simultaneously.
* Optionally (off by default) use secp256k1's efficiently-computable endomorphism to split the P multiplicand into 2 half-sized ones.
* Point multiplication for signing
* Use a precomputed table of multiples of powers of 16 multiplied with the generator, so general multiplication becomes a series of additions.
* Access the table with branch-free conditional moves so memory access is uniform.
* No data-dependent branches
* The precomputed tables add and eventually subtract points for which no known scalar (private key) is known, preventing even an attacker with control over the private key used to control the data internally.
Build steps
-----------
libsecp256k1 is built using autotools:
$ ./autogen.sh
$ ./configure
$ make
$ ./tests
$ sudo make install # optional

View File

@ -0,0 +1,3 @@
* Unit tests for fieldelem/groupelem, including ones intended to
trigger fieldelem's boundary cases.
* Complete constant-time operations for signing/keygen

View File

@ -0,0 +1,3 @@
#!/bin/sh
set -e
autoreconf -if --warnings=all

View File

@ -0,0 +1,140 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_jni_include_dir.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_JNI_INCLUDE_DIR
#
# DESCRIPTION
#
# AX_JNI_INCLUDE_DIR finds include directories needed for compiling
# programs using the JNI interface.
#
# JNI include directories are usually in the Java distribution. This is
# deduced from the value of $JAVA_HOME, $JAVAC, or the path to "javac", in
# that order. When this macro completes, a list of directories is left in
# the variable JNI_INCLUDE_DIRS.
#
# Example usage follows:
#
# AX_JNI_INCLUDE_DIR
#
# for JNI_INCLUDE_DIR in $JNI_INCLUDE_DIRS
# do
# CPPFLAGS="$CPPFLAGS -I$JNI_INCLUDE_DIR"
# done
#
# If you want to force a specific compiler:
#
# - at the configure.in level, set JAVAC=yourcompiler before calling
# AX_JNI_INCLUDE_DIR
#
# - at the configure level, setenv JAVAC
#
# Note: This macro can work with the autoconf M4 macros for Java programs.
# This particular macro is not part of the original set of macros.
#
# LICENSE
#
# Copyright (c) 2008 Don Anderson <dda@sleepycat.com>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 10
AU_ALIAS([AC_JNI_INCLUDE_DIR], [AX_JNI_INCLUDE_DIR])
AC_DEFUN([AX_JNI_INCLUDE_DIR],[
JNI_INCLUDE_DIRS=""
if test "x$JAVA_HOME" != x; then
_JTOPDIR="$JAVA_HOME"
else
if test "x$JAVAC" = x; then
JAVAC=javac
fi
AC_PATH_PROG([_ACJNI_JAVAC], [$JAVAC], [no])
if test "x$_ACJNI_JAVAC" = xno; then
AC_MSG_WARN([cannot find JDK; try setting \$JAVAC or \$JAVA_HOME])
fi
_ACJNI_FOLLOW_SYMLINKS("$_ACJNI_JAVAC")
_JTOPDIR=`echo "$_ACJNI_FOLLOWED" | sed -e 's://*:/:g' -e 's:/[[^/]]*$::'`
fi
case "$host_os" in
darwin*) _JTOPDIR=`echo "$_JTOPDIR" | sed -e 's:/[[^/]]*$::'`
_JINC="$_JTOPDIR/Headers";;
*) _JINC="$_JTOPDIR/include";;
esac
_AS_ECHO_LOG([_JTOPDIR=$_JTOPDIR])
_AS_ECHO_LOG([_JINC=$_JINC])
# On Mac OS X 10.6.4, jni.h is a symlink:
# /System/Library/Frameworks/JavaVM.framework/Versions/Current/Headers/jni.h
# -> ../../CurrentJDK/Headers/jni.h.
AC_CACHE_CHECK(jni headers, ac_cv_jni_header_path,
[
if test -f "$_JINC/jni.h"; then
ac_cv_jni_header_path="$_JINC"
JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $ac_cv_jni_header_path"
else
_JTOPDIR=`echo "$_JTOPDIR" | sed -e 's:/[[^/]]*$::'`
if test -f "$_JTOPDIR/include/jni.h"; then
ac_cv_jni_header_path="$_JTOPDIR/include"
JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $ac_cv_jni_header_path"
else
ac_cv_jni_header_path=none
fi
fi
])
# get the likely subdirectories for system specific java includes
case "$host_os" in
bsdi*) _JNI_INC_SUBDIRS="bsdos";;
darwin*) _JNI_INC_SUBDIRS="darwin";;
freebsd*) _JNI_INC_SUBDIRS="freebsd";;
linux*) _JNI_INC_SUBDIRS="linux genunix";;
osf*) _JNI_INC_SUBDIRS="alpha";;
solaris*) _JNI_INC_SUBDIRS="solaris";;
mingw*) _JNI_INC_SUBDIRS="win32";;
cygwin*) _JNI_INC_SUBDIRS="win32";;
*) _JNI_INC_SUBDIRS="genunix";;
esac
if test "x$ac_cv_jni_header_path" != "xnone"; then
# add any subdirectories that are present
for JINCSUBDIR in $_JNI_INC_SUBDIRS
do
if test -d "$_JTOPDIR/include/$JINCSUBDIR"; then
JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $_JTOPDIR/include/$JINCSUBDIR"
fi
done
fi
])
# _ACJNI_FOLLOW_SYMLINKS <path>
# Follows symbolic links on <path>,
# finally setting variable _ACJNI_FOLLOWED
# ----------------------------------------
AC_DEFUN([_ACJNI_FOLLOW_SYMLINKS],[
# find the include directory relative to the javac executable
_cur="$1"
while ls -ld "$_cur" 2>/dev/null | grep " -> " >/dev/null; do
AC_MSG_CHECKING([symlink for $_cur])
_slink=`ls -ld "$_cur" | sed 's/.* -> //'`
case "$_slink" in
/*) _cur="$_slink";;
# 'X' avoids triggering unwanted echo options.
*) _cur=`echo "X$_cur" | sed -e 's/^X//' -e 's:[[^/]]*$::'`"$_slink";;
esac
AC_MSG_RESULT([$_cur])
done
_ACJNI_FOLLOWED="$_cur"
])# _ACJNI

View File

@ -0,0 +1,125 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_prog_cc_for_build.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_PROG_CC_FOR_BUILD
#
# DESCRIPTION
#
# This macro searches for a C compiler that generates native executables,
# that is a C compiler that surely is not a cross-compiler. This can be
# useful if you have to generate source code at compile-time like for
# example GCC does.
#
# The macro sets the CC_FOR_BUILD and CPP_FOR_BUILD macros to anything
# needed to compile or link (CC_FOR_BUILD) and preprocess (CPP_FOR_BUILD).
# The value of these variables can be overridden by the user by specifying
# a compiler with an environment variable (like you do for standard CC).
#
# It also sets BUILD_EXEEXT and BUILD_OBJEXT to the executable and object
# file extensions for the build platform, and GCC_FOR_BUILD to `yes' if
# the compiler we found is GCC. All these variables but GCC_FOR_BUILD are
# substituted in the Makefile.
#
# LICENSE
#
# Copyright (c) 2008 Paolo Bonzini <bonzini@gnu.org>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 8
AU_ALIAS([AC_PROG_CC_FOR_BUILD], [AX_PROG_CC_FOR_BUILD])
AC_DEFUN([AX_PROG_CC_FOR_BUILD], [dnl
AC_REQUIRE([AC_PROG_CC])dnl
AC_REQUIRE([AC_PROG_CPP])dnl
AC_REQUIRE([AC_EXEEXT])dnl
AC_REQUIRE([AC_CANONICAL_HOST])dnl
dnl Use the standard macros, but make them use other variable names
dnl
pushdef([ac_cv_prog_CPP], ac_cv_build_prog_CPP)dnl
pushdef([ac_cv_prog_gcc], ac_cv_build_prog_gcc)dnl
pushdef([ac_cv_prog_cc_works], ac_cv_build_prog_cc_works)dnl
pushdef([ac_cv_prog_cc_cross], ac_cv_build_prog_cc_cross)dnl
pushdef([ac_cv_prog_cc_g], ac_cv_build_prog_cc_g)dnl
pushdef([ac_cv_exeext], ac_cv_build_exeext)dnl
pushdef([ac_cv_objext], ac_cv_build_objext)dnl
pushdef([ac_exeext], ac_build_exeext)dnl
pushdef([ac_objext], ac_build_objext)dnl
pushdef([CC], CC_FOR_BUILD)dnl
pushdef([CPP], CPP_FOR_BUILD)dnl
pushdef([CFLAGS], CFLAGS_FOR_BUILD)dnl
pushdef([CPPFLAGS], CPPFLAGS_FOR_BUILD)dnl
pushdef([LDFLAGS], LDFLAGS_FOR_BUILD)dnl
pushdef([host], build)dnl
pushdef([host_alias], build_alias)dnl
pushdef([host_cpu], build_cpu)dnl
pushdef([host_vendor], build_vendor)dnl
pushdef([host_os], build_os)dnl
pushdef([ac_cv_host], ac_cv_build)dnl
pushdef([ac_cv_host_alias], ac_cv_build_alias)dnl
pushdef([ac_cv_host_cpu], ac_cv_build_cpu)dnl
pushdef([ac_cv_host_vendor], ac_cv_build_vendor)dnl
pushdef([ac_cv_host_os], ac_cv_build_os)dnl
pushdef([ac_cpp], ac_build_cpp)dnl
pushdef([ac_compile], ac_build_compile)dnl
pushdef([ac_link], ac_build_link)dnl
save_cross_compiling=$cross_compiling
save_ac_tool_prefix=$ac_tool_prefix
cross_compiling=no
ac_tool_prefix=
AC_PROG_CC
AC_PROG_CPP
AC_EXEEXT
ac_tool_prefix=$save_ac_tool_prefix
cross_compiling=$save_cross_compiling
dnl Restore the old definitions
dnl
popdef([ac_link])dnl
popdef([ac_compile])dnl
popdef([ac_cpp])dnl
popdef([ac_cv_host_os])dnl
popdef([ac_cv_host_vendor])dnl
popdef([ac_cv_host_cpu])dnl
popdef([ac_cv_host_alias])dnl
popdef([ac_cv_host])dnl
popdef([host_os])dnl
popdef([host_vendor])dnl
popdef([host_cpu])dnl
popdef([host_alias])dnl
popdef([host])dnl
popdef([LDFLAGS])dnl
popdef([CPPFLAGS])dnl
popdef([CFLAGS])dnl
popdef([CPP])dnl
popdef([CC])dnl
popdef([ac_objext])dnl
popdef([ac_exeext])dnl
popdef([ac_cv_objext])dnl
popdef([ac_cv_exeext])dnl
popdef([ac_cv_prog_cc_g])dnl
popdef([ac_cv_prog_cc_cross])dnl
popdef([ac_cv_prog_cc_works])dnl
popdef([ac_cv_prog_gcc])dnl
popdef([ac_cv_prog_CPP])dnl
dnl Finally, set Makefile variables
dnl
BUILD_EXEEXT=$ac_build_exeext
BUILD_OBJEXT=$ac_build_objext
AC_SUBST(BUILD_EXEEXT)dnl
AC_SUBST(BUILD_OBJEXT)dnl
AC_SUBST([CFLAGS_FOR_BUILD])dnl
AC_SUBST([CPPFLAGS_FOR_BUILD])dnl
AC_SUBST([LDFLAGS_FOR_BUILD])dnl
])

View File

@ -0,0 +1,69 @@
dnl libsecp25k1 helper checks
AC_DEFUN([SECP_INT128_CHECK],[
has_int128=$ac_cv_type___int128
])
dnl escape "$0x" below using the m4 quadrigaph @S|@, and escape it again with a \ for the shell.
AC_DEFUN([SECP_64BIT_ASM_CHECK],[
AC_MSG_CHECKING(for x86_64 assembly availability)
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <stdint.h>]],[[
uint64_t a = 11, tmp;
__asm__ __volatile__("movq \@S|@0x100000000,%1; mulq %%rsi" : "+a"(a) : "S"(tmp) : "cc", "%rdx");
]])],[has_64bit_asm=yes],[has_64bit_asm=no])
AC_MSG_RESULT([$has_64bit_asm])
])
dnl
AC_DEFUN([SECP_OPENSSL_CHECK],[
has_libcrypto=no
m4_ifdef([PKG_CHECK_MODULES],[
PKG_CHECK_MODULES([CRYPTO], [libcrypto], [has_libcrypto=yes],[has_libcrypto=no])
if test x"$has_libcrypto" = x"yes"; then
TEMP_LIBS="$LIBS"
LIBS="$LIBS $CRYPTO_LIBS"
AC_CHECK_LIB(crypto, main,[AC_DEFINE(HAVE_LIBCRYPTO,1,[Define this symbol if libcrypto is installed])],[has_libcrypto=no])
LIBS="$TEMP_LIBS"
fi
])
if test x$has_libcrypto = xno; then
AC_CHECK_HEADER(openssl/crypto.h,[
AC_CHECK_LIB(crypto, main,[
has_libcrypto=yes
CRYPTO_LIBS=-lcrypto
AC_DEFINE(HAVE_LIBCRYPTO,1,[Define this symbol if libcrypto is installed])
])
])
LIBS=
fi
if test x"$has_libcrypto" = x"yes" && test x"$has_openssl_ec" = x; then
AC_MSG_CHECKING(for EC functions in libcrypto)
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <openssl/ec.h>
#include <openssl/ecdsa.h>
#include <openssl/obj_mac.h>]],[[
EC_KEY *eckey = EC_KEY_new_by_curve_name(NID_secp256k1);
ECDSA_sign(0, NULL, 0, NULL, NULL, eckey);
ECDSA_verify(0, NULL, 0, NULL, 0, eckey);
EC_KEY_free(eckey);
ECDSA_SIG *sig_openssl;
sig_openssl = ECDSA_SIG_new();
(void)sig_openssl->r;
ECDSA_SIG_free(sig_openssl);
]])],[has_openssl_ec=yes],[has_openssl_ec=no])
AC_MSG_RESULT([$has_openssl_ec])
fi
])
dnl
AC_DEFUN([SECP_GMP_CHECK],[
if test x"$has_gmp" != x"yes"; then
CPPFLAGS_TEMP="$CPPFLAGS"
CPPFLAGS="$GMP_CPPFLAGS $CPPFLAGS"
LIBS_TEMP="$LIBS"
LIBS="$GMP_LIBS $LIBS"
AC_CHECK_HEADER(gmp.h,[AC_CHECK_LIB(gmp, __gmpz_init,[has_gmp=yes; GMP_LIBS="$GMP_LIBS -lgmp"; AC_DEFINE(HAVE_LIBGMP,1,[Define this symbol if libgmp is installed])])])
CPPFLAGS="$CPPFLAGS_TEMP"
LIBS="$LIBS_TEMP"
fi
])

View File

@ -0,0 +1,493 @@
AC_PREREQ([2.60])
AC_INIT([libsecp256k1],[0.1])
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_MACRO_DIR([build-aux/m4])
AC_CANONICAL_HOST
AH_TOP([#ifndef LIBSECP256K1_CONFIG_H])
AH_TOP([#define LIBSECP256K1_CONFIG_H])
AH_BOTTOM([#endif /*LIBSECP256K1_CONFIG_H*/])
AM_INIT_AUTOMAKE([foreign subdir-objects])
LT_INIT
dnl make the compilation flags quiet unless V=1 is used
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
PKG_PROG_PKG_CONFIG
AC_PATH_TOOL(AR, ar)
AC_PATH_TOOL(RANLIB, ranlib)
AC_PATH_TOOL(STRIP, strip)
AX_PROG_CC_FOR_BUILD
if test "x$CFLAGS" = "x"; then
CFLAGS="-g"
fi
AM_PROG_CC_C_O
AC_PROG_CC_C89
if test x"$ac_cv_prog_cc_c89" = x"no"; then
AC_MSG_ERROR([c89 compiler support required])
fi
AM_PROG_AS
case $host_os in
*darwin*)
if test x$cross_compiling != xyes; then
AC_PATH_PROG([BREW],brew,)
if test x$BREW != x; then
dnl These Homebrew packages may be keg-only, meaning that they won't be found
dnl in expected paths because they may conflict with system files. Ask
dnl Homebrew where each one is located, then adjust paths accordingly.
openssl_prefix=`$BREW --prefix openssl 2>/dev/null`
gmp_prefix=`$BREW --prefix gmp 2>/dev/null`
if test x$openssl_prefix != x; then
PKG_CONFIG_PATH="$openssl_prefix/lib/pkgconfig:$PKG_CONFIG_PATH"
export PKG_CONFIG_PATH
fi
if test x$gmp_prefix != x; then
GMP_CPPFLAGS="-I$gmp_prefix/include"
GMP_LIBS="-L$gmp_prefix/lib"
fi
else
AC_PATH_PROG([PORT],port,)
dnl if homebrew isn't installed and macports is, add the macports default paths
dnl as a last resort.
if test x$PORT != x; then
CPPFLAGS="$CPPFLAGS -isystem /opt/local/include"
LDFLAGS="$LDFLAGS -L/opt/local/lib"
fi
fi
fi
;;
esac
CFLAGS="$CFLAGS -W"
warn_CFLAGS="-std=c89 -pedantic -Wall -Wextra -Wcast-align -Wnested-externs -Wshadow -Wstrict-prototypes -Wno-unused-function -Wno-long-long -Wno-overlength-strings"
saved_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $warn_CFLAGS"
AC_MSG_CHECKING([if ${CC} supports ${warn_CFLAGS}])
AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])],
[ AC_MSG_RESULT([yes]) ],
[ AC_MSG_RESULT([no])
CFLAGS="$saved_CFLAGS"
])
saved_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS -fvisibility=hidden"
AC_MSG_CHECKING([if ${CC} supports -fvisibility=hidden])
AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])],
[ AC_MSG_RESULT([yes]) ],
[ AC_MSG_RESULT([no])
CFLAGS="$saved_CFLAGS"
])
AC_ARG_ENABLE(benchmark,
AS_HELP_STRING([--enable-benchmark],[compile benchmark (default is no)]),
[use_benchmark=$enableval],
[use_benchmark=no])
AC_ARG_ENABLE(coverage,
AS_HELP_STRING([--enable-coverage],[enable compiler flags to support kcov coverage analysis]),
[enable_coverage=$enableval],
[enable_coverage=no])
AC_ARG_ENABLE(tests,
AS_HELP_STRING([--enable-tests],[compile tests (default is yes)]),
[use_tests=$enableval],
[use_tests=yes])
AC_ARG_ENABLE(openssl_tests,
AS_HELP_STRING([--enable-openssl-tests],[enable OpenSSL tests, if OpenSSL is available (default is auto)]),
[enable_openssl_tests=$enableval],
[enable_openssl_tests=auto])
AC_ARG_ENABLE(experimental,
AS_HELP_STRING([--enable-experimental],[allow experimental configure options (default is no)]),
[use_experimental=$enableval],
[use_experimental=no])
AC_ARG_ENABLE(exhaustive_tests,
AS_HELP_STRING([--enable-exhaustive-tests],[compile exhaustive tests (default is yes)]),
[use_exhaustive_tests=$enableval],
[use_exhaustive_tests=yes])
AC_ARG_ENABLE(endomorphism,
AS_HELP_STRING([--enable-endomorphism],[enable endomorphism (default is no)]),
[use_endomorphism=$enableval],
[use_endomorphism=no])
AC_ARG_ENABLE(ecmult_static_precomputation,
AS_HELP_STRING([--enable-ecmult-static-precomputation],[enable precomputed ecmult table for signing (default is yes)]),
[use_ecmult_static_precomputation=$enableval],
[use_ecmult_static_precomputation=auto])
AC_ARG_ENABLE(module_ecdh,
AS_HELP_STRING([--enable-module-ecdh],[enable ECDH shared secret computation (experimental)]),
[enable_module_ecdh=$enableval],
[enable_module_ecdh=no])
AC_ARG_ENABLE(module_recovery,
AS_HELP_STRING([--enable-module-recovery],[enable ECDSA pubkey recovery module (default is no)]),
[enable_module_recovery=$enableval],
[enable_module_recovery=no])
AC_ARG_ENABLE(jni,
AS_HELP_STRING([--enable-jni],[enable libsecp256k1_jni (default is auto)]),
[use_jni=$enableval],
[use_jni=auto])
AC_ARG_WITH([field], [AS_HELP_STRING([--with-field=64bit|32bit|auto],
[Specify Field Implementation. Default is auto])],[req_field=$withval], [req_field=auto])
AC_ARG_WITH([bignum], [AS_HELP_STRING([--with-bignum=gmp|no|auto],
[Specify Bignum Implementation. Default is auto])],[req_bignum=$withval], [req_bignum=auto])
AC_ARG_WITH([scalar], [AS_HELP_STRING([--with-scalar=64bit|32bit|auto],
[Specify scalar implementation. Default is auto])],[req_scalar=$withval], [req_scalar=auto])
AC_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|arm|no|auto]
[Specify assembly optimizations to use. Default is auto (experimental: arm)])],[req_asm=$withval], [req_asm=auto])
AC_CHECK_TYPES([__int128])
AC_MSG_CHECKING([for __builtin_expect])
AC_COMPILE_IFELSE([AC_LANG_SOURCE([[void myfunc() {__builtin_expect(0,0);}]])],
[ AC_MSG_RESULT([yes]);AC_DEFINE(HAVE_BUILTIN_EXPECT,1,[Define this symbol if __builtin_expect is available]) ],
[ AC_MSG_RESULT([no])
])
if test x"$enable_coverage" = x"yes"; then
AC_DEFINE(COVERAGE, 1, [Define this symbol to compile out all VERIFY code])
CFLAGS="$CFLAGS -O0 --coverage"
LDFLAGS="--coverage"
else
CFLAGS="$CFLAGS -O3"
fi
if test x"$use_ecmult_static_precomputation" != x"no"; then
save_cross_compiling=$cross_compiling
cross_compiling=no
TEMP_CC="$CC"
CC="$CC_FOR_BUILD"
AC_MSG_CHECKING([native compiler: ${CC_FOR_BUILD}])
AC_RUN_IFELSE(
[AC_LANG_PROGRAM([], [return 0])],
[working_native_cc=yes],
[working_native_cc=no],[dnl])
CC="$TEMP_CC"
cross_compiling=$save_cross_compiling
if test x"$working_native_cc" = x"no"; then
set_precomp=no
if test x"$use_ecmult_static_precomputation" = x"yes"; then
AC_MSG_ERROR([${CC_FOR_BUILD} does not produce working binaries. Please set CC_FOR_BUILD])
else
AC_MSG_RESULT([${CC_FOR_BUILD} does not produce working binaries. Please set CC_FOR_BUILD])
fi
else
AC_MSG_RESULT([ok])
set_precomp=yes
fi
else
set_precomp=no
fi
if test x"$req_asm" = x"auto"; then
SECP_64BIT_ASM_CHECK
if test x"$has_64bit_asm" = x"yes"; then
set_asm=x86_64
fi
if test x"$set_asm" = x; then
set_asm=no
fi
else
set_asm=$req_asm
case $set_asm in
x86_64)
SECP_64BIT_ASM_CHECK
if test x"$has_64bit_asm" != x"yes"; then
AC_MSG_ERROR([x86_64 assembly optimization requested but not available])
fi
;;
arm)
;;
no)
;;
*)
AC_MSG_ERROR([invalid assembly optimization selection])
;;
esac
fi
if test x"$req_field" = x"auto"; then
if test x"set_asm" = x"x86_64"; then
set_field=64bit
fi
if test x"$set_field" = x; then
SECP_INT128_CHECK
if test x"$has_int128" = x"yes"; then
set_field=64bit
fi
fi
if test x"$set_field" = x; then
set_field=32bit
fi
else
set_field=$req_field
case $set_field in
64bit)
if test x"$set_asm" != x"x86_64"; then
SECP_INT128_CHECK
if test x"$has_int128" != x"yes"; then
AC_MSG_ERROR([64bit field explicitly requested but neither __int128 support or x86_64 assembly available])
fi
fi
;;
32bit)
;;
*)
AC_MSG_ERROR([invalid field implementation selection])
;;
esac
fi
if test x"$req_scalar" = x"auto"; then
SECP_INT128_CHECK
if test x"$has_int128" = x"yes"; then
set_scalar=64bit
fi
if test x"$set_scalar" = x; then
set_scalar=32bit
fi
else
set_scalar=$req_scalar
case $set_scalar in
64bit)
SECP_INT128_CHECK
if test x"$has_int128" != x"yes"; then
AC_MSG_ERROR([64bit scalar explicitly requested but __int128 support not available])
fi
;;
32bit)
;;
*)
AC_MSG_ERROR([invalid scalar implementation selected])
;;
esac
fi
if test x"$req_bignum" = x"auto"; then
SECP_GMP_CHECK
if test x"$has_gmp" = x"yes"; then
set_bignum=gmp
fi
if test x"$set_bignum" = x; then
set_bignum=no
fi
else
set_bignum=$req_bignum
case $set_bignum in
gmp)
SECP_GMP_CHECK
if test x"$has_gmp" != x"yes"; then
AC_MSG_ERROR([gmp bignum explicitly requested but libgmp not available])
fi
;;
no)
;;
*)
AC_MSG_ERROR([invalid bignum implementation selection])
;;
esac
fi
# select assembly optimization
use_external_asm=no
case $set_asm in
x86_64)
AC_DEFINE(USE_ASM_X86_64, 1, [Define this symbol to enable x86_64 assembly optimizations])
;;
arm)
use_external_asm=yes
;;
no)
;;
*)
AC_MSG_ERROR([invalid assembly optimizations])
;;
esac
# select field implementation
case $set_field in
64bit)
AC_DEFINE(USE_FIELD_5X52, 1, [Define this symbol to use the FIELD_5X52 implementation])
;;
32bit)
AC_DEFINE(USE_FIELD_10X26, 1, [Define this symbol to use the FIELD_10X26 implementation])
;;
*)
AC_MSG_ERROR([invalid field implementation])
;;
esac
# select bignum implementation
case $set_bignum in
gmp)
AC_DEFINE(HAVE_LIBGMP, 1, [Define this symbol if libgmp is installed])
AC_DEFINE(USE_NUM_GMP, 1, [Define this symbol to use the gmp implementation for num])
AC_DEFINE(USE_FIELD_INV_NUM, 1, [Define this symbol to use the num-based field inverse implementation])
AC_DEFINE(USE_SCALAR_INV_NUM, 1, [Define this symbol to use the num-based scalar inverse implementation])
;;
no)
AC_DEFINE(USE_NUM_NONE, 1, [Define this symbol to use no num implementation])
AC_DEFINE(USE_FIELD_INV_BUILTIN, 1, [Define this symbol to use the native field inverse implementation])
AC_DEFINE(USE_SCALAR_INV_BUILTIN, 1, [Define this symbol to use the native scalar inverse implementation])
;;
*)
AC_MSG_ERROR([invalid bignum implementation])
;;
esac
#select scalar implementation
case $set_scalar in
64bit)
AC_DEFINE(USE_SCALAR_4X64, 1, [Define this symbol to use the 4x64 scalar implementation])
;;
32bit)
AC_DEFINE(USE_SCALAR_8X32, 1, [Define this symbol to use the 8x32 scalar implementation])
;;
*)
AC_MSG_ERROR([invalid scalar implementation])
;;
esac
if test x"$use_tests" = x"yes"; then
SECP_OPENSSL_CHECK
if test x"$has_openssl_ec" = x"yes"; then
if test x"$enable_openssl_tests" != x"no"; then
AC_DEFINE(ENABLE_OPENSSL_TESTS, 1, [Define this symbol if OpenSSL EC functions are available])
SECP_TEST_INCLUDES="$SSL_CFLAGS $CRYPTO_CFLAGS"
SECP_TEST_LIBS="$CRYPTO_LIBS"
case $host in
*mingw*)
SECP_TEST_LIBS="$SECP_TEST_LIBS -lgdi32"
;;
esac
fi
else
if test x"$enable_openssl_tests" = x"yes"; then
AC_MSG_ERROR([OpenSSL tests requested but OpenSSL with EC support is not available])
fi
fi
else
if test x"$enable_openssl_tests" = x"yes"; then
AC_MSG_ERROR([OpenSSL tests requested but tests are not enabled])
fi
fi
if test x"$use_jni" != x"no"; then
AX_JNI_INCLUDE_DIR
have_jni_dependencies=yes
if test x"$enable_module_ecdh" = x"no"; then
have_jni_dependencies=no
fi
if test "x$JNI_INCLUDE_DIRS" = "x"; then
have_jni_dependencies=no
fi
if test "x$have_jni_dependencies" = "xno"; then
if test x"$use_jni" = x"yes"; then
AC_MSG_ERROR([jni support explicitly requested but headers/dependencies were not found. Enable ECDH and try again.])
fi
AC_MSG_WARN([jni headers/dependencies not found. jni support disabled])
use_jni=no
else
use_jni=yes
for JNI_INCLUDE_DIR in $JNI_INCLUDE_DIRS; do
JNI_INCLUDES="$JNI_INCLUDES -I$JNI_INCLUDE_DIR"
done
fi
fi
if test x"$set_bignum" = x"gmp"; then
SECP_LIBS="$SECP_LIBS $GMP_LIBS"
SECP_INCLUDES="$SECP_INCLUDES $GMP_CPPFLAGS"
fi
if test x"$use_endomorphism" = x"yes"; then
AC_DEFINE(USE_ENDOMORPHISM, 1, [Define this symbol to use endomorphism optimization])
fi
if test x"$set_precomp" = x"yes"; then
AC_DEFINE(USE_ECMULT_STATIC_PRECOMPUTATION, 1, [Define this symbol to use a statically generated ecmult table])
fi
if test x"$enable_module_ecdh" = x"yes"; then
AC_DEFINE(ENABLE_MODULE_ECDH, 1, [Define this symbol to enable the ECDH module])
fi
if test x"$enable_module_recovery" = x"yes"; then
AC_DEFINE(ENABLE_MODULE_RECOVERY, 1, [Define this symbol to enable the ECDSA pubkey recovery module])
fi
AC_C_BIGENDIAN()
if test x"$use_external_asm" = x"yes"; then
AC_DEFINE(USE_EXTERNAL_ASM, 1, [Define this symbol if an external (non-inline) assembly implementation is used])
fi
AC_MSG_NOTICE([Using static precomputation: $set_precomp])
AC_MSG_NOTICE([Using assembly optimizations: $set_asm])
AC_MSG_NOTICE([Using field implementation: $set_field])
AC_MSG_NOTICE([Using bignum implementation: $set_bignum])
AC_MSG_NOTICE([Using scalar implementation: $set_scalar])
AC_MSG_NOTICE([Using endomorphism optimizations: $use_endomorphism])
AC_MSG_NOTICE([Building for coverage analysis: $enable_coverage])
AC_MSG_NOTICE([Building ECDH module: $enable_module_ecdh])
AC_MSG_NOTICE([Building ECDSA pubkey recovery module: $enable_module_recovery])
AC_MSG_NOTICE([Using jni: $use_jni])
if test x"$enable_experimental" = x"yes"; then
AC_MSG_NOTICE([******])
AC_MSG_NOTICE([WARNING: experimental build])
AC_MSG_NOTICE([Experimental features do not have stable APIs or properties, and may not be safe for production use.])
AC_MSG_NOTICE([Building ECDH module: $enable_module_ecdh])
AC_MSG_NOTICE([******])
else
if test x"$enable_module_ecdh" = x"yes"; then
AC_MSG_ERROR([ECDH module is experimental. Use --enable-experimental to allow.])
fi
if test x"$set_asm" = x"arm"; then
AC_MSG_ERROR([ARM assembly optimization is experimental. Use --enable-experimental to allow.])
fi
fi
AC_CONFIG_HEADERS([src/libsecp256k1-config.h])
AC_CONFIG_FILES([Makefile libsecp256k1.pc])
AC_SUBST(JNI_INCLUDES)
AC_SUBST(SECP_INCLUDES)
AC_SUBST(SECP_LIBS)
AC_SUBST(SECP_TEST_LIBS)
AC_SUBST(SECP_TEST_INCLUDES)
AM_CONDITIONAL([ENABLE_COVERAGE], [test x"$enable_coverage" = x"yes"])
AM_CONDITIONAL([USE_TESTS], [test x"$use_tests" != x"no"])
AM_CONDITIONAL([USE_EXHAUSTIVE_TESTS], [test x"$use_exhaustive_tests" != x"no"])
AM_CONDITIONAL([USE_BENCHMARK], [test x"$use_benchmark" = x"yes"])
AM_CONDITIONAL([USE_ECMULT_STATIC_PRECOMPUTATION], [test x"$set_precomp" = x"yes"])
AM_CONDITIONAL([ENABLE_MODULE_ECDH], [test x"$enable_module_ecdh" = x"yes"])
AM_CONDITIONAL([ENABLE_MODULE_RECOVERY], [test x"$enable_module_recovery" = x"yes"])
AM_CONDITIONAL([USE_JNI], [test x"$use_jni" == x"yes"])
AM_CONDITIONAL([USE_EXTERNAL_ASM], [test x"$use_external_asm" = x"yes"])
AM_CONDITIONAL([USE_ASM_ARM], [test x"$set_asm" = x"arm"])
dnl make sure nothing new is exported so that we don't break the cache
PKGCONFIG_PATH_TEMP="$PKG_CONFIG_PATH"
unset PKG_CONFIG_PATH
PKG_CONFIG_PATH="$PKGCONFIG_PATH_TEMP"
AC_OUTPUT

View File

@ -0,0 +1,7 @@
// +build dummy
// Package c contains only a C file.
//
// This Go file is part of a workaround for `go mod vendor`.
// Please see the file crypto/secp256k1/dummy.go for more information.
package contrib

View File

@ -0,0 +1,150 @@
/**********************************************************************
* Copyright (c) 2015 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#include <string.h>
#include <secp256k1.h>
#include "lax_der_parsing.h"
int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const unsigned char *input, size_t inputlen) {
size_t rpos, rlen, spos, slen;
size_t pos = 0;
size_t lenbyte;
unsigned char tmpsig[64] = {0};
int overflow = 0;
/* Hack to initialize sig with a correctly-parsed but invalid signature. */
secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig);
/* Sequence tag byte */
if (pos == inputlen || input[pos] != 0x30) {
return 0;
}
pos++;
/* Sequence length bytes */
if (pos == inputlen) {
return 0;
}
lenbyte = input[pos++];
if (lenbyte & 0x80) {
lenbyte -= 0x80;
if (pos + lenbyte > inputlen) {
return 0;
}
pos += lenbyte;
}
/* Integer tag byte for R */
if (pos == inputlen || input[pos] != 0x02) {
return 0;
}
pos++;
/* Integer length for R */
if (pos == inputlen) {
return 0;
}
lenbyte = input[pos++];
if (lenbyte & 0x80) {
lenbyte -= 0x80;
if (pos + lenbyte > inputlen) {
return 0;
}
while (lenbyte > 0 && input[pos] == 0) {
pos++;
lenbyte--;
}
if (lenbyte >= sizeof(size_t)) {
return 0;
}
rlen = 0;
while (lenbyte > 0) {
rlen = (rlen << 8) + input[pos];
pos++;
lenbyte--;
}
} else {
rlen = lenbyte;
}
if (rlen > inputlen - pos) {
return 0;
}
rpos = pos;
pos += rlen;
/* Integer tag byte for S */
if (pos == inputlen || input[pos] != 0x02) {
return 0;
}
pos++;
/* Integer length for S */
if (pos == inputlen) {
return 0;
}
lenbyte = input[pos++];
if (lenbyte & 0x80) {
lenbyte -= 0x80;
if (pos + lenbyte > inputlen) {
return 0;
}
while (lenbyte > 0 && input[pos] == 0) {
pos++;
lenbyte--;
}
if (lenbyte >= sizeof(size_t)) {
return 0;
}
slen = 0;
while (lenbyte > 0) {
slen = (slen << 8) + input[pos];
pos++;
lenbyte--;
}
} else {
slen = lenbyte;
}
if (slen > inputlen - pos) {
return 0;
}
spos = pos;
pos += slen;
/* Ignore leading zeroes in R */
while (rlen > 0 && input[rpos] == 0) {
rlen--;
rpos++;
}
/* Copy R value */
if (rlen > 32) {
overflow = 1;
} else {
memcpy(tmpsig + 32 - rlen, input + rpos, rlen);
}
/* Ignore leading zeroes in S */
while (slen > 0 && input[spos] == 0) {
slen--;
spos++;
}
/* Copy S value */
if (slen > 32) {
overflow = 1;
} else {
memcpy(tmpsig + 64 - slen, input + spos, slen);
}
if (!overflow) {
overflow = !secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig);
}
if (overflow) {
memset(tmpsig, 0, 64);
secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig);
}
return 1;
}

View File

@ -0,0 +1,91 @@
/**********************************************************************
* Copyright (c) 2015 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
/****
* Please do not link this file directly. It is not part of the libsecp256k1
* project and does not promise any stability in its API, functionality or
* presence. Projects which use this code should instead copy this header
* and its accompanying .c file directly into their codebase.
****/
/* This file defines a function that parses DER with various errors and
* violations. This is not a part of the library itself, because the allowed
* violations are chosen arbitrarily and do not follow or establish any
* standard.
*
* In many places it matters that different implementations do not only accept
* the same set of valid signatures, but also reject the same set of signatures.
* The only means to accomplish that is by strictly obeying a standard, and not
* accepting anything else.
*
* Nonetheless, sometimes there is a need for compatibility with systems that
* use signatures which do not strictly obey DER. The snippet below shows how
* certain violations are easily supported. You may need to adapt it.
*
* Do not use this for new systems. Use well-defined DER or compact signatures
* instead if you have the choice (see secp256k1_ecdsa_signature_parse_der and
* secp256k1_ecdsa_signature_parse_compact).
*
* The supported violations are:
* - All numbers are parsed as nonnegative integers, even though X.609-0207
* section 8.3.3 specifies that integers are always encoded as two's
* complement.
* - Integers can have length 0, even though section 8.3.1 says they can't.
* - Integers with overly long padding are accepted, violation section
* 8.3.2.
* - 127-byte long length descriptors are accepted, even though section
* 8.1.3.5.c says that they are not.
* - Trailing garbage data inside or after the signature is ignored.
* - The length descriptor of the sequence is ignored.
*
* Compared to for example OpenSSL, many violations are NOT supported:
* - Using overly long tag descriptors for the sequence or integers inside,
* violating section 8.1.2.2.
* - Encoding primitive integers as constructed values, violating section
* 8.3.1.
*/
#ifndef _SECP256K1_CONTRIB_LAX_DER_PARSING_H_
#define _SECP256K1_CONTRIB_LAX_DER_PARSING_H_
#include <secp256k1.h>
# ifdef __cplusplus
extern "C" {
# endif
/** Parse a signature in "lax DER" format
*
* Returns: 1 when the signature could be parsed, 0 otherwise.
* Args: ctx: a secp256k1 context object
* Out: sig: a pointer to a signature object
* In: input: a pointer to the signature to be parsed
* inputlen: the length of the array pointed to be input
*
* This function will accept any valid DER encoded signature, even if the
* encoded numbers are out of range. In addition, it will accept signatures
* which violate the DER spec in various ways. Its purpose is to allow
* validation of the Bitcoin blockchain, which includes non-DER signatures
* from before the network rules were updated to enforce DER. Note that
* the set of supported violations is a strict subset of what OpenSSL will
* accept.
*
* After the call, sig will always be initialized. If parsing failed or the
* encoded numbers are out of range, signature validation with it is
* guaranteed to fail for every message and public key.
*/
int ecdsa_signature_parse_der_lax(
const secp256k1_context* ctx,
secp256k1_ecdsa_signature* sig,
const unsigned char *input,
size_t inputlen
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
#ifdef __cplusplus
}
#endif
#endif

Some files were not shown because too many files have changed in this diff Show More