diff --git a/element_unchecked.go b/element_unchecked.go index b887b6e9f98bd9cadefeaf35ccba2e1fe1671e95..1d4297199c348b331db74b40e9f39371409bc8d9 100644 --- a/element_unchecked.go +++ b/element_unchecked.go @@ -75,7 +75,7 @@ func (el *elementImpl) SetString(s string, base int) (Element, bool) { } func (el *elementImpl) BigInt() *big.Int { - mpz := newmpz() + mpz := newMpz() C.element_to_mpz(&mpz[0], el.data) return mpz2big(mpz) } diff --git a/errors.go b/errors.go index bc5006fdc8789cb32dd04dd0527d5fa23ac19864..5ae343dc835d6304732fda60384d5175cf40e81f 100644 --- a/errors.go +++ b/errors.go @@ -11,6 +11,8 @@ var ( ErrBadPairList = errors.New("pairing product list is in an invalid format") ErrBadInput = errors.New("invalid element format during scan") ErrBadVerb = errors.New("invalid verb specified for scan") + ErrIllegalNil = errors.New("received nil when non-nil was expected") ErrOutOfRange = errors.New("index out of range") + ErrEntropyFailure = errors.New("error while reading from entropy source") ErrInternal = errors.New("a severe internal error has lead to possible memory corruption") ) diff --git a/gmp_big.go b/gmp_big.go index 7b5561770d45ce54b54449a47fadc8c3db0817da..0668c77304693e4359f7d53c3424cc0a8e9b0dd2 100644 --- a/gmp_big.go +++ b/gmp_big.go @@ -14,34 +14,42 @@ import ( var wordSize C.size_t var bitsPerWord C.size_t -func clearmpz(x *C.mpz_t) { +func clearMpz(x *C.mpz_t) { println("clearmpz") C.mpz_clear(&x[0]) } -func newmpz() *C.mpz_t { +func newMpz() *C.mpz_t { out := &C.mpz_t{} C.mpz_init(&out[0]) - runtime.SetFinalizer(out, clearmpz) + runtime.SetFinalizer(out, clearMpz) return out } -func big2mpz(num *big.Int) *C.mpz_t { +func big2thisMpz(num *big.Int, out *C.mpz_t) { words := num.Bits() - out := newmpz() if len(words) > 0 { C.mpz_import(&out[0], C.size_t(len(words)), -1, wordSize, 0, 0, unsafe.Pointer(&words[0])) } +} + +func big2mpz(num *big.Int) *C.mpz_t { + out := newMpz() + big2thisMpz(num, out) return out } -func mpz2big(num *C.mpz_t) (out *big.Int) { +func mpz2thisBig(num *C.mpz_t, out *big.Int) { wordsNeeded := (C.mpz_sizeinbase(&num[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]) - out = &big.Int{} out.SetBits(words) +} + +func mpz2big(num *C.mpz_t) (out *big.Int) { + out = &big.Int{} + mpz2thisBig(num, out) return } diff --git a/rand_hook.c b/rand_hook.c new file mode 100644 index 0000000000000000000000000000000000000000..809c39477721ab850a5eeffdaae2bffce0f007f0 --- /dev/null +++ b/rand_hook.c @@ -0,0 +1,17 @@ +#include "_cgo_export.h" +#include <pbc/pbc.h> + +void pbc_init_random(); + +void goRandomHook(mpz_t out, mpz_t limit, void* data) { + UNUSED_VAR(data); + goGenerateRandom(out, limit); +} + +void installRandomHook() { + pbc_random_set_function(goRandomHook, NULL); +} + +void uninstallRandomHook() { + pbc_init_random(); +} \ No newline at end of file diff --git a/utils.go b/utils.go new file mode 100644 index 0000000000000000000000000000000000000000..656a5e17bfab9f68b812223c8a433a69597b6ceb --- /dev/null +++ b/utils.go @@ -0,0 +1,95 @@ +package pbc + +/* +#include <pbc/pbc.h> + +void installRandomHook(); +void uninstallRandomHook(); +*/ +import "C" + +import ( + cryptorand "crypto/rand" + "io" + "math/big" + "math/rand" + "unsafe" +) + +var logging bool + +func Logging() bool { return logging } + +func SetLogging(log bool) { + logging = log + if log { + C.pbc_set_msg_to_stderr(C.int(1)) + } else { + C.pbc_set_msg_to_stderr(C.int(0)) + } +} + +type RandomSource interface { + Rand(limit *big.Int) *big.Int +} + +var randomProvider RandomSource + +func RandomProvider() RandomSource { return randomProvider } + +func SetRandomProvider(provider RandomSource) { + randomProvider = provider + if provider == nil { + C.uninstallRandomHook() + } else { + C.installRandomHook() + } +} + +//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) +} + +type readerProvider struct { + source io.Reader +} + +func (provider readerProvider) Rand(limit *big.Int) (result *big.Int) { + result, err := cryptorand.Int(provider.source, limit) + if err != nil { + panic(ErrEntropyFailure) + } + return +} + +type randProvider struct { + source *rand.Rand +} + +func (provider randProvider) Rand(limit *big.Int) (result *big.Int) { + result = &big.Int{} + result.Rand(provider.source, limit) + return +} + +func SetCryptoRandom() { SetReaderRandom(cryptorand.Reader) } + +func SetReaderRandom(reader io.Reader) { + if reader == nil { + panic(ErrIllegalNil) + } + SetRandomProvider(&readerProvider{reader}) +} + +func SetRandRandom(rand *rand.Rand) { SetRandomProvider(&randProvider{rand}) } + +func SetDefaultRandom() { SetRandomProvider(nil) } + +func init() { + SetLogging(false) + SetDefaultRandom() +}