新しい“マイ・マイナンバー”で氏名という概念を再び破壊する

# はじめに

筑波大学情報科学類誌WORD編集部が発行している学類誌のバックナンバー[WORD 39号](https://www.word-ac.net/post/2016/0705-word39/)において、**マイ・マイナンバー**が提案されました。この記事では、元の記事で述べられているマイナンバーとその問題について説明し、次に現在日本などで運用されている氏名について説明します。そして、過去に提案されたマイ・マイナンバーについて説明し、最後に著者が考案した新しいマイ・マイナンバーのエンコーディングについて述べます。この記事で紹介するプログラムは次のリポジトリに置かれています。

- https://github.com/y-yu/mymynumber

この記事を読んで疑問や改善すべきところを見つけた場合は、コメントなどで気軽に教えていただきたいです。

# マイナンバーと氏名

この節では現在日本において運用されているマイナンバーと氏名について説明します。この節の多くは参考文献をもとにしています。

## 現行のマイナンバー

マイナンバーとは個人番号とも呼ばれ、日本の法律に基づいて全ての国民に付与される12桁の番号です。マイナンバーは11桁の住民票コードを変換した11桁の数字と、それから計算される1桁のチェックデジットから構成されています。マイナンバーの持つ性質として重要なことは（1）正の整数であること、（2）他人と重複しないこと、（3）住民票を持つ全ての国民に付与されることの3点です。マイナンバーについては次のような議論があります。

<dl>
  <dt>マイナンバーの枯渇</dt>
  <dd>12桁と桁数が固定されているため国民が何度も再発行を行うなどしたり、ベビーブームが再来したりすることで枯渇する恐れがあります。</dd>

  <dt>マイナンバーのランダムさ</dt>
  <dd>マイナンバーは国がランダムに付与するため、たとえ血縁がある者の間でもまるで違う数字になります。このため、国民は自身のマイナンバーに対する関心が少なくなってしまう可能性があります。</dd>
</dl>

## 氏名に関する話題

また、氏名については次のような議論があります。

<dl>
  <dt>夫婦別姓と子どもの姓</dt>
  <dd>近年は夫婦の姓を妻か夫のどちらか一方へ改めることを強制する夫婦同性と、改める必要がないとする夫婦別姓の間で議論を醸しています。別姓と同姓のどちらを選択したとしても、子どもの姓は妻か夫のどちらかにする必要があり、性別の非対称さを感じざるを得ません。この解決策として、両親の姓を両方名乗るという方法がありますが、どちらの姓を第一姓にするのかという問題があります。</dd>

  <dt>姓の淘汰</dt>
  <dd>姓は増えることがないので、種類が少なくなっていくことが危惧されています。姓が皆同じになってしまったら、そもそも姓を持つ意味が薄れてしまいます。</dd>

  <dt>同姓同名</dt>
  <dd>氏名の組は必ずしもユニークであるとは限らなため、同姓同名が存在する可能性があります。親が子どもにどのような名を付けたとしても、その名が永遠にユニークである保証はありません。</dd>
</dl>

## マイナンバーと氏名の問題点

このように現在のマイナンバーと氏名には次のような問題があります。

- マイナンバーが枯渇する恐れがある
- ランダムな番号なので、ありがたみがない
- 夫婦同姓や子どもの姓などで、性別に非対称さが発生する
- 同姓同名によりユニークさが保てない

# マイ・マイナンバー

このような問題を解決するために、マイ・マイナンバーが考案されました。このマイ・マイナンバーは次のような性質を持ちます。

- マイ・マイナンバーには家系情報が全て含まれる
  - そのため、2つのマイ・マイナンバーから親等数を計算できる
- 重複しない正の整数である
- 固定長ではなく、数に上限がない

このようなマイ・マイナンバーは次のように作ります。

## 素数発行機関としての国

まず、マイ・マイナンバー制度では国が名の代わりとなる素数を支給します。素数はその数自身と1のみでしか割ることができない数で、これは国民ひとりひとりがプライムな存在であることを示します。

## マイ・マイナンバーの計算方法

マイ・マイナンバーは個人に支給された素数と両親のマイ・マイナンバーを引数に取る関数$M$で計算されます。これは血縁に相当します。関数$M$は次のような関数です。

```math
  M(p, a, b) = p \cdot a^a \cdot b^b 
```

たとえばアリスのマイ・マイナンバーが$\mathcal{A}$であり、ボブのマイ・マイナンバーが$\mathcal{B}$であるとします。また、アリスとボブの間に生まれた子どもチャーリーには国から素数$p_c$が支給されたとします。このときチャーリーのマイ・マイナンバー$\mathcal{C}$は次のようになります。

```math
  \begin{align*}
    \mathcal{C} &:= M(p_c, \mathcal{A}, \mathcal{B}) \\
                &= p_c \cdot \mathcal{A}^\mathcal{A} \cdot \mathcal{B}^\mathcal{B}
  \end{align*}
```

これは次の図[^figure]のようになります。

<img width="600vw" alt="image.png" src="https://qiita-image-store.s3.amazonaws.com/0/10815/472457cd-3695-0622-7a09-05fc1cf2f65d.png">

[^figure]: 図は参考文献より引用しました。

マイ・マイナンバーを計算する関数$M$は、任意の正の整数$a, b, p$に対して$M(p, a, b) = M(p, b, a)$です。この対称さはかけ算の交換法則に由来する性質であり、子どもを作るうえで男女の扱いが平等であることを意味します。

## 家系図との対応

マイ・マイナンバーには祖先の情報が全て含まれています。自分のマイ・マイナンバー$\mathcal{C} = p_c \cdot \mathcal{A}^\mathcal{A} \cdot \mathcal{B}^\mathcal{B}$となる$\mathcal{A}, \mathcal{B}$を見つけることで、両親のマイ・マイナンバーが判明します。同様の計算を$\mathcal{A}, \mathcal{B}$に対して行えば祖父母のマイ・マイナンバーが得られます。

## マイ・マイナンバーの問題

ただし、マイ・マイナンバーは指数関数的に値が増加するため、最も少ない数からはじめたとしても数世代で桁が100万桁程度となってしまいます。

# 新しいマイ・マイナンバー

そこで、マイ・マイナンバーの性質をそのままにして、桁数を圧縮することができないかという課題があります。この節では著者の考えた新しいエンコーディングを述べます。

## 新しいマイ・マイナンバーの計算方法

マイ・マイナンバーは$3$以上の素数として、マイ・マイナンバー$\mathcal{A}$を持つアリスとマイ・マイナンバー$\mathcal{B}$を持つボブの子どもチャーリーのマイ・マイナンバー$\mathcal{C}$をどのように計算するかについて述べます。まず国が次を満すフレッシュな素数$p$を計算します。ただし関数$\text{isprime}$は引数が素数ならば$\text{true}$を返し、合成数ならば$\text{false}$を返す関数とします。

```math
  p > \mathcal{A} \wedge p > \mathcal{B} \wedge \text{isprime}(2 \cdot p \cdot \mathcal{A} \cdot \mathcal{B} + 1) = \text{true}
```

そして$\mathcal{C} := \mathcal2 \cdot p \cdot \mathcal{A} \cdot \mathcal{B} + 1$とします。$\mathcal{C}$から家系情報を取り出す場合は、$\frac{\mathcal{C} - 1}{2}$を素因数分解します。この操作を繰り返すことで、家系情報を取り出すことができます。

## 新しいマイ・マイナンバーの例

上記の新しいマイ・マイナンバーの計算をPythonで実装すると次のようになります。

```py:my_number.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys
import random
import sympy

if __name__ == "__main__":
    try:
        mother = int(sys.argv[1])
        father = int(sys.argv[2])
        env    = [] if len(sys.argv) <= 3 else map(int, sys.argv[3].split(","))
    except Exception:
        print "usage: python my_number.py {mother's number} {father's number} {env}"
        sys.exit(0)
    
    print "mother: %s, father: %s, env: %s" % (mother, father, env)

    p = sympy.nextprime(max(mother, father))
    my_number = 0
    while True:
        my_number = 2 * mother * father * p + 1
        if p not in env and sympy.isprime(my_number):
            break
        else:
            p = sympy.nextprime(p)

    print "prime: %s, number: %s" % (p, my_number)
```

これを用いて、たとえばマイ・マイナンバー$5$を持つアダムとマイ・マイナンバー$3$を持つイブの子どもであるアリスのマイ・マイナンバーは次のようになります。

```console
$ python my_number.py 3 5
mother: 3, father: 5, env: []
prime: 7, number: 211
```

つまり、アリスのマイ・マイナンバーは$211$となります。アリスの兄弟にボブがいるとしたとき、次のように計算します。ただし、素数$7$はアリスに発行済みであることを示すため第3引数を渡します。

```console
$ python my_number.py 3 5 7
mother: 3, father: 5, env: [7]
prime: 11, number: 331
```

つまりボブのマイ・マイナンバーは$331$となります。

### 親等数の計算

2人の親等数が1の場合、少なくとも片方の親が共通します。マイ・マイナンバー$\mathcal{N}, \mathcal{M}$について兄弟かどうかを判定するには、$\frac{\mathcal{N} - 1}{2}, \frac{\mathcal{M} - 1}{2}$を素因数分解し、もし素因数に共通の数字があれば親等数が1であると判定できます。

# まとめ

このようなマイ・マイナンバーを導入することで、従来のマイナンバーと氏名にあった問題を解決しました。ただ、エンコーディングについてはさらなる改良ができそうなので、より圧縮できるエンコーディングの開発を今後の課題としたいと思います。

# 参考文献

- [マイ・マイナンバーで氏名という概念を破壊する（WORD 39号）](https://www.word-ac.net/post/2016/0705-word39/)