Files
mev-beta/vendor/github.com/supranational/blst/bindings/go/blst.tgo

475 lines
14 KiB
Plaintext

/*
* Copyright Supranational LLC
* Licensed under the Apache License, Version 2.0, see LICENSE for details.
* SPDX-License-Identifier: Apache-2.0
*/
package blst
// #cgo CFLAGS: -I${SRCDIR}/.. -I${SRCDIR}/../../build -I${SRCDIR}/../../src -D__BLST_CGO__ -fno-builtin-memcpy -fno-builtin-memset
// #cgo amd64 CFLAGS: -D__ADX__ -mno-avx
// // no-asm 64-bit platforms from https://go.dev/doc/install/source
// #cgo loong64 mips64 mips64le ppc64 ppc64le riscv64 s390x CFLAGS: -D__BLST_NO_ASM__
//
// #include "blst.h"
//
// #if defined(__x86_64__) && (defined(__unix__) || defined(__APPLE__))
// # include <signal.h>
// # include <unistd.h>
// static void handler(int signum)
// { ssize_t n = write(2, "Caught SIGILL in blst_cgo_init, "
// "consult <blst>/bindings/go/README.md.\n", 70);
// _exit(128+SIGILL);
// (void)n;
// }
// __attribute__((constructor)) static void blst_cgo_init()
// { blst_fp temp = { 0 };
// struct sigaction act = { handler }, oact;
// sigaction(SIGILL, &act, &oact);
// blst_fp_sqr(&temp, &temp);
// sigaction(SIGILL, &oact, NULL);
// }
// #endif
//
// static void go_pairing_init(blst_pairing *new_ctx, bool hash_or_encode,
// const byte *DST, size_t DST_len)
// { if (DST != NULL) {
// byte *dst = (byte*)new_ctx + blst_pairing_sizeof();
// for(size_t i = 0; i < DST_len; i++) dst[i] = DST[i];
// DST = dst;
// }
// blst_pairing_init(new_ctx, hash_or_encode, DST, DST_len);
// }
// static void go_pairing_as_fp12(blst_fp12 *pt, blst_pairing *ctx)
// { *pt = *blst_pairing_as_fp12(ctx); }
//
// static void go_p1slice_to_affine(blst_p1_affine dst[],
// const blst_p1 points[], size_t npoints)
// { const blst_p1 *ppoints[2] = { points, NULL };
// blst_p1s_to_affine(dst, ppoints, npoints);
// }
// static void go_p1slice_add(blst_p1 *dst, const blst_p1_affine points[],
// size_t npoints)
// { const blst_p1_affine *ppoints[2] = { points, NULL };
// blst_p1s_add(dst, ppoints, npoints);
// }
// static void go_p2slice_to_affine(blst_p2_affine dst[],
// const blst_p2 points[], size_t npoints)
// { const blst_p2 *ppoints[2] = { points, NULL };
// blst_p2s_to_affine(dst, ppoints, npoints);
// }
// static void go_p2slice_add(blst_p2 *dst, const blst_p2_affine points[],
// size_t npoints)
// { const blst_p2_affine *ppoints[2] = { points, NULL };
// blst_p2s_add(dst, ppoints, npoints);
// }
//
// static void go_p1_mult_n_acc(blst_p1 *acc, const blst_fp *x, bool affine,
// const byte *scalar, size_t nbits)
// { blst_p1 m[1];
// const void *p = x;
// if (p == NULL)
// p = blst_p1_generator();
// else if (affine)
// blst_p1_from_affine(m, p), p = m;
// blst_p1_mult(m, p, scalar, nbits);
// blst_p1_add_or_double(acc, acc, m);
// }
// static void go_p2_mult_n_acc(blst_p2 *acc, const blst_fp2 *x, bool affine,
// const byte *scalar, size_t nbits)
// { blst_p2 m[1];
// const void *p = x;
// if (p == NULL)
// p = blst_p2_generator();
// else if (affine)
// blst_p2_from_affine(m, p), p = m;
// blst_p2_mult(m, p, scalar, nbits);
// blst_p2_add_or_double(acc, acc, m);
// }
//
// static void go_p1_sub_assign(blst_p1 *a, const blst_fp *x, bool affine)
// { blst_p1 minus_b;
// if (affine)
// blst_p1_from_affine(&minus_b, (const blst_p1_affine*)x);
// else
// minus_b = *(const blst_p1*)x;
// blst_p1_cneg(&minus_b, 1);
// blst_p1_add_or_double(a, a, &minus_b);
// }
//
// static void go_p2_sub_assign(blst_p2 *a, const blst_fp2 *x, bool affine)
// { blst_p2 minus_b;
// if (affine)
// blst_p2_from_affine(&minus_b, (const blst_p2_affine*)x);
// else
// minus_b = *(const blst_p2*)x;
// blst_p2_cneg(&minus_b, 1);
// blst_p2_add_or_double(a, a, &minus_b);
// }
//
// static bool go_scalar_from_bendian(blst_scalar *ret, const byte *in)
// { blst_scalar_from_bendian(ret, in);
// return blst_sk_check(ret);
// }
// static bool go_hash_to_scalar(blst_scalar *ret,
// const byte *msg, size_t msg_len,
// const byte *DST, size_t DST_len)
// { byte elem[48];
// blst_expand_message_xmd(elem, sizeof(elem), msg, msg_len, DST, DST_len);
// return blst_scalar_from_be_bytes(ret, elem, sizeof(elem));
// }
// static void go_miller_loop_n(blst_fp12 *dst, const blst_p2_affine Q[],
// const blst_p1_affine P[],
// size_t npoints, bool acc)
// { const blst_p2_affine *Qs[2] = { Q, NULL };
// const blst_p1_affine *Ps[2] = { P, NULL };
// if (acc) {
// blst_fp12 tmp;
// blst_miller_loop_n(&tmp, Qs, Ps, npoints);
// blst_fp12_mul(dst, dst, &tmp);
// } else {
// blst_miller_loop_n(dst, Qs, Ps, npoints);
// }
// }
// static void go_fp12slice_mul(blst_fp12 *dst, const blst_fp12 in[], size_t n)
// { size_t i;
// blst_fp12_mul(dst, &in[0], &in[1]);
// for (i = 2; i < n; i++)
// blst_fp12_mul(dst, dst, &in[i]);
// }
// static bool go_p1_affine_validate(const blst_p1_affine *p, bool infcheck)
// { if (infcheck && blst_p1_affine_is_inf(p))
// return 0;
// return blst_p1_affine_in_g1(p);
// }
// static bool go_p2_affine_validate(const blst_p2_affine *p, bool infcheck)
// { if (infcheck && blst_p2_affine_is_inf(p))
// return 0;
// return blst_p2_affine_in_g2(p);
// }
import "C"
import "runtime"
const BLST_SCALAR_BYTES = 256 / 8
const BLST_FP_BYTES = 384 / 8
const BLST_P1_COMPRESS_BYTES = BLST_FP_BYTES
const BLST_P1_SERIALIZE_BYTES = BLST_FP_BYTES * 2
const BLST_P2_COMPRESS_BYTES = BLST_FP_BYTES * 2
const BLST_P2_SERIALIZE_BYTES = BLST_FP_BYTES * 4
type Scalar struct{ cgo C.blst_scalar }
type Fp struct{ cgo C.blst_fp }
type Fp2 struct{ cgo C.blst_fp2 }
type Fp6 = C.blst_fp6
type Fp12 struct{ cgo C.blst_fp12 }
type P1 struct{ cgo C.blst_p1 }
type P2 struct{ cgo C.blst_p2 }
type P1Affine struct{ cgo C.blst_p1_affine }
type P2Affine struct{ cgo C.blst_p2_affine }
type Message = []byte
type Pairing = []C.blst_pairing
type SecretKey = Scalar
type P1s []P1
type P2s []P2
type P1Affines []P1Affine
type P2Affines []P2Affine
//
// Configuration
//
var maxProcs = initMaxProcs()
func initMaxProcs() int {
maxProcs := runtime.GOMAXPROCS(0)
var version float32
_, err := fmt.Sscanf(runtime.Version(), "go%f", &version)
if err != nil || version < 1.14 {
// be cooperative and leave one processor for the application
maxProcs -= 1
}
if maxProcs <= 0 {
maxProcs = 1
}
return maxProcs
}
func SetMaxProcs(procs int) {
if procs <= 0 {
procs = 1
}
maxProcs = procs
}
func numThreads(maxThreads int) int {
numThreads := maxProcs
// take into consideration the possility that application reduced
// GOMAXPROCS after |maxProcs| was initialized
numProcs := runtime.GOMAXPROCS(0)
if maxProcs > numProcs {
numThreads = numProcs
}
if maxThreads > 0 && numThreads > maxThreads {
return maxThreads
}
return numThreads
}
var cgo_pairingSizeOf = C.blst_pairing_sizeof()
var cgo_p1Generator = P1{*C.blst_p1_generator()}
var cgo_p2Generator = P2{*C.blst_p2_generator()}
var cgo_fp12One = Fp12{*C.blst_fp12_one()}
//
// Secret key
//
func (sk *SecretKey) Zeroize() {
var zero SecretKey
*sk = zero
}
func KeyGen(ikm []byte, optional ...[]byte) *SecretKey {
var sk SecretKey
var info []byte
if len(optional) > 0 {
info = optional[0]
}
if len(ikm) < 32 {
return nil
}
C.blst_keygen(&sk.cgo, (*C.byte)(&ikm[0]), C.size_t(len(ikm)),
ptrOrNil(info), C.size_t(len(info)))
// Postponing secret key zeroing till garbage collection can be too
// late to be effective, but every little bit helps...
runtime.SetFinalizer(&sk, func(sk *SecretKey) { sk.Zeroize() })
return &sk
}
func KeyGenV3(ikm []byte, optional ...[]byte) *SecretKey {
if len(ikm) < 32 {
return nil
}
var sk SecretKey
var info []byte
if len(optional) > 0 {
info = optional[0]
}
C.blst_keygen_v3(&sk.cgo, (*C.byte)(&ikm[0]), C.size_t(len(ikm)),
ptrOrNil(info), C.size_t(len(info)))
// Postponing secret key zeroing till garbage collection can be too
// late to be effective, but every little bit helps...
runtime.SetFinalizer(&sk, func(sk *SecretKey) { sk.Zeroize() })
return &sk
}
func KeyGenV45(ikm []byte, salt []byte, optional ...[]byte) *SecretKey {
if len(ikm) < 32 {
return nil
}
var sk SecretKey
var info []byte
if len(optional) > 0 {
info = optional[0]
}
C.blst_keygen_v4_5(&sk.cgo, (*C.byte)(&ikm[0]), C.size_t(len(ikm)),
(*C.byte)(&salt[0]), C.size_t(len(salt)),
ptrOrNil(info), C.size_t(len(info)))
// Postponing secret key zeroing till garbage collection can be too
// late to be effective, but every little bit helps...
runtime.SetFinalizer(&sk, func(sk *SecretKey) { sk.Zeroize() })
return &sk
}
func KeyGenV5(ikm []byte, salt []byte, optional ...[]byte) *SecretKey {
if len(ikm) < 32 {
return nil
}
var sk SecretKey
var info []byte
if len(optional) > 0 {
info = optional[0]
}
C.blst_keygen_v5(&sk.cgo, (*C.byte)(&ikm[0]), C.size_t(len(ikm)),
(*C.byte)(&salt[0]), C.size_t(len(salt)),
ptrOrNil(info), C.size_t(len(info)))
// Postponing secret key zeroing till garbage collection can be too
// late to be effective, but every little bit helps...
runtime.SetFinalizer(&sk, func(sk *SecretKey) { sk.Zeroize() })
return &sk
}
func DeriveMasterEip2333(ikm []byte) *SecretKey {
if len(ikm) < 32 {
return nil
}
var sk SecretKey
C.blst_derive_master_eip2333(&sk.cgo, (*C.byte)(&ikm[0]), C.size_t(len(ikm)))
// Postponing secret key zeroing till garbage collection can be too
// late to be effective, but every little bit helps...
runtime.SetFinalizer(&sk, func(sk *SecretKey) { sk.Zeroize() })
return &sk
}
func (master *SecretKey) DeriveChildEip2333(child_index uint32) *SecretKey {
var sk SecretKey
C.blst_derive_child_eip2333(&sk.cgo, &master.cgo, C.uint(child_index))
// Postponing secret key zeroing till garbage collection can be too
// late to be effective, but every little bit helps...
runtime.SetFinalizer(&sk, func(sk *SecretKey) { sk.Zeroize() })
return &sk
}
//
// Pairing
//
func pairingSizeOf(DST_len C.size_t) int {
return int((cgo_pairingSizeOf + DST_len + 7) / 8)
}
func PairingCtx(hash_or_encode bool, DST []byte) Pairing {
DST_len := C.size_t(len(DST))
ctx := make([]C.blst_pairing, pairingSizeOf(DST_len))
C.go_pairing_init(&ctx[0], C.bool(hash_or_encode), ptrOrNil(DST), DST_len)
return ctx
}
func PairingCommit(ctx Pairing) {
C.blst_pairing_commit(&ctx[0])
}
func PairingMerge(ctx Pairing, ctx1 Pairing) int {
r := C.blst_pairing_merge(&ctx[0], &ctx1[0])
return int(r)
}
func PairingFinalVerify(ctx Pairing, optional ...*Fp12) bool {
var gtsig *Fp12
if len(optional) > 0 {
gtsig = optional[0]
}
return bool(C.blst_pairing_finalverify(&ctx[0], gtsig.asPtr()))
}
func PairingRawAggregate(ctx Pairing, q *P2Affine, p *P1Affine) {
C.blst_pairing_raw_aggregate(&ctx[0], &q.cgo, &p.cgo)
}
func PairingAsFp12(ctx Pairing) *Fp12 {
var pt Fp12
C.go_pairing_as_fp12(&pt.cgo, &ctx[0])
return &pt
}
func Fp12One() Fp12 {
return cgo_fp12One
}
func Fp12FinalVerify(pt1 *Fp12, pt2 *Fp12) bool {
return bool(C.blst_fp12_finalverify(&pt1.cgo, &pt2.cgo))
}
func Fp12MillerLoop(q *P2Affine, p *P1Affine) *Fp12 {
var pt Fp12
C.blst_miller_loop(&pt.cgo, &q.cgo, &p.cgo)
return &pt
}
func Fp12MillerLoopN(qs []P2Affine, ps []P1Affine) *Fp12 {
if len(qs) != len(ps) || len(qs) == 0 {
panic("inputs' lengths mismatch")
}
nElems := uint32(len(qs))
nThreads := uint32(maxProcs)
if nThreads == 1 || nElems == 1 {
var pt Fp12
C.go_miller_loop_n(&pt.cgo, &qs[0].cgo, &ps[0].cgo, C.size_t(nElems), false)
return &pt
}
stride := (nElems + nThreads - 1) / nThreads
if stride > 16 {
stride = 16
}
strides := (nElems + stride - 1) / stride
if nThreads > strides {
nThreads = strides
}
msgsCh := make(chan Fp12, nThreads)
curElem := uint32(0)
for tid := uint32(0); tid < nThreads; tid++ {
go func() {
acc := Fp12One()
first := true
for {
work := atomic.AddUint32(&curElem, stride) - stride
if work >= nElems {
break
}
n := nElems - work
if n > stride {
n = stride
}
C.go_miller_loop_n(&acc.cgo, &qs[work].cgo, &ps[work].cgo, C.size_t(n),
C.bool(!first))
first = false
}
msgsCh <- acc
}()
}
var ret = make([]Fp12, nThreads);
for i := range(ret) {
ret[i] = <- msgsCh
}
var pt Fp12
C.go_fp12slice_mul(&pt.cgo, &ret[0].cgo, C.size_t(nThreads))
return &pt
}
func (pt *Fp12) MulAssign(p *Fp12) {
C.blst_fp12_mul(&pt.cgo, &pt.cgo, &p.cgo)
}
func (pt *Fp12) FinalExp() {
C.blst_final_exp(&pt.cgo, &pt.cgo)
}
func (pt *Fp12) InGroup() bool {
return bool(C.blst_fp12_in_group(&pt.cgo))
}
func (pt *Fp12) ToBendian() []byte {
var out [BLST_FP_BYTES*12]byte
C.blst_bendian_from_fp12((*C.byte)(&out[0]), &pt.cgo)
return out[:]
}
func (pt1 *Fp12) Equals(pt2 *Fp12) bool {
return *pt1 == *pt2
}
func (pt *Fp12) asPtr() *C.blst_fp12 {
if (pt != nil) {
return &pt.cgo
}
return nil
}
func ptrOrNil(bytes []byte) *C.byte {
var ptr *C.byte
if len(bytes) > 0 {
ptr = (*C.byte)(&bytes[0])
}
return ptr
}