std.crypto.random — Geração Aleatória Criptograficamente Segura
O std.crypto.random fornece acesso a um gerador de números aleatórios criptograficamente seguro (CSPRNG). Ele utiliza a fonte de entropia do sistema operacional (getrandom no Linux, BCryptGenRandom no Windows, /dev/urandom em outros Unix) para produzir bytes imprevisíveis adequados para chaves criptográficas, tokens, nonces e qualquer cenário onde previsibilidade seria uma vulnerabilidade.
Visão Geral
const std = @import("std");
const random = std.crypto.random;
O std.crypto.random é uma instância global e thread-safe que pode ser usada diretamente sem inicialização.
Funções Principais
// Preenche um buffer com bytes aleatórios
pub fn bytes(buf: []u8) void
// Retorna um inteiro aleatório do tipo T
pub fn int(comptime T: type) T
// Retorna inteiro em range [at_least, at_most]
pub fn intRangeAtMost(comptime T: type, at_least: T, at_most: T) T
// Retorna inteiro em range [0, less_than)
pub fn intRangeLessThan(comptime T: type, less_than: T) T
// Retorna um float em [0.0, 1.0)
pub fn float(comptime T: type) T
// Embaralha os elementos de um slice
pub fn shuffle(comptime T: type, buf: []T) void
// Preenche com valor booleano aleatório
pub fn boolean() bool
// Usa a interface Random para compatibilidade
// std.crypto.random implementa std.Random
Exemplo 1: Geração de Tokens e Chaves
const std = @import("std");
const random = std.crypto.random;
fn gerarTokenHex(comptime n_bytes: usize) [n_bytes * 2]u8 {
var bytes_raw: [n_bytes]u8 = undefined;
random.bytes(&bytes_raw);
var hex: [n_bytes * 2]u8 = undefined;
const chars = "0123456789abcdef";
for (bytes_raw, 0..) |byte, i| {
hex[i * 2] = chars[byte >> 4];
hex[i * 2 + 1] = chars[byte & 0x0f];
}
return hex;
}
fn gerarSenha(buf: []u8) []u8 {
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%&*";
for (buf) |*c| {
const idx = random.intRangeLessThan(usize, charset.len);
c.* = charset[idx];
}
return buf;
}
pub fn main() !void {
const stdout = std.io.getStdOut().writer();
// Token de sessão (32 bytes = 256 bits)
const token = gerarTokenHex(32);
try stdout.print("Token de sessão: {s}\n", .{token});
// API key (16 bytes)
const api_key = gerarTokenHex(16);
try stdout.print("API Key: {s}\n", .{api_key});
// Senha aleatória
var buf_senha: [20]u8 = undefined;
const senha = gerarSenha(&buf_senha);
try stdout.print("Senha gerada: {s}\n", .{senha});
// UUID v4 (simplificado)
var uuid_bytes: [16]u8 = undefined;
random.bytes(&uuid_bytes);
uuid_bytes[6] = (uuid_bytes[6] & 0x0f) | 0x40; // versão 4
uuid_bytes[8] = (uuid_bytes[8] & 0x3f) | 0x80; // variante
try stdout.print("UUID v4: ", .{});
for (uuid_bytes, 0..) |b, i| {
if (i == 4 or i == 6 or i == 8 or i == 10) {
try stdout.writeByte('-');
}
try stdout.print("{x:0>2}", .{b});
}
try stdout.writeAll("\n");
}
Exemplo 2: Jogos e Simulações
const std = @import("std");
const random = std.crypto.random;
fn rolarDado(lados: u32) u32 {
return random.intRangeAtMost(u32, 1, lados);
}
fn sortearCartas(comptime n: usize) [n]u8 {
var baralho: [52]u8 = undefined;
for (&baralho, 0..) |*c, i| {
c.* = @intCast(i);
}
random.shuffle(u8, &baralho);
var mao: [n]u8 = undefined;
@memcpy(&mao, baralho[0..n]);
return mao;
}
fn nomeCarta(carta: u8) struct { naipe: []const u8, valor: []const u8 } {
const naipes = [_][]const u8{ "Espadas", "Copas", "Ouros", "Paus" };
const valores = [_][]const u8{
"A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K",
};
return .{
.naipe = naipes[carta / 13],
.valor = valores[carta % 13],
};
}
pub fn main() !void {
const stdout = std.io.getStdOut().writer();
// Rolagem de dados
try stdout.writeAll("=== Dados ===\n");
try stdout.writeAll("3d6: ");
var soma: u32 = 0;
for (0..3) |_| {
const dado = rolarDado(6);
soma += dado;
try stdout.print("{d} ", .{dado});
}
try stdout.print("= {d}\n", .{soma});
try stdout.print("1d20: {d}\n", .{rolarDado(20)});
// Cartas
try stdout.writeAll("\n=== Mão de Poker ===\n");
const mao = sortearCartas(5);
for (mao) |carta| {
const info = nomeCarta(carta);
try stdout.print(" {s} de {s}\n", .{ info.valor, info.naipe });
}
// Moeda
try stdout.writeAll("\n=== Moeda ===\n");
for (0..10) |_| {
const cara = random.boolean();
try stdout.print("{s} ", .{if (cara) "Cara" else "Coroa"});
}
try stdout.writeAll("\n");
}
Exemplo 3: Monte Carlo — Estimação de Pi
const std = @import("std");
const random = std.crypto.random;
pub fn main() !void {
const stdout = std.io.getStdOut().writer();
try stdout.writeAll("=== Estimação de Pi (Monte Carlo) ===\n\n");
const amostras_lista = [_]u64{ 1000, 10_000, 100_000, 1_000_000 };
for (amostras_lista) |n_amostras| {
var dentro: u64 = 0;
for (0..n_amostras) |_| {
const x = random.float(f64); // [0, 1)
const y = random.float(f64); // [0, 1)
// Verifica se o ponto está dentro do círculo unitário
if (x * x + y * y <= 1.0) {
dentro += 1;
}
}
const pi_estimado = 4.0 * @as(f64, @floatFromInt(dentro)) / @as(f64, @floatFromInt(n_amostras));
const erro = @abs(pi_estimado - std.math.pi);
try stdout.print(" n={d:>10}: pi ~ {d:.6} (erro: {d:.6})\n", .{
n_amostras, pi_estimado, erro,
});
}
try stdout.print("\n Pi real: {d:.6}\n", .{std.math.pi});
}
random vs std.Random
| Característica | std.crypto.random | std.Random (PRNG) |
|---|---|---|
| Segurança | Criptográfico | Pseudo-aleatório |
| Desempenho | Mais lento | Mais rápido |
| Reprodutível | Não | Sim (com seed) |
| Uso | Segurança, tokens | Jogos, simulações |
Para cenários onde velocidade importa mais que segurança (simulações, jogos), considere usar std.Random.DefaultPrng com uma seed inicial de std.crypto.random.
Módulos Relacionados
- std.crypto — Visão geral da criptografia
- std.crypto.hash — Funções de hash
- std.base64 — Codificação de tokens
- std.math — Funções matemáticas