Skip to content

Using libgroupsig

jdv-ibm edited this page Aug 10, 2021 · 12 revisions

Versions

All the variants of the library follow the MAJOR.MINOR.PATCH semantic versioning pattern.

However, the latest available patch number may be different across wrappers, and core and wrappers. But wrappers (and core) with the same MAJOR.MINOR numbers should be compatible.

In general, whenever some fix or small modification that does not affect the currently supported functionality is made, the PATCH number is increased. When a change, including additions, in the functionality (e.g. a new scheme, some extra feature, or tool) that does not break backwards compatibility, the MINOR number is increased. For backwards incompatible changes, the MAJOR number is updated.

Using the core library

To use the core library in a C program, you need to build it and install it as described in Building libgroupsig. (Installation may be skipped if you want to develop tools for the library.)

The most important part is to include the main groupsig header with #include <groupsig/groupsig>. This will give you access to all the necessary functionality. Also, any produced binaries need to be linked with libgroupsig, and, if you are using a scheme that requires pairing based crypto (provided by MCL in libgroupsig), you also need to link with mcl and mclbn384_256. How to do this will vary depending on your OS. In Linux machines you can do it with lgroupsig, lmcl and lmclbn384_256. Also, by default (in Linux machines) the library is installed in /usr/local. You may need to pass this to your library search path by specifying -Wl,-rpath=/usr/local/lib during link.

C code samples

You can get the most complete C examples from the src/tools directory of the repository. For completeness, I give some basic samples next. I assume a Linux & gcc-based environment.

Hello, World! in C

Create a hello_world.c program with the following content:

#include <groupsig/groupsig.h>
int main (int argc, char *argv[]) {
return groupsig_hello_world();
}

Then, compile and link with:

$ gcc -o hello_world hello_world.c -lgroupsig -Wl,-rpath=/usr/local/lib

Running $ ./hello_world should then output:

Hello, World!

Signing in C

Warning!: For brevity, the following code does not check for errors! You should not do this! Except in some rare cases, all functions that return a pointer will return NULL on error and not NULL otherwise; and all functions returning an integer will return 1 (IERROR) on error, and 0 (IOK) if all went well. In many cases, the specific reason for error can be checked with the global errno.

Create a file named sign_gl19.c with the following content:

#include <groupsig/groupsig.h>
int main (int argc, char *argv[]) {
groupsig_config_t *cfg;
groupsig_key_t *grpkey, *isskey, *cnvkey, *memkey;
groupsig_signature_t *sig;
message_t *msg, *m1, *m2, *m3, *m4;
uint8_t b;
/* Initialize environment for GL19 */
cfg = groupsig_init(GROUPSIG_GL19_CODE, 0);
/** Create the group **/
/* Initialize the group and manager keys */
grpkey = groupsig_grp_key_init(GROUPSIG_GL19_CODE);
isskey = groupsig_mgr_key_init(GROUPSIG_GL19_CODE);
cnvkey = groupsig_mgr_key_init(GROUPSIG_GL19_CODE);
/* Run the Issuer part of the setup */
groupsig_setup(GROUPSIG_GL19_CODE, grpkey, isskey, NULL, cfg);
/* Run the Converter part of the setup */
groupsig_setup(GROUPSIG_GL19_CODE, grpkey, cnvkey, NULL, cfg);
/** Add a member to the group **/
/* Initialize the member key */
memkey = groupsig_mem_key_init(GROUPSIG_GL19_CODE);
/* Simulate the issue-join interactive process */
m1 = m2 = m3 = m4 = NULL;
groupsig_join_mgr(&m1, NULL, isskey, 0, NULL, grpkey);
groupsig_join_mem(&m2, memkey, 1, m1, grpkey);
groupsig_join_mgr(&m3, NULL, isskey, 2, m2, grpkey);
groupsig_join_mem(&m4, memkey, 3, m3, grpkey);
/** Sign a message **/
/* Prepare the message */
msg = message_from_string("Hello, World!");
/* Initialize the signature object */
sig = groupsig_signature_init(GROUPSIG_GL19_CODE); groupsig_sign(sig, msg, memkey, grpkey, 0);
/** Verify the signature **/
groupsig_verify(&b, sig, msg, grpkey);
if (b) {
fprintf(stdout, "VALID signature.\n");
} else {
fprintf(stdout, "WRONG signature.\n");
}
/* Free memory */
groupsig_clear(GROUPSIG_GL19_CODE, cfg); cfg = NULL;
groupsig_grp_key_free(grpkey); grpkey = NULL;
groupsig_mgr_key_free(isskey); isskey = NULL;
groupsig_mgr_key_free(cnvkey); cnvkey = NULL;
groupsig_mem_key_free(memkey); memkey = NULL;
groupsig_signature_free(sig); sig = NULL;
message_free(msg); msg = NULL;
message_free(m1); m1 = NULL;
message_free(m2); m2 = NULL;
message_free(m3); m3 = NULL;
message_free(m4); m4 = NULL;
return 0;
}

Compile and link with:

gcc sign_gl19.c -o sign_gl19 -lgroupsig -lmcl -Wl,-rpath=/usr/local/lib

And running $ ./sign_gl19 should produce:

VALID signature.

Congratulations! You just initialized a GL19 group setting up the group, issuer and converter keys, added a new member to the group, signed the message "Hello, World!" with that member's private key, and verified the signature correctly! (And all in less than 100 lines of C code!!)

For most cases, the overall approach will be the same, specifying the scheme you are interested in (check Supported schemes). Variations are to be expected in the setup and join protocols: depending on the scheme internals, you may need to setup other keys, or the join protocol may be initiated by the prospective member instead of the manager, or require a different number of messages.

Using pygroupsig

To start using pygroupsig, the Python wrapper for libgroupsig, you just need to run:

pip3 install pygroupsig

This will fetch the package from pypi.org and install it in your local Python environment. If this does not work for you, you can try to build the wrapper manually, as described in Building libgroupsig (and please let us know so that we can try to fix it!)

In the Python wrapper, the functionality is divided in modules. Specifically, the modules are:

  • groupsig: Module to the main group operations (setup, join, sign, verify...).
  • signature: Module to manage signature objects.
  • message: Module to manage message objects.
  • grpkey: Module to manage group keys.
  • mgrkey: Module to manage manager keys.
  • memkey: Module to manage member keys.
  • bldkey: Module to manage blinding keys.
  • signature: Module to manage signatures.
  • blindsig: Module to manage blinded signatures.
  • proof: Module to manage proofs.
  • constants: Module to ease access to relevant constants (like group codes.)

Modules for signatures and keys allow to initialize, free, export and import the objects they represent. The interface they expose is mostly equivalent across modules, so you'll probably get used easily.

Also, the Python wrapper abstracts some internals out. For instance, you do not need to initialize the groupsig environment (as was needed in C with groupsig_init).

Python code samples

Hello, World! in Python

Paste the following code into a file named hello_world.py:

#!/usr/bin/env python3
from pygroupsig import groupsig;
groupsig.hello_world()

Then, run python3 hello_world.py. You should see:

Hello, World!

Signing in Python

Paste the following code into a file named sign_gl19.py:

#!/usr/bin/env python3
from pygroupsig import groupsig
from pygroupsig import signature
from pygroupsig import memkey
from pygroupsig import grpkey
from pygroupsig import mgrkey
from pygroupsig import constants
# Setup
_gl19 = groupsig.setup(constants.GL19_CODE)
_gpk = _gl19['grpkey']
isk = _gl19['mgrkey']
gl19 = groupsig.setup(constants.GL19_CODE, _gpk);
csk = gl19['mgrkey']
gpk = gl19['grpkey']
# Join
msg1 = groupsig.join_mgr(0, isk, gpk)
msg2 = groupsig.join_mem(1, gpk, msgin = msg1)
usk = msg2['memkey']
msg3 = groupsig.join_mgr(2, isk, gpk, msg2['msgout'])
msg4 = groupsig.join_mem(3, gpk, msgin = msg3, memkey = usk)
usk = msg4['memkey']
# Sign
sig = groupsig.sign("Hello, World!", usk, gpk)
# Verify
b = groupsig.verify(sig, "Hello, World!", gpk)
if b == True:
print ("VALID signature.")
else:
print ("WRONG signature.")
sys.exit()
groupsig.clear(constants.GL19_CODE, gl19['config'])

By running python3 sign_gl19.py, you should obtain:

VALID signature.

As in the C signing example, you just created a GL19 group, added a new member, generated a group signature with the key of that member, and verified the signature. Now, in 36 lines of Python code!

For further Python examples, please check src/wrappers/python/samples.

Using jsgroupsig

To start using jsgroupsig, the NodeJS wrapper for libgroupsig, you just need to run npm install jsgroupsig. If this does not work for you, you may try building it from source as described in Building libgroupsig (and please, let us know so that we can try to fix it!)

All the NodeJS functionality is exposed via the jsgroupsig module.

NodeJS code samples

Hello, World! in NodeJS

Store the following in a file named hello.js:

#!/usr/bin/env nodejs
const jsgroupsig = require('jsgroupsig');
jsgroupsig.hello_world();

Running this program with nodejs hello.js should produce, as expected:

Hello, World!

Signing in NodeJS

Paste the following code in a file named sign.js:

#!/usr/bin/env nodejs
const jsgroupsig = require('jsgroupsig');
/* Init groupsig */
let cfg = jsgroupsig.init(jsgroupsig.GL19, 0);
/* Init grp_key */
let grpkey = jsgroupsig.grp_key_init(jsgroupsig.GL19);
/* Init issuer and converter keys */
let isskey = jsgroupsig.mgr_key_init(jsgroupsig.GL19);
let cnvkey = jsgroupsig.mgr_key_init(jsgroupsig.GL19);
/* Setup call 1: initializes (partial) group key and issuer key */
jsgroupsig.setup(jsgroupsig.GL19, grpkey, isskey);
/* Setup call 2: completes group key and initializes converter key */
jsgroupsig.setup(jsgroupsig.GL19, grpkey, cnvkey);
/* Add a member */
let memkey = jsgroupsig.mem_key_init(jsgroupsig.GL19);
let msg1 = jsgroupsig.join_mgr(0, isskey, grpkey);
let msg2 = jsgroupsig.join_mem(1, memkey, grpkey, msg1);
let msg3 = jsgroupsig.join_mgr(2, isskey, grpkey, msg2);
let msg4 = jsgroupsig.join_mem(3, memkey, grpkey, msg3);
/* sign */
let sig = jsgroupsig.sign("Hello, World!", memkey, grpkey);
/* verify */
let ok = jsgroupsig.verify(sig, "Hello, World!", grpkey);
if (ok) console.log("VALID signature.");
else console.log("WRONG signature.");
jsgroupsig.clear(jsgroupsig.GL19, cfg);

Then, run nodejs sign.js from the command line. You should get:

VALID signature.

As for C and Python, this NodeJS code creates a GL19 group, adds a member, generates a signature with this member's key, and verifies the signature.

For further NodeJS samples, check src/wrappers/nodejs/samples.

REST API in NodeJS

If you even want to play more, there is a simple HTTP REST API available in src/wrappers/nodejs/server, including a Postman collection for the main queries. Although it should be easy to generalize, this API is hard-coded to manage GL19 groups. To test it, go to the src/wrappers/nodejs/server directory, and run something like:

$ npm install # installs the server
$ DATABASE=groupsig_issuer PORT=3000 npm start
$ DATABASE=groupsig_converter PORT=3001 npm start

Note: This assumes that you have two Postgresql databases named groupsig_issuer and groupsig_converter.

The issuer will be listening at port 3000, and the converter at port 3001.

Then, try running npm test, or some of the requests in the Postman collection (for the latter, make sure to use a correct order -- you cannot sign messages if you don't create a group and add members first!)

Sample REST Server Tutorial

Check out the Tutorial on how to create a GL19 group and add members, sign messages, verify them, and link them. It is based on a sample REST server, and includes test Dockerfiles and scripts that will help you understand how to use the library in a realistic setting (also, the sample REST server should be easily extensible to other schemes!).

Using jgroupsig

Being object oriented, the Java wrapper is different than the rest. A group will have a group key and one or more manager keys associated. This simplifies the invocations (you don't need to pass the keys!) Otherwise, the classes are as expected:

  • GS.java: An interface represnting group signature schemes. All group schemes must implement this interface.
  • GrpKey.java: A class for representing group keys.
  • MgrKey.java: A class for representing manager keys.
  • MemKey.java: A class for representing member keys.
  • BldKey.java: A class for representing blinding keys.
  • Signature.java: A class for representing group signatures.
  • Blindsig.java: A class for representing blinded signatures.
  • Identity.java: A class for representing identities.

For the moment, there is no publicly available Java package to download and easily install jgroupsig. However, building from source is easy, and can be done as described in Building libgroupsig.

Java code samples

Hello, World! in Java

Copy the following code into a file named HelloWorld.java:

import com.ibm.jgroupsig.GL19;
public class HelloWorld {
public static void main (String args[]) {
try {
GL19 gl19 = new GL19();
gl19.helloWorld();
return;
} catch (Exception e) {
e.printStackTrace();
}
}
}

Make sure that the libjgroupsig.jar file produced when you built jgroupsig is in your classpath, and libjnigroupsig.so, also produced when building jgroupsig is in your java.library.path. In the next commands, I just assume they are in the same directory as HelloWorld.java (but this will most probably not be the case for non trivial settings!). Then, run:

$ javac -cp libjgroupsig-0.1.jar HelloWorld.java
$ java -cp .:libjgroupsig-0.1.jar -Djava.library.path=. HelloWorld

You should see Hello, World! in your console.

Signing in Java

Paste the following code in a file named Sign.java:

import com.ibm.jgroupsig.GS;
import com.ibm.jgroupsig.GL19;
import com.ibm.jgroupsig.Signature;
import com.ibm.jgroupsig.MemKey;
import java.io.UnsupportedEncodingException;
import java.lang.IllegalArgumentException;
public class Sign {
public static void main (String args[]) {
try {
/* Instantiate and setup the group. To simulate a real setting, we use three different "environments", issuer (who controls the issuing key),
converter (who controls the converter key), and user
(who controls a member key)
*/
GL19 issuer = new GL19();
GL19 converter = new GL19();
GL19 user = new GL19();
issuer.setup();
converter.setup(issuer.getGrpKey());
issuer.setup(converter.getGrpKey());
user.setGrpKey(issuer.getGrpKey());
/* Simulate adding one member */
MemKey memkey = new MemKey(GS.GL19_CODE); long mout1 = issuer.joinMgr(0, 0);
long mout2 = issuer.joinMem(memkey, 1, mout1);
long mout3 = issuer.joinMgr(2, mout2);
issuer.joinMem(memkey, 3, mout3);
/* Create sample signatures */
Signature sig = user.sign("Hello, World!", memkey);
boolean b = user.verify(sig, "Hello, World!");
if (b == true) {
System.out.println("VALID signature.");
} else {
System.out.println("WRONG signature.");
}
issuer.finalize();
converter.finalize();
user.finalize();
return;
} catch(UnsupportedEncodingException |
IllegalArgumentException e) {
e.printStackTrace();
} catch(Exception e) {
e.printStackTrace();
}
}
}

Again, assuming that the files libjgroupsig.jar and libjnigroupsig.so are in the same directory as Sign.java, run:

$ javac -cp libjgroupsig-0.1.jar Sign.java
$ java -cp .:libjgroupsig-0.1.jar -Djava.library.path=. Sign

You should see VALID signature. in your console.

As in the previous examples, this code generates, in Java, a GL19 group, adds a member to it, signs a message with this member's private key, and verifies the produced signature.

Reusability

You may already be thinking: "OK, but all the previous examples use the same scheme. You promised it would be easy to change to other schemes, but so far we've seen nothing of it."

To showcase this, I'll reproduce the previous C signing example, this time for the BBS04 scheme. From this, it is easy to extrapolate to any of the variants (pygroupsig, jsgroupsig or jgroupsig). After all, C is the most cumbersome to use.

Copy the following code into a file named: sign_bbs04.c:

#include <groupsig/groupsig.h>
int main (int argc, char *argv[]) {
groupsig_config_t *cfg;
groupsig_key_t *grpkey, *mgrkey, *cnvkey, *memkey;
groupsig_signature_t *sig;
gml_t *gml;
message_t *msg, *m1, *m2;
uint8_t b;
/* Initialize environment for GL19 */
cfg = groupsig_init(GROUPSIG_BBS04_CODE, 0);
/** Create the group **/
/* Initialize the group and manager keys */
grpkey = groupsig_grp_key_init(GROUPSIG_BBS04_CODE);
mgrkey = groupsig_mgr_key_init(GROUPSIG_BBS04_CODE);
/* Initialize the Group Membership List */
gml = gml_init(GROUPSIG_BBS04_CODE);
/* BBS04 only needs one call to setup */
groupsig_setup(GROUPSIG_BBS04_CODE, grpkey, mgrkey, gml, cfg);
/** Add a member to the group **/
/* Initialize the member key */
memkey = groupsig_mem_key_init(GROUPSIG_BBS04_CODE);
/* Simulate the issue-join interactive process */
m1 = m2 = NULL;
groupsig_join_mgr(&m1, gml, mgrkey, 0, NULL, grpkey);
groupsig_join_mem(&m2, memkey, 1, m1, grpkey);
/** Sign a message **/
/* Prepare the message */
msg = message_from_string("Hello, World!");
/* Initialize the signature object */
sig = groupsig_signature_init(GROUPSIG_BBS04_CODE); groupsig_sign(sig, msg, memkey, grpkey, 0);
/** Verify the signature **/
groupsig_verify(&b, sig, msg, grpkey);
if (b) {
fprintf(stdout, "VALID signature.\n");
} else {
fprintf(stdout, "WRONG signature.\n");
}
/* Free memory */
groupsig_clear(GROUPSIG_BBS04_CODE, cfg); cfg = NULL;
groupsig_grp_key_free(grpkey); grpkey = NULL;
groupsig_mgr_key_free(mgrkey); mgrkey = NULL;
groupsig_mem_key_free(memkey); memkey = NULL;
gml_free(gml); gml = NULL;
groupsig_signature_free(sig); sig = NULL;
message_free(msg); msg = NULL;
message_free(m1); m1 = NULL;
message_free(m2); m2 = NULL;
return 0;
}

To test it, compile with gcc -o sign_bbs04 sign_bbs04.c -lgroupsig -lmcl and run $ ./sign_bbs04. You should see VALID signature. in your console.

If you understood the initial signing example, this should be easy to grasp. Some key differences, though: now, we only run the groupsig_setup function once. This is because in BBS04, all the setup is done by a single group manager, whereas in GL19 we had an Issuer and a Converter, and the multiple groupsig_setup calls in the example simulated running their respective parts. The joining process is also different, and we need to do only one round-trip instead of two. Finally, BBS04 keeps a Group Membership List in order to be able to open signatures, this is why we need to instantiate it with gml_init. But, hopefully, you still appreciate that the overall idea is the same and, undoubtedly, we use the same library for both schemes. The minor differences that remain are, however, hard (and probably unwise) to abstract out.

For more details on the different schemes, see Supported schemes.