質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.34%

C言語のrand関数は、同じ値が返されることが保証されていますか?

解決済

回答 4

投稿

  • 評価
  • クリップ 0
  • VIEW 2,191

dkyukinaga

score 17

お世話になります。私の拙い文章に目を通していただければ幸いに存じます。

以下のようなプログラムを走らせると、同じシードを設定した場合、シードを設定してからの呼び出し回数に応じて、rand関数は同じ値を返すようであることがわかります。この挙動を利用すれば、暗号化(例えば暗号化したいデータに対して1バイトずつrandの結果を加算していき、復号化の時は暗号化の時と同じシードを設定して、1バイトずつrandの結果を除算していくなど)なんかも実現できそうです。しかし、そこで疑問に思ったのですが、この同じシードが設定されれば同じ値を返すという挙動は仕様書なんかで保証されているのでしょうか?保証されてないのに、「どうやらそういう挙動らしい」で暗号化なんかを実装するのはやはり危険でしょうか?

#include <stdio.h>
#include <stdlib.h>

void showRand()
{
    srand(0u);
    for (int i = 0; i < 10; ++i) {
        printf("%d ", rand());
    }
    printf("\n");
}

int main()
{
    showRand();
    showRand();
    showRand();
    system("pause");
}

実行結果

38 7719 21238 2437 8855 11797 8365 32285 10450 30612
38 7719 21238 2437 8855 11797 8365 32285 10450 30612
38 7719 21238 2437 8855 11797 8365 32285 10450 30612
続行するには何かキーを押してください . . .

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 4

checkベストアンサー

+3

こんにちは。

n1570(C言語の規格書に近いもの)によると下記のように記載されてます。

If srand is then called with the same seed value, the sequence of pseudo-random numbers shall be repeated.

同じシードを与えたら、同じ擬似乱数のシーケンスを繰り返すとは記載されてますが、それだけです。
リビルドした時さえ特に言及されてないので、リビルド前とリビルド後で同じシードに対して異なるシーケンスを返却しても規格には合致していると解釈した方が良いと思います。
実際には、リビルドだけなら同じシーケンスが返却すれるとは思いますが、異なるコンパイラ間で保証されるとはとても思えませんし、バージョンアップで変更されても文句は言えないように思います。

そのような使い方であれば、ご自身で乱数を実装すれば簡単な暗号化には使えるように思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/05/07 23:43 編集

    リビルドはともかく、コンパイラのバージョンアップで結果が変わってしまうということはあり得るかもしれませんね。復号できなくなってしまうと厄介なので、rand()を使っての(簡単な)暗号化は少し考えものです。

    ご回答、誠にありがとうございました。

    raccyさんもYsManaさんもcarbonさんも、ご回答誠にありがとうございました。

    キャンセル

  • 2016/05/08 00:38

    追記:
    > ご自身で乱数を実装すれば

    初めは、そんな無茶な・・・と思って、流してしまっていましたが、調べてみると疑似乱数を実装するだけなら拍子抜けするほど簡単なんですね(アルゴリズムを自分で作り出すことは僕には出来そうもないですが)

    http://d.hatena.ne.jp/pashango_p/20090717/1247848900

    万が一、バージョンアップ等でrand()の中身が変わると嫌なので、自分で実装した疑似乱数を使ってみることにします。

    キャンセル

+1

rand()関数の実装は環境依存です。全く同じOS(バージョン含む)、全く同じコンパイラ(バージョン含む)、全く同じコンパイルオプション、全く同じアーキテクチャ(32bitや64bitとか)、全く同じ標準ライブラリ(glibcとかの)であれば、同じ環境になっているため、同じシードであれば同じ結果になります。逆にいうと、OSやコンパイラ等が違っていれば異なる場合があります。実際にMacのclangでコンパイルした場合とLinuxのgccでは違うようです。なので、どのような環境であっても同じであるという前提をしてはいけません。

C標準のrand()ではなくメルセンヌ・ツイスタ等の外部ライブラリを使用した場合はそのライブラリが環境依存では無いと同じ結果になります。また、C++ではmt19937など環境依存では無い乱数もあります。

次に、rand()の乱数をそのまま暗号化の処理には使用してはいけません。ほとんどのrand()の実装では次の値が容易に予想可能であり、規則性もあるため、ある程度の暗号文から簡単に予測できてしまい、誰でも容易に復号できてしまう可能性が高いです。AESなどの暗号化処理は、こういった予測が数学的に極めて困難であるという特性をもつ処理を含んでおり、そのような特性が無い物を暗号化に用いると脆弱なシステムになってしまいます。

安全な暗号を作るには極めて高度な計算科学及び数学的知識が必要であり、知識無く新しい暗号化の仕組みを作るのは極めて危険です。思いつきで作った物を実際に使うことは推奨できかねます。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/05/07 23:35

    思い付きの暗号化への警鐘ありがとうございます。やはり暗号化というと、極めて高度な計算科学及び数学的知識の世界になってしまうわけですね(汗) 逆アセンブルが少しでも面倒になるくらいの簡単な暗号化と割り切って実装しようと思います^^;

    ご回答、誠にありがとうございました!

    キャンセル

+1

srandで同じseedを設定すれば、randが同じ乱数列を返すことは保証されています。
ただし、randには移植性がないのでコンパイラが変わると結果が変わることはあり得ます。

乱数列とxorを取るなどした暗号化は可能でしょう。
ただし、暗号に使うことを考慮していない疑似乱数を使った暗号化は
非常に脆弱なものになるということは意識しておいてください。
(使うなら実験や遊びまでにしておきましょう。)

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

randので出てくるような乱数を擬似乱数をと言いますがsrandで同一の値を入れれば全く同じ結果が得られます。なので、確かに暗号化に利用できなくはないのですが、randの場合はかなり簡単に次の値が予測できるので暗号には向かないようです。
ですが、randを使った(randでも可能な)新しい暗号化手法を考えれば、かなり実用的な暗号化方式になるので、面白いかもしれないですね。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.34%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る