github.com/onflow/flow-go/crypto@v0.24.8/bls12381_utils.go (about)

     1  //go:build relic
     2  // +build relic
     3  
     4  package crypto
     5  
     6  // this file contains utility functions for the curve BLS 12-381
     7  // these tools are shared by the BLS signature scheme, the BLS based threshold signature
     8  // and the BLS distributed key generation protocols
     9  
    10  // #cgo CFLAGS: -g -Wall -std=c99 -I${SRCDIR}/ -I${SRCDIR}/relic/build/include -I${SRCDIR}/relic/include -I${SRCDIR}/relic/include/low
    11  // #cgo LDFLAGS: -L${SRCDIR}/relic/build/lib -l relic_s
    12  // #include "bls12381_utils.h"
    13  // #include "bls_include.h"
    14  import "C"
    15  import (
    16  	"errors"
    17  )
    18  
    19  // Go wrappers to Relic C types
    20  // Relic is compiled with ALLOC=AUTO
    21  type pointG1 C.ep_st
    22  type pointG2 C.ep2_st
    23  type scalar C.bn_st
    24  
    25  // context required for the BLS set-up
    26  type ctx struct {
    27  	relicCtx *C.ctx_t
    28  	precCtx  *C.prec_st
    29  }
    30  
    31  // get some constants from the C layer
    32  // (Cgo does not export C macros)
    33  var valid = C.get_valid()
    34  var invalid = C.get_invalid()
    35  
    36  // initContext sets relic B12_381 parameters and precomputes some data in the C layer
    37  func (ct *ctx) initContext() error {
    38  	c := C.relic_init_BLS12_381()
    39  	if c == nil {
    40  		return errors.New("Relic core init failed")
    41  	}
    42  	ct.relicCtx = c
    43  	ct.precCtx = C.init_precomputed_data_BLS12_381()
    44  	return nil
    45  }
    46  
    47  // seeds the internal relic random function.
    48  // relic context must be initialized before seeding.
    49  func seedRelic(seed []byte) error {
    50  	if len(seed) < (securityBits / 8) {
    51  		return invalidInputsErrorf(
    52  			"seed length needs to be larger than %d",
    53  			securityBits/8)
    54  	}
    55  	if len(seed) > maxRelicPrgSeed {
    56  		return invalidInputsErrorf(
    57  			"seed length needs to be less than %x",
    58  			maxRelicPrgSeed)
    59  	}
    60  	C.seed_relic((*C.uchar)(&seed[0]), (C.int)(len(seed)))
    61  	return nil
    62  }
    63  
    64  // setContext sets the context (previously initialized) of the C layer with
    65  // pre-saved data.
    66  func (ct *ctx) setContext() {
    67  	C.core_set(ct.relicCtx)
    68  	C.precomputed_data_set(ct.precCtx)
    69  }
    70  
    71  // Exponentiation in G1 (scalar point multiplication)
    72  func (p *pointG1) scalarMultG1(res *pointG1, expo *scalar) {
    73  	C.ep_mult((*C.ep_st)(res), (*C.ep_st)(p), (*C.bn_st)(expo))
    74  }
    75  
    76  // This function is for TEST only
    77  // Exponentiation of g1 in G1
    78  func generatorScalarMultG1(res *pointG1, expo *scalar) {
    79  	C.ep_mult_gen_bench((*C.ep_st)(res), (*C.bn_st)(expo))
    80  }
    81  
    82  // This function is for TEST only
    83  // Generic Exponentiation G1
    84  func genericScalarMultG1(res *pointG1, expo *scalar) {
    85  	C.ep_mult_generic_bench((*C.ep_st)(res), (*C.bn_st)(expo))
    86  }
    87  
    88  // Exponentiation of g2 in G2
    89  func generatorScalarMultG2(res *pointG2, expo *scalar) {
    90  	C.ep2_mult_gen((*C.ep2_st)(res), (*C.bn_st)(expo))
    91  }
    92  
    93  // comparison in Zr where r is the group order of G1/G2
    94  // (both scalars should be reduced mod r)
    95  func (x *scalar) equals(other *scalar) bool {
    96  	return C.bn_cmp((*C.bn_st)(x), (*C.bn_st)(other)) == valid
    97  }
    98  
    99  // comparison in G2
   100  func (p *pointG2) equals(other *pointG2) bool {
   101  	return C.ep2_cmp((*C.ep2_st)(p), (*C.ep2_st)(other)) == valid
   102  }
   103  
   104  // Comparison to zero in Zr.
   105  // Scalar must be already reduced modulo r
   106  func (x *scalar) isZero() bool {
   107  	return C.bn_is_zero((*C.bn_st)(x)) == 1
   108  }
   109  
   110  // Comparison to point at infinity in G2.
   111  func (p *pointG2) isInfinity() bool {
   112  	return C.ep2_is_infty((*C.ep2_st)(p)) == 1
   113  }
   114  
   115  // returns a random number in Zr
   116  func randZr(x *scalar) {
   117  	C.bn_randZr((*C.bn_st)(x))
   118  }
   119  
   120  // returns a random non-zero number in Zr
   121  func randZrStar(x *scalar) {
   122  	C.bn_randZr_star((*C.bn_st)(x))
   123  }
   124  
   125  // mapToZr reads a scalar from a slice of bytes and maps it to Zr.
   126  // The resulting scalar `k` satisfies 0 <= k < r.
   127  // It returns true if scalar is zero and false otherwise.
   128  func mapToZr(x *scalar, src []byte) bool {
   129  	isZero := C.bn_map_to_Zr((*C.bn_st)(x),
   130  		(*C.uchar)(&src[0]),
   131  		(C.int)(len(src)))
   132  	return isZero == valid
   133  }
   134  
   135  // writeScalar writes a G2 point in a slice of bytes
   136  func writeScalar(dest []byte, x *scalar) {
   137  	C.bn_write_bin((*C.uchar)(&dest[0]),
   138  		(C.ulong)(prKeyLengthBLSBLS12381),
   139  		(*C.bn_st)(x),
   140  	)
   141  }
   142  
   143  // readScalar reads a scalar from a slice of bytes
   144  func readScalar(x *scalar, src []byte) {
   145  	C.bn_read_bin((*C.bn_st)(x),
   146  		(*C.uchar)(&src[0]),
   147  		(C.ulong)(len(src)),
   148  	)
   149  }
   150  
   151  // writePointG2 writes a G2 point in a slice of bytes
   152  // The slice should be of size PubKeyLenBLSBLS12381 and the serialization will
   153  // follow the Zcash format specified in draft-irtf-cfrg-pairing-friendly-curves
   154  func writePointG2(dest []byte, a *pointG2) {
   155  	C.ep2_write_bin_compact((*C.uchar)(&dest[0]),
   156  		(*C.ep2_st)(a),
   157  		(C.int)(pubKeyLengthBLSBLS12381),
   158  	)
   159  }
   160  
   161  // writePointG1 writes a G1 point in a slice of bytes
   162  // The slice should be of size SignatureLenBLSBLS12381 and the serialization will
   163  // follow the Zcash format specified in draft-irtf-cfrg-pairing-friendly-curves
   164  func writePointG1(dest []byte, a *pointG1) {
   165  	C.ep_write_bin_compact((*C.uchar)(&dest[0]),
   166  		(*C.ep_st)(a),
   167  		(C.int)(signatureLengthBLSBLS12381),
   168  	)
   169  }
   170  
   171  // readPointG2 reads a G2 point from a slice of bytes
   172  // The slice is expected to be of size PubKeyLenBLSBLS12381 and the deserialization will
   173  // follow the Zcash format specified in draft-irtf-cfrg-pairing-friendly-curves
   174  func readPointG2(a *pointG2, src []byte) error {
   175  	switch C.ep2_read_bin_compact((*C.ep2_st)(a),
   176  		(*C.uchar)(&src[0]),
   177  		(C.int)(len(src))) {
   178  	case valid:
   179  		return nil
   180  	case invalid:
   181  		return invalidInputsErrorf("input is not a G2 point")
   182  	default:
   183  		return errors.New("reading a G2 point failed")
   184  	}
   185  }
   186  
   187  // readPointG1 reads a G1 point from a slice of bytes
   188  // The slice should be of size SignatureLenBLSBLS12381 and the deserialization will
   189  // follow the Zcash format specified in draft-irtf-cfrg-pairing-friendly-curves
   190  func readPointG1(a *pointG1, src []byte) error {
   191  	switch C.ep_read_bin_compact((*C.ep_st)(a),
   192  		(*C.uchar)(&src[0]),
   193  		(C.int)(len(src))) {
   194  	case valid:
   195  		return nil
   196  	case invalid:
   197  		return invalidInputsErrorf("input is not a G1 point")
   198  	default:
   199  		return errors.New("reading a G1 point failed")
   200  	}
   201  }
   202  
   203  // checkMembershipG1 wraps a call to a subgroup check in G1 since cgo can't be used
   204  // in go test files.
   205  func checkMembershipG1(pt *pointG1) int {
   206  	return int(C.check_membership_G1((*C.ep_st)(pt)))
   207  }
   208  
   209  // checkMembershipG2 wraps a call to a subgroup check in G2 since cgo can't be used
   210  // in go test files.
   211  func checkMembershipG2(pt *pointG2) int {
   212  	return int(C.check_membership_G2((*C.ep2_st)(pt)))
   213  }
   214  
   215  // randPointG1 wraps a call to C since cgo can't be used in go test files.
   216  // It generates a random point in G1 and stores it in input point.
   217  func randPointG1(pt *pointG1) {
   218  	C.ep_rand_G1((*C.ep_st)(pt))
   219  }
   220  
   221  // randPointG1Complement wraps a call to C since cgo can't be used in go test files.
   222  // It generates a random point in E1\G1 and stores it in input point.
   223  func randPointG1Complement(pt *pointG1) {
   224  	C.ep_rand_G1complement((*C.ep_st)(pt))
   225  }
   226  
   227  // randPointG2 wraps a call to C since cgo can't be used in go test files.
   228  // It generates a random point in G2 and stores it in input point.
   229  func randPointG2(pt *pointG2) {
   230  	C.ep2_rand_G2((*C.ep2_st)(pt))
   231  }
   232  
   233  // randPointG1Complement wraps a call to C since cgo can't be used in go test files.
   234  // It generates a random point in E2\G2 and stores it in input point.
   235  func randPointG2Complement(pt *pointG2) {
   236  	C.ep2_rand_G2complement((*C.ep2_st)(pt))
   237  }
   238  
   239  // This is only a TEST function.
   240  // It hashes `data` to a G1 point using the tag `dst` and returns the G1 point serialization.
   241  // The function uses xmd with SHA256 in the hash-to-field.
   242  func hashToG1Bytes(data, dst []byte) []byte {
   243  	hash := make([]byte, expandMsgOutput)
   244  
   245  	inputLength := len(data)
   246  	if len(data) == 0 {
   247  		data = make([]byte, 1)
   248  	}
   249  
   250  	// XMD using SHA256
   251  	C.xmd_sha256((*C.uchar)(&hash[0]),
   252  		(C.int)(expandMsgOutput),
   253  		(*C.uchar)(&data[0]), (C.int)(inputLength),
   254  		(*C.uchar)(&dst[0]), (C.int)(len(dst)))
   255  
   256  	// map the hash to G1
   257  	var point pointG1
   258  	C.map_to_G1((*C.ep_st)(&point), (*C.uchar)(&hash[0]), (C.int)(len(hash)))
   259  
   260  	// serialize the point
   261  	pointBytes := make([]byte, signatureLengthBLSBLS12381)
   262  	writePointG1(pointBytes, &point)
   263  	return pointBytes
   264  }