Files

962 lines
33 KiB
Plaintext

// Copyright Supranational LLC
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
%module blst
%rename("%(strip:[blst_])s") ""; // prefix is redundant in named module
%include "exception.i"
#ifdef __cplusplus
%include "std_string.i"
%typemap(out) SELF* OUTPUT = SWIGTYPE*; // to be overridden as required
#else
#warning consider using C++ interface
#endif
%include "stdint.i"
%apply const char* { const byte*, const byte[ANY] }
%apply (const char *STRING, size_t LENGTH) { (const byte *STRING,
size_t LENGTH) }
#if defined(SWIGPYTHON)
%header %{
#if PY_VERSION_HEX<0x030d0000
/* Tailored polyfill, for example no need to handle |n_bytes| == 0 here */
static Py_ssize_t PyLong_AsNativeBytes(PyObject* v, void* buffer,
Py_ssize_t n_bytes, int flags)
{
return _PyLong_AsByteArray((PyLongObject*)v,
(unsigned char*)buffer, n_bytes,
flags&1, (flags&4) == 0) < 0 ? -1 : n_bytes;
}
# define My_PYLONG_FLAGS (1 | 4 | 8)
#else
# define My_PYLONG_FLAGS (Py_ASNATIVEBYTES_LITTLE_ENDIAN | \
Py_ASNATIVEBYTES_UNSIGNED_BUFFER | \
Py_ASNATIVEBYTES_REJECT_NEGATIVE)
#endif
#if PY_VERSION_HEX<0x030e0000
static int PyLong_GetSign(PyObject *obj, int *sign)
{
if (!PyLong_Check(obj))
return -1;
*sign = _PyLong_Sign(obj);
return 0;
}
#endif
%}
// some sorcery to allow assignments as output, e.g.
// hash = blst.encode_to_g1(b"foo")
%typemap(in, numinputs=0) OBJECT *OUTPUT($1_basetype temp) %{ $1 = &temp; %}
%typemap(argout) OBJECT *OUTPUT {
PyObject *obj = SWIG_NewPointerObj(memcpy(malloc(sizeof($1_basetype)),
$1,sizeof($1_basetype)),
$descriptor, SWIG_POINTER_NEW);
$result = SWIG_AppendOutput($result, obj);
}
%apply OBJECT *OUTPUT {
blst_p1 *out, blst_p1 *out_pk, blst_p1 *out_sig,
blst_p1_affine *out, blst_p1_affine *out_pk, blst_p1_affine *out_sig,
blst_p2 *out, blst_p2 *out_pk, blst_p2 *out_sig,
blst_p2_affine *out, blst_p2_affine *out_pk, blst_p2_affine *out_sig,
blst_scalar *out, blst_scalar *out_SK,
blst_fp12 *out
}
// accept 'bytes' and 'bytearray' as inputs...
%typemap(in) const byte* %{
if ($input == Py_None) {
$1 = NULL;
} else if (PyBytes_Check($input)) {
char *buf;
Py_ssize_t nbytes;
if (PyBytes_AsStringAndSize($input, &buf, &nbytes) < 0)
SWIG_exception_fail(SWIG_TypeError, "in method '$symname'");
$1 = ($1_ltype)buf;
} else if (PyByteArray_Check($input)) {
$1 = ($1_ltype)PyByteArray_AsString($input);
} else {
SWIG_exception_fail(SWIG_TypeError, "in method '$symname', "
"expecting 'bytes' or 'bytearray'");
}
%}
%typemap(freearg) const byte* ""
%typemap(in) const byte[ANY] %{
if (PyBytes_Check($input)) {
char *buf;
Py_ssize_t nbytes;
if (PyBytes_AsStringAndSize($input, &buf, &nbytes) < 0)
SWIG_exception_fail(SWIG_TypeError, "in method '$symname'");
if (nbytes != $1_dim0)
SWIG_exception_fail(SWIG_ValueError, "in method '$symname', "
"expecting $1_dim0 bytes");
$1 = ($1_ltype)buf;
} else if (PyByteArray_Check($input)) {
if (PyByteArray_Size($input) != $1_dim0)
SWIG_exception_fail(SWIG_ValueError, "in method '$symname', "
"expecting $1_dim0 bytes");
$1 = ($1_ltype)PyByteArray_AsString($input);
} else {
SWIG_exception_fail(SWIG_TypeError, "in method '$symname', "
"expecting 'bytes' or 'bytearray'");
}
%}
%typemap(freearg) const byte[ANY] ""
%typemap(in) (const byte *STRING, size_t LENGTH) %{
if ($input == Py_None) {
$1 = NULL;
$2 = 0;
} else if (PyBytes_Check($input)) {
char *buf;
Py_ssize_t nbytes;
if (PyBytes_AsStringAndSize($input, &buf, &nbytes) < 0)
SWIG_exception_fail(SWIG_ValueError, "in method '$symname'");
$1 = ($1_ltype)buf;
$2 = nbytes;
} else if (PyByteArray_Check($input)) {
$1 = ($1_ltype)PyByteArray_AsString($input);
$2 = PyByteArray_Size($input);
#ifdef Py_USING_UNICODE
} else if (PyUnicode_Check($input)) {
char *buf;
Py_ssize_t nbytes;
PyObject *obj = PyUnicode_AsUTF8String($input);
if (obj == NULL || PyBytes_AsStringAndSize(obj, &buf, &nbytes) < 0)
SWIG_exception_fail(SWIG_ValueError, "in method '$symname'");
$1 = ($1_ltype)alloca($2 = nbytes);
memcpy($1, buf, $2);
Py_DECREF(obj);
#endif
} else {
SWIG_exception_fail(SWIG_TypeError, "in method '$symname', "
"expecting 'bytes' or 'bytearray'");
}
%}
%typemap(freearg) (const byte *STRING, size_t LENGTH) ""
%typemap(in) blst::bytes_t %{
if ($input == Py_None) {
$1.ptr = NULL;
$1.len = 0;
} else if (PyBytes_Check($input)) {
char *buf;
Py_ssize_t nbytes;
if (PyBytes_AsStringAndSize($input, &buf, &nbytes) < 0)
SWIG_exception_fail(SWIG_ValueError, "in method '$symname'");
$1.ptr = (byte*)buf;
$1.len = nbytes;
} else if (PyByteArray_Check($input)) {
$1.ptr = (byte*)PyByteArray_AsString($input);
$1.len = PyByteArray_Size($input);
#ifdef Py_USING_UNICODE
} else if (PyUnicode_Check($input)) {
char *buf;
Py_ssize_t nbytes;
PyObject *obj = PyUnicode_AsUTF8String($input);
if (obj == NULL || PyBytes_AsStringAndSize(obj, &buf, &nbytes) < 0)
SWIG_exception_fail(SWIG_ValueError, "in method '$symname'");
auto ptr = alloca(nbytes);
memcpy(ptr, buf, nbytes);
$1.ptr = (byte*)ptr;
$1.len = nbytes;
Py_DECREF(obj);
#endif
} else {
SWIG_exception_fail(SWIG_TypeError, "in method '$symname', "
"expecting 'bytes' or 'bytearray'");
}
%}
%typemap(freearg) blst::bytes_t ""
%typemap(typecheck) blst::bytes_t ""
// let users use Python 'int', 'bytes' and 'bytearray' as scalars
%typemap(in) (const byte* scalar, size_t nbits) %{
if (PyBytes_Check($input)) {
char *scalar;
Py_ssize_t nbytes;
if (PyBytes_AsStringAndSize($input, &scalar, &nbytes) < 0)
SWIG_exception_fail(SWIG_TypeError, "in method '$symname'");
$1 = ($1_ltype)scalar;
$2 = 8 * nbytes;
} else if (PyByteArray_Check($input)) {
$1 = ($1_ltype)PyByteArray_AsString($input);
$2 = 8 * PyByteArray_Size($input);
} else if (PyLong_Check($input)) {
size_t nbytes;
$2 = _PyLong_NumBits($input);
$1 = ($1_ltype)alloca(nbytes = ($2 + 7)/8);
if (PyLong_AsNativeBytes($input, $1, nbytes, My_PYLONG_FLAGS) < 0)
SWIG_exception_fail(SWIG_OverflowError, "in method '$symname'");
} else {
SWIG_exception_fail(SWIG_TypeError, "in method '$symname', "
"expecting 'int', 'bytes' "
"or 'bytearray'");
}
%}
#ifdef __cplusplus
%typemap(in) (const POINT* points[], size_t npoints)
(std::unique_ptr<$*1_ltype[]> points, size_t _global_npoints) %{
if (PyList_Check($input)) {
_global_npoints = PyList_Size($input);
points = std::unique_ptr<$*1_ltype[]>(new $*1_ltype[_global_npoints]);
PyObject* obj = PyList_GET_ITEM($input, 0);
// check the type of the 1st element
if (SWIG_ConvertPtr(obj, (void**)&points[0], $*1_descriptor, 0) != SWIG_OK)
SWIG_exception_fail(SWIG_TypeError, "in method '$symname', "
"expecting 'list' of '$*1_ltype'");
for (size_t i = 1; i < _global_npoints; i++) {
obj = PyList_GET_ITEM($input, i);
points[i] = ($*1_ltype)SWIG_Python_GetSwigThis(obj)->ptr;
}
$1 = points.get();
$2 = _global_npoints;
} else if (PyBytes_Check($input)) {
char *bytes;
Py_ssize_t nbytes;
if (PyBytes_AsStringAndSize($input, &bytes, &nbytes) < 0)
SWIG_exception_fail(SWIG_TypeError, "in method '$symname'");
points = std::unique_ptr<$*1_ltype[]>(new $*1_ltype[2]);
points[0] = ($*1_ltype)bytes;
points[1] = nullptr;
$1 = points.get();
$2 = _global_npoints = nbytes / sizeof(points[0][0]);
} else if (PyMemoryView_Check($input)) { // output from to_affine()
Py_buffer *buf = PyMemoryView_GET_BUFFER($input);
if (!PyBytes_Check(buf->obj))
SWIG_exception_fail(SWIG_TypeError, "in method '$symname', "
"expecting 'bytes' in "
"'memoryview' for points[]");
points = std::unique_ptr<$*1_ltype[]>(new $*1_ltype[2]);
points[0] = ($*1_ltype)buf->buf;
points[1] = nullptr;
$1 = points.get();
$2 = _global_npoints = buf->len / sizeof(points[0][0]);
} else {
SWIG_exception_fail(SWIG_TypeError, "in method '$symname', expecting "
"'list', 'bytes' or 'memoryview' "
"for points[]");
}
%}
%apply (const POINT* points[], size_t npoints) {
(const blst::P1_Affine* const points[], size_t npoints),
(const blst::P2_Affine* const points[], size_t npoints),
(const blst::P1* const points[], size_t npoints),
(const blst::P2* const points[], size_t npoints)
}
%typemap(in, numinputs=0) POINT points[] (PyObject *obj) ""
%typemap(check) POINT points[] {
char *bytes;
Py_ssize_t size = sizeof($1[0]) * _global_npoints;
obj$argnum = PyBytes_FromStringAndSize(NULL, size);
if (obj$argnum == NULL) SWIG_fail;
PyBytes_AsStringAndSize(obj$argnum, &bytes, &size);
$1 = ($1_ltype)bytes;
}
%typemap(argout) POINT points[] %{
$result = PyMemoryView_FromObject(obj$argnum);
if ($result != NULL) {
// .itemsize to return size of point, and len() - amount of points
PyMemoryView_GET_BUFFER($result)->itemsize = sizeof($1[0]);
PyMemoryView_GET_BUFFER($result)->shape[0] /= sizeof($1[0]);
} else {
Py_DECREF(obj$argnum);
}
%}
%apply POINT points[] { blst_p1_affine dst[], blst_p2_affine dst[] }
%extend blst::P1_Affines {
static PyObject* as_memory(blst_p1_affine dst[],
const blst::P1* const points[], size_t npoints)
{ blst_p1s_to_affine(dst, (const blst_p1 *const*)points, npoints);
return Py_None; // ignored by 'argout' typemap above
}
}
%extend blst::P2_Affines {
static PyObject* as_memory(blst_p2_affine dst[],
const blst::P2* const points[], size_t npoints)
{ blst_p2s_to_affine(dst, (const blst_p2 *const*)points, npoints);
return Py_None; // ignored by 'argout' typemap above
}
}
%nodefault blst::P1_Affines;
%nodefault blst::P2_Affines;
%typemap(in) (const byte* const scalars[], size_t nbits)
(std::unique_ptr<byte[]> bytes, byte *scalars[2]) %{
if (PyList_Check($input)) {
if ((size_t)PyList_Size($input) != _global_npoints)
SWIG_exception_fail(SWIG_IndexError, "in method '$symname', 'list' "
"length mismatch for scalars[]");
PyObject *obj = PyList_GET_ITEM($input, 0);
if (PyLong_Check(obj)) {
$2 = _PyLong_NumBits(obj);
for (size_t i = 1; i < _global_npoints; i++) {
size_t nbits;
int sign;
obj = PyList_GET_ITEM($input, i);
if (PyLong_GetSign(obj, &sign) < 0 || sign < 0)
SWIG_exception_fail(SWIG_TypeError, "in method '$symname', "
"expecting all 'long's");
nbits = _PyLong_NumBits(obj);
if (nbits > $2) $2 = nbits;
}
size_t nbytes = ($2 + 7)/8;
bytes = std::unique_ptr<byte[]>(new byte[_global_npoints*nbytes]);
byte* scalar = bytes.get();
for (size_t i = 0; i < _global_npoints; i++, scalar += nbytes)
PyLong_AsNativeBytes(PyList_GET_ITEM($input, i),
scalar, nbytes, My_PYLONG_FLAGS);
scalars[0] = bytes.get();
scalars[1] = nullptr;
$1 = scalars;
} else {
SWIG_exception_fail(SWIG_TypeError, "in method '$symname', "
"expecting 'list' of 'long's "
"for scalars[]");
}
} else if (PyBytes_Check($input)) {
char *bytes;
Py_ssize_t nbytes;
if (PyBytes_AsStringAndSize($input, &bytes, &nbytes) < 0)
SWIG_exception_fail(SWIG_TypeError, "in method '$symname'");
scalars[0] = ($*1_ltype)bytes;
scalars[1] = nullptr;
$1 = scalars;
$2 = 8 * (nbytes / _global_npoints);
} else if (PyByteArray_Check($input)) {
scalars[0] = ($*1_ltype)PyByteArray_AsString($input);
scalars[1] = nullptr;
$1 = scalars;
$2 = 8 * (PyByteArray_Size($input) / _global_npoints);
} else if (PyMemoryView_Check($input)) {
Py_buffer *buf = PyMemoryView_GET_BUFFER($input);
if (!PyBytes_Check(buf->obj) && !PyByteArray_Check(buf->obj))
SWIG_exception_fail(SWIG_TypeError, "in method '$symname', "
"expecting 'bytes' in "
"'memoryview' for points[]");
scalars[0] = ($*1_ltype)buf->buf;
scalars[1] = nullptr;
$1 = scalars;
$2 = 8 * (buf->len / _global_npoints);
} else {
SWIG_exception_fail(SWIG_TypeError, "in method '$symname', expecting "
"'list', 'bytes', 'bytearray' "
"or 'memoryview' for scalars[]");
}
%}
%typemap(out) BLST_ERROR %{
if ($1 != BLST_SUCCESS) {
SWIG_exception(SWIG_ValueError, BLST_ERROR_str[$1]);
SWIG_fail;
}
$result = SWIG_From_int($1);
%}
// return |this|
%typemap(out) SELF* OUTPUT %{ (void)$1; Py_INCREF($result = swig_obj[0]); %}
#endif
#elif defined(SWIGJAVA)
%header %{
#ifdef __cplusplus
# define JCALL(func, ...) jenv->func(__VA_ARGS__)
#else
# define JCALL(func, ...) (*jenv)->func(jenv, __VA_ARGS__)
#endif
%}
%include "enums.swg"
%include "arrays_java.i"
%javaconst(1);
#if SWIG_VERSION < 0x040000
%apply (char *STRING, size_t LENGTH) { (const byte *STRING, size_t LENGTH) }
#endif
%pragma(java) jniclassimports=%{
import java.io.*;
import java.nio.file.*;
%}
%pragma(java) jniclasscode=%{
final static String libName = System.mapLibraryName("$module");
final static String resName = System.getProperty("os.name").replaceFirst(" .*","")
+ "/" + System.getProperty("os.arch")
+ "/" + libName;
static {
Class<?> imClazz = $imclassname.class;
InputStream res = imClazz.getResourceAsStream(
System.getProperty(imClazz.getPackageName() + ".jniResource", resName));
if (res == null) {
try {
System.loadLibrary("$module");
} catch (UnsatisfiedLinkError e) {
String[] cmd = System.getProperty("sun.java.command").split("/");
if (!"$imclassname".equals(cmd[cmd.length-1]))
// suppress exception if 'main' below is executed
throw new RuntimeException(e.getMessage());
}
} else {
// unpack shared library into a temporary directory and load it
try {
Path tmpdir = Files.createTempDirectory("$module@");
tmpdir.toFile().deleteOnExit();
Path tmpdll = Paths.get(tmpdir.toString(), libName);
tmpdll.toFile().deleteOnExit();
Files.copy(res, tmpdll, StandardCopyOption.REPLACE_EXISTING);
res.close();
System.load(tmpdll.toString());
} catch (IOException e) {
throw new RuntimeException(e.getMessage());
}
}
}
public static void main(String argv[]) {
System.out.println(resName);
}
%}
#ifdef __cplusplus
// Extensive sorcery to shift memory management to JVM GC. General idea is
// to use Java long[] as opaque storage for blst data. Methods that return
// new objects allocate suitably sized long[] arrays from JVM heap,
// references to which are then assigned to |swigCPtr| on the Java side.
// And when passed back to JNI, |swigCPtr|s are dereferenced with
// GetLongArrayElements... And no destructors!
%nodefaultdtor;
%typemap(javafinalize) SWIGTYPE ""
%typemap(javadestruct) SWIGTYPE ""
%typemap(javabody) SWIGTYPE %{
private transient long[] swigCPtr;
protected $javaclassname(long[] cPtr) { swigCPtr = cPtr; }
protected static long[] getCPtr($javaclassname obj) {
return obj != null ? obj.swigCPtr : null;
}
public $javaclassname dup() { return new $javaclassname(swigCPtr.clone()); }
%}
%ignore dup;
%typemap(javaconstruct) SWIGTYPE { this($imcall); }
%typemap(jni) SWIGTYPE, SWIGTYPE&, SWIGTYPE* "jlongArray"
%typemap(jtype) SWIGTYPE, SWIGTYPE&, SWIGTYPE* "long[]"
%typemap(javaout) SWIGTYPE, SWIGTYPE&, SWIGTYPE* {
return new $javaclassname($jnicall);
}
%typemap(in) SWIGTYPE&, SWIGTYPE* %{
$1 = ($1_ltype)JCALL(GetLongArrayElements, $input, 0);
%}
%typemap(in) const SWIGTYPE&, const SWIGTYPE* %{
$1 = $input ? ($1_ltype)JCALL(GetLongArrayElements, $input, 0) : NULL;
%}
%typemap(out) SWIGTYPE&, SWIGTYPE* %{
if ($1 != $null) {
size_t sz = (sizeof($1_basetype) + sizeof(jlong) - 1)/sizeof(jlong);
$result = JCALL(NewLongArray, sz);
if ($result != $null)
JCALL(SetLongArrayRegion, $result, 0, sz, (const jlong *)$1);
}
%}
%typemap(out) SWIGTYPE {
size_t sz = (sizeof($1_basetype) + sizeof(jlong) - 1)/sizeof(jlong);
$result = JCALL(NewLongArray, sz);
if ($result != $null)
JCALL(SetLongArrayRegion, $result, 0, sz, (const jlong *)&$1);
}
%typemap(newfree) SWIGTYPE* "delete $1;"
%typemap(freearg) SWIGTYPE&, SWIGTYPE* %{
JCALL(ReleaseLongArrayElements, $input, (jlong *)$1, 0);
%}
%typemap(freearg) const SWIGTYPE&, const SWIGTYPE* %{
if ($input) JCALL(ReleaseLongArrayElements, $input, (jlong *)$1, JNI_ABORT);
%}
%typemap(freearg) const std::string& ""
// I wish |jenv| was available in the constructor, so that NewLongArray
// could be called at once, without having to resort to matching
// %typemap(out)...
%extend blst::Pairing {
Pairing(bool hash_or_encode, const std::string& DST)
{ size_t sz = blst_pairing_sizeof();
size_t SZ = (sz + DST.size() + sizeof(jlong) - 1)/sizeof(jlong);
blst_pairing *ret = (blst_pairing *)malloc(SZ*sizeof(jlong));
if (DST.size() != 0) {
byte *dst = (byte *)ret + sz;
memcpy(dst, DST.data(), DST.size());
blst_pairing_init(ret, hash_or_encode, dst, DST.size());
} else {
blst_pairing_init(ret, hash_or_encode, NULL, 0);
}
return (Pairing *)ret;
}
}
%typemap(out) blst::Pairing* {
size_t sz = blst_pairing_sizeof();
size_t SZ = (sz + arg2->size() + sizeof(jlong) - 1)/sizeof(jlong);
$result = JCALL(NewLongArray, SZ);
if ($result != $null)
JCALL(SetLongArrayRegion, $result, 0, SZ, (const jlong *)$1);
}
%typemap(newfree) blst::Pairing* "free($1);"
%typemap(javaout) SELF* OUTPUT { $jnicall; return this; }
%typemap(out) SELF* OUTPUT "(void)$1;"
%typemap(jni) SELF* OUTPUT "void"
%typemap(jtype) SELF* OUTPUT "void"
#endif
%typemap(throws) BLST_ERROR %{
SWIG_JavaThrowException(jenv, SWIG_JavaRuntimeException,
BLST_ERROR_str[$1]);
%}
// handle input const byte[] more efficiently...
%apply signed char[] { const byte* }
%typemap(in) const byte* %{
$1 = $input ? ($1_ltype)JCALL(GetByteArrayElements, $input, 0) : NULL;
%}
%typemap(argout) const byte* ""
%typemap(freearg) const byte* %{
if ($input) JCALL(ReleaseByteArrayElements, $input, (jbyte *)$1, JNI_ABORT);
%}
%apply const byte* { const byte[ANY] }
%typemap(in) const byte[ANY] {
size_t sz = JCALL(GetArrayLength, $input);
if (sz != $1_dim0) {
SWIG_JavaThrowException(jenv, SWIG_JavaIndexOutOfBoundsException,
"BLST_ERROR: input size mismatch");
return $null;
}
$1 = ($1_ltype)JCALL(GetByteArrayElements, $input, 0);
}
// let users use 'java.math.BigInteger' as scalars
%typemap(in) (const byte* scalar, size_t nbits) %{
$2 = JCALL(GetArrayLength, $input);
$1 = ($1_ltype)alloca($2);
JCALL(GetByteArrayRegion, $input, 0, $2, (jbyte*)$1);
if (*(jbyte*)$1 < 0) {
SWIG_JavaThrowException(jenv, SWIG_JavaIllegalArgumentException,
"expecting unsigned value");
return $null;
}
{ // BigInteger.toByteArray() emits big-endian, flip the order...
size_t i, j;
for(i=0, j=$2-1; i<$2/2; i++, j--) {
$*1_ltype t=$1[i]; $1[i]=$1[j]; $1[j]=t;
}
}
if ($1[$2-1] == 0)
$2--;
$2 *= 8;
%}
%typemap(jni) (const byte* scalar, size_t nbits) "jbyteArray"
%typemap(jtype) (const byte* scalar, size_t nbits) "byte[]"
%typemap(jstype) (const byte* scalar, size_t nbits) "java.math.BigInteger"
%typemap(javain) (const byte* scalar, size_t nbits) "$javainput.toByteArray()"
%typemap(jni) (const byte *STRING, size_t LENGTH) "jbyteArray"
%typemap(jtype) (const byte *STRING, size_t LENGTH) "byte[]"
%typemap(jstype) (const byte *STRING, size_t LENGTH) "byte[]"
%typemap(javain) (const byte *STRING, size_t LENGTH) "$javainput"
%typemap(freearg)(const byte *STRING, size_t LENGTH) ""
%typemap(jni) blst::bytes_t "jbyteArray"
%typemap(jtype) blst::bytes_t "byte[]"
%typemap(jstype) blst::bytes_t "byte[]"
%typemap(javain) blst::bytes_t "$javainput"
%typemap(freearg)blst::bytes_t ""
%typemap(in) blst::bytes_t %{
$1.ptr = (const byte*)JCALL(GetByteArrayElements, $input, 0);
$1.len = JCALL(GetArrayLength, $input);
%}
%typemap(argout) blst::bytes_t %{
JCALL(ReleaseByteArrayElements, $input, (jbyte *)$1.ptr, JNI_ABORT);
%}
#elif defined(SWIGJAVASCRIPT) && defined(SWIG_JAVASCRIPT_V8)
%header %{
#if V8_MAJOR_VERSION >= 8
# define GetData() GetBackingStore()->Data()
#else
# define GetData() GetContents().Data()
#endif
%}
%typemap(throws) BLST_ERROR %{ SWIG_V8_Raise(BLST_ERROR_str[$1]); SWIG_fail; %}
%typemap(in) const byte* %{
if ($input->IsArrayBufferView()) {
auto av = v8::Local<v8::ArrayBufferView>::Cast($input);
auto buf = av->Buffer();
$1 = ($1_ltype)buf->GetData() + av->ByteOffset();
} else if ($input->IsNull()) {
$1 = nullptr;
} else {
SWIG_exception_fail(SWIG_TypeError, "in method '$symname', "
"expecting <Buffer>");
}
%}
%typemap(argout) const byte* ""
%typemap(freearg) const byte* ""
%apply const byte* { const byte[ANY] }
%typemap(in) const byte[ANY] %{
if ($input->IsArrayBufferView()) {
auto av = v8::Local<v8::ArrayBufferView>::Cast($input);
if (av->ByteLength() != $1_dim0)
SWIG_exception_fail(SWIG_IndexError, "in method '$symname', "
"expecting $1_dim0 bytes");
auto buf = av->Buffer();
$1 = ($1_ltype)buf->GetData() + av->ByteOffset();
} else {
SWIG_exception_fail(SWIG_TypeError, "in method '$symname', "
"expecting <Buffer>");
}
%}
// let users use JavaScript <BigInt> and <Buffer> as scalars
%typemap(in) (const byte* scalar, size_t nbits) %{
if ($input->IsArrayBufferView()) {
auto av = v8::Local<v8::ArrayBufferView>::Cast($input);
auto buf = av->Buffer();
$1 = ($1_ltype)buf->GetData() + av->ByteOffset();
$2 = 8*av->ByteLength();
#if V8_MAJOR_VERSION >=6 && V8_MINOR_VERSION >= 8
} else if ($input->IsBigInt()) {
auto bi = v8::Local<v8::BigInt>::Cast($input);
int sign, word_count = bi->WordCount();
uint64_t* words = (uint64_t*)alloca($2 = word_count*sizeof(uint64_t));
bi->ToWordsArray(&sign, &word_count, words);
if (sign)
SWIG_exception_fail(SWIG_TypeError, "in method '$symname', "
"expecting unsigned value");
$1 = ($1_ltype)words;
$2 *= 8;
const union {
long one;
char little;
} is_endian = { 1 };
if (!is_endian.little) {
byte* p = $1;
for (int i = 0; i < word_count; i++) {
uint64_t val = words[i];
for (size_t j = 0; j < sizeof(val); j++, val >>= 8)
*p++ = (byte)val;
}
}
#endif
} else {
SWIG_exception_fail(SWIG_TypeError, "in method '$symname', "
"expecting <Buffer> or <BigInt>");
}
%}
%typemap(in) (const byte *STRING, size_t LENGTH) %{
if ($input->IsArrayBufferView()) {
auto av = v8::Local<v8::ArrayBufferView>::Cast($input);
auto buf = av->Buffer();
$1 = ($1_ltype)buf->GetData() + av->ByteOffset();
$2 = av->ByteLength();
} else if ($input->IsString()) {
auto str = v8::Local<v8::String>::Cast($input);
$2 = SWIGV8_UTF8_LENGTH(str);
$1 = ($1_ltype)alloca($2);
SWIGV8_WRITE_UTF8(str, (char *)$1, $2);
} else if ($input->IsNull()) {
$1 = nullptr;
$2 = 0;
} else {
SWIG_exception_fail(SWIG_TypeError, "in method '$symname', "
"expecting <Buffer> or <String>");
}
%}
%typemap(freearg) (const byte *STRING, size_t LENGTH) ""
%typemap(in) blst::bytes_t %{
if ($input->IsArrayBufferView()) {
auto av = v8::Local<v8::ArrayBufferView>::Cast($input);
auto buf = av->Buffer();
$1.ptr = (byte*)buf->GetData() + av->ByteOffset();
$1.len = av->ByteLength();
} else if ($input->IsString()) {
auto str = v8::Local<v8::String>::Cast($input);
$1.len = SWIGV8_UTF8_LENGTH(str);
$1.ptr = (byte*)alloca($1.len);
SWIGV8_WRITE_UTF8(str, (char *)$1.ptr, $1.len);
} else if ($input->IsNull()) {
$1.ptr = nullptr;
$1.len = 0;
} else {
SWIG_exception_fail(SWIG_TypeError, "in method '$symname', "
"expecting <Buffer> or <String>");
}
%}
%typemap(freearg) blst::bytes_t ""
// return |this|
%typemap(out) SELF* OUTPUT %{ (void)$1; $result = args.Holder(); %}
#elif defined(SWIGPERL)
// let users use byte[] as scalars
%apply (const char *STRING, size_t LENGTH) { (const byte* scalar, size_t nbits) }
%typemap(check) (const byte* scalar, size_t nbits) %{ $2 *= 8; %}
#ifdef __cplusplus
// return |this|
%typemap(out) SELF* OUTPUT %{ (void)$1; argvi++; %}
#endif
#endif // SWIG<language>
// everybody has a way to bundle pointer and buffer size, but C:-(
%apply (const byte *STRING, size_t LENGTH) {
(const byte *msg, size_t msg_len),
(const byte *DST, size_t DST_len),
(const byte *aug, size_t aug_len),
(const byte *IKM, size_t IKM_len),
(const byte *info, size_t info_len),
(const byte *salt, size_t salt_len),
(const byte *in, size_t len)
}
// some sorcery to return byte[] from serialization methods
%typemap(in, numinputs=0) byte out[ANY] (byte temp[$1_dim0]) %{ $1 = temp; %}
%typemap(argout) byte out[ANY] {
#if defined(SWIGPYTHON)
PyObject *obj = SWIG_FromCharPtrAndSize((char *)$1, $1_dim0);
$result = SWIG_AppendOutput($result, obj);
#elif defined(SWIGJAVA)
$result = JCALL(NewByteArray, $1_dim0);
if ($result != $null) {
JCALL(SetByteArrayRegion, $result, 0, $1_dim0, (const jbyte *)$1);
}
#elif defined(SWIGJAVASCRIPT) && defined(SWIG_JAVASCRIPT_V8)
auto ab = v8::ArrayBuffer::New(v8::Isolate::GetCurrent(), $1_dim0);
memcpy(ab->GetData(), $1, $1_dim0);
$result = v8::Uint8Array::New(ab, 0, $1_dim0);
#elif defined(SWIGPERL)
$result = SWIG_FromCharPtrAndSize((char *)$1, $1_dim0); argvi++;
#else // TODO: figure out more language-specific ways to return multi-values...
if ($result == NULL)
$result = SWIG_FromCharPtrAndSize((char *)$1, $1_dim0);
#endif
}
%typemap(freearg) byte out[ANY] ""
#ifdef SWIGJAVA
%typemap(jni) byte out[ANY] "jbyteArray"
%typemap(jtype) byte out[ANY] "byte[]"
%typemap(jstype) byte out[ANY] "byte[]"
%typemap(javaout) byte out[ANY] { return $jnicall; }
#endif
%apply byte out[ANY] {
void to_bendian, void blst_bendian_from_scalar,
void to_lendian, void blst_lendian_from_scalar,
void serialize, void blst_p1_serialize, void blst_p1_affine_serialize,
void blst_p2_serialize, void blst_p2_affine_serialize,
void compress, void blst_p1_compress, void blst_p1_affine_compress,
void blst_p2_compress, void blst_p2_affine_compress,
void blst_sk_to_pk2_in_g1, void blst_sign_pk2_in_g1,
void blst_sk_to_pk2_in_g2, void blst_sign_pk2_in_g2
}
#ifdef __cplusplus
%apply const std::string& { const std::string* }
#pragma SWIG nowarn=509,516
#if !defined(SWIGPYTHON)
%ignore P1_Affines;
%ignore P2_Affines;
#endif
%ignore nullptr;
%ignore None;
%ignore C_bytes;
%ignore bytes_t;
%feature("novaluewrapper") bytes_t;
%catches(BLST_ERROR) P1(const byte* in, size_t len);
%catches(BLST_ERROR) P1_Affine(const byte* in, size_t len);
%catches(BLST_ERROR) aggregate(const P1_Affine& in);
%catches(BLST_ERROR) P2(const byte* in, size_t len);
%catches(BLST_ERROR) P2_Affine(const byte* in, size_t len);
%catches(BLST_ERROR) aggregate(const P2_Affine& in);
%catches(BLST_ERROR) blst::Scalar::add;
%catches(BLST_ERROR) blst::Scalar::sub;
%catches(BLST_ERROR) blst::Scalar::mul;
// methods returning |this|
%apply SELF* OUTPUT {
blst::P1* sign_with, blst::P2* sign_with,
blst::P1* hash_to, blst::P2* hash_to,
blst::P1* encode_to, blst::P2* encode_to,
blst::P1* mult, blst::P2* mult,
blst::P1* cneg, blst::P2* cneg,
blst::P1* neg, blst::P2* neg,
blst::P1* add, blst::P2* add,
blst::P1* dbl, blst::P2* dbl,
blst::PT* mul, blst::PT* sqr,
blst::PT* final_exp,
blst::Scalar* from_bendian,
blst::Scalar* from_lendian,
blst::Scalar* add,
blst::Scalar* sub,
blst::Scalar* mul,
blst::Scalar* inverse
}
typedef enum {
BLST_SUCCESS = 0,
BLST_BAD_ENCODING,
BLST_POINT_NOT_ON_CURVE,
BLST_POINT_NOT_IN_GROUP,
BLST_AGGR_TYPE_MISMATCH,
BLST_VERIFY_FAIL,
BLST_PK_IS_INFINITY,
} BLST_ERROR;
%include "blst.hpp"
extern const blst::P1_Affine BLS12_381_G1;
extern const blst::P1_Affine BLS12_381_NEG_G1;
extern const blst::P2_Affine BLS12_381_G2;
extern const blst::P2_Affine BLS12_381_NEG_G2;
#else
%ignore blst_fr;
%ignore blst_fp;
%ignore blst_fp2;
%ignore blst_fp6;
%ignore blst_scalar_from_uint32;
%ignore blst_scalar_from_uint64;
%ignore blst_uint32_from_scalar;
%ignore blst_uint64_from_scalar;
%ignore blst_pairing_init;
%ignore blst_pairing_get_dst;
%include "blst.h"
%include "blst_aux.h"
%extend blst_pairing {
blst_pairing(bool hash_or_encode, const byte *DST DEFNULL,
size_t DST_len DEFNULL)
{ void *ret = malloc(blst_pairing_sizeof());
if (DST_len != 0) {
void *dst = malloc(DST_len);
memcpy(dst, DST, DST_len);
blst_pairing_init(ret, hash_or_encode, dst, DST_len);
} else {
blst_pairing_init(ret, hash_or_encode, NULL, 0);
}
return ret;
}
~blst_pairing()
{ void *dst = (void *)blst_pairing_get_dst($self);
if (dst != NULL) free(dst);
free($self);
}
}
#endif
%begin %{
#ifdef __cplusplus
# include <memory>
# include "blst.hpp"
using namespace blst;
#else
# include "blst.h"
#endif
static const char *const BLST_ERROR_str [] = {
"BLST_ERROR: success",
"BLST_ERROR: bad point encoding",
"BLST_ERROR: point is not on curve",
"BLST_ERROR: point is not in group",
"BLST_ERROR: context type mismatch",
"BLST_ERROR: verify failed",
"BLST_ERROR: public key is infinite",
};
#define SWIG_PYTHON_STRICT_BYTE_CHAR
#if defined(__GNUC__)
# ifndef alloca
# define alloca(s) __builtin_alloca(s)
# endif
#elif defined(__sun)
# include <alloca.h>
#elif defined(_WIN32)
# include <malloc.h>
# ifndef alloca
# define alloca(s) _alloca(s)
# endif
#endif
%}
#if defined(SWIGPYTHON) || defined(SWIGPERL)
%include "cdata.i"
#endif
#if SWIG_VERSION < 0x040100 && defined(SWIGJAVASCRIPT)
%wrapper %{
#ifdef NODE_MODULE
# undef NODE_MODULE
# define NODE_MODULE NODE_MODULE_CONTEXT_AWARE
// actually error-prone and not exactly suitable for production, but
// sufficient for development purposes till SWIG 4.1.0 is released...
#endif
%}
#endif
#if SWIG_VERSION < 0x040100 && defined(SWIGJAVA)
/* SWIG versions prior 4.1 were crossing the MinGW's ways on the path
* to JNI 'jlong' type */
%begin %{
#if defined(__MINGW32__) && defined(__int64)
# undef __int64
#endif
%}
#endif