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 }