Feature/key compression (#1990)
## What has changed? I've introduced to the public binding functionality that will compress and decompress public keys of a variety of encoding and key types. This functionality supports all major byte encoding formats and the following EC public key types: - `secp256k1` pks - `bls12-381 g1` pks - `bls12-381 g2` pks ## Why make the change? We want shorter public (chat) keys and we want to be future proof and encoding agnostic. See the issue here https://github.com/status-im/status-go/issues/1937 --- * Added basic signature for compresspk and uncompresspk * Added basic encoding information * make vendor * formatted imports for the linter * Reformatted imports hoping linter likes it * This linter is capricious * Added check that the secp256k1 key is valid * Added test for valid key * Added multiformat/go-varint dep * Added public key type handling * Added key decompression with key type handling * Added handling for '0x' type indentifying * Added more robust testing * Less lint for the linting gods * make vendor for bls12_381 * Added bls12-381 compression tests * Added decompress key expected results * Refactor of typed and untyped keys in tests * Lint god appeasment * Refactor of sample public keys * Implemented bls12-381 decompression * gofmt * Renamed decode/encode funcs to be more descriptive * Added binary bindings for key de/compression * Refactor of func parameters gomobile is a bit tempermental using raw bytes as a parameter, so I've decided to use string only inputs and outputs * gofmt * Added function documentation * Moved multiformat de/compression into api/multiformat ns * Moved multiformat de/compression into api/multiformat ns * Changed compress to serialize on API
This commit is contained in:
parent
4720224ba2
commit
c8f9dad554
|
@ -0,0 +1,221 @@
|
|||
package multiformat
|
||||
|
||||
import (
|
||||
"crypto/elliptic"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/crypto/secp256k1"
|
||||
|
||||
bls12381 "github.com/kilic/bls12-381"
|
||||
|
||||
"github.com/multiformats/go-multibase"
|
||||
"github.com/multiformats/go-varint"
|
||||
)
|
||||
|
||||
const (
|
||||
secp256k1KeyType = 0xe7
|
||||
bls12p381g1KeyType = 0xea
|
||||
bls12p381g2KeyType = 0xeb
|
||||
)
|
||||
|
||||
// SerializePublicKey serialises a non-serialised multibase encoded multicodec identified EC public key
|
||||
// For details on usage see specs //TODO add the link to the specs
|
||||
func SerializePublicKey(key, outputBase string) (string, error) {
|
||||
dKey, err := multibaseDecode(key)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
kt, i, err := getPublicKeyType(dKey)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
cpk, err := compressPublicKey(dKey[i:], kt)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
cpk = prependKeyIdentifier(cpk, kt, i)
|
||||
|
||||
return multibaseEncode(outputBase, cpk)
|
||||
}
|
||||
|
||||
// DeserializePublicKey deserialise a serialised multibase encoded multicodec identified EC public key
|
||||
// For details on usage see specs //TODO add the link to the specs
|
||||
func DeserializePublicKey(key, outputBase string) (string, error) {
|
||||
cpk, err := multibaseDecode(key)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
kt, i, err := getPublicKeyType(cpk)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
pk, err := decompressPublicKey(cpk[i:], kt)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
pk = prependKeyIdentifier(pk, kt, i)
|
||||
|
||||
return multibaseEncode(outputBase, pk)
|
||||
}
|
||||
|
||||
// getPublicKeyType wrapper for the `varint.FromUvarint()` func
|
||||
func getPublicKeyType(key []byte) (uint64, int, error) {
|
||||
return varint.FromUvarint(key)
|
||||
}
|
||||
|
||||
// prependKeyIdentifier prepends an Unsigned Variable Integer (uvarint) to a given []byte
|
||||
func prependKeyIdentifier(key []byte, kt uint64, ktl int) []byte {
|
||||
buf := make([]byte, ktl)
|
||||
varint.PutUvarint(buf, kt)
|
||||
|
||||
key = append(buf, key...)
|
||||
return key
|
||||
}
|
||||
|
||||
// compressPublicKey serves as logic switch function to parse key data for compression based on the given keyType
|
||||
func compressPublicKey(key []byte, keyType uint64) ([]byte, error) {
|
||||
switch keyType {
|
||||
case secp256k1KeyType:
|
||||
return compressSecp256k1PublicKey(key)
|
||||
|
||||
case bls12p381g1KeyType:
|
||||
return compressBls12p381g1PublicKey(key)
|
||||
|
||||
case bls12p381g2KeyType:
|
||||
return compressBls12p381g2PublicKey(key)
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported public key type '%X'", keyType)
|
||||
}
|
||||
}
|
||||
|
||||
// compressSecp256k1PublicKey is a dedicated key compression function for secp256k1 pks
|
||||
func compressSecp256k1PublicKey(key []byte) ([]byte, error) {
|
||||
x, y := elliptic.Unmarshal(secp256k1.S256(), key)
|
||||
|
||||
if err := isSecp256k1XYValid(key, x, y); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cpk := secp256k1.CompressPubkey(x, y)
|
||||
|
||||
return cpk, nil
|
||||
}
|
||||
|
||||
// compressBls12p381g1PublicKey is a dedicated key compression function for bls12 381 g1 pks
|
||||
func compressBls12p381g1PublicKey(key []byte) ([]byte, error) {
|
||||
g1 := bls12381.NewG1()
|
||||
|
||||
// Generate the G1 point
|
||||
pg1, err := g1.FromBytes(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cpk := g1.ToCompressed(pg1)
|
||||
return cpk, nil
|
||||
}
|
||||
|
||||
// compressBls12p381g1PublicKey is a dedicated key compression function for bls12 381 g2 pks
|
||||
func compressBls12p381g2PublicKey(key []byte) ([]byte, error) {
|
||||
g2 := bls12381.NewG2()
|
||||
|
||||
// Generate the G2 point
|
||||
pg2, err := g2.FromBytes(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cpk := g2.ToCompressed(pg2)
|
||||
return cpk, nil
|
||||
}
|
||||
|
||||
// decompressPublicKey serves as logic switch function to parse key data for decompression based on the given keyType
|
||||
func decompressPublicKey(key []byte, keyType uint64) ([]byte, error) {
|
||||
switch keyType {
|
||||
case secp256k1KeyType:
|
||||
return decompressSecp256k1PublicKey(key)
|
||||
|
||||
case bls12p381g1KeyType:
|
||||
return decompressBls12p381g1PublicKey(key)
|
||||
|
||||
case bls12p381g2KeyType:
|
||||
return decompressBls12p381g2PublicKey(key)
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported public key type '%X'", keyType)
|
||||
}
|
||||
}
|
||||
|
||||
// decompressSecp256k1PublicKey is a dedicated key decompression function for secp256k1 pks
|
||||
func decompressSecp256k1PublicKey(key []byte) ([]byte, error) {
|
||||
x, y := secp256k1.DecompressPubkey(key)
|
||||
|
||||
if err := isSecp256k1XYValid(key, x, y); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
k := elliptic.Marshal(secp256k1.S256(), x, y)
|
||||
|
||||
return k, nil
|
||||
}
|
||||
|
||||
// isSecp256k1XYValid checks if a given x and y coordinate is nil, returns an error if either x or y is nil
|
||||
// secp256k1.DecompressPubkey will not return an error if a compressed pk fails decompression and instead returns
|
||||
// nil x, y coordinates
|
||||
func isSecp256k1XYValid(key []byte, x, y *big.Int) error {
|
||||
if x == nil || y == nil {
|
||||
return fmt.Errorf("invalid public key format, '%b'", key)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// decompressBls12p381g1PublicKey is a dedicated key decompression function for bls12 381 g1 pks
|
||||
func decompressBls12p381g1PublicKey(key []byte) ([]byte, error) {
|
||||
g1 := bls12381.NewG1()
|
||||
pg1, err := g1.FromCompressed(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pk := g1.ToUncompressed(pg1)
|
||||
return pk, nil
|
||||
}
|
||||
|
||||
// decompressBls12p381g2PublicKey is a dedicated key decompression function for bls12 381 g2 pks
|
||||
func decompressBls12p381g2PublicKey(key []byte) ([]byte, error) {
|
||||
g2 := bls12381.NewG2()
|
||||
pg2, err := g2.FromCompressed(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pk := g2.ToUncompressed(pg2)
|
||||
return pk, nil
|
||||
}
|
||||
|
||||
// multibaseEncode wraps `multibase.Encode()` extending the base functionality to support `0x` prefixed strings
|
||||
func multibaseEncode(base string, data []byte) (string, error) {
|
||||
if base == "0x" {
|
||||
base = "f"
|
||||
}
|
||||
return multibase.Encode(multibase.Encoding(base[0]), data)
|
||||
}
|
||||
|
||||
// multibaseDecode wraps `multibase.Decode()` extending the base functionality to support `0x` prefixed strings
|
||||
func multibaseDecode(data string) ([]byte, error) {
|
||||
if data[0:2] == "0x" {
|
||||
data = "f" + data[2:]
|
||||
}
|
||||
|
||||
_, dd, err := multibase.Decode(data)
|
||||
return dd, err
|
||||
}
|
|
@ -0,0 +1,293 @@
|
|||
package multiformat
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var (
|
||||
// secp256k1 sample public key
|
||||
secPkB = []byte{
|
||||
0x04,
|
||||
0x26, 0x1c, 0x55, 0x67, 0x5e, 0x55, 0xff, 0x25,
|
||||
0xed, 0xb5, 0x0b, 0x34, 0x5c, 0xfb, 0x3a, 0x3f,
|
||||
0x35, 0xf6, 0x07, 0x12, 0xd2, 0x51, 0xcb, 0xaa,
|
||||
0xab, 0x97, 0xbd, 0x50, 0x05, 0x4c, 0x6e, 0xbc,
|
||||
0x3c, 0xd4, 0xe2, 0x22, 0x00, 0xc6, 0x8d, 0xaf,
|
||||
0x74, 0x93, 0xe1, 0xf8, 0xda, 0x6a, 0x19, 0x0a,
|
||||
0x68, 0xa6, 0x71, 0xe2, 0xd3, 0x97, 0x78, 0x09,
|
||||
0x61, 0x24, 0x24, 0xc7, 0xc3, 0x88, 0x8b, 0xc6,
|
||||
}
|
||||
secPk = "f" + hex.EncodeToString(secPkB)
|
||||
secPkBt = append([]byte{0xe7, 0x01}, secPkB...)
|
||||
secPkt = "f" + hex.EncodeToString(secPkBt)
|
||||
|
||||
// bls12-381 G1 sample public key
|
||||
bls12G1PkB = []byte{
|
||||
0x17, 0xf1, 0xd3, 0xa7, 0x31, 0x97, 0xd7, 0x94,
|
||||
0x26, 0x95, 0x63, 0x8c, 0x4f, 0xa9, 0xac, 0x0f,
|
||||
0xc3, 0x68, 0x8c, 0x4f, 0x97, 0x74, 0xb9, 0x05,
|
||||
0xa1, 0x4e, 0x3a, 0x3f, 0x17, 0x1b, 0xac, 0x58,
|
||||
0x6c, 0x55, 0xe8, 0x3f, 0xf9, 0x7a, 0x1a, 0xef,
|
||||
0xfb, 0x3a, 0xf0, 0x0a, 0xdb, 0x22, 0xc6, 0xbb,
|
||||
0x08, 0xb3, 0xf4, 0x81, 0xe3, 0xaa, 0xa0, 0xf1,
|
||||
0xa0, 0x9e, 0x30, 0xed, 0x74, 0x1d, 0x8a, 0xe4,
|
||||
0xfc, 0xf5, 0xe0, 0x95, 0xd5, 0xd0, 0x0a, 0xf6,
|
||||
0x00, 0xdb, 0x18, 0xcb, 0x2c, 0x04, 0xb3, 0xed,
|
||||
0xd0, 0x3c, 0xc7, 0x44, 0xa2, 0x88, 0x8a, 0xe4,
|
||||
0x0c, 0xaa, 0x23, 0x29, 0x46, 0xc5, 0xe7, 0xe1,
|
||||
}
|
||||
bls12G1Pk = "f" + hex.EncodeToString(bls12G1PkB)
|
||||
bls12G1PkBt = append([]byte{0xea, 0x01}, bls12G1PkB...)
|
||||
bls12G1Pkt = "f" + hex.EncodeToString(bls12G1PkBt)
|
||||
|
||||
// bls12 381 G2 sample public key
|
||||
bls12G2PkB = []byte{
|
||||
0x13, 0xe0, 0x2b, 0x60, 0x52, 0x71, 0x9f, 0x60,
|
||||
0x7d, 0xac, 0xd3, 0xa0, 0x88, 0x27, 0x4f, 0x65,
|
||||
0x59, 0x6b, 0xd0, 0xd0, 0x99, 0x20, 0xb6, 0x1a,
|
||||
0xb5, 0xda, 0x61, 0xbb, 0xdc, 0x7f, 0x50, 0x49,
|
||||
0x33, 0x4c, 0xf1, 0x12, 0x13, 0x94, 0x5d, 0x57,
|
||||
0xe5, 0xac, 0x7d, 0x05, 0x5d, 0x04, 0x2b, 0x7e,
|
||||
0x02, 0x4a, 0xa2, 0xb2, 0xf0, 0x8f, 0x0a, 0x91,
|
||||
0x26, 0x08, 0x05, 0x27, 0x2d, 0xc5, 0x10, 0x51,
|
||||
0xc6, 0xe4, 0x7a, 0xd4, 0xfa, 0x40, 0x3b, 0x02,
|
||||
0xb4, 0x51, 0x0b, 0x64, 0x7a, 0xe3, 0xd1, 0x77,
|
||||
0x0b, 0xac, 0x03, 0x26, 0xa8, 0x05, 0xbb, 0xef,
|
||||
0xd4, 0x80, 0x56, 0xc8, 0xc1, 0x21, 0xbd, 0xb8,
|
||||
0x06, 0x06, 0xc4, 0xa0, 0x2e, 0xa7, 0x34, 0xcc,
|
||||
0x32, 0xac, 0xd2, 0xb0, 0x2b, 0xc2, 0x8b, 0x99,
|
||||
0xcb, 0x3e, 0x28, 0x7e, 0x85, 0xa7, 0x63, 0xaf,
|
||||
0x26, 0x74, 0x92, 0xab, 0x57, 0x2e, 0x99, 0xab,
|
||||
0x3f, 0x37, 0x0d, 0x27, 0x5c, 0xec, 0x1d, 0xa1,
|
||||
0xaa, 0xa9, 0x07, 0x5f, 0xf0, 0x5f, 0x79, 0xbe,
|
||||
0x0c, 0xe5, 0xd5, 0x27, 0x72, 0x7d, 0x6e, 0x11,
|
||||
0x8c, 0xc9, 0xcd, 0xc6, 0xda, 0x2e, 0x35, 0x1a,
|
||||
0xad, 0xfd, 0x9b, 0xaa, 0x8c, 0xbd, 0xd3, 0xa7,
|
||||
0x6d, 0x42, 0x9a, 0x69, 0x51, 0x60, 0xd1, 0x2c,
|
||||
0x92, 0x3a, 0xc9, 0xcc, 0x3b, 0xac, 0xa2, 0x89,
|
||||
0xe1, 0x93, 0x54, 0x86, 0x08, 0xb8, 0x28, 0x01,
|
||||
}
|
||||
bls12G2Pk = "f" + hex.EncodeToString(bls12G2PkB)
|
||||
bls12G2PkBt = append([]byte{0xeb, 0x01}, bls12G2PkB...)
|
||||
bls12G2Pkt = "f" + hex.EncodeToString(bls12G2PkBt)
|
||||
)
|
||||
|
||||
func TestSerialisePublicKey(t *testing.T) {
|
||||
cs := []struct {
|
||||
Description string
|
||||
OutBase string
|
||||
Key string
|
||||
Expected string
|
||||
Error error
|
||||
}{
|
||||
{
|
||||
"invalid key, with valid key type",
|
||||
"z",
|
||||
"0xe701ff42ea",
|
||||
"",
|
||||
fmt.Errorf("invalid public key format, '[11111111 1000010 11101010]'"),
|
||||
},
|
||||
{
|
||||
"invalid key type, with invalid key",
|
||||
"z",
|
||||
"0xeeff42ea",
|
||||
"",
|
||||
fmt.Errorf("unsupported public key type '10BFEE'"),
|
||||
},
|
||||
{
|
||||
"invalid encoding type, with valid key",
|
||||
"p",
|
||||
secPkt,
|
||||
"",
|
||||
fmt.Errorf("selected encoding not supported"),
|
||||
},
|
||||
{
|
||||
"valid key, no key type defined",
|
||||
"z",
|
||||
secPk,
|
||||
"",
|
||||
fmt.Errorf("unsupported public key type '4'"),
|
||||
},
|
||||
{
|
||||
"valid key, with base58 bitcoin encoding",
|
||||
"z",
|
||||
secPkt,
|
||||
"zQ3shPyZJnxZK4Bwyx9QsaksNKDYTPmpwPvGSjMYVHoXHeEgB",
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"valid key, with traditional hex encoding",
|
||||
"0x",
|
||||
secPkt,
|
||||
"fe70102261c55675e55ff25edb50b345cfb3a3f35f60712d251cbaaab97bd50054c6ebc",
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"valid secp256k1 key, with multiencoding hex encoding",
|
||||
"f",
|
||||
secPkt,
|
||||
"fe70102261c55675e55ff25edb50b345cfb3a3f35f60712d251cbaaab97bd50054c6ebc",
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"valid bls12-381 g1 key, with multiencoding hex encoding",
|
||||
"f",
|
||||
bls12G1Pkt,
|
||||
"fea0197f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb",
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"valid bls12-381 g1 key, with base58 bitcoin encoding",
|
||||
"z",
|
||||
bls12G1Pkt,
|
||||
"z3tEFUdV4D3tCMG6Fr1deVvt32DCS1Y4SxDGoELedXaMUdTdr5FfZvBnbK9bWMhAGj3RHk",
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"valid bls12-381 g1 key, with no key type",
|
||||
"f",
|
||||
bls12G1Pk,
|
||||
"",
|
||||
fmt.Errorf("unsupported public key type '17'"),
|
||||
},
|
||||
{
|
||||
"valid bls12-381 g2 key, with multiencoding hex encoding",
|
||||
"f",
|
||||
bls12G2Pkt,
|
||||
"feb0193e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8",
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"valid bls12-381 g2 key, with base58 bitcoin encoding",
|
||||
"z",
|
||||
bls12G2Pkt,
|
||||
"zUC77n3BqSWuoGMY7ut91NDoWzpithCd4GwPLAnv9fc7drWY4wBTvMX1y9eGSAuiBpktqGAocND2KXdu1HqNgrd6i3vCZKCLqZ3nQFaEA2FpTs7ZEChRpWReLvYyXNYUHvQjyKd",
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"valid bls12-381 g2 key, with no key type",
|
||||
"f",
|
||||
bls12G2Pk,
|
||||
"",
|
||||
fmt.Errorf("unsupported public key type '13'"),
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range cs {
|
||||
cpk, err := SerializePublicKey(c.Key, c.OutBase)
|
||||
|
||||
require.Equal(t, c.Expected, cpk, c.Description)
|
||||
|
||||
if c.Error != nil {
|
||||
require.EqualError(t, err, c.Error.Error(), c.Description)
|
||||
continue
|
||||
}
|
||||
|
||||
require.NoError(t, err, c.Description)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeserialisePublicKey(t *testing.T) {
|
||||
cs := []struct {
|
||||
Description string
|
||||
Key string
|
||||
OutBase string
|
||||
Expected string
|
||||
Error error
|
||||
}{
|
||||
{
|
||||
"valid key with valid encoding type '0x'",
|
||||
"0xe70102261c55675e55ff25edb50b345cfb3a3f35f60712d251cbaaab97bd50054c6ebc",
|
||||
"f",
|
||||
secPkt,
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"valid key with valid encoding type 'f'",
|
||||
"fe70102261c55675e55ff25edb50b345cfb3a3f35f60712d251cbaaab97bd50054c6ebc",
|
||||
"f",
|
||||
secPkt,
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"valid key with valid encoding type 'z'",
|
||||
"zQ3shPyZJnxZK4Bwyx9QsaksNKDYTPmpwPvGSjMYVHoXHeEgB",
|
||||
"f",
|
||||
secPkt,
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"valid key with mismatched encoding type 'f' instead of 'z'",
|
||||
"fQ3shPyZJnxZK4Bwyx9QsaksNKDYTPmpwPvGSjMYVHoXHeEgB",
|
||||
"f",
|
||||
"",
|
||||
fmt.Errorf("encoding/hex: invalid byte: U+0051 'Q'"),
|
||||
},
|
||||
{
|
||||
"valid key with no encoding type, in base58 encoding",
|
||||
"Q3shPyZJnxZK4Bwyx9QsaksNKDYTPmpwPvGSjMYVHoXHeEgB",
|
||||
"f",
|
||||
"",
|
||||
fmt.Errorf("selected encoding not supported"),
|
||||
},
|
||||
{
|
||||
"valid bls12-381 g1 key encoding type 'z'",
|
||||
"z3tEFUdV4D3tCMG6Fr1deVvt32DCS1Y4SxDGoELedXaMUdTdr5FfZvBnbK9bWMhAGj3RHk",
|
||||
"f",
|
||||
bls12G1Pkt,
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"valid bls12-381 g1 key encoding type 'f'",
|
||||
"fea0197f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb",
|
||||
"f",
|
||||
bls12G1Pkt,
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"valid bls12-381 g1 key encoding type '0x'",
|
||||
"0xea0197f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb",
|
||||
"f",
|
||||
bls12G1Pkt,
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"valid bls12-381 g2 key encoding type 'z'",
|
||||
"zUC77n3BqSWuoGMY7ut91NDoWzpithCd4GwPLAnv9fc7drWY4wBTvMX1y9eGSAuiBpktqGAocND2KXdu1HqNgrd6i3vCZKCLqZ3nQFaEA2FpTs7ZEChRpWReLvYyXNYUHvQjyKd",
|
||||
"f",
|
||||
bls12G2Pkt,
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"valid bls12-381 g2 key encoding type 'f'",
|
||||
"feb0193e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8",
|
||||
"f",
|
||||
bls12G2Pkt,
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"valid bls12-381 g2 key encoding type '0x'",
|
||||
"0xeb0193e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8",
|
||||
"f",
|
||||
bls12G2Pkt,
|
||||
nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range cs {
|
||||
key, err := DeserializePublicKey(c.Key, c.OutBase)
|
||||
|
||||
require.Exactly(t, c.Expected, key, c.Description)
|
||||
|
||||
if c.Error != nil {
|
||||
require.EqualError(t, err, c.Error.Error(), c.Description)
|
||||
continue
|
||||
}
|
||||
|
||||
require.NoError(t, err, c.Description)
|
||||
}
|
||||
}
|
3
go.mod
3
go.mod
|
@ -22,6 +22,7 @@ require (
|
|||
github.com/google/uuid v1.1.1
|
||||
github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a
|
||||
github.com/karalabe/usb v0.0.0-20191104083709-911d15fe12a9 // indirect
|
||||
github.com/kilic/bls12-381 v0.0.0-20200607163746-32e1441c8a9f
|
||||
github.com/leodido/go-urn v1.2.0 // indirect
|
||||
github.com/lib/pq v1.3.0
|
||||
github.com/libp2p/go-libp2p v0.4.2 // indirect
|
||||
|
@ -29,6 +30,8 @@ require (
|
|||
github.com/lucasb-eyer/go-colorful v1.0.3
|
||||
github.com/mattn/go-pointer v0.0.0-20190911064623-a0a44394634f
|
||||
github.com/multiformats/go-multiaddr v0.1.1
|
||||
github.com/multiformats/go-multibase v0.0.1
|
||||
github.com/multiformats/go-varint v0.0.5
|
||||
github.com/mutecomm/go-sqlcipher v0.0.0-20190227152316-55dbde17881f
|
||||
github.com/okzk/sdnotify v0.0.0-20180710141335-d9becc38acbd
|
||||
github.com/pborman/uuid v1.2.0
|
||||
|
|
7
go.sum
7
go.sum
|
@ -138,7 +138,6 @@ github.com/elastic/gosigar v0.10.4/go.mod h1:cdorVVzy1fhmEqmtgqkoE3bYtCfSCkVyjTy
|
|||
github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
|
||||
github.com/ethereum/go-ethereum v1.8.20/go.mod h1:PwpWDrCLZrV+tfrhqqF6kPknbISMHaJv9Ln3kPCZLwY=
|
||||
github.com/ethereum/go-ethereum v1.9.2/go.mod h1:PwpWDrCLZrV+tfrhqqF6kPknbISMHaJv9Ln3kPCZLwY=
|
||||
github.com/ethereum/go-ethereum v1.9.13 h1:rOPqjSngvs1VSYH2H+PMPiWt4VEulvNRbFgqiGqJM3E=
|
||||
github.com/fatih/color v1.3.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fjl/memsize v0.0.0-20180418122429-ca190fb6ffbc h1:jtW8jbpkO4YirRSyepBOH8E+2HEw6/hKkBvFPwhUN8c=
|
||||
github.com/fjl/memsize v0.0.0-20180418122429-ca190fb6ffbc/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0=
|
||||
|
@ -303,6 +302,8 @@ github.com/karalabe/usb v0.0.0-20190819132248-550797b1cad8/go.mod h1:Od972xHfMJo
|
|||
github.com/karalabe/usb v0.0.0-20191104083709-911d15fe12a9 h1:ZHuwnjpP8LsVsUYqTqeVAI+GfDfJ6UNPrExZF+vX/DQ=
|
||||
github.com/karalabe/usb v0.0.0-20191104083709-911d15fe12a9/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU=
|
||||
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
|
||||
github.com/kilic/bls12-381 v0.0.0-20200607163746-32e1441c8a9f h1:qET3Wx0v8tMtoTOQnsJXVvqvCopSf48qobR6tcJuDHo=
|
||||
github.com/kilic/bls12-381 v0.0.0-20200607163746-32e1441c8a9f/go.mod h1:XXfR6YFCRSrkEXbNlIyDsgXVNJWVUV30m/ebkVy9n6s=
|
||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
|
@ -498,6 +499,8 @@ github.com/multiformats/go-multihash v0.0.8 h1:wrYcW5yxSi3dU07n5jnuS5PrNwyHy0zRH
|
|||
github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew=
|
||||
github.com/multiformats/go-multistream v0.1.0 h1:UpO6jrsjqs46mqAK3n6wKRYFhugss9ArzbyUzU+4wkQ=
|
||||
github.com/multiformats/go-multistream v0.1.0/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg=
|
||||
github.com/multiformats/go-varint v0.0.5 h1:XVZwSo04Cs3j/jS0uAEPpT3JY6DzMcVLLoWOSnCxOjg=
|
||||
github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
|
||||
github.com/mutecomm/go-sqlcipher v0.0.0-20190227152316-55dbde17881f h1:hd3r+uv9DNLScbOrnlj82rBldHQf3XWmCeXAWbw8euQ=
|
||||
github.com/mutecomm/go-sqlcipher v0.0.0-20190227152316-55dbde17881f/go.mod h1:MyUWrZlB1aI5bs7j9/pJ8ckLLZ4QcCYcNiSbsAW32D4=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
|
@ -636,7 +639,6 @@ github.com/status-im/rendezvous v1.3.0/go.mod h1:+hzjuP+j/XzLPeF6E50b88pWOTLdTcw
|
|||
github.com/status-im/status-go/extkeys v1.0.0/go.mod h1:GdqJbrcpkNm5ZsSCpp+PdMxnXx+OcRBdm3PI0rs1FpU=
|
||||
github.com/status-im/status-go/extkeys v1.1.2 h1:FSjARgDathJ3rIapJt851LsIXP9Oyuu2M2jPJKuzloU=
|
||||
github.com/status-im/status-go/extkeys v1.1.2/go.mod h1:hCmFzb2jiiVF2voZKYbzuhOQiHHCmyLJsZJXrFFg7BY=
|
||||
github.com/status-im/status-go/waku v1.3.1 h1:hXvWsS/5ZKJ5iUXJvIZRE4Z78OH5u4d7OwBEPLNY9Gs=
|
||||
github.com/status-im/status-go/whisper/v6 v6.2.6 h1:xELIv/8QB9CQlJjChnCPt4COWOFmgsc2kl03Y3Dspmo=
|
||||
github.com/status-im/status-go/whisper/v6 v6.2.6/go.mod h1:csqMoPMkCPW1NJO56HJzNTWAl9UMdetnQzkPbPjsAC4=
|
||||
github.com/status-im/tcp-shaker v0.0.0-20191114194237-215893130501 h1:oa0KU5jJRNtXaM/P465MhvSFo/HM2O8qi2DDuPcd7ro=
|
||||
|
@ -789,6 +791,7 @@ golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191025090151-53bf42e6b339/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191113165036-4c7a9d0fe056 h1:dHtDnRWQtSx0Hjq9kvKFpBh9uPPKfQN70NZZmvssGwk=
|
||||
golang.org/x/sys v0.0.0-20191113165036-4c7a9d0fe056/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82 h1:ywK/j/KkyTHcdyYSZNXGjMwgmDSfjglYZ3vStQ/gSCU=
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/log"
|
||||
|
||||
"github.com/status-im/status-go/api"
|
||||
"github.com/status-im/status-go/api/multiformat"
|
||||
"github.com/status-im/status-go/eth-node/types"
|
||||
"github.com/status-im/status-go/exportlogs"
|
||||
"github.com/status-im/status-go/extkeys"
|
||||
|
@ -668,3 +669,25 @@ func ValidateMnemonic(mnemonic string) string {
|
|||
err := m.ValidateMnemonic(mnemonic, extkeys.Language(0))
|
||||
return makeJSONResponse(err)
|
||||
}
|
||||
|
||||
// SerializePublicKey compresses an uncompressed multibase encoded multicodec identified EC public key
|
||||
// For details on usage see specs //TODO add the link to the specs
|
||||
func MultiformatSerializePublicKey(key, outBase string) string {
|
||||
cpk, err := multiformat.SerializePublicKey(key, outBase)
|
||||
if err != nil {
|
||||
return makeJSONResponse(err)
|
||||
}
|
||||
|
||||
return cpk
|
||||
}
|
||||
|
||||
// DeserializePublicKey decompresses a compressed multibase encoded multicodec identified EC public key
|
||||
// For details on usage see specs //TODO add the link to the specs
|
||||
func MultiformatDeserializePublicKey(key, outBase string) string {
|
||||
pk, err := multiformat.DeserializePublicKey(key, outBase)
|
||||
if err != nil {
|
||||
return makeJSONResponse(err)
|
||||
}
|
||||
|
||||
return pk
|
||||
}
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
*.out
|
||||
eip2537
|
|
@ -0,0 +1,202 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
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.
|
|
@ -0,0 +1,30 @@
|
|||
### High Speed BLS12-381 Implementation in Go
|
||||
|
||||
#### Pairing Instance
|
||||
|
||||
A Group instance or a pairing engine instance _is not_ suitable for concurrent processing since an instance has its own preallocated memory for temporary variables. A new instance must be created for each thread.
|
||||
|
||||
#### Base Field
|
||||
|
||||
x86 optimized base field is generated with [kilic/fp](https://github.com/kilic/fp) and for native go is generated with [goff](https://github.com/ConsenSys/goff). Generated codes are slightly edited in both for further requirements.
|
||||
|
||||
#### Scalar Field
|
||||
|
||||
Standart big.Int module is currently used for scalar field implementation. x86 optimized faster field implementation is planned to be added.
|
||||
|
||||
#### Serialization
|
||||
|
||||
Point serialization is in line with [zkcrypto library](https://github.com/zkcrypto/pairing/tree/master/src/bls12_381#serialization).
|
||||
|
||||
#### Hashing to Curve
|
||||
|
||||
Hashing to curve implementations for both G1 and G2 follows `_XMD:SHA-256_SSWU_RO_` and `_XMD:SHA-256_SSWU_NU_` suites as defined in `v7` of [irtf hash to curve draft](https://github.com/cfrg/draft-irtf-cfrg-hash-to-curve/).
|
||||
|
||||
#### Benchmarks
|
||||
|
||||
on _3.1 GHz i5_
|
||||
|
||||
```
|
||||
BenchmarkPairing 1034837 ns/op
|
||||
```
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
// +build amd64,!generic
|
||||
|
||||
package bls12381
|
||||
|
||||
import (
|
||||
"golang.org/x/sys/cpu"
|
||||
)
|
||||
|
||||
func init() {
|
||||
if !cpu.X86.HasADX || !cpu.X86.HasBMI2 {
|
||||
mul = mulNoADX
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
|
@ -0,0 +1,566 @@
|
|||
// +build !amd64 generic
|
||||
|
||||
// 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
|
||||
|
||||
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
|
@ -0,0 +1,234 @@
|
|||
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}
|
||||
|
||||
// -p^(-1) mod 2^64
|
||||
var inp uint64 = 0x89f3fffcfffcfffd
|
||||
|
||||
// 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},
|
||||
}
|
||||
|
||||
// Group order
|
||||
var q = bigFromHex("0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001")
|
||||
|
||||
// G1 cofactor
|
||||
var cofactorG1 = bigFromHex("0x396c8c005555e1568c00aaab0000aaab")
|
||||
|
||||
// G2 cofactor
|
||||
var cofactorG2 = bigFromHex("5d543a95414e7f1091d50792876a202cd91de4547085abaa68a205b2e5a7ddfa628f1cb4d9e82ef21537e293a6691ae1616ec6e786f0c70cf1c38e31c7238e5")
|
||||
|
||||
// Efficient G1 cofactor
|
||||
var cofactorEFFG1 = bigFromHex("0xd201000000010001")
|
||||
|
||||
// Efficient G2 cofactor
|
||||
var cofactorEFFG2 = bigFromHex("0x0bc69f08f2ee75b3584c6a0ea91b352888e2a8e9145ad7689986ff031508ffe1329c2f178731db956d82bf015d1212b02ec0ec69d7477c1ae954cbc06689f6a359894c0adebbf6b4e8020005aaa95551")
|
||||
|
||||
// G1 generator
|
||||
var g1One = PointG1{
|
||||
fe{0x5cb38790fd530c16, 0x7817fc679976fff5, 0x154f95c7143ba1c1, 0xf0ae6acdf3d0e747, 0xedce6ecc21dbf440, 0x120177419e0bfb75},
|
||||
fe{0xbaac93d50ce72271, 0x8c22631a7918fd8e, 0xdd595f13570725ce, 0x51ac582950405194, 0x0e1c8c3fad0059c0, 0x0bbc3efc5008a26a},
|
||||
fe{0x760900000002fffd, 0xebf4000bc40c0002, 0x5f48985753c758ba, 0x77ce585370525745, 0x5c071a97a256ec6d, 0x15f65ec3fa80e493},
|
||||
}
|
||||
|
||||
var G1One = g1One
|
||||
|
||||
// Negated G1 generator
|
||||
var g1NegativeOne = PointG1{
|
||||
fe{0x5cb38790fd530c16, 0x7817fc679976fff5, 0x154f95c7143ba1c1, 0xf0ae6acdf3d0e747, 0xedce6ecc21dbf440, 0x120177419e0bfb75},
|
||||
fe{0xff526c2af318883a, 0x92899ce4383b0270, 0x89d7738d9fa9d055, 0x12caf35ba344c12a, 0x3cff1b76964b5317, 0x0e44d2ede9774430},
|
||||
fe{0x760900000002fffd, 0xebf4000bc40c0002, 0x5f48985753c758ba, 0x77ce585370525745, 0x5c071a97a256ec6d, 0x15f65ec3fa80e493},
|
||||
}
|
||||
|
||||
// G2 generator
|
||||
var g2One = PointG2{
|
||||
fe2{
|
||||
fe{0xf5f28fa202940a10, 0xb3f5fb2687b4961a, 0xa1a893b53e2ae580, 0x9894999d1a3caee9, 0x6f67b7631863366b, 0x058191924350bcd7},
|
||||
fe{0xa5a9c0759e23f606, 0xaaa0c59dbccd60c3, 0x3bb17e18e2867806, 0x1b1ab6cc8541b367, 0xc2b6ed0ef2158547, 0x11922a097360edf3},
|
||||
},
|
||||
fe2{
|
||||
fe{0x4c730af860494c4a, 0x597cfa1f5e369c5a, 0xe7e6856caa0a635a, 0xbbefb5e96e0d495f, 0x07d3a975f0ef25a2, 0x083fd8e7e80dae5},
|
||||
fe{0xadc0fc92df64b05d, 0x18aa270a2b1461dc, 0x86adac6a3be4eba0, 0x79495c4ec93da33a, 0xe7175850a43ccaed, 0xb2bc2a163de1bf2},
|
||||
},
|
||||
fe2{
|
||||
fe{0x760900000002fffd, 0xebf4000bc40c0002, 0x5f48985753c758ba, 0x77ce585370525745, 0x5c071a97a256ec6d, 0x15f65ec3fa80e493},
|
||||
fe{0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000},
|
||||
},
|
||||
}
|
||||
|
||||
var G2One = g2One
|
||||
|
||||
/*
|
||||
Frobenious Coeffs
|
||||
*/
|
||||
|
||||
var frobeniusCoeffs2 = [2]fe{
|
||||
fe{0x760900000002fffd, 0xebf4000bc40c0002, 0x5f48985753c758ba, 0x77ce585370525745, 0x5c071a97a256ec6d, 0x15f65ec3fa80e493},
|
||||
fe{0x43f5fffffffcaaae, 0x32b7fff2ed47fffd, 0x07e83a49a2e99d69, 0xeca8f3318332bb7a, 0xef148d1ea0f4c069, 0x040ab3263eff0206},
|
||||
}
|
||||
|
||||
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")
|
|
@ -0,0 +1,338 @@
|
|||
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 extention of base field 'fp'
|
||||
// Representation follows c[0] + c[1] * u encoding order.
|
||||
type fe2 /** ***/ [2]fe
|
||||
|
||||
// fe6 is element representation of 'fp6' field which is cubic extention of 'fp2'
|
||||
// Representation follows c[0] + c[1] * v + c[2] * v^2 encoding order.
|
||||
type fe6 /** ***/ [3]fe2
|
||||
|
||||
// fe12 is element representation of 'fp12' field which is quadratic extention of 'fp6'
|
||||
// Representation follows c[0] + c[1] * w encoding order.
|
||||
type fe12 /** ***/ [2]fe6
|
||||
|
||||
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) == -1
|
||||
}
|
||||
|
||||
func (fe *fe) isOdd() bool {
|
||||
var mask uint64 = 1
|
||||
return fe[0]&mask != 0
|
||||
}
|
||||
|
||||
func (fe *fe) isEven() bool {
|
||||
var mask uint64 = 1
|
||||
return fe[0]&mask == 0
|
||||
}
|
||||
|
||||
func (fe *fe) isZero() bool {
|
||||
return (fe[5] | fe[4] | fe[3] | fe[2] | fe[1] | fe[0]) == 0
|
||||
}
|
||||
|
||||
func (fe *fe) isOne() bool {
|
||||
return fe.equal(r1)
|
||||
}
|
||||
|
||||
func (fe *fe) cmp(fe2 *fe) int {
|
||||
for i := 5; i > -1; i-- {
|
||||
if fe[i] > fe2[i] {
|
||||
return 1
|
||||
} else if fe[i] < fe2[i] {
|
||||
return -1
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (fe *fe) equal(fe2 *fe) bool {
|
||||
return fe2[0] == fe[0] && fe2[1] == fe[1] && fe2[2] == fe[2] && fe2[3] == fe[3] && fe2[4] == fe[4] && fe2[5] == fe[5]
|
||||
}
|
||||
|
||||
func (e *fe) signBE() bool {
|
||||
negZ, z := new(fe), new(fe)
|
||||
fromMont(z, e)
|
||||
neg(negZ, z)
|
||||
return negZ.cmp(z) > -1
|
||||
}
|
||||
|
||||
func (e *fe) sign() bool {
|
||||
r := new(fe)
|
||||
fromMont(r, e)
|
||||
return r[0]&1 == 0
|
||||
}
|
||||
|
||||
func (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) signBE() bool {
|
||||
if !e[1].isZero() {
|
||||
return e[1].signBE()
|
||||
}
|
||||
return e[0].signBE()
|
||||
}
|
||||
|
||||
func (e *fe2) sign() bool {
|
||||
r := new(fe)
|
||||
if !e[0].isZero() {
|
||||
fromMont(r, &e[0])
|
||||
return r[0]&1 == 0
|
||||
}
|
||||
fromMont(r, &e[1])
|
||||
return r[0]&1 == 0
|
||||
}
|
||||
|
||||
func (e *fe6) zero() *fe6 {
|
||||
e[0].zero()
|
||||
e[1].zero()
|
||||
e[2].zero()
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *fe6) one() *fe6 {
|
||||
e[0].one()
|
||||
e[1].zero()
|
||||
e[2].zero()
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *fe6) set(e2 *fe6) *fe6 {
|
||||
e[0].set(&e2[0])
|
||||
e[1].set(&e2[1])
|
||||
e[2].set(&e2[2])
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *fe6) 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])
|
||||
}
|
|
@ -0,0 +1,183 @@
|
|||
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 from64Bytes(in []byte) (*fe, error) {
|
||||
if len(in) != 64 {
|
||||
return nil, errors.New("input string should be equal 64 bytes")
|
||||
}
|
||||
a0 := make([]byte, 48)
|
||||
copy(a0[16:48], in[:32])
|
||||
a1 := make([]byte, 48)
|
||||
copy(a1[16:48], in[32:])
|
||||
e0, err := fromBytes(a0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
e1, err := fromBytes(a1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// F = 2 ^ 256 * R
|
||||
F := fe{
|
||||
0x75b3cd7c5ce820f,
|
||||
0x3ec6ba621c3edb0b,
|
||||
0x168a13d82bff6bce,
|
||||
0x87663c4bf8c449d2,
|
||||
0x15f34c83ddc8d830,
|
||||
0xf9628b49caa2e85,
|
||||
}
|
||||
|
||||
mul(e0, e0, &F)
|
||||
add(e1, e1, e0)
|
||||
return e1, nil
|
||||
}
|
||||
|
||||
func fromBig(in *big.Int) (*fe, error) {
|
||||
fe := new(fe).setBig(in)
|
||||
if !fe.isValid() {
|
||||
return nil, errors.New("invalid input string")
|
||||
}
|
||||
toMont(fe, fe)
|
||||
return fe, nil
|
||||
}
|
||||
|
||||
func fromString(in string) (*fe, error) {
|
||||
fe, err := new(fe).setString(in)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !fe.isValid() {
|
||||
return nil, errors.New("invalid input string")
|
||||
}
|
||||
toMont(fe, fe)
|
||||
return fe, nil
|
||||
}
|
||||
|
||||
func toBytes(e *fe) []byte {
|
||||
e2 := new(fe)
|
||||
fromMont(e2, e)
|
||||
return e2.bytes()
|
||||
}
|
||||
|
||||
func toBig(e *fe) *big.Int {
|
||||
e2 := new(fe)
|
||||
fromMont(e2, e)
|
||||
return e2.big()
|
||||
}
|
||||
|
||||
func toString(e *fe) (s string) {
|
||||
e2 := new(fe)
|
||||
fromMont(e2, e)
|
||||
return e2.string()
|
||||
}
|
||||
|
||||
func toMont(c, a *fe) {
|
||||
mul(c, a, r2)
|
||||
}
|
||||
|
||||
func fromMont(c, a *fe) {
|
||||
mul(c, a, &fe{1})
|
||||
}
|
||||
|
||||
func 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)
|
||||
return
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
|
@ -0,0 +1,263 @@
|
|||
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])
|
||||
}
|
||||
}
|
|
@ -0,0 +1,245 @@
|
|||
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("input string should be larger than 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) fromMont(c, a *fe2) {
|
||||
fromMont(&c[0], &a[0])
|
||||
fromMont(&c[1], &a[1])
|
||||
}
|
||||
|
||||
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) conjugate(c, a *fe2) {
|
||||
c[0].set(&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) frobeniousMap(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) frobeniousMapAssign(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 {
|
||||
c0, c1 := new(fe), new(fe)
|
||||
square(c0, &a[0])
|
||||
square(c1, &a[1])
|
||||
add(c1, c1, c0)
|
||||
return isQuadraticNonResidue(c1)
|
||||
}
|
|
@ -0,0 +1,342 @@
|
|||
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) conjugate(c, a *fe6) {
|
||||
fp2 := e.fp2
|
||||
c[0].set(&a[0])
|
||||
fp2.neg(&c[1], &a[1])
|
||||
c[0].set(&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.frobeniousMap(&c[0], &a[0], power)
|
||||
fp2.frobeniousMap(&c[1], &a[1], power)
|
||||
fp2.frobeniousMap(&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.frobeniousMapAssign(&a[0], power)
|
||||
fp2.frobeniousMapAssign(&a[1], power)
|
||||
fp2.frobeniousMapAssign(&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])
|
||||
}
|
||||
}
|
|
@ -0,0 +1,551 @@
|
|||
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 accounted 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
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
// FromUncompressed expects byte slice larger than 96 bytes and given bytes returns a new point in G1.
|
||||
// Serialization rules are in line with zcash library. See below for details.
|
||||
// https://github.com/zcash/librustzcash/blob/master/pairing/src/bls12_381/README.md#serialization
|
||||
// https://docs.rs/bls12_381/0.1.1/bls12_381/notes/serialization/index.html
|
||||
func (g *G1) FromUncompressed(uncompressed []byte) (*PointG1, error) {
|
||||
if len(uncompressed) < 96 {
|
||||
return nil, errors.New("input string should be equal or larger than 96")
|
||||
}
|
||||
var in [96]byte
|
||||
copy(in[:], uncompressed[:96])
|
||||
if in[0]&(1<<7) != 0 {
|
||||
return nil, errors.New("input string should be equal or larger than 96")
|
||||
}
|
||||
if in[0]&(1<<5) != 0 {
|
||||
return nil, errors.New("input string should be equal or larger than 96")
|
||||
}
|
||||
if in[0]&(1<<6) != 0 {
|
||||
for i, v := range in {
|
||||
if (i == 0 && v != 0x40) || (i != 0 && v != 0x00) {
|
||||
return nil, errors.New("input string should be equal or larger than 96")
|
||||
}
|
||||
}
|
||||
return g.Zero(), nil
|
||||
}
|
||||
in[0] &= 0x1f
|
||||
x, err := fromBytes(in[:48])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
y, err := fromBytes(in[48:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
z := new(fe).one()
|
||||
p := &PointG1{*x, *y, *z}
|
||||
if !g.IsOnCurve(p) {
|
||||
return nil, errors.New("input string should be equal or larger than 96")
|
||||
}
|
||||
if !g.InCorrectSubgroup(p) {
|
||||
return nil, errors.New("input string should be equal or larger than 96")
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// ToUncompressed given a G1 point returns bytes in uncompressed (x, y) form of the point.
|
||||
// Serialization rules are in line with zcash library. See below for details.
|
||||
// https://github.com/zcash/librustzcash/blob/master/pairing/src/bls12_381/README.md#serialization
|
||||
// https://docs.rs/bls12_381/0.1.1/bls12_381/notes/serialization/index.html
|
||||
func (g *G1) ToUncompressed(p *PointG1) []byte {
|
||||
out := make([]byte, 96)
|
||||
if g.IsZero(p) {
|
||||
out[0] |= 1 << 6
|
||||
return out
|
||||
}
|
||||
g.Affine(p)
|
||||
copy(out[:48], toBytes(&p[0]))
|
||||
copy(out[48:], toBytes(&p[1]))
|
||||
return out
|
||||
}
|
||||
|
||||
// FromCompressed expects byte slice larger than 96 bytes and given bytes returns a new point in G1.
|
||||
// Serialization rules are in line with zcash library. See below for details.
|
||||
// https://github.com/zcash/librustzcash/blob/master/pairing/src/bls12_381/README.md#serialization
|
||||
// https://docs.rs/bls12_381/0.1.1/bls12_381/notes/serialization/index.html
|
||||
func (g *G1) FromCompressed(compressed []byte) (*PointG1, error) {
|
||||
if len(compressed) < 48 {
|
||||
return nil, errors.New("input string should be equal or larger than 48")
|
||||
}
|
||||
var in [48]byte
|
||||
copy(in[:], compressed[:])
|
||||
if in[0]&(1<<7) == 0 {
|
||||
return nil, errors.New("compression flag should be set")
|
||||
}
|
||||
if in[0]&(1<<6) != 0 {
|
||||
// in[0] == (1 << 6) + (1 << 7)
|
||||
for i, v := range in {
|
||||
if (i == 0 && v != 0xc0) || (i != 0 && v != 0x00) {
|
||||
return nil, errors.New("input string should be zero when infinity flag is set")
|
||||
}
|
||||
}
|
||||
return g.Zero(), nil
|
||||
}
|
||||
a := in[0]&(1<<5) != 0
|
||||
in[0] &= 0x1f
|
||||
x, err := fromBytes(in[:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// solve curve equation
|
||||
y := &fe{}
|
||||
square(y, x)
|
||||
mul(y, y, x)
|
||||
add(y, y, b)
|
||||
if ok := sqrt(y, y); !ok {
|
||||
return nil, errors.New("point is not on curve")
|
||||
}
|
||||
if y.signBE() == a {
|
||||
neg(y, y)
|
||||
}
|
||||
z := new(fe).one()
|
||||
p := &PointG1{*x, *y, *z}
|
||||
if !g.InCorrectSubgroup(p) {
|
||||
return nil, errors.New("point is not on correct subgroup")
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// ToCompressed given a G1 point returns bytes in compressed form of the point.
|
||||
// Serialization rules are in line with zcash library. See below for details.
|
||||
// https://github.com/zcash/librustzcash/blob/master/pairing/src/bls12_381/README.md#serialization
|
||||
// https://docs.rs/bls12_381/0.1.1/bls12_381/notes/serialization/index.html
|
||||
func (g *G1) ToCompressed(p *PointG1) []byte {
|
||||
out := make([]byte, 48)
|
||||
g.Affine(p)
|
||||
if g.IsZero(p) {
|
||||
out[0] |= 1 << 6
|
||||
} else {
|
||||
copy(out[:], toBytes(&p[0]))
|
||||
if !p[1].signBE() {
|
||||
out[0] |= 1 << 5
|
||||
}
|
||||
}
|
||||
out[0] |= 1 << 7
|
||||
return out
|
||||
}
|
||||
|
||||
func (g *G1) fromBytesUnchecked(in []byte) (*PointG1, error) {
|
||||
p0, err := fromBytes(in[: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
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// 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)
|
||||
} else {
|
||||
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
|
||||
}
|
||||
|
||||
// EncodeToCurve given a message and domain seperator tag returns the hash result
|
||||
// which is a valid curve point.
|
||||
// Implementation follows BLS12381G1_XMD:SHA-256_SSWU_NU_ suite at
|
||||
// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06
|
||||
func (g *G1) EncodeToCurve(msg, domain []byte) (*PointG1, error) {
|
||||
hashRes, err := hashToFpXMDSHA256(msg, domain, 1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
u := hashRes[0]
|
||||
x, y := swuMapG1(u)
|
||||
isogenyMapG1(x, y)
|
||||
one := new(fe).one()
|
||||
p := &PointG1{*x, *y, *one}
|
||||
g.ClearCofactor(p)
|
||||
return g.Affine(p), nil
|
||||
}
|
||||
|
||||
// HashToCurve given a message and domain seperator tag returns the hash result
|
||||
// which is a valid curve point.
|
||||
// Implementation follows BLS12381G1_XMD:SHA-256_SSWU_RO_ suite at
|
||||
// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06
|
||||
func (g *G1) HashToCurve(msg, domain []byte) (*PointG1, error) {
|
||||
hashRes, err := hashToFpXMDSHA256(msg, domain, 2)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
u0, u1 := hashRes[0], hashRes[1]
|
||||
x0, y0 := swuMapG1(u0)
|
||||
x1, y1 := swuMapG1(u1)
|
||||
one := new(fe).one()
|
||||
p0, p1 := &PointG1{*x0, *y0, *one}, &PointG1{*x1, *y1, *one}
|
||||
g.Add(p0, p0, p1)
|
||||
g.Affine(p0)
|
||||
isogenyMapG1(&p0[0], &p0[1])
|
||||
g.ClearCofactor(p0)
|
||||
return g.Affine(p0), nil
|
||||
}
|
|
@ -0,0 +1,604 @@
|
|||
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 accounted 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
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
// FromUncompressed expects byte slice larger than 192 bytes and given bytes returns a new point in G2.
|
||||
// Serialization rules are in line with zcash library. See below for details.
|
||||
// https://github.com/zcash/librustzcash/blob/master/pairing/src/bls12_381/README.md#serialization
|
||||
// https://docs.rs/bls12_381/0.1.1/bls12_381/notes/serialization/index.html
|
||||
func (g *G2) FromUncompressed(uncompressed []byte) (*PointG2, error) {
|
||||
if len(uncompressed) < 192 {
|
||||
return nil, errors.New("input string should be equal or larger than 192")
|
||||
}
|
||||
var in [192]byte
|
||||
copy(in[:], uncompressed[:192])
|
||||
if in[0]&(1<<7) != 0 {
|
||||
return nil, errors.New("compression flag should be zero")
|
||||
}
|
||||
if in[0]&(1<<5) != 0 {
|
||||
return nil, errors.New("sort flag should be zero")
|
||||
}
|
||||
if in[0]&(1<<6) != 0 {
|
||||
for i, v := range in {
|
||||
if (i == 0 && v != 0x40) || (i != 0 && v != 0x00) {
|
||||
return nil, errors.New("input string should be zero when infinity flag is set")
|
||||
}
|
||||
}
|
||||
return g.Zero(), nil
|
||||
}
|
||||
in[0] &= 0x1f
|
||||
x, err := g.f.fromBytes(in[:96])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
y, err := g.f.fromBytes(in[96:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
z := new(fe2).one()
|
||||
p := &PointG2{*x, *y, *z}
|
||||
if !g.IsOnCurve(p) {
|
||||
return nil, errors.New("point is not on curve")
|
||||
}
|
||||
if !g.InCorrectSubgroup(p) {
|
||||
return nil, errors.New("point is not on correct subgroup")
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// ToUncompressed given a G2 point returns bytes in uncompressed (x, y) form of the point.
|
||||
// Serialization rules are in line with zcash library. See below for details.
|
||||
// https://github.com/zcash/librustzcash/blob/master/pairing/src/bls12_381/README.md#serialization
|
||||
// https://docs.rs/bls12_381/0.1.1/bls12_381/notes/serialization/index.html
|
||||
func (g *G2) ToUncompressed(p *PointG2) []byte {
|
||||
out := make([]byte, 192)
|
||||
g.Affine(p)
|
||||
if g.IsZero(p) {
|
||||
out[0] |= 1 << 6
|
||||
return out
|
||||
}
|
||||
copy(out[:96], g.f.toBytes(&p[0]))
|
||||
copy(out[96:], g.f.toBytes(&p[1]))
|
||||
return out
|
||||
}
|
||||
|
||||
// FromCompressed expects byte slice larger than 96 bytes and given bytes returns a new point in G2.
|
||||
// Serialization rules are in line with zcash library. See below for details.
|
||||
// https://github.com/zcash/librustzcash/blob/master/pairing/src/bls12_381/README.md#serialization
|
||||
// https://docs.rs/bls12_381/0.1.1/bls12_381/notes/serialization/index.html
|
||||
func (g *G2) FromCompressed(compressed []byte) (*PointG2, error) {
|
||||
if len(compressed) < 96 {
|
||||
return nil, errors.New("input string should be equal or larger than 96")
|
||||
}
|
||||
var in [96]byte
|
||||
copy(in[:], compressed[:])
|
||||
if in[0]&(1<<7) == 0 {
|
||||
return nil, errors.New("bad compression")
|
||||
}
|
||||
if in[0]&(1<<6) != 0 {
|
||||
// in[0] == (1 << 6) + (1 << 7)
|
||||
for i, v := range in {
|
||||
if (i == 0 && v != 0xc0) || (i != 0 && v != 0x00) {
|
||||
return nil, errors.New("input string should be zero when infinity flag is set")
|
||||
}
|
||||
}
|
||||
return g.Zero(), nil
|
||||
}
|
||||
a := in[0]&(1<<5) != 0
|
||||
in[0] &= 0x1f
|
||||
x, err := g.f.fromBytes(in[:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// solve curve equation
|
||||
y := &fe2{}
|
||||
g.f.square(y, x)
|
||||
g.f.mul(y, y, x)
|
||||
g.f.add(y, y, b2)
|
||||
if ok := g.f.sqrt(y, y); !ok {
|
||||
return nil, errors.New("point is not on curve")
|
||||
}
|
||||
if y.signBE() == a {
|
||||
g.f.neg(y, y)
|
||||
}
|
||||
z := new(fe2).one()
|
||||
p := &PointG2{*x, *y, *z}
|
||||
if !g.InCorrectSubgroup(p) {
|
||||
return nil, errors.New("point is not on correct subgroup")
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// ToCompressed given a G2 point returns bytes in compressed form of the point.
|
||||
// Serialization rules are in line with zcash library. See below for details.
|
||||
// https://github.com/zcash/librustzcash/blob/master/pairing/src/bls12_381/README.md#serialization
|
||||
// https://docs.rs/bls12_381/0.1.1/bls12_381/notes/serialization/index.html
|
||||
func (g *G2) ToCompressed(p *PointG2) []byte {
|
||||
out := make([]byte, 96)
|
||||
g.Affine(p)
|
||||
if g.IsZero(p) {
|
||||
out[0] |= 1 << 6
|
||||
} else {
|
||||
copy(out[:], g.f.toBytes(&p[0]))
|
||||
if !p[1].signBE() {
|
||||
out[0] |= 1 << 5
|
||||
}
|
||||
}
|
||||
out[0] |= 1 << 7
|
||||
return out
|
||||
}
|
||||
|
||||
func (g *G2) fromBytesUnchecked(in []byte) (*PointG2, error) {
|
||||
p0, err := g.f.fromBytes(in[: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
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// 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)
|
||||
} else {
|
||||
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) *PointG2 {
|
||||
return g.wnafMul(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
|
||||
}
|
||||
|
||||
func (g *G2) wnafMul(c, p *PointG2, e *big.Int) *PointG2 {
|
||||
windowSize := uint(6)
|
||||
precompTable := make([]*PointG2, (1 << (windowSize - 1)))
|
||||
for i := 0; i < len(precompTable); i++ {
|
||||
precompTable[i] = g.New()
|
||||
}
|
||||
var indexForPositive uint64 = (1 << (windowSize - 2))
|
||||
precompTable[indexForPositive].Set(p)
|
||||
g.Neg(precompTable[indexForPositive-1], p)
|
||||
doubled, precomp := g.New(), g.New()
|
||||
g.Double(doubled, p)
|
||||
precomp.Set(p)
|
||||
for i := uint64(1); i < indexForPositive; i++ {
|
||||
g.Add(precomp, precomp, doubled)
|
||||
precompTable[indexForPositive+i].Set(precomp)
|
||||
g.Neg(precompTable[indexForPositive-1-i], precomp)
|
||||
}
|
||||
wnaf := wnaf(e, windowSize)
|
||||
q := g.Zero()
|
||||
found := false
|
||||
var idx uint64
|
||||
for i := len(wnaf) - 1; i >= 0; i-- {
|
||||
if found {
|
||||
g.Double(q, q)
|
||||
}
|
||||
if wnaf[i] != 0 {
|
||||
found = true
|
||||
if wnaf[i] > 0 {
|
||||
idx = uint64(wnaf[i] >> 1)
|
||||
g.Add(q, q, precompTable[indexForPositive+idx])
|
||||
} else {
|
||||
idx = uint64(((0 - wnaf[i]) >> 1))
|
||||
g.Add(q, q, precompTable[indexForPositive-1-idx])
|
||||
}
|
||||
}
|
||||
}
|
||||
return c.Set(q)
|
||||
}
|
||||
|
||||
// MapToCurve given a byte slice returns a valid G2 point.
|
||||
// This mapping function implements the Simplified Shallue-van de Woestijne-Ulas method.
|
||||
// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-05#section-6.6.2
|
||||
// Input byte slice should be a valid field element, otherwise an error is returned.
|
||||
func (g *G2) MapToCurve(in []byte) (*PointG2, error) {
|
||||
fp2 := g.f
|
||||
u, err := fp2.fromBytes(in)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
x, y := swuMapG2(fp2, u)
|
||||
isogenyMapG2(fp2, x, y)
|
||||
z := new(fe2).one()
|
||||
q := &PointG2{*x, *y, *z}
|
||||
g.ClearCofactor(q)
|
||||
return g.Affine(q), nil
|
||||
}
|
||||
|
||||
// EncodeToCurve given a message and domain seperator tag returns the hash result
|
||||
// which is a valid curve point.
|
||||
// Implementation follows BLS12381G1_XMD:SHA-256_SSWU_NU_ suite at
|
||||
// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06
|
||||
func (g *G2) EncodeToCurve(msg, domain []byte) (*PointG2, error) {
|
||||
hashRes, err := hashToFpXMDSHA256(msg, domain, 2)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fp2 := g.f
|
||||
u := &fe2{*hashRes[0], *hashRes[1]}
|
||||
x, y := swuMapG2(fp2, u)
|
||||
isogenyMapG2(fp2, x, y)
|
||||
z := new(fe2).one()
|
||||
q := &PointG2{*x, *y, *z}
|
||||
g.ClearCofactor(q)
|
||||
return g.Affine(q), nil
|
||||
}
|
||||
|
||||
// HashToCurve given a message and domain seperator tag returns the hash result
|
||||
// which is a valid curve point.
|
||||
// Implementation follows BLS12381G1_XMD:SHA-256_SSWU_RO_ suite at
|
||||
// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06
|
||||
func (g *G2) HashToCurve(msg, domain []byte) (*PointG2, error) {
|
||||
hashRes, err := hashToFpXMDSHA256(msg, domain, 4)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fp2 := g.f
|
||||
u0, u1 := &fe2{*hashRes[0], *hashRes[1]}, &fe2{*hashRes[2], *hashRes[3]}
|
||||
x0, y0 := swuMapG2(fp2, u0)
|
||||
x1, y1 := swuMapG2(fp2, u1)
|
||||
z0 := new(fe2).one()
|
||||
z1 := new(fe2).one()
|
||||
p0, p1 := &PointG2{*x0, *y0, *z0}, &PointG2{*x1, *y1, *z1}
|
||||
g.Add(p0, p0, p1)
|
||||
g.Affine(p0)
|
||||
isogenyMapG2(fp2, &p0[0], &p0[1])
|
||||
g.ClearCofactor(p0)
|
||||
return g.Affine(p0), nil
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
module github.com/kilic/bls12-381
|
||||
|
||||
go 1.12
|
||||
|
||||
require golang.org/x/sys v0.0.0-20191025090151-53bf42e6b339
|
|
@ -0,0 +1,2 @@
|
|||
golang.org/x/sys v0.0.0-20191025090151-53bf42e6b339 h1:zSqWKgm/o7HAnlAzBQ+aetp9fpuyytsXnKA8eiLHYQM=
|
||||
golang.org/x/sys v0.0.0-20191025090151-53bf42e6b339/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
@ -0,0 +1,106 @@
|
|||
package bls12381
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
// E is type for target group element
|
||||
type E = fe12
|
||||
|
||||
// GT is type for target multiplicative group GT.
|
||||
type GT struct {
|
||||
fp12 *fp12
|
||||
}
|
||||
|
||||
// Set copies given value into the destination
|
||||
func (e *E) Set(e2 *E) *E {
|
||||
return e.set(e2)
|
||||
}
|
||||
|
||||
// One sets a new target group element to one
|
||||
func (e *E) One() *E {
|
||||
e = new(fe12).one()
|
||||
return e
|
||||
}
|
||||
|
||||
// IsOne returns true if given element equals to one
|
||||
func (e *E) IsOne() bool {
|
||||
return e.isOne()
|
||||
}
|
||||
|
||||
// Equal returns true if given two element is equal, otherwise returns false
|
||||
func (g *E) Equal(g2 *E) bool {
|
||||
return g.equal(g2)
|
||||
}
|
||||
|
||||
// NewGT constructs new target group instance.
|
||||
func NewGT() *GT {
|
||||
fp12 := newFp12(nil)
|
||||
return >{fp12}
|
||||
}
|
||||
|
||||
// Q returns group order in big.Int.
|
||||
func (g *GT) Q() *big.Int {
|
||||
return new(big.Int).Set(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)
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
package bls12381
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"errors"
|
||||
)
|
||||
|
||||
func hashToFpXMDSHA256(msg []byte, domain []byte, count int) ([]*fe, error) {
|
||||
randBytes, err := expandMsgSHA256XMD(msg, domain, count*64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
els := make([]*fe, count)
|
||||
for i := 0; i < count; i++ {
|
||||
els[i], err = from64Bytes(randBytes[i*64 : (i+1)*64])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return els, nil
|
||||
}
|
||||
|
||||
func expandMsgSHA256XMD(msg []byte, domain []byte, outLen int) ([]byte, error) {
|
||||
h := sha256.New()
|
||||
domainLen := uint8(len(domain))
|
||||
if domainLen > 255 {
|
||||
return nil, errors.New("invalid domain length")
|
||||
}
|
||||
// DST_prime = DST || I2OSP(len(DST), 1)
|
||||
// b_0 = H(Z_pad || msg || l_i_b_str || I2OSP(0, 1) || DST_prime)
|
||||
_, _ = h.Write(make([]byte, h.BlockSize()))
|
||||
_, _ = h.Write(msg)
|
||||
_, _ = h.Write([]byte{uint8(outLen >> 8), uint8(outLen)})
|
||||
_, _ = h.Write([]byte{0})
|
||||
_, _ = h.Write(domain)
|
||||
_, _ = h.Write([]byte{domainLen})
|
||||
b0 := h.Sum(nil)
|
||||
|
||||
// b_1 = H(b_0 || I2OSP(1, 1) || DST_prime)
|
||||
h.Reset()
|
||||
_, _ = h.Write(b0)
|
||||
_, _ = h.Write([]byte{1})
|
||||
_, _ = h.Write(domain)
|
||||
_, _ = h.Write([]byte{domainLen})
|
||||
b1 := h.Sum(nil)
|
||||
|
||||
// b_i = H(strxor(b_0, b_(i - 1)) || I2OSP(i, 1) || DST_prime)
|
||||
ell := (outLen + h.Size() - 1) / h.Size()
|
||||
bi := b1
|
||||
out := make([]byte, outLen)
|
||||
for i := 1; i < ell; i++ {
|
||||
h.Reset()
|
||||
// b_i = H(strxor(b_0, b_(i - 1)) || I2OSP(i, 1) || DST_prime)
|
||||
tmp := make([]byte, h.Size())
|
||||
for j := 0; j < h.Size(); j++ {
|
||||
tmp[j] = b0[j] ^ bi[j]
|
||||
}
|
||||
_, _ = h.Write(tmp)
|
||||
_, _ = h.Write([]byte{1 + uint8(i)})
|
||||
_, _ = h.Write(domain)
|
||||
_, _ = h.Write([]byte{domainLen})
|
||||
|
||||
// b_1 || ... || b_(ell - 1)
|
||||
copy(out[(i-1)*h.Size():i*h.Size()], bi[:])
|
||||
bi = h.Sum(nil)
|
||||
}
|
||||
// b_ell
|
||||
copy(out[(ell-1)*h.Size():], bi[:])
|
||||
return out[:outLen], nil
|
||||
}
|
|
@ -0,0 +1,211 @@
|
|||
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},
|
||||
},
|
||||
},
|
||||
}
|
|
@ -0,0 +1,266 @@
|
|||
package bls12381
|
||||
|
||||
type pair struct {
|
||||
g1 *PointG1
|
||||
g2 *PointG2
|
||||
}
|
||||
|
||||
func newPair(g1 *PointG1, g2 *PointG2) pair {
|
||||
return pair{g1, g2}
|
||||
}
|
||||
|
||||
// Engine is BLS12-381 elliptic curve pairing engine
|
||||
type Engine struct {
|
||||
G1 *G1
|
||||
G2 *G2
|
||||
fp12 *fp12
|
||||
fp2 *fp2
|
||||
pairingEngineTemp
|
||||
pairs []pair
|
||||
}
|
||||
|
||||
// NewEngine creates new pairing engine insteace.
|
||||
func NewEngine() *Engine {
|
||||
fp2 := newFp2()
|
||||
fp6 := newFp6(fp2)
|
||||
fp12 := newFp12(fp6)
|
||||
g1 := NewG1()
|
||||
g2 := newG2(fp2)
|
||||
return &Engine{
|
||||
fp2: fp2,
|
||||
fp12: fp12,
|
||||
G1: g1,
|
||||
G2: g2,
|
||||
pairingEngineTemp: newEngineTemp(),
|
||||
}
|
||||
}
|
||||
|
||||
type pairingEngineTemp struct {
|
||||
t2 [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 := int(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()
|
||||
}
|
|
@ -0,0 +1,142 @@
|
|||
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},
|
||||
},
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package bls12381
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
)
|
||||
|
||||
func bigFromHex(hex string) *big.Int {
|
||||
if len(hex) > 1 && hex[:2] == "0x" {
|
||||
hex = hex[2:]
|
||||
}
|
||||
n, _ := new(big.Int).SetString(hex, 16)
|
||||
return n
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package bls12381
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
)
|
||||
|
||||
func wnaf(e0 *big.Int, window uint) []int64 {
|
||||
e := new(big.Int).Set(e0)
|
||||
zero := big.NewInt(0)
|
||||
if e.Cmp(zero) == 0 {
|
||||
return []int64{}
|
||||
}
|
||||
max := int64(1 << window)
|
||||
midpoint := int64(1 << (window - 1))
|
||||
modulusMask := uint64(1<<window) - 1
|
||||
var out []int64
|
||||
for e.Cmp(zero) != 0 {
|
||||
var z int64
|
||||
if e.Bit(0)&1 == 1 {
|
||||
maskedBits := int64(e.Uint64() & modulusMask)
|
||||
if maskedBits > midpoint {
|
||||
z = maskedBits - max
|
||||
e.Add(e, new(big.Int).SetInt64(0-z))
|
||||
} else {
|
||||
z = maskedBits
|
||||
e.Sub(e, new(big.Int).SetInt64(z))
|
||||
}
|
||||
} else {
|
||||
z = 0
|
||||
}
|
||||
out = append(out, z)
|
||||
e.Rsh(e, 1)
|
||||
}
|
||||
return out
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
os:
|
||||
- linux
|
||||
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.11.x
|
||||
|
||||
env:
|
||||
global:
|
||||
- GOTFLAGS="-race"
|
||||
- GO111MODULE=on
|
||||
matrix:
|
||||
- BUILD_DEPTYPE=gomod
|
||||
|
||||
|
||||
# disable travis install
|
||||
install:
|
||||
- true
|
||||
|
||||
script:
|
||||
- bash <(curl -s https://raw.githubusercontent.com/ipfs/ci-helpers/master/travis-ci/run-standard-tests.sh)
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- $GOPATH/pkg/mod
|
||||
- /home/travis/.cache/go-build
|
||||
|
||||
notifications:
|
||||
email: false
|
|
@ -0,0 +1,21 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2019 Protocol Labs
|
||||
|
||||
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.
|
|
@ -0,0 +1,35 @@
|
|||
# go-varint
|
||||
|
||||
[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](https://protocol.ai)
|
||||
[![](https://img.shields.io/badge/project-multiformats-blue.svg?style=flat-square)](https://github.com/multiformats/multiformats)
|
||||
[![](https://img.shields.io/badge/freenode-%23ipfs-blue.svg?style=flat-square)](https://webchat.freenode.net/?channels=%23ipfs)
|
||||
[![](https://img.shields.io/badge/readme%20style-standard-brightgreen.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme)
|
||||
[![GoDoc](https://godoc.org/github.com/multiformats/go-varint?status.svg)](https://godoc.org/github.com/multiformats/go-varint)
|
||||
[![Travis CI](https://img.shields.io/travis/multiformats/go-varint.svg?style=flat-square&branch=master)](https://travis-ci.org/multiformats/go-varint)
|
||||
[![codecov.io](https://img.shields.io/codecov/c/github/multiformats/go-varint.svg?style=flat-square&branch=master)](https://codecov.io/github/multiformats/go-varint?branch=master)
|
||||
|
||||
> Varint helpers that enforce minimal encoding.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Install](#install)
|
||||
- [Contribute](#contribute)
|
||||
- [License](#license)
|
||||
|
||||
## Install
|
||||
|
||||
```sh
|
||||
go get github.com/multiformats/go-varint
|
||||
```
|
||||
|
||||
## Contribute
|
||||
|
||||
Contributions welcome. Please check out [the issues](https://github.com/multiformats/go-multiaddr/issues).
|
||||
|
||||
Check out our [contributing document](https://github.com/multiformats/multiformats/blob/master/contributing.md) for more information on how we work, and about contributing in general. Please be aware that all interactions related to multiformats are subject to the IPFS [Code of Conduct](https://github.com/ipfs/community/blob/master/code-of-conduct.md).
|
||||
|
||||
Small note: If editing the README, please conform to the [standard-readme](https://github.com/RichardLitt/standard-readme) specification.
|
||||
|
||||
## License
|
||||
|
||||
[MIT](LICENSE) © 2019 Protocol Labs
|
|
@ -0,0 +1,2 @@
|
|||
ignore:
|
||||
- "multiaddr"
|
|
@ -0,0 +1,3 @@
|
|||
module github.com/multiformats/go-varint
|
||||
|
||||
go 1.12
|
|
@ -0,0 +1,94 @@
|
|||
package varint
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"io"
|
||||
"math/bits"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrOverflow = errors.New("varints larger than uint64 not yet supported")
|
||||
ErrUnderflow = errors.New("varints malformed, could not reach the end")
|
||||
ErrNotMinimal = errors.New("varint not minimally encoded")
|
||||
)
|
||||
|
||||
// UvarintSize returns the size (in bytes) of `num` encoded as a unsigned varint.
|
||||
func UvarintSize(num uint64) int {
|
||||
bits := bits.Len64(num)
|
||||
q, r := bits/7, bits%7
|
||||
size := q
|
||||
if r > 0 || size == 0 {
|
||||
size++
|
||||
}
|
||||
return size
|
||||
}
|
||||
|
||||
// ToUvarint converts an unsigned integer to a varint-encoded []byte
|
||||
func ToUvarint(num uint64) []byte {
|
||||
buf := make([]byte, UvarintSize(num))
|
||||
n := binary.PutUvarint(buf, uint64(num))
|
||||
return buf[:n]
|
||||
}
|
||||
|
||||
// FromUvarint reads an unsigned varint from the beginning of buf, returns the
|
||||
// varint, and the number of bytes read.
|
||||
func FromUvarint(buf []byte) (uint64, int, error) {
|
||||
// Modified from the go standard library. Copyright the Go Authors and
|
||||
// released under the BSD License.
|
||||
var x uint64
|
||||
var s uint
|
||||
for i, b := range buf {
|
||||
if b < 0x80 {
|
||||
if i > 9 || i == 9 && b > 1 {
|
||||
return 0, 0, ErrOverflow
|
||||
} else if b == 0 && s > 0 {
|
||||
return 0, 0, ErrNotMinimal
|
||||
}
|
||||
return x | uint64(b)<<s, i + 1, nil
|
||||
}
|
||||
x |= uint64(b&0x7f) << s
|
||||
s += 7
|
||||
}
|
||||
return 0, 0, ErrUnderflow
|
||||
}
|
||||
|
||||
// ReadUvarint reads a unsigned varint from the given reader.
|
||||
func ReadUvarint(r io.ByteReader) (uint64, error) {
|
||||
// Modified from the go standard library. Copyright the Go Authors and
|
||||
// released under the BSD License.
|
||||
var x uint64
|
||||
var s uint
|
||||
for i := 0; ; i++ {
|
||||
b, err := r.ReadByte()
|
||||
if err != nil {
|
||||
if err == io.EOF && i != 0 {
|
||||
// "eof" will look like a success.
|
||||
// If we've read part of a value, this is not a
|
||||
// success.
|
||||
err = io.ErrUnexpectedEOF
|
||||
}
|
||||
return 0, err
|
||||
}
|
||||
if b < 0x80 {
|
||||
if i > 9 || i == 9 && b > 1 {
|
||||
return 0, ErrOverflow
|
||||
} else if b == 0 && s > 0 {
|
||||
// we should never _finish_ on a 0 byte if we
|
||||
// have more than one byte.
|
||||
return 0, ErrNotMinimal
|
||||
}
|
||||
return x | uint64(b)<<s, nil
|
||||
}
|
||||
x |= uint64(b&0x7f) << s
|
||||
s += 7
|
||||
}
|
||||
}
|
||||
|
||||
// PutUvarint is an alias for binary.PutUvarint.
|
||||
//
|
||||
// This is provided for convenience so users of this library can avoid built-in
|
||||
// varint functions and easily audit code for uses of those functions.
|
||||
func PutUvarint(buf []byte, x uint64) int {
|
||||
return binary.PutUvarint(buf, x)
|
||||
}
|
|
@ -181,6 +181,8 @@ github.com/jbenet/goprocess/periodic
|
|||
github.com/jinzhu/copier
|
||||
# github.com/karalabe/usb v0.0.0-20191104083709-911d15fe12a9
|
||||
github.com/karalabe/usb
|
||||
# github.com/kilic/bls12-381 v0.0.0-20200607163746-32e1441c8a9f
|
||||
github.com/kilic/bls12-381
|
||||
# github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d
|
||||
github.com/koron/go-ssdp
|
||||
# github.com/leodido/go-urn v1.2.0
|
||||
|
@ -312,6 +314,8 @@ github.com/multiformats/go-multibase
|
|||
github.com/multiformats/go-multihash
|
||||
# github.com/multiformats/go-multistream v0.1.0
|
||||
github.com/multiformats/go-multistream
|
||||
# github.com/multiformats/go-varint v0.0.5
|
||||
github.com/multiformats/go-varint
|
||||
# github.com/mutecomm/go-sqlcipher v0.0.0-20190227152316-55dbde17881f
|
||||
github.com/mutecomm/go-sqlcipher
|
||||
# github.com/okzk/sdnotify v0.0.0-20180710141335-d9becc38acbd
|
||||
|
|
Loading…
Reference in New Issue