sign static method

Future<Uint8List> sign({
  1. required List<MlDsaShare> shares,
  2. required Uint8List message,
  3. Uint8List? context,
  4. String? mithrilBridgePath,
})

Threshold-sign message with ≥ params.t shares from shares.

M2 beta: uses in-process Mithril coordinator (honest combine model). Requires mithril_bridge binary and ML-DSA-44 scheme (mlDsa44ThresholdV1) until native ML-DSA-65 lands.

Implementation

static Future<Uint8List> sign({
  required List<MlDsaShare> shares,
  required Uint8List message,
  Uint8List? context,
  String? mithrilBridgePath,
}) async {
  assertMlDsaShareSetConsistent(shares);
  final params = shares.first.params;
  if (params.scheme != SchemeId.mlDsa44ThresholdV1) {
    throw SchemeNotImplemented(
      'M2 Mithril bridge supports mlDsa44ThresholdV1 only; got ${params.scheme}',
    );
  }
  if (shares.length < params.t) {
    throw InsufficientShares(
      'Need at least ${params.t} shares, got ${shares.length}',
    );
  }

  final publicKey = MlDsaPublicKey.create(
    params: params,
    ceremonyId: shares.first.ceremonyId,
    publicKeyBytes: await _derivePublicKey(
      params: params,
      ceremonySeed: shares.first.ceremonySeedBytes(),
      mithrilBridgePath: mithrilBridgePath,
    ),
  );

  final active = shares
      .take(params.t)
      .map((s) => s.mithrilPartyId)
      .toList()
    ..sort();

  final signature = await mithrilThresholdSign(
    t: params.t,
    n: params.n,
    ceremonySeed: shares.first.ceremonySeedBytes(),
    activePartyIdsZeroBased: active,
    message: message,
    executablePath: mithrilBridgePath,
  );

  if (!MlDsaThresholdVerifier.verify(
    scheme: params.scheme,
    publicKey: publicKey.bytes,
    message: message,
    signature: signature,
    context: context,
  )) {
    throw InvalidPartialSignature('Mithril produced invalid ML-DSA signature');
  }
  return signature;
}