#cards #playing #entropy #rng #derive #signing-key

cardseed

使用PBKDF2从扑克牌生成伪随机数

2个版本

0.0.2 2023年9月8日
0.0.1 2023年9月8日

#1071加密学

Unlicense

23KB
477

cardseed

cardseed crate提供解析和序列化扑克牌的功能。

在加密环境中,扑克牌可以用来编码和生成熵。一副随机洗好的52张扑克牌可以编码$52! \approx 2^{228}$种不同的组合。cardseed crate可以轻松地将现实世界中洗好的牌解析和转换为安全的伪随机数据,这些数据可以用来派生加密或签名密钥、随机数生成器的种子或其他类似的操作。

use cardseed::Deck;
use std::error::Error;

fn main() -> Result<(), Box<dyn Error>> {
    let deck = "AS 3H KC 3C".parse::<Deck>()?;
    let secret = deck.hash(Some("bestpasswordever"))?;
    let expected = [35, 20, 205, 7, 35, 104, 123, 150, 57, 148, 101,
                    109, 151, 0, 87, 15, 103, 14, 67, 214, 165, 165,
                    44, 218, 5, 232, 30, 26, 100, 90, 169, 244];
    assert_eq!(secret, expected);
    Ok(())
}

扑克牌

扑克牌由两个字段组成:一个value和一个suit。value字段是一个u32,对应于牌的面值减1(因为我们从零开始计数)。suit字段是一个cardseed::Suit枚举成员,对应于四种扑克牌花色之一。

序列化时,Card表示为包含两个字符的字符串。第一个字符代表牌的面值,第二个字符代表花色。例如,"7H"代表红桃7。

面值

字符
A Ace 0
2 2 1
3 3 2
4 4 3
5 5 4
6 6 5
7 7 6
8 8 7
9 9 8
T Ten 9
J Jack 10
Q Queen 11
K King 12

花色

字符 花色
S Spades 0
C Clubs 1
H Hearts 2
D Diamonds 3

任何标准牌组的牌都可以唯一地表示为从0到51的任何u32。通过将suit字段值乘以13,然后加上牌的value字段。

use cardseed::{Card, Suit};

let card = Card {
    suit: Suit::Clubs,
    value: 4,
};
assert_eq!(u32::from(card), 17);

例如,牌"TD"(红桃10),可以表示为整数$(3 \cdot 13) + 9 = 48$。

牌组

Deck是一个任意数量牌的向量。Deck可以序列化和解析为序列化的Card字符串,每个Card字符串由空白字符分隔。

use cardseed::{Deck, Card, Suit};
use std::vec::Vec;

let deck = Deck {
    cards: vec![
        Card {
            suit: Suit::Clubs,
            value: 10,
        },
        Card {
            suit: Suit::Hearts,
            value: 12,
        },
        Card {
            suit: Suit::Diamonds,
            value: 1,
        },
    ],
};

let deck_str = format!("{}", deck);
assert_eq!(deck_str, "JC KH 2D");

let parsed_deck = match deck_str.parse::<Deck>() {
    Ok(deck) => deck,
    Err(e) => panic!("failed to parse deck: {}", e),
};
assert_eq!(parsed_deck, deck);

依赖项

~1MB
~16K SLoC