misc/cgo/gmp/gmp.go GO 380 lines View on github.com → Search inside
1// Copyright 2009 The Go Authors. All rights reserved.2// Use of this source code is governed by a BSD-style3// license that can be found in the LICENSE file.45/*6An example of wrapping a C library in Go. This is the GNU7multiprecision library gmp's integer type mpz_t wrapped to look like8the Go package big's integer type Int.910This is a syntactically valid Go programit can be parsed with the Go11parser and processed by godocbut it is not compiled directly by gc.12Instead, a separate tool, cgo, processes it to produce three output13files.  The first two, 6g.go and 6c.c, are a Go source file for 6g and14a C source file for 6c; both compile as part of the named package15(gmp, in this example).  The third, gcc.c, is a C source file for gcc;16it compiles into a shared object (.so) that is dynamically linked into17any 6.out that imports the first two files.1819The stanza2021	// #include <gmp.h>22	import "C"2324is a signal to cgo.  The doc comment on the import of "C" provides25additional context for the C file.  Here it is just a single #include26but it could contain arbitrary C definitions to be imported and used.2728Cgo recognizes any use of a qualified identifier C.xxx and uses gcc to29find the definition of xxx.  If xxx is a type, cgo replaces C.xxx with30a Go translation.  C arithmetic types translate to precisely-sized Go31arithmetic types.  A C struct translates to a Go struct, field by32field; unrepresentable fields are replaced with opaque byte arrays.  A33C union translates into a struct containing the first union member and34perhaps additional padding.  C arrays become Go arrays.  C pointers35become Go pointers.  C function pointers become Go's uintptr.36C void pointers become Go's unsafe.Pointer.3738For example, mpz_t is defined in <gmp.h> as:3940	typedef unsigned long int mp_limb_t;4142	typedef struct43	{44		int _mp_alloc;45		int _mp_size;46		mp_limb_t *_mp_d;47	} __mpz_struct;4849	typedef __mpz_struct mpz_t[1];5051Cgo generates:5253	type _C_int int3254	type _C_mp_limb_t uint6455	type _C___mpz_struct struct {56		_mp_alloc _C_int;57		_mp_size _C_int;58		_mp_d *_C_mp_limb_t;59	}60	type _C_mpz_t [1]_C___mpz_struct6162and then replaces each occurrence of a type C.xxx with _C_xxx.6364If xxx is data, cgo arranges for C.xxx to refer to the C variable,65with the type translated as described above.  To do this, cgo must66introduce a Go variable that points at the C variable (the linker can67be told to initialize this pointer).  For example, if the gmp library68provided6970	mpz_t zero;7172then cgo would rewrite a reference to C.zero by introducing7374	var _C_zero *C.mpz_t7576and then replacing all instances of C.zero with (*_C_zero).7778Cgo's most interesting translation is for functions.  If xxx is a C79function, then cgo rewrites C.xxx into a new function _C_xxx that80calls the C xxx in a standard pthread.  The new function translates81its arguments, calls xxx, and translates the return value.8283Translation of parameters and the return value follows the type84translation above except that arrays passed as parameters translate85explicitly in Go to pointers to arrays, as they do (implicitly) in C.8687Garbage collection is the big problem.  It is fine for the Go world to88have pointers into the C world and to free those pointers when they89are no longer needed.  To help, the Go code can define Go objects90holding the C pointers and use runtime.SetFinalizer on those Go objects.9192It is much more difficult for the C world to have pointers into the Go93world, because the Go garbage collector is unaware of the memory94allocated by C.  The most important consideration is not to95constrain future implementations, so the rule is that Go code can96hand a Go pointer to C code but must separately arrange for97Go to hang on to a reference to the pointer until C is done with it.98*/99package gmp100101/*102#cgo LDFLAGS: -lgmp103#include <gmp.h>104#include <stdlib.h>105106// gmp 5.0.0+ changed the type of the 3rd argument to mp_bitcnt_t,107// so, to support older versions, we wrap these two functions.108void _mpz_mul_2exp(mpz_ptr a, mpz_ptr b, unsigned long n) {109	mpz_mul_2exp(a, b, n);110}111void _mpz_div_2exp(mpz_ptr a, mpz_ptr b, unsigned long n) {112	mpz_div_2exp(a, b, n);113}114*/115import "C"116117import (118	"os"119	"unsafe"120)121122/*123 * one of a kind124 */125126// An Int represents a signed multi-precision integer.127// The zero value for an Int represents the value 0.128type Int struct {129	i    C.mpz_t130	init bool131}132133// NewInt returns a new Int initialized to x.134func NewInt(x int64) *Int { return new(Int).SetInt64(x) }135136// Int promises that the zero value is a 0, but in gmp137// the zero value is a crash.  To bridge the gap, the138// init bool says whether this is a valid gmp value.139// doinit initializes z.i if it needs it.  This is not inherent140// to FFI, just a mismatch between Go's convention of141// making zero values useful and gmp's decision not to.142func (z *Int) doinit() {143	if z.init {144		return145	}146	z.init = true147	C.mpz_init(&z.i[0])148}149150// Bytes returns z's representation as a big-endian byte array.151func (z *Int) Bytes() []byte {152	b := make([]byte, (z.Len()+7)/8)153	n := C.size_t(len(b))154	C.mpz_export(unsafe.Pointer(&b[0]), &n, 1, 1, 1, 0, &z.i[0])155	return b[0:n]156}157158// Len returns the length of z in bits.  0 is considered to have length 1.159func (z *Int) Len() int {160	z.doinit()161	return int(C.mpz_sizeinbase(&z.i[0], 2))162}163164// Set sets z = x and returns z.165func (z *Int) Set(x *Int) *Int {166	z.doinit()167	C.mpz_set(&z.i[0], &x.i[0])168	return z169}170171// SetBytes interprets b as the bytes of a big-endian integer172// and sets z to that value.173func (z *Int) SetBytes(b []byte) *Int {174	z.doinit()175	if len(b) == 0 {176		z.SetInt64(0)177	} else {178		C.mpz_import(&z.i[0], C.size_t(len(b)), 1, 1, 1, 0, unsafe.Pointer(&b[0]))179	}180	return z181}182183// SetInt64 sets z = x and returns z.184func (z *Int) SetInt64(x int64) *Int {185	z.doinit()186	// TODO(rsc): more work on 32-bit platforms187	C.mpz_set_si(&z.i[0], C.long(x))188	return z189}190191// SetString interprets s as a number in the given base192// and sets z to that value.  The base must be in the range [2,36].193// SetString returns an error if s cannot be parsed or the base is invalid.194func (z *Int) SetString(s string, base int) error {195	z.doinit()196	if base < 2 || base > 36 {197		return os.ErrInvalid198	}199	p := C.CString(s)200	defer C.free(unsafe.Pointer(p))201	if C.mpz_set_str(&z.i[0], p, C.int(base)) < 0 {202		return os.ErrInvalid203	}204	return nil205}206207// String returns the decimal representation of z.208func (z *Int) String() string {209	if z == nil {210		return "nil"211	}212	z.doinit()213	p := C.mpz_get_str(nil, 10, &z.i[0])214	s := C.GoString(p)215	C.free(unsafe.Pointer(p))216	return s217}218219func (z *Int) destroy() {220	if z.init {221		C.mpz_clear(&z.i[0])222	}223	z.init = false224}225226/*227 * arithmetic228 */229230// Add sets z = x + y and returns z.231func (z *Int) Add(x, y *Int) *Int {232	x.doinit()233	y.doinit()234	z.doinit()235	C.mpz_add(&z.i[0], &x.i[0], &y.i[0])236	return z237}238239// Sub sets z = x - y and returns z.240func (z *Int) Sub(x, y *Int) *Int {241	x.doinit()242	y.doinit()243	z.doinit()244	C.mpz_sub(&z.i[0], &x.i[0], &y.i[0])245	return z246}247248// Mul sets z = x * y and returns z.249func (z *Int) Mul(x, y *Int) *Int {250	x.doinit()251	y.doinit()252	z.doinit()253	C.mpz_mul(&z.i[0], &x.i[0], &y.i[0])254	return z255}256257// Div sets z = x / y, rounding toward zero, and returns z.258func (z *Int) Div(x, y *Int) *Int {259	x.doinit()260	y.doinit()261	z.doinit()262	C.mpz_tdiv_q(&z.i[0], &x.i[0], &y.i[0])263	return z264}265266// Mod sets z = x % y and returns z.267// Like the result of the Go % operator, z has the same sign as x.268func (z *Int) Mod(x, y *Int) *Int {269	x.doinit()270	y.doinit()271	z.doinit()272	C.mpz_tdiv_r(&z.i[0], &x.i[0], &y.i[0])273	return z274}275276// Lsh sets z = x << s and returns z.277func (z *Int) Lsh(x *Int, s uint) *Int {278	x.doinit()279	z.doinit()280	C._mpz_mul_2exp(&z.i[0], &x.i[0], C.ulong(s))281	return z282}283284// Rsh sets z = x >> s and returns z.285func (z *Int) Rsh(x *Int, s uint) *Int {286	x.doinit()287	z.doinit()288	C._mpz_div_2exp(&z.i[0], &x.i[0], C.ulong(s))289	return z290}291292// Exp sets z = x^y % m and returns z.293// If m == nil, Exp sets z = x^y.294func (z *Int) Exp(x, y, m *Int) *Int {295	m.doinit()296	x.doinit()297	y.doinit()298	z.doinit()299	if m == nil {300		C.mpz_pow_ui(&z.i[0], &x.i[0], C.mpz_get_ui(&y.i[0]))301	} else {302		C.mpz_powm(&z.i[0], &x.i[0], &y.i[0], &m.i[0])303	}304	return z305}306307func (z *Int) Int64() int64 {308	if !z.init {309		return 0310	}311	return int64(C.mpz_get_si(&z.i[0]))312}313314// Neg sets z = -x and returns z.315func (z *Int) Neg(x *Int) *Int {316	x.doinit()317	z.doinit()318	C.mpz_neg(&z.i[0], &x.i[0])319	return z320}321322// Abs sets z to the absolute value of x and returns z.323func (z *Int) Abs(x *Int) *Int {324	x.doinit()325	z.doinit()326	C.mpz_abs(&z.i[0], &x.i[0])327	return z328}329330/*331 * functions without a clear receiver332 */333334// CmpInt compares x and y. The result is335//336//	-1 if x <  y337//	 0 if x == y338//	+1 if x >  y339func CmpInt(x, y *Int) int {340	x.doinit()341	y.doinit()342	switch cmp := C.mpz_cmp(&x.i[0], &y.i[0]); {343	case cmp < 0:344		return -1345	case cmp == 0:346		return 0347	}348	return +1349}350351// DivModInt sets q = x / y and r = x % y.352func DivModInt(q, r, x, y *Int) {353	q.doinit()354	r.doinit()355	x.doinit()356	y.doinit()357	C.mpz_tdiv_qr(&q.i[0], &r.i[0], &x.i[0], &y.i[0])358}359360// GcdInt sets d to the greatest common divisor of a and b,361// which must be positive numbers.362// If x and y are not nil, GcdInt sets x and y such that d = a*x + b*y.363// If either a or b is not positive, GcdInt sets d = x = y = 0.364func GcdInt(d, x, y, a, b *Int) {365	d.doinit()366	x.doinit()367	y.doinit()368	a.doinit()369	b.doinit()370	C.mpz_gcdext(&d.i[0], &x.i[0], &y.i[0], &a.i[0], &b.i[0])371}372373// ProbablyPrime performs n Miller-Rabin tests to check whether z is prime.374// If it returns true, z is prime with probability 1 - 1/4^n.375// If it returns false, z is not prime.376func (z *Int) ProbablyPrime(n int) bool {377	z.doinit()378	return int(C.mpz_probab_prime_p(&z.i[0], C.int(n))) > 0379}

Code quality findings 5

Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
C void pointers become Go's unsafe.Pointer.
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
C.mpz_export(unsafe.Pointer(&b[0]), &n, 1, 1, 1, 0, &z.i[0])
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
C.mpz_import(&z.i[0], C.size_t(len(b)), 1, 1, 1, 0, unsafe.Pointer(&b[0]))
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
defer C.free(unsafe.Pointer(p))
Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
warning safety unsafe-package
C.free(unsafe.Pointer(p))

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.