batchVerify function

bool batchVerify(
  1. List<PublicKey> publicKeys,
  2. List<List<int>> messages,
  3. List<Signature> signatures
)

Implementation

bool batchVerify(List<PublicKey> publicKeys, List<List<int>> messages,
    List<Signature> signatures) {
  if (publicKeys.isEmpty) {
    throw SchnorrException(
        'publicKeys must be an array with one or more elements');
  }
  if (messages.isEmpty) {
    throw SchnorrException(
        'messages must be an array with one or more elements');
  }
  if (signatures.isEmpty) {
    throw SchnorrException(
        'signatures must be an array with one or more elements');
  }
  if (publicKeys.length != messages.length ||
      messages.length != signatures.length) {
    throw SchnorrException(
        'all parameters must be an array with the same length');
  }

  var curve = publicKeys[0].curve;

  var ls = BigInt.zero;
  var a = BigInt.one;
  var rs = AffinePoint();

  var big7 = BigInt.from(7);

  var result = false;
  for (final i in signatures.asMap().keys) {
    var signature = signatures[i];
    var publicKey = publicKeys[i];
    var message = messages[i];
    if (curve != publicKey.curve) {
      throw SchnorrException('publickeys must be on the same curve');
    }

    if (!curve.isOnCurve(publicKey)) {
      throw SchnorrException('publickey is not on the curve');
    }

    var r = signature.R;
    if (r >= curve.p) {
      throw SchnorrException('r is larger than or equal to field size');
    }
    var s = signature.S;
    if (s >= curve.n) {
      throw SchnorrException('s is larger than or equal to curve order');
    }

    var e = getE(curve, publicKey, intToByte(curve, r), message);

    var r2 = r.pow(3);
    r2 = r2 + big7;
    r2 = r2 % curve.p;
    var c = r2;
    var exp = curve.p + BigInt.one;
    exp = exp >> 2;

    var y = c.modPow(exp, curve.p);

    if (y.modPow(BigInt.two, curve.p) != c) {
      break;
    }

    var R = AffinePoint.fromXY(r, y);

    if (i != 0) {
      a = deterministicGetRandA(curve);
    }

    var aR = curve.scalarMul(R, intToByte(curve, a));
    var ae = (a * e);
    var aeHex = ae.toRadixString(16).padLeft((ae.bitLength + 7) >> 3, '0');
    var aeBytes = List<int>.generate((ae.bitLength + 7) >> 3,
        (index) => int.parse(aeHex.substring(2 * index, 2 * index + 2)));
    var aeP = curve.scalarMul(publicKey, aeBytes);
    rs = curve.add(rs, aR);
    rs = curve.add(rs, aeP);
    s = s * a;
    ls = ls + s;
  }

  var G = curve.scalarBaseMul(intToByte(curve, ls % curve.n));
  if (G != rs) {
    return false;
  }

  return result;
}