Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Одноразовые значения

Иногда нужны значения, которые можно использовать только один раз. Один из важнейших примеров — криптография: «nonce» (одноразовое число).

// Copyright 2025 Google LLC
// SPDX-License-Identifier: Apache-2.0

pub struct Key(/* детали опущены */);

/// Одноразовое число, пригодное для криптографических целей.
pub struct Nonce(u32);

/// Криптографически стойкая функция генерации случайных чисел.
pub fn new_nonce() -> Nonce {
    Nonce(4) // выбрано честным броском кубика, https://xkcd.com/221/
}

/// Потребляет nonce, но не ключ и не данные.
pub fn encrypt(nonce: Nonce, key: &Key, data: &[u8]) {}

fn main() {
    let nonce = new_nonce();
    let data_1: [u8; 4] = [1, 2, 3, 4];
    let data_2: [u8; 4] = [4, 3, 2, 1];
    let key = Key(/* детали опущены */);

    // Ключ и данные можно повторно использовать, копировать и т. д., а nonce — нельзя.
    encrypt(nonce, &key, &data_1);
    // encrypt(nonce, &key, &data_2); // 🛠️❌
}
  • Проблема: как гарантировать, что значение будет использовано только один раз?

  • Мотивация: nonce — это случайные уникальные данные, которые используются в криптографических протоколах для защиты от атак повторного воспроизведения.

    Контекст: на практике люди случайно повторно использовали nonce. Чаще всего это приводит к полному краху криптографического протокола, и он перестаёт выполнять свою функцию.

    В зависимости от деталей повторного использования nonce и конкретной криптографии злоумышленники могут также вычислить закрытые ключи.

  • У Rust есть очевидный инструмент для обеспечения инварианта «после использования повторно воспользоваться нельзя»: передача значения как аргумента, переданного по значению.

  • Обратите внимание: функция encrypt принимает nonce по значению, а key и data — по ссылке.

  • Техника для значений одноразового использования такова:

    • Делайте конструкторы приватными, чтобы пользователь не мог создать два значения с одним и тем же внутренним значением.

    • Не реализуйте трейты Clone/Copy или эквивалентные методы, чтобы пользователь не мог дублировать данные, которые мы хотим сохранить уникальными.

    • Сделайте внутренний тип непрозрачным (как в паттерне newtype), чтобы пользователь не мог самостоятельно изменить существующее значение.

  • Спросите: чего не хватает в коде слайда для полноценного паттерна newtype?

    Ожидаемый ответ: граница модуля.

    Продемонстрируйте: без границы модуля пользователь может самостоятельно создать nonce.

    Исправление: поместите Key, Nonce и new_nonce внутрь модуля.

Для дальнейшего изучения

  • Нюанс криптографии: nonce всё же может быть использован дважды, если он был создан псевдослучайным процессом без настоящей случайности. Этот метод такое предотвратить не может. Данный дизайн API предотвращает дублирование nonce, но не все логические ошибки.