blsCreateProofFFI method

Future<Uint8List> blsCreateProofFFI({
  1. required Uint8List publicKey,
  2. required Uint8List nonce,
  3. required Uint8List signature,
  4. required List<ProofMessage> messages,
})

Creates a BBS+ proof using the BLS public key, nonce, signature, and messages.

This method leverages FFI calls to interact with the native BBS+ library for proof generation.

  • Converts the provided BLS public key to a BBS public key before proceeding with the proof creation.
  • Handles the allocation and deallocation of required memory during the FFI calls.

Implementation

Future<Uint8List> blsCreateProofFFI({
  required Uint8List publicKey,
  required Uint8List nonce,
  required Uint8List signature,
  required List<ProofMessage> messages,
}) {
  // Convert publickey bls to bbs
  final bbsPublicKey = blsPublicToBbsPublicKey(publicKey, messages.length);
  Tools.logDebug('bbsPublicKey length = ${bbsPublicKey.length}');

  Tools.logDebug('BBS public key (base64): ${base64.encode(bbsPublicKey)}');

  final err1 = calloc<ExternError>();
  final handle = bbs.bbsCreateProofContextInit(err1);
  Tools.logDebug('handle init: $handle');
  if (handle == 0) {
    throw Exception('Unable to create proof context');
  }
  calloc.free(err1);

  final publicKeyPtr = ByteArrayHelper.allocate(bbsPublicKey);

  final err2 = calloc<ExternError>();

  final result = bbs.bbsCreateProofContextSetPublicKey(
    handle,
    publicKeyPtr.ref,
    err2,
  );
  Tools.logDebug('result bbsCreateProofContextSetPublicKey: $result');

  calloc.free(publicKeyPtr.ref.data);
  calloc.free(publicKeyPtr);

  if (result != 0) {
    throwIfError(result, err2, 'Unable to set public key');
  }

  calloc.free(err2);

  final noncePtr = ByteArrayHelper.allocate(nonce); // nonce is Uint8List
  final err3 = calloc<ExternError>();

  final result1 = bbs.bbsCreateProofContextSetNonceBytes(
    handle,
    noncePtr.ref,
    err3,
  );
  Tools.logDebug('result bbsCreateProofContextSetNonceBytes: $result1');

  calloc.free(noncePtr.ref.data);
  calloc.free(noncePtr);

  if (result1 != 0) {
    throwIfError(result1, err3, 'Unable to set nonce');
  }

  calloc.free(err3);

  final sigPtr = ByteArrayHelper.allocate(signature); // signature: Uint8List
  final err4 = calloc<ExternError>();

  final result2 = bbs.bbsCreateProofContextSetSignature(
    handle,
    sigPtr.ref,
    err4,
  );
  Tools.logDebug('result bbsCreateProofContextSetSignature: $result2');

  calloc.free(sigPtr.ref.data);
  calloc.free(sigPtr);

  if (result2 != 0) {
    throwIfError(result2, err4, 'Unable to set signature');
  }

  calloc.free(err4);

  final err5 = calloc<ExternError>();

  for (final msg in messages) {
    final msgPtr = ByteArrayHelper.allocate(msg.message);
    final blindPtr = ByteArrayHelper.allocate(msg.blindingFactor);

    final result3 = bbs.bbsCreateProofContextAddProofMessageBytes(
      handle,
      msgPtr.ref,
      msg.type,
      blindPtr.ref,
      err5,
    );

    calloc.free(msgPtr.ref.data);
    calloc.free(msgPtr);
    calloc.free(blindPtr.ref.data);
    calloc.free(blindPtr);

    if (result3 != 0) {
      throwIfError(result3, err5, 'Unable to add proof message');
    }
  }

  calloc.free(err5);

  final proofSize = bbs.bbsCreateProofContextSize(handle);
  Tools.logDebug('proofSize: $proofSize');
  if (proofSize <= 0) {
    throw Exception('Invalid proof size from bbs_create_proof_size()');
  }

  final proofPtr = calloc<ByteBuffer>();
  final err6 = calloc<ExternError>();

  final result4 = bbs.bbsCreateProofContextFinish(handle, proofPtr, err6);
  Tools.logDebug('result bbsCreateProofContextFinish: $result4');
  if (result4 != 0) {
    calloc.free(proofPtr);
    throwIfError(result4, err6, 'Unable to create proof');
  }

  calloc.free(err6);

  final proofBytes = proofPtr.ref.data.asTypedList(proofPtr.ref.len);

  calloc.free(proofPtr);

  return Future.value(Uint8List.fromList(proofBytes));
}