#include <bits/stdc++.h>
using namespace std;
template <class _T>
inline _T sqr(const _T& x) {
  return x * x;
}
template <class _T>
inline string tostr(const _T& a) {
  ostringstream os("");
  os << a;
  return os.str();
}
const long double PI = 3.1415926535897932384626433832795L;
const long double EPS = 1e-11;
char TEMPORARY_CHAR;
const int INF = 0x3f3f3f3f;
const int N = 1 << 16;
inline void input(int& a) {
  a = 0;
  while ((TEMPORARY_CHAR = getchar()) > '9' || TEMPORARY_CHAR < '0') {
  }
  while (TEMPORARY_CHAR <= '9' && TEMPORARY_CHAR >= '0') {
    a = (a << 3) + (a << 1) + TEMPORARY_CHAR - '0';
    TEMPORARY_CHAR = getchar();
  }
}
const long long p = 1003001;
long long has(vector<int>& a) {
  long long ans = 0;
  for (__typeof((a).begin()) it = (a).begin(); it != (a).end(); it++) {
    ans = ans * p + (long long)(*it);
  }
  return ans;
}
int main() {
  int(n);
  input((n));
  ;
  int(m);
  input((m));
  ;
  vector<vector<int> > g(n);
  for (int i = 0; i < (int)(m); i++) {
    int(a);
    input((a));
    ;
    int(b);
    input((b));
    ;
    g[a - 1].push_back(b);
    g[b - 1].push_back(a);
  }
  vector<long long> h(n);
  for (int i = 0; i < (int)(n); i++) {
    sort((g[i]).begin(), (g[i]).end());
    h[i] = has(g[i]);
  }
  sort((h).begin(), (h).end());
  long long ans = 0;
  for (int i = 0; i < (int)(n); i++) {
    int cnt = 0;
    while (i + cnt < n && h[i] == h[i + cnt]) cnt++;
    i = i + cnt - 1;
    ans += ((long long)cnt * (long long)(cnt - 1)) >> 1;
  }
  for (int i = 0; i < (int)(n); i++) {
    g[i].push_back(i + 1);
    sort((g[i]).begin(), (g[i]).end());
    h[i] = has(g[i]);
  }
  sort((h).begin(), (h).end());
  for (int i = 0; i < (int)(n); i++) {
    int cnt = 0;
    while (i + cnt < n && h[i] == h[i + cnt]) cnt++;
    i = i + cnt - 1;
    ans += ((long long)cnt * (long long)(cnt - 1)) >> 1;
  }
  cout << ans;
  return 0;
}
