/*
*******************************************************************************
\file stack.h
\brief Controlled stack 
\project bee2 [cryptographic library]
\created 2012.05.10
\version 2025.08.09
\copyright The Bee2 authors
\license Licensed under the Apache License, Version 2.0 (see LICENSE.txt).
*******************************************************************************
*/

/*!
*******************************************************************************
\file stack.h
\brief Контролируемый стек
*******************************************************************************
*/

#ifndef __BEE2_STACK_H
#define __BEE2_STACK_H

#ifdef __cplusplus
extern "C" {
#endif

/*!
*******************************************************************************
\file stack.h

Локальные переменные функций могут размещаться в контролируемом стеке --
области памяти, указатель на которую передается как дополнительный
параметр функции.

Контролируемый стек создается в высокоуровневой функции, передается по
цепочке в низкоуровневые функции, очищается и разрушается при завершении
высокоуровневой функции.

Низкоуровневые функции могут не заботиться об утечке данных через
контролируемый стек и размещать в этом стеке критические объекты.

Низкоуровневые функции могут размещать критические объекты не только
в контролируемом стеке, но еще в переменных, объявленных с ключевым
словом register. При завершении низкоуровневой функции такие переменные
должны быть обнулены.

Значения критических переменных могут определяться через возвращаемые
функциями значения (как правило, значения возвращаются через регистр).

Критические переменные не должны передаваться через обычный стек как
параметры функций.

Для корректной работы функций библиотеки на разных аппаратных платформах
указатели на объекты, размещенные в контролируемом стеке, должны быть
выровнены на границу фундаментального блока (см. mem.h). Для этого следует
строить функции по следующей схеме:
1. [Предусловие функции] Указатель stack на контролируемый стек обязательно
   выровнен на границу фундаментального блока:
   \code
   ASSERT(memIsAligned(stack, sizeof(mem_align_t)));
   \endcode
2. [Разметка стека в функции] Фрагменты памяти для объектов стека выделяются
   с помощью функций memSlice() или memSlice2(). Эти функции гарантируют
   выравнивание фрагментов на границу фундаментального блока.
3. [Смещение границы стека] Последним фрагментом памяти при разметке stack
   может быть стек для подчиненных функций. Указатель на этот фрагмент можно
   получать по адресу &stack, смещая тем самым границу стека.

Пример работы с контролируемым стеком и критической переменной:
\code
	void f2(octet a[], size_t n, octet b[], size_t m, void* stack)
	{
		register word sensitive;
		octet* var1; // [n]
		word* var2;  // [m]
		memSlice(stack,
			n, O_OF_W(m), SIZE_0, SIZE_MAX,
			&var1, &var2, &stack);
		...
		sensitive = f1(var1, 2 * n, stack);
		...
		sensitive = 0;
	}
\endcode

В этом примере функция memSlice2() размечает контролируемый стек stack:
- выделяет в стеке переменные var1 и var2;
- смещает stack, делая его указателем на стек подчиненной функции f1.
.
После разметки выравнивание stack на границу фундаментального блока
сохраняется.

Определение функции f, которая использует контролируемый стек, должно
сопровождаться определением функции f_deep, которая определяет
максимальную глубину стека f. Функция f_deep берет на вход произвольное
число аргументов типа size_t (размерностей) или других типов и возвращает 
глубину стека в октетах.

Пример (продолжение предыдущего):
\code
	size_t f2_deep(size_t n, size_t m)
	{
		return memSliceSize(
			n, O_OF_W(m), f1_deep(n), SIZE_MAX);
	}
\endcode

Значение f_deep не должно уменьшаться при увеличении любого ее аргумента.

В описании функции f, использующей вспомогательный стек, должен быть
описаны параметры f_deep (схема расчета глубины стека).
Схему рекомендуется описывать следующим образом:
\code
	f_deep(		// функция
		dim1,	// первая размерность
		dim2,	// вторая размерность
		...
		dimX	// последняя размерность
	);
\endcode
Например, f1_deep(n), f2_deep2(n, m), f3_deep().

Локальные переменные, размещаемые в контролируемом стеке, могут использоваться
не в одной, а в нескольких функциях. Эти функции образуют, так называемую, 
\e связку. Общие локальные переменные функций связки образуют \e состояние.
Указатель на состояние передается как дополнительный параметр функций связки.
Определение связки g должно сопровождаться функцией g_keep, которая возвращает
\e захват стека -- длину состояния в октетах. Функции типа _keep имеют такой 
же интерфейс, как и функции типа _deep.

Состояние функции связки и ее стек могут размещаться в одном буфере памяти. 
Тем не менее, указатель на состояние (state) рекомендуется отделять от 
указателя на стек (stack). Тогда высокоуровневые функции могут более точно 
рассчитывать суммарный объем контролируемого стека (состояния различных 
связок надо поддерживать неизменными, а стек -- не обязательно).

Для стандартизированного оформления описаний в doxygen предусмотрены 
окружения \\deep, \\deep{stack}, \\keep, \\keep{state}.
*******************************************************************************
*/

#ifdef __cplusplus
} /* extern "C" */
#endif

#endif /* __BEE2_STACK_H */
