Vivadoで自作IPコアのソースを暗号化して秘匿することのススメ

# はじめに
自分で作ったFPGAのデザインは公開したいけれども、秘密にしたいソースもある。
そんな場合にどうしたらよいでしょうか。

- EDIFネットリストを作る
- ISEでNGCのネットリストを作る
- DCPを作る

いろいろな方法があるかと思いますが、どれもいまいちです。
今更ISEを持ち出すのも嫌だし、DCPを作るにはおそらく非プロジェクトモードでVivadoを操るという難易度の高いことをしなければなりません。そもそもネットリストだとソースをコンパイルした後なので、ラッパを作ったりしなければならないし、パラメタライズも完全ではありません。

それから、お金を払ってくれたお客様には特別版の機能を提供したいというときに、**秘密にしておいたGeneric文に値を設定すると、眠っているコアが動き出す**とか・・。

そういったことをするオススメの方法は、**暗号化VHDL**を作ることです。

詳しいやり方は[VivadoでIEEE-1735によるソースコード暗号化](http://nahitafu.cocolog-nifty.com/nahitafu/2018/07/vivadoieee-1735.html)に書いたとおりの方法なのですが、実際にやってみてうまく動いたので、今のやり方を紹介します。
# 準備
私のVivadoは2018.3ですが、このやり方はその後も変わらないでしょう。
## ライセンスの取得
まず、XILINXのサポートに連絡してIEEE-1735という暗号化ライセンスをもらいます。サブスクリプションとかせずに無料でもらえます。

ライセンスが送られてきたらVivado License Managerで登録します。
EncryptedWriter_v2というのが使えるようになっているのがわかります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542455/e4f7e830-3ce8-b1cb-719f-004900026682.png)

## keyファイルの作成
以下のkeyファイルを作成し、適当なフォルダに置きます。

```keyfile.txt:
`protect version = 2
`protect encrypt_agent = "XILINX"
`protect encrypt_agent_info = "Xilinx Encryption Tool 2017"
`protect begin_commonblock
`protect control error_handling = "delegated"
`protect control runtime_visibility = "delegated"
`protect control child_visibility = "delegated"
`protect control decryption=(activity==simulation) ? "false" : "true"
`protect end_commonblock
`protect begin_toolblock
`protect rights_digest_method="sha256"
`protect key_keyowner = "Xilinx", key_keyname= "xilinxt_2017_05", key_method = "rsa", key_public_key
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxngMPQrDv/s/Rz/ED4Ri
j3tGzeObw/Topab4sl+WDRl/up6SWpAfcgdqb2jvLontfkiQS2xnGoq/Ye0JJEp2
h0NYydCB5GtcEBEe+2n5YJxgiHJ5fGaPguuM6pMX2GcBfKpp3dg8hA/KVTGwvX6a
L4ThrFgEyCSRe2zVd4DpayOre1LZlFVO8X207BNIJD29reTGSFzj5fbVsHSyRpPl
kmOpFQiXMjqOtYFAwI9LyVEJpfx2B6GxwA+5zrGC/ZptmaTTj1a3Z815q1GUZu1A
dpBK2uY9B4wXer6M8yKeqGX0uxDAOW1zh7tvzBysCJoWkZD39OJJWaoaddvhq6HU
MwIDAQAB
`protect control xilinx_configuration_visible = "false"
`protect control xilinx_enable_modification = "false"
`protect control xilinx_enable_probing = "false"
`protect control xilinx_enable_netlist_export = "false"
`protect control xilinx_enable_bitstream = "true"
`protect control decryption=(xilinx_activity==simulation) ? "false" : "true"
`protect end_toolblock = ""
```
真ん中にあるMIIB～AQABのぐちゃっとした文字列は、Vivadoをインストールしたディレクトリの\data\pubkeyにあるxilinxt_2017_05_active.vhdの中身そのものです。公開鍵ってやつです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542455/152ee13b-04be-8e5b-8c90-d7969051a23a.png)

上のtrueとかfalseをいじると、秘密にする度合いを変えられます。

- xilinx_configuration_visible・・・VivadoビューワーでLUT値を表示できるかどうかを設定します。
- xilinx_enable_modification・・・Vivadoツールで、保護領域内の情報を変更できるかどうかを設定します。
- xilinx_enable_probing・・・Vivadoデバッグプローブを保護領域内に挿入できるかどうかを設定します。
- xilinx_enable_netlist_export・・・保護領域のネットリストをエクスポートできるかどうかを指定します。
- xilinx_enable_bitstream・・・Vivadoでビットストリームを生成できるようにします。

## いざ、暗号化
Vivadoで以下のtclスクリプトを走らせると暗号化が行われます。
```encrypt -key <キーファイルのパス> -ext .vhdp -lang vhd <暗号化したいファイル名>.vhd```

これで、<ファイル>*.vhdから<ファイル名>.vhdが作られるのですが、普通、IPコアのプロジェクトには複数のファイルがあるので、全部のファイルに対してこれを行って、たくさんの暗号化ファイルが作られるのは管理上よくありません。

### 結合してから暗号化しよう
以下の例では、*adcblock*という名前のIPコアを暗号化したいとします。
全ソースは/adcblock/srcに入っているとします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542455/2651b686-a327-27ac-3cab-5031c086f4f8.png)
これを効率よく暗号化するTCLスクリプトは、

```encrypt.tcl
cd D:/<プロジェクトのフォルダ>/ip_repo/<IPコア名>/src
file delete adcblock_all.vhd
exec $env(COMSPEC) /c copy *.vhd adcblock_all.vhd
encrypt -key ../../keyfile.txt -ext .vhdp -lang vhd adcblock_all.vhd
file delete adcblock_all.vhd
```
暗号化は一瞬で終わります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542455/3a9f7d35-bc74-6648-058d-7ab952318f6a.png)

フォルダやファイル名はプロジェクトに合わせて適当に修正してください。
このスクリプトをVivadoのTCLコンソールから実行してもよいですが、ファイルにしてしまって、
```source <スクリプトへのパス>/encrypt.tcl```
で起動してもよいでしょう。

### TCLの解説
ちょっと解説すると、最初のcdでソースファイルのあるディレクトリに移動し、そのディレクトリにあるすべてのvhdファイルを結合して、adcblock_all.vhdというファイルを作っています。
ファイルの結合はMS-DOSのCOPYコマンドを使うのですが、COPYコマンドはEXEファイルではなくCMD.EXEの機能なので、TCLの外部コマンド起動であるexecコマンドを使ってCMD.EXEを起動しなければならなりません。
```exec $env(COMSPEC) /c copy```
というのはそういう意味です。
copyで全部のVHDを連結して一つのadcblock_all.vhdというファイルにしています。

そして、これをencryptコマンドで暗号化し、暗号化が終わったら消去します。暗号化の前にもadcblock_all.vhdがあるといけないので、前にも消します。

暗号化してsrcフォルダの中にある平文のVHDLファイルがadcblock_allになりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542455/bd8903da-8a15-e14a-328d-889197e53e14.png)
このファイルの中身は、

```adcblock_all.vhdlp:
`protect begin_protected
`protect version = 2
`protect encrypt_agent = "XILINX"
`protect encrypt_agent_info = "Xilinx Encryption Tool 2015"
`protect begin_commonblock
`protect control error_handling = "delegated"
`protect control runtime_visibility = "delegated"
`protect control child_visibility = "delegated"
`protect control decryption=(activity==simulation) ? "false" : "true"
`protect end_commonblock
`protect begin_toolblock
`protect rights_digest_method="sha256"
`protect key_keyowner = "Xilinx", key_keyname= "xilinxt_2017_05", key_method = "rsa", key_block
RQcl0RqDWSgIc/if+S7UG9VkbuTSinRb/ZyMwp/Ql6JvqMhBpsQO9NmyvvnlESUIETIpiFW1Fd4I
qj3WxAhpKLFKdMMjf3p+VirpK+lZUqBI59RBohdvY9ZmLzVWCoSJ6OZG0JQe28viL/+ID7cRRe/7
r1cFTKffv+R/vuiYe+mZZZK9uhstfjVZdSrTkX5Q6Kv4MyGF8UP91CKnkR5C4RXV8J6ZmwypZd56
eRPT7IsPUqStNPXtjDQIHYqQWar2PteqY85lGJWM/DZx9ay9g115BpHEh2wtSm9H3GitpGbq6PxB
1RFGYPAoNTUxw9FdNokPphvgtvBQK6ql2p4RcQ==

`protect control xilinx_configuration_visible = "false"
`protect control xilinx_enable_modification = "false"
`protect control xilinx_enable_probing = "false"
`protect control xilinx_enable_netlist_export = "false"
`protect control xilinx_enable_bitstream = "true"
`protect control decryption=(xilinx_activity==simulation) ? "false" : "true"
`protect end_toolblock="FyG2o1sxRN0bUcoH9FvnBoZfAAn2rNnSlrSuWbGmhdA="
`protect data_method = "AES128-CBC"
`protect encoding = (enctype = "BASE64", line_length = 76, bytes = 182336)
`protect data_block
qG7sXwG4OIDfArPOLjiP6FkK6hbiV6k0RpFoPxv/KHPcea/2EfGSaFJ6g9Zu9u1qOy5uuQCjCapz
MDLgwaqZSJmUdXxL3X2i1+pGscFrJQFOUIGfq/1y1CS6VrksNHIdAzcS+ZJE/zsh2QIVWrxFzNED
m9rG75jpeKRZdNb31OcrxCigUeoGdlutifvXLE4d8vdQ+OICpNLzHACMlGWmIKPxu4ZpiIEk3qVH
W2Nqs8jGY9AL6RL3jEZ9BGdmYED1coII8ImM20K0zOaGCBmYBnzuvPZ0vD7bC9WeozeUqwFrXvww
vOKY3OH0pUpBo40yA9ze5JJzdshKFlSfU01O2RxsnOdx8q+XM0F7CBpJdQSOz9IEFPABXNXcM3rp
A3kxbme4O6fTAd30UTZM7EV1giD8eu1hChJ+/Bkt1O+Ct6n1WXo1qJhoyVxZexqb33grrxFTb774
dzwKZ7QD/jrJBuT6hUqSqcXd0zX+4qJu+RUszJIhFHSbgMCmOmV8/ogDvgq7FAwCu0nGtjw5/SZY
Ei6dDA3VP+b0NhazBtoz0ovyuDkTTGIv3s/KxGUcB1cdplUMVCzK5m8lTjyiIphNwaYCDYTpVldw
60vmPb+52Y5V02xBgiklsw6Pgr1kxwjta9xeLmW7DNz7iM9v587kTh7EZJuzNgJsFIrq72zxWP/E
8jnt4qxrYEvxwCUqK9qbnB3+EQeNTP9jKPcF3nNJ2o2fOsyQ/hUO15PpfzyaVO5bDf8ameQ8wfIJ
83IKMbhCGUCmNZKpBC6VDODl+iPeFfvmqil9bY4g4/xUqEOCKbfl2noYNryxBdlcz51pccoz8CZZ
z+ZDY4GkkQqlKvOWZ8FrR51q3NlOAB7oNH95rXjR/Vl/pkYaiICqYsEkjlWPeqSq9BxHB8EF65rZ
・・・
```
と人間が読めない形になりました。
Vivadoはこれを解読するための秘密鍵を内部にもっているのでデコードできるのでしょう。

## IP Packagerでの操作
Vivadoで子IPをEdit in IP Packagerで開いたら、既存のVHDLソースを全部、プロジェクトから外します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542455/eaf46678-4c64-b2c6-fae8-7ad0c6961678.png)

File GroupsからもソースをすべてRemoveします。XILINXが作ったIP(FIFOやBRAM、SelectIOなど)を含んでいる場合は、それらは削除しません。あくまでも削除するのは自分で作ったvhdlのソースのみです。xci以外を選んでremoveです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542455/9bfd2099-dc6b-0369-6405-c8434a040a50.png)

xciなどのXILINXコアのみを残します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542455/7296df80-bddb-6618-ff03-4a4704839661.png)

これで、平文のソースは一切、プロジェクトから参照されなくなりました。

次に、**＋**ボタンを押して先ほどのvhdlpを追加するのですが、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542455/e4769742-d977-e149-d46c-b8015aa4be70.png)
**Copy sources into IP Directory**のチェックは外します。

Sourcesのツリーにはモジュールの名前や階層構造が見えていますが、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542455/a9bbf3be-4ce0-5b26-81ff-89c877431d14.png)

ダブルクリックして開こうとしても、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542455/63972b09-df7f-905c-4d4d-8dc665126bf7.png)
と警告が出て開くことはできません。
Vivadoには解読できるけれどもユーザには見せないということができました。

## 暗号化版と平文版の切り替え
自分で開発するときには平文にして、リリース時には暗号化版にしたいということがあると思います。
私はgitでブランチを分けることにしましたが、どうでしょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542455/9a0da8c7-3848-a62c-373a-f32d8880ba0f.png)

# まとめ
VivadoでIPのVHDLソースをIEEE-1735で暗号化することによって、

- 秘密にすべきコードは秘密にしながら
- パラメータをダイアログでカスタマイズ可能にして
- ユーザ回路を自由に追加する
- 正規ユーザ(課金ユーザ)だけが使える秘密の機能を用意する

ということができるようになります。
この方法は、ライセンスファイルを取得するのが敷居が高く感じるかもしれませんが、google翻訳を使いながらライセンスが欲しい旨をサポートにメールで書けばもらえます。サブスクリプションとか不要ですべて無料でできるのでオススメですよ。

ぜひ皆さんも、知的財産の詰まったコアな部分は暗号化して、いろいろリリースしてみてください。