bool PrioEncoder::IsValidHexPublicKey(mozilla::Span<const char> aStr) {
  if (aStr.Length() != CURVE25519_KEY_LEN_HEX) {
    return false;
  }

  for (auto c : aStr) {
    if (!IsAsciiHexDigit(c)) {
      return false;
    }
  }

  return true;
}
/*
** The workhorse sprintf code.
*/
int
nsTextFormatter::dosprintf(SprintfStateStr* aState, const char16_t* aFmt,
                           mozilla::Span<BoxedValue> aValues)
{
  static const char16_t space = ' ';
  static const char16_t hex[] = u"0123456789abcdef";
  static char16_t HEX[] = u"0123456789ABCDEF";
  static const BoxedValue emptyString(u"");

  char16_t c;
  int flags, width, prec, radix;

  const char16_t* hexp;

  // Next argument for non-numbered arguments.
  size_t nextNaturalArg = 0;
  // True if we ever saw a numbered argument.
  bool sawNumberedArg = false;

  while ((c = *aFmt++) != 0) {
    int rv;

    if (c != '%') {
      rv = (*aState->stuff)(aState, aFmt - 1, 1);
      if (rv < 0) {
        return rv;
      }
      continue;
    }

    // Save the location of the "%" in case we decide it isn't a
    // format and want to just emit the text from the format string.
    const char16_t* percentPointer = aFmt - 1;

    /*
    ** Gobble up the % format string. Hopefully we have handled all
    ** of the strange cases!
    */
    flags = 0;
    c = *aFmt++;
    if (c == '%') {
      /* quoting a % with %% */
      rv = (*aState->stuff)(aState, aFmt - 1, 1);
      if (rv < 0) {
        return rv;
      }
      continue;
    }

    // Check for a numbered argument.
    bool sawWidth = false;
    const BoxedValue* thisArg = nullptr;
    if (c >= '0' && c <= '9') {
      size_t argNumber = 0;
      while (c && c >= '0' && c <= '9') {
        argNumber = (argNumber * 10) + (c - '0');
        c = *aFmt++;
      }

      if (c == '$') {
        // Mixing numbered arguments and implicit arguments is
        // disallowed.
        if (nextNaturalArg > 0) {
          return -1;
        }

        c = *aFmt++;

        // Numbered arguments start at 1.
        --argNumber;
        if (argNumber >= aValues.Length()) {
          // A correctness issue but not a safety issue.
          MOZ_ASSERT(false);
          thisArg = &emptyString;
        } else {
          thisArg = &aValues[argNumber];
        }
        sawNumberedArg = true;
      } else {
        width = argNumber;
        sawWidth = true;
      }
    }

    if (!sawWidth) {
      /*
       * Examine optional flags.  Note that we do not implement the
       * '#' flag of sprintf().  The ANSI C spec. of the '#' flag is
       * somewhat ambiguous and not ideal, which is perhaps why
       * the various sprintf() implementations are inconsistent
       * on this feature.
       */
      while ((c == '-') || (c == '+') || (c == ' ') || (c == '0')) {
        if (c == '-') {
          flags |= _LEFT;
        }
        if (c == '+') {
          flags |= _SIGNED;
        }
        if (c == ' ') {
          flags |= _SPACED;
        }
        if (c == '0') {
          flags |= _ZEROS;
        }
        c = *aFmt++;
      }
      if (flags & _SIGNED) {
        flags &= ~_SPACED;
      }
      if (flags & _LEFT) {
        flags &= ~_ZEROS;
      }

      /* width */
      if (c == '*') {
        // Not supported with numbered arguments.
        if (sawNumberedArg) {
          return -1;
        }

        if (nextNaturalArg >= aValues.Length() || !aValues[nextNaturalArg].IntCompatible()) {
          // A correctness issue but not a safety issue.
          MOZ_ASSERT(false);
          width = 0;
        } else {
          width = aValues[nextNaturalArg++].mValue.mInt;
        }
        c = *aFmt++;
      } else {
        width = 0;
        while ((c >= '0') && (c <= '9')) {
          width = (width * 10) + (c - '0');
          c = *aFmt++;
        }
      }
    }

    /* precision */
    prec = -1;
    if (c == '.') {
      c = *aFmt++;
      if (c == '*') {
        // Not supported with numbered arguments.
        if (sawNumberedArg) {
          return -1;
        }

        if (nextNaturalArg >= aValues.Length() || !aValues[nextNaturalArg].IntCompatible()) {
          // A correctness issue but not a safety issue.
          MOZ_ASSERT(false);
        } else {
          prec = aValues[nextNaturalArg++].mValue.mInt;
        }
        c = *aFmt++;
      } else {
        prec = 0;
        while ((c >= '0') && (c <= '9')) {
          prec = (prec * 10) + (c - '0');
          c = *aFmt++;
        }
      }
    }

    // If the argument isn't known yet, find it now.  This is done
    // after the width and precision code, in case '*' was used.
    if (thisArg == nullptr) {
      // Mixing numbered arguments and implicit arguments is
      // disallowed.
      if (sawNumberedArg) {
        return -1;
      }

      if (nextNaturalArg >= aValues.Length()) {
        // A correctness issue but not a safety issue.
        MOZ_ASSERT(false);
        thisArg = &emptyString;
      } else {
        thisArg = &aValues[nextNaturalArg++];
      }
    }

    /* Size.  Defaults to 32 bits.  */
    uint64_t mask = UINT32_MAX;
    if (c == 'h') {
      c = *aFmt++;
      mask = UINT16_MAX;
    } else if (c == 'L') {
      c = *aFmt++;
      mask = UINT64_MAX;
    } else if (c == 'l') {
      c = *aFmt++;
      if (c == 'l') {
        c = *aFmt++;
        mask = UINT64_MAX;
      } else {
        mask = UINT32_MAX;
      }
    }

    /* format */
    hexp = hex;
    radix = 10;
    // Several `MOZ_ASSERT`s below check for argument compatibility
    // with the format specifier.  These are only debug assertions,
    // not release assertions, and exist to catch problems in C++
    // callers of `nsTextFormatter`, as we do not have compile-time
    // checking of format strings.  In release mode, these assertions
    // will be no-ops, and we will fall through to printing the
    // argument based on the known type of the argument.
    switch (c) {
      case 'd':
      case 'i':                               /* decimal/integer */
        MOZ_ASSERT(thisArg->IntCompatible());
        break;

      case 'o':                               /* octal */
        MOZ_ASSERT(thisArg->IntCompatible());
        radix = 8;
        flags |= _UNSIGNED;
        break;

      case 'u':                               /* unsigned decimal */
        MOZ_ASSERT(thisArg->IntCompatible());
        radix = 10;
        flags |= _UNSIGNED;
        break;

      case 'x':                               /* unsigned hex */
        MOZ_ASSERT(thisArg->IntCompatible());
        radix = 16;
        flags |= _UNSIGNED;
        break;

      case 'X':                               /* unsigned HEX */
        MOZ_ASSERT(thisArg->IntCompatible());
        radix = 16;
        hexp = HEX;
        flags |= _UNSIGNED;
        break;

      case 'e':
      case 'E':
      case 'f':
      case 'g':
      case 'G':
        MOZ_ASSERT(thisArg->mKind == DOUBLE);
        // Type-based printing below.
        break;

      case 'S':
        MOZ_ASSERT(thisArg->mKind == STRING16);
        // Type-based printing below.
        break;

      case 's':
        MOZ_ASSERT(thisArg->mKind == STRING);
        // Type-based printing below.
        break;

      case 'c': {
          if (!thisArg->IntCompatible()) {
            MOZ_ASSERT(false);
            // Type-based printing below.
            break;
          }

          if ((flags & _LEFT) == 0) {
            while (width-- > 1) {
              rv = (*aState->stuff)(aState, &space, 1);
              if (rv < 0) {
                return rv;
              }
            }
          }
          char16_t ch = thisArg->mValue.mInt;
          rv = (*aState->stuff)(aState, &ch, 1);
          if (rv < 0) {
            return rv;
          }
          if (flags & _LEFT) {
            while (width-- > 1) {
              rv = (*aState->stuff)(aState, &space, 1);
              if (rv < 0) {
                return rv;
              }
            }
          }
        }
        continue;

      case 'p':
        if (!thisArg->PointerCompatible()) {
            MOZ_ASSERT(false);
            break;
        }
        static_assert(sizeof(uint64_t) >= sizeof(void*), "pointers are larger than 64 bits");
        rv = cvt_ll(aState, uintptr_t(thisArg->mValue.mPtr), width, prec, 16, flags | _UNSIGNED,
                    hexp);
        if (rv < 0) {
          return rv;
        }
        continue;

      case 'n':
        if (thisArg->mKind != INTPOINTER) {
          return -1;
        }

        if (thisArg->mValue.mIntPtr != nullptr) {
          *thisArg->mValue.mIntPtr = aState->cur - aState->base;
        }
        continue;

      default:
        /* Not a % token after all... skip it */
        rv = (*aState->stuff)(aState, percentPointer, aFmt - percentPointer);
        if (rv < 0) {
          return rv;
        }
        continue;
    }

    // If we get here, we want to handle the argument according to its
    // actual type; modified by the flags as appropriate.
    switch (thisArg->mKind) {
      case INT:
      case UINT: {
          int64_t val = thisArg->mValue.mInt;
          if ((flags & _UNSIGNED) == 0 && val < 0) {
            val = -val;
            flags |= _NEG;
          }
          rv = cvt_ll(aState, uint64_t(val) & mask, width, prec, radix, flags, hexp);
        }
        break;
      case INTPOINTER:
      case POINTER:
        // Always treat these as unsigned hex, no matter the format.
        static_assert(sizeof(uint64_t) >= sizeof(void*), "pointers are larger than 64 bits");
        rv = cvt_ll(aState, uintptr_t(thisArg->mValue.mPtr), width, prec, 16, flags | _UNSIGNED,
                    hexp);
        break;
      case DOUBLE:
        if (c != 'f' && c != 'E' && c != 'e' && c != 'G' && c != 'g') {
          // Pick some default.
          c = 'g';
        }
        rv = cvt_f(aState, thisArg->mValue.mDouble, width, prec, c, flags);
        break;
      case STRING:
        rv = cvt_s(aState, thisArg->mValue.mString, width, prec, flags);
        break;
      case STRING16:
        rv = cvt_S(aState, thisArg->mValue.mString16, width, prec, flags);
        break;
      default:
        // Can't happen.
        MOZ_ASSERT(0);
    }

    if (rv < 0) {
      return rv;
    }
  }

  return 0;
}