diff --git a/element.go b/element.go index 2e1e085175f2d34b68bf057b458a8eafd1a18f51..ddc6d47c16ae66931aa0016f7df7f4524ae0147e 100644 --- a/element.go +++ b/element.go @@ -23,6 +23,12 @@ package pbc /* #include <pbc/pbc.h> + +struct element_s* newElementStruct() { return malloc(sizeof(struct element_s)); } +void freeElementStruct(struct element_s* x) { + element_clear(x); + free(x); +} */ import "C" @@ -108,12 +114,12 @@ type Element struct { } func clearElement(element *Element) { - C.element_clear(element.cptr) + C.freeElementStruct(element.cptr) } func makeUncheckedElement(pairing *Pairing, initialize bool, field Field) *Element { element := &Element{ - cptr: &C.struct_element_s{}, + cptr: C.newElementStruct(), pairing: pairing, } if initialize { diff --git a/element_arith.go b/element_arith.go index f9874a1756d1caf3d75827aa2e4faf6c9b1a20bf..81573f4f5f70c44f81ef1968e732a4980d223e01 100644 --- a/element_arith.go +++ b/element_arith.go @@ -23,6 +23,18 @@ package pbc /* #include <pbc/pbc.h> + +struct element_pp_s* newElementPPStruct() { return malloc(sizeof(struct element_pp_s)); } +void freeElementPPStruct(struct element_pp_s* x) { + element_pp_clear(x); + free(x); +} + +struct pairing_pp_s* newPairingPPStruct() { return malloc(sizeof(struct pairing_pp_s)); } +void freePairingPPStruct(struct pairing_pp_s* x) { + pairing_pp_clear(x); + free(x); +} */ import "C" @@ -141,7 +153,7 @@ func (el *Element) MulBig(x *Element, i *big.Int) *Element { if el.checked { el.checkCompatible(x) } - C.element_mul_mpz(el.cptr, x.cptr, &big2mpz(i)[0]) + C.element_mul_mpz(el.cptr, x.cptr, &big2mpz(i).i[0]) return el } @@ -257,7 +269,7 @@ func (el *Element) PowBig(x *Element, i *big.Int) *Element { if el.checked { el.checkCompatible(x) } - C.element_pow_mpz(el.cptr, x.cptr, &big2mpz(i)[0]) + C.element_pow_mpz(el.cptr, x.cptr, &big2mpz(i).i[0]) return el } @@ -286,7 +298,7 @@ func (el *Element) Pow2Big(x *Element, i *big.Int, y *Element, j *big.Int) *Elem if el.checked { el.checkAllCompatible(x, y) } - C.element_pow2_mpz(el.cptr, x.cptr, &big2mpz(i)[0], y.cptr, &big2mpz(j)[0]) + C.element_pow2_mpz(el.cptr, x.cptr, &big2mpz(i).i[0], y.cptr, &big2mpz(j).i[0]) return el } @@ -316,7 +328,7 @@ func (el *Element) Pow3Big(x *Element, i *big.Int, y *Element, j *big.Int, z *El if el.checked { el.checkAllCompatible(x, y, z) } - C.element_pow3_mpz(el.cptr, x.cptr, &big2mpz(i)[0], y.cptr, &big2mpz(j)[0], z.cptr, &big2mpz(k)[0]) + C.element_pow3_mpz(el.cptr, x.cptr, &big2mpz(i).i[0], y.cptr, &big2mpz(j).i[0], z.cptr, &big2mpz(k).i[0]) return el } @@ -370,7 +382,7 @@ func (power *Power) PowZn(target *Element, i *Element) *Element { } func clearPower(power *Power) { - C.element_pp_clear(power.pp) + C.freeElementPPStruct(power.pp) } // PreparePower generates pre-processing data for repeatedly exponentiating el. @@ -379,7 +391,7 @@ func clearPower(power *Power) { func (el *Element) PreparePower() *Power { power := &Power{ source: el, - pp: &C.struct_element_pp_s{}, + pp: C.newElementPPStruct(), } C.element_pp_init(power.pp, el.cptr) runtime.SetFinalizer(power, clearPower) @@ -395,7 +407,7 @@ func (el *Element) PowerBig(power *Power, i *big.Int) *Element { if el.checked { el.checkCompatible(power.source) } - C.element_pp_pow(el.cptr, &big2mpz(i)[0], power.pp) + C.element_pp_pow(el.cptr, &big2mpz(i).i[0], power.pp) return el } @@ -551,7 +563,7 @@ func (pairer *Pairer) Pair(target *Element, y *Element) *Element { } func clearPairer(pairer *Pairer) { - C.pairing_pp_clear(pairer.pp) + C.freePairingPPStruct(pairer.pp) } // PreparePairer generates pre-processing data for repeatedly pairing el. The @@ -566,7 +578,7 @@ func (el *Element) PreparePairer() *Pairer { } pairer := &Pairer{ source: el, - pp: &C.struct_pairing_pp_s{}, + pp: C.newPairingPPStruct(), } C.pairing_pp_init(pairer.pp, el.cptr, el.pairing.cptr) runtime.SetFinalizer(pairer, clearPairer) diff --git a/element_io.go b/element_io.go index 2a80dd449815d2847aa632ff8e42ac576a868952..7007556877cea95df0b00058c90f714c4a3f2cbe 100644 --- a/element_io.go +++ b/element_io.go @@ -44,9 +44,9 @@ func (el *Element) BigInt() *big.Int { if el.checked { el.checkInteger() } - mpz := newMpz() - C.element_to_mpz(&mpz[0], el.cptr) - return mpz2big(mpz) + m := newMpz() + C.element_to_mpz(&m.i[0], el.cptr) + return mpz2big(m) } // Set sets the value of el to be the same as src. @@ -83,7 +83,7 @@ func (el *Element) SetBig(i *big.Int) *Element { if el.checked { el.checkInteger() } - C.element_set_mpz(el.cptr, &big2mpz(i)[0]) + C.element_set_mpz(el.cptr, &big2mpz(i).i[0]) return el } diff --git a/generation.go b/generation.go index bb9ce576a0760f765b189c6668f130c1340e2d70..a69cf16137c7195d8e292a4c26079dd7d354c943 100644 --- a/generation.go +++ b/generation.go @@ -82,7 +82,7 @@ func GenerateA(rbits uint32, qbits uint32) *Params { // More details: https://crypto.stanford.edu/pbc/manual/ch08s03.html func GenerateA1(r *big.Int) *Params { params := makeParams() - C.pbc_param_init_a1_gen(params.cptr, &big2mpz(r)[0]) + C.pbc_param_init_a1_gen(params.cptr, &big2mpz(r).i[0]) return params } diff --git a/gmp_big.go b/gmp_big.go index e315ae2345b7db0ec8adbf5de35bcd63db97d174..555fc5d7bed1ebfcbd83f7fe73931f8cc9d3954e 100644 --- a/gmp_big.go +++ b/gmp_big.go @@ -32,46 +32,50 @@ import ( "unsafe" ) +type mpz struct { + i C.mpz_t +} + var wordSize C.size_t var bitsPerWord C.size_t -func clearMpz(x *C.mpz_t) { - C.mpz_clear(&x[0]) +func clearMpz(x *mpz) { + C.mpz_clear(&x.i[0]) } -func newMpz() *C.mpz_t { - out := &C.mpz_t{} - C.mpz_init(&out[0]) +func newMpz() *mpz { + out := &mpz{} + C.mpz_init(&out.i[0]) runtime.SetFinalizer(out, clearMpz) return out } // big2thisMpz imports the value of num into out -func big2thisMpz(num *big.Int, out *C.mpz_t) { +func big2thisMpz(num *big.Int, out *mpz) { words := num.Bits() if len(words) > 0 { - C.mpz_import(&out[0], C.size_t(len(words)), -1, wordSize, 0, 0, unsafe.Pointer(&words[0])) + C.mpz_import(&out.i[0], C.size_t(len(words)), -1, wordSize, 0, 0, unsafe.Pointer(&words[0])) } } // big2mpz allocates a new mpz_t and imports a big.Int value -func big2mpz(num *big.Int) *C.mpz_t { +func big2mpz(num *big.Int) *mpz { out := newMpz() big2thisMpz(num, out) return out } // mpz2thisBig imports the value of num into out -func mpz2thisBig(num *C.mpz_t, out *big.Int) { - wordsNeeded := (C.mpz_sizeinbase(&num[0], 2) + (bitsPerWord - 1)) / bitsPerWord +func mpz2thisBig(num *mpz, out *big.Int) { + wordsNeeded := (C.mpz_sizeinbase(&num.i[0], 2) + (bitsPerWord - 1)) / bitsPerWord words := make([]big.Word, wordsNeeded) var wordsWritten C.size_t - C.mpz_export(unsafe.Pointer(&words[0]), &wordsWritten, -1, wordSize, 0, 0, &num[0]) + C.mpz_export(unsafe.Pointer(&words[0]), &wordsWritten, -1, wordSize, 0, 0, &num.i[0]) out.SetBits(words) } // mpz2big allocates a new big.Int and imports an mpz_t value -func mpz2big(num *C.mpz_t) (out *big.Int) { +func mpz2big(num *mpz) (out *big.Int) { out = &big.Int{} mpz2thisBig(num, out) return diff --git a/pairing.go b/pairing.go index 69ac21380bcd7010b5fa27655804bcdb292efdd7..6abc8974e9cd2a0f2cea5370f5f01f800b42f5b3 100644 --- a/pairing.go +++ b/pairing.go @@ -23,6 +23,12 @@ package pbc /* #include <pbc/pbc.h> + +struct pairing_s* newPairingStruct() { return malloc(sizeof(struct pairing_s)); } +void freePairingStruct(struct pairing_s* x) { + pairing_clear(x); + free(x); +} */ import "C" @@ -152,11 +158,11 @@ func (pairing *Pairing) NewUncheckedElement(field Field) *Element { } func clearPairing(pairing *Pairing) { - C.pairing_clear(pairing.cptr) + C.freePairingStruct(pairing.cptr) } func makePairing() *Pairing { - pairing := &Pairing{cptr: &C.struct_pairing_s{}} + pairing := &Pairing{cptr: C.newPairingStruct()} runtime.SetFinalizer(pairing, clearPairing) return pairing } diff --git a/params.go b/params.go index 314d31cc49569ef4bd890fc19692865f550c9a2f..0e20843559da389d02cc257365015808d7ad993b 100644 --- a/params.go +++ b/params.go @@ -25,6 +25,12 @@ package pbc #include <pbc/pbc.h> #include "memstream.h" +struct pbc_param_s* newParamStruct() { return malloc(sizeof(struct pbc_param_s)); } +void freeParamStruct(struct pbc_param_s* x) { + pbc_param_clear(x); + free(x); +} + int param_out_str_wrapper(char** bufp, size_t* sizep, pbc_param_t p) { memstream_t* stream = pbc_open_memstream(); if (stream == NULL) return 0; @@ -102,11 +108,11 @@ func (params *Params) String() string { } func clearParams(params *Params) { - C.pbc_param_clear(params.cptr) + C.freeParamStruct(params.cptr) } func makeParams() *Params { - params := &Params{cptr: &C.struct_pbc_param_s{}} + params := &Params{cptr: C.newParamStruct()} runtime.SetFinalizer(params, clearParams) return params } diff --git a/pbc_test.go b/pbc_test.go index af99836580ee36faaab8c55ecc635a1f6b4477ea..8f2fe3addb8f9f0fa8713895aa7c75b434105cd6 100644 --- a/pbc_test.go +++ b/pbc_test.go @@ -24,6 +24,7 @@ package pbc import ( "crypto/sha256" "math/big" + "runtime" "testing" ) @@ -523,3 +524,11 @@ func TestZhangKim(t *testing.T) { t.Fatal("signature does not verify") } } + +// TestGC ensures that there are no errors when running struct finalizers. +func TestGC(t *testing.T) { + TestBLS(t) + for i := 0; i < 5; i++ { // Multiple rounds to resolve dependencies + runtime.GC() + } +} diff --git a/utils.go b/utils.go index 6c62d0292aa7a365185a49eac78b430cc3b26bbf..d41b36575c788dfdcbcdef5ab41e79745cdc2487 100644 --- a/utils.go +++ b/utils.go @@ -81,10 +81,10 @@ func SetRandomProvider(provider RandomSource) { //export goGenerateRandom func goGenerateRandom(out, limit unsafe.Pointer) { - outPtr := (*C.mpz_t)(out) - limitPtr := (*C.mpz_t)(limit) - r := randomProvider.Rand(mpz2big(limitPtr)) - big2thisMpz(r, outPtr) + outMpz := &mpz{i: *(*C.mpz_t)(out) } + limitMpz := &mpz{i: *(*C.mpz_t)(limit) } + r := randomProvider.Rand(mpz2big(limitMpz)) + big2thisMpz(r, outMpz) } type readerProvider struct {