public KeyPair generate() {
      if (p == null) {
         BigInteger[] params = new RFC2631(m, l, rnd).generateParameters();
         seed = params[RFC2631.DH_PARAMS_SEED];
         counter = params[RFC2631.DH_PARAMS_COUNTER];
         q = params[RFC2631.DH_PARAMS_Q];
         p = params[RFC2631.DH_PARAMS_P];
         j = params[RFC2631.DH_PARAMS_J];
         g = params[RFC2631.DH_PARAMS_G];
         if (DEBUG && debuglevel > 0) {
            debug("seed: 0x"+seed.toString(16));
            debug("counter: "+counter.intValue());
            debug("q: 0x"+q.toString(16));
            debug("p: 0x"+p.toString(16));
            debug("j: 0x"+j.toString(16));
            debug("g: 0x"+g.toString(16));
         }
      }

      // generate a private number x of length m such as: 1 < x < q - 1
      BigInteger q_minus_1 = q.subtract(BigInteger.ONE);
      byte[] mag = new byte[(m + 7) / 8];
      BigInteger x;
      while (true) {
         nextRandomBytes(mag);
         x = new BigInteger(1, mag);
         if (x.bitLength() == m
               && x.compareTo(BigInteger.ONE) > 0
               && x.compareTo(q_minus_1) < 0) {
            break;
         }
      }
      BigInteger y = g.modPow(x, p);

      PrivateKey secK = new GnuDHPrivateKey(q, p, g, x);
      PublicKey pubK = new GnuDHPublicKey(q, p, g, y);

      return new KeyPair(pubK, secK);
   }