\documentclass[11pt,a4paper]{article}

\usepackage{polyglossia}
\usepackage{xltxtra}
\usepackage[margin=2cm,a4paper]{geometry}% http://ctan.org/pkg/geometry
\usepackage{pdfpages}
\usepackage{graphicx}
\usepackage[ddmmyyyy]{datetime}
\usepackage{booktabs}
\usepackage{enumitem}
\usepackage{amssymb}
\usepackage{amsmath}
\usepackage{bm}
\usepackage[nomessages]{fp}
\usepackage{caption}
\usepackage{url}
\usepackage{indentfirst}
\usepackage[parfill]{parskip}
\usepackage[ colorlinks=true
           , linkcolor=black
		   , anchorcolor=black
		   , citecolor=black
		   , filecolor=black
		   , menucolor=black
		   , runcolor=black
		   , urlcolor=blue]{hyperref}
\usepackage{tikz}
\usetikzlibrary{arrows,arrows.meta,snakes,shapes,backgrounds,positioning,calc}
\usepackage{marvosym}
\usepackage{pifont}
\usepackage{fontspec}
\usepackage{fontawesome5}
\usepackage{listings}
\usepackage{verbatim}
\usepackage{xcolor}
\usepackage{float} % Needed for the floating environment
\usepackage{fancyvrb}
\usepackage[most]{tcolorbox}
\usepackage{authblk}
\usepackage{url}

\setmainlanguage{russian}
\defaultfontfeatures{Ligatures=TeX,Mapping=tex-text}
\setmainfont{Liberation Serif}
\newfontfamily\cyrillicfont{Liberation Serif}[Script=Cyrillic]
\newfontfamily{\cyrillicfonttt}{Liberation Mono}[Scale=0.8]

\setlist{noitemsep}
\setlength{\intextsep}{2cm}

\renewcommand\Authands{ и }
\renewcommand\Affilfont{\itshape\small} % Мелкий и курсивный шрифт для аффилиаций

\newtcolorbox{myverbatim}{colback=lightgray, colframe=lightgray, boxrule=0pt, arc=0pt,
                          top=0pt, bottom=0pt, left=0pt, right=0pt,
                          boxsep=5pt, leftupper=5pt, rightupper=5pt}


\newcommand{\term}[2]{\textit{#2}}
\renewcommand{\dateseparator}{.}
\renewcommand*\contentsname{Содержание}

\lstset{
  language=Haskell,
  basicstyle=\ttfamily\small,
  keywordstyle=\color{blue},
  commentstyle=\color{green},
  stringstyle=\color{red},
  % numberstyle=\tiny\color{gray},
  % numbers=left,
  % stepnumber=1,
  showstringspaces=false,
  breaklines=true,
  frame=single,
}

\newfloat{Code}{t}{myc}

\graphicspath{ {img/}}

\title{hbs2-git 0.24.1}

\author{%
    email: dzuikov@gmail.com | telegram: @voidlizard
}

\begin{document}

\maketitle

% \noindent % Убирает отступ слева для таблицы, чтобы она начиналась с края страницы
% \begin{tabular}{l l} % Две колонки выравнивания текста по левому краю
%   email:    & dzuikov@gmail.com \\
%   telegram: & @voidlizard \\
% \end{tabular}

\tableofcontents

\section{Идея}

hbs2-git это адаптер, позволяющий git работать с HBS2 в качестве бекенда для сохранения и получения
объектов. HBS2 это распределённый P2P CAS, позволяющий обмениваться данными, синхронизировать их,
подписываться на специфические источники при помощи механизма \term{references}{ссылок}.

Таким образом, hbs2-git позволяет производить децентрализованную синхронизацию репозиториев без
участия какого-то выделенного сервера/сервиса, используя вместо него множество пиров, которые
находят соседей при помощи механизма \term{pex}{PEX} (Peer Exchange) --- то есть при помощи
broadcast сообщений, DNS бутстрапа и списка известных пиров, то есть примерно  теми же способами,
что используются в прочих децентрализованных сетях.

Авторизация и аутентификация осуществляются при помощи криптографических механизмов: криптоподписи
и шифрования.

Механизмы эти работают на уровне ссылок, блоков, протоколов и можно еще дополнительно шифровать
собственный контент, если будет такое желание и необходимость.

\begin{description}
  \item[Ссылка] --- это некий уникальный идентификатор, указывающий на блок в \textit{хранилище} по
    его хэшу; Ссылки бывают локальные и те, которые распространяются по некоему протоколу. Примеры
    распространяемых ссылок и их протоколов: RefLog, LWWRef, RefChan.

  \item[Блок]   --- это данные в хранилище, имеющие хэш, которым этот блок и адресуется. Блок может
    содержать произвольные данные. Это могут быть сериализованные структуры данных, разбираемые
    hbs2, но не обязательно.
\end{description}


Вместо того, что бы делать $git~push$ в remote на каком-то сервере с доменным именем, доступом и
прочее, $git~push$ происходит в \term{references}{ссылку}, которая поддерживается всеми пирами,
которые согласны поддерживать эту ссылку.

Узел hbs2-peer может отправлять и получать транзакции обновления ссылок, а также получать журнал
транзакций как дерево Меркла.

Как было сказано выше, hbs2-git использует механизм \term{references}{ссылок} для своей работы.

Ссылка --- это идентификатор, часто связанный с публичным ключом шифрования, который может быть
любым хешируемым объектом. Она должна однозначно ассоциироваться с обновляющим её пользователем и
быть уникальной.

Одним из способов добиться уникальности является использование пары публичный
ключ/приватный ключ и публичного ключа в качестве идентификатора.

Владелец приватного ключа заинтересован в том, что бы его приватный ключ был уникален и известен
только ему и он изо всех сил старается эту уникальность поддерживать, в частности, использует
качественный генератор случайных чисел и никому свой приватный ключ не сообщает.

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

Ссылки могут быть разных типов.  Конкретно, hbs2-git использует ссылки двух видов:

\begin{description}
  \item[LWWRef] В терминах CRDT это Last~Write~Wins~Register, где некое значение
    ассоциировано с монотонно возрастающим счётчиком, и все участники (пиры) принимают
    то значение, у которого этот счётчик больше. См: lwwref, lww-cсылка.

  \item[RefLog] В терминах CRDT это G-Set или же Grow~Only~Set транзакций, где множество
    транзакций представлено деревом Меркла. Транзакции (в рамках RefLog) упорядочены строго
    по их хэшам. Содержимое транзакций может быть произвольно и определяется клиентским приложением.
    Наличие порядка, таким образом, приводит к тому, что всё множество может быть адресовано
    неким хэшем (дерева Меркла) и хэш этот одинаков для одинакового набора транзакций. Также:
    рефлог.
\end{description}

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

Например, допущениями для рефлогов и lww-ссылок является то, что они кому-то принадлежат,
и только этот кто-то может их изменять.

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

Технически это означает, что для lww-ссылок -- пирами будут приниматься только такие ссылки,
которые содержат подписанный владельцем приватного ключа блок и подпись валидна.

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

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

Механизм обновления lww-ссылки подразумевает, что каждый пир возьмёт то значение, у которого
больше счётчик и подпись для которого валидна.

Таким образом, если владелец lww-ссылки на разных пирах опубликует значение ссылки с одинаковым
счётчиком, но разным содержимым --- мы получим разные значения на разных пирах. Для того, что бы
значения всё же сходились -- в случае, если счётчик одинаков --- выбирается то значение, хэш
которого больше. Никакого другого смысла, кроме обеспечения лучшей сходимости, это не несёт.

Предполагается, что поскольку значение ссылки контролируется владельцем, владелец заинтересован
в том, что бы обеспечить однозначность значения этой ссылки. Если он по ошибке (например, с разных
хостов) опубликовал <<одновременно>> транзакции с одинаковым счётчиком, но разными значениями, то:

\begin{enumerate}
  \item В итоге всеми будет принято то значение, у которого хэш лексикографически больше;
  \item У владельца есть шанс устранить беспорядок, опубликовав <<правильное>> значение.
\end{enumerate}

Мы видим, что такая ссылка так себе подходит для обеспечения конкурентных обновлений чего-либо,
поэтому подразумеваем, что она будет использоваться для хранения некоей настроечной информации и
меняться относительно редко и осознанно, непосредственно владельцем. Кроме того, факт конкурентного
публикования ссылки с разных пиров означает, что владелец экспонировал свой приватный ключ много
раз, а не в одном месте в один момент времени. Значит, он небрежен и к нему есть вопросы --
например, можно не доверять такому владельцу (не принимать ссылок от него).

\section{Компоненты}


\begin{figure}[h!]
\centering
\begin{tikzpicture}[ every label/.style={font=\scriptsize},
                     every node/.style={font=\scriptsize},
                     handle/.style={ draw=black
                                   , circle
                                   , inner sep=2pt
                                   },
                     box/.style={ draw=black
                                , rounded corners,
                                , anchor=base
                                , font=\scriptsize
                                , minimum height=1.5cm
                                , text width=1.5cm
                                , align=center
                                },
                    db/.style={ cylinder
                              , draw
                              , fill=gray!10
                              , minimum height=1cm
                              , minimum width=1.5cm
                              , shape border rotate=90
                              , aspect=0.5
                              }
                   ]

  \node[box,minimum height=2cm] (peer) {hbs2-peer};

  \node[ box
       , minimum height=1cm
       , text width=6em
       , left=5cm of peer.north west
       , anchor = north east
       ] (git-remote-hbs2) {git-remote-hbs2};

  \node[ box
       , minimum height=1cm
       , text width=6em
       , below=1cm of git-remote-hbs2.south east, anchor = north east
       ] (git-hbs2) {git-hbs2};

  \node[ rectangle
       , draw
       , dashed
       , above = 2mm of git-remote-hbs2.north west
       , xshift = -2mm
       , text width=2.8cm
       , minimum height=3.6cm
       , anchor=north west] (tools) {};

  \node[box, minimum height=1cm, below=2cm of git-hbs2.south, anchor=north] (git) {git};

  \node[db,below=1.6cm of git.north,anchor=north] (repo) {git repo};

  \draw[->] (git.south) -- ($(repo.north) - (0,+2mm)$) ;

  \draw[->] (git.north) -- ($(tools.south west)!(git.north)!(tools.south east)$)
    node[midway,right] {CLI/PIPE};

  \node[ db
       , left=1cm of git-remote-hbs2.north west, anchor=north east
       , yshift=-1cm
       ] (state) {State};

  \draw[->] (git-remote-hbs2.west) -| ($(state.north) - (0,+2mm)$) ;
  \draw[->] (git-hbs2.west) -| (state.south);

  \node[handle,left=1cm of peer.west] (rpc) {};

  \draw[-] (peer.west) -- (rpc.east) node [midway,above] {RPC};

  \draw[->] ($(tools.north east)!(rpc)!(tools.south east)$) -- (rpc);


  \node[ db
       , below=1cm of peer.south
       ] (store) {Store};

  \draw[->] (peer.south) -- ($(store.north) - (0,+2mm)$) ;

  \node[ box
       , minimum height=1cm
       , below=1cm of store.south, anchor=north
       ] (hbs2) {hbs2};

  \draw[->] (hbs2) -- (store);

  \node[ box
       , left=1cm of hbs2.west, anchor=east
       , text width=2cm
       , minimum height=1cm
       ] (hbs2-keyman) {hbs2-keyman};


  \draw[-,thick] (tools.320) -| (hbs2-keyman.140) node[near end,right] {library};

  \node[ db
       , below=1cm of hbs2-keyman.south
       ] (keyman-state) {State};

  \draw[->] (hbs2-keyman) -- ($(keyman-state.north) - (0,+2mm)$);

\end{tikzpicture}
\end{figure}

\subsection*{git-remote-hbs2}

Исполняемый файл, git-remote-helper, хэлпер git для протокола hbs2://

\subsection*{git-hbs2}

Исполняемый файл, различные функции для работы с hbs2-git, например,
export для первоначальной  инициализации \textit{ссылки} и т.п.

\subsection*{git}

Процесс git

\subsection*{hbs2-keyman}

Индексатор ключей

\subsection*{hbs2}

Утилита для управления storage, ключами и прочим.

\subsection*{hbs2-git-subscribe}

Подписаться на обновления ссылки lwwref и reflog для репозитория
без импорта самого репозитория.

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

\subsection*{hbs2-peer}

Процесс hbs2-peer

\subsection*{Store}

Хранилище объектов HBS2 (меркл-деревья, блоки, ссылки, ...)



\section{Установка}

В настоящий момент hbs2-git доступен в виде исходных кодов или кэшированных
артефактов и пакета для пакетного менеджера nix.

В случае использования nix необходимо включить поддержку nix flakes и nix profile

\subsection{Установка при помощи nix profile}

\begin{verbatim}

nix profile install git+http://git.hbs2.net/BTThPdHKF8XnEq4m6wzbKHKA6geLFK4ydYhBXAqBdHSP \
      --substituters http://nix.hbs2.net:6000 \
      --trusted-public-keys git.hbs2.net-1:HYIYU3xWetj0NasmHrxsWQTVzQUjawOE8ejZAW2xUS4= \
\end{verbatim}

\subsection{Сборка при помощи cabal}

Проект представляет собой типичный проект для языка haskell и собирается системой сборки cabal.

В случае такой сборки зависимости придется установить самостоятельно, либо же использовать
прилагаемые файлы ( flake.nix ) для установки окружения и установки зависимостей.

Желательно использовать direnv

\begin{verbatim}
nix develop       # при наличии
cabal build all
make symlinks     # при желании, создаёт симлинки в каталоге ./bin
\end{verbatim}

\subsection{Сборка при помощи nix}

\begin{verbatim}
nix build
\end{verbatim}

\section{Использование}

\begin{enumerate}
  \item Настройка hbs2-peer
  \item Запуск hbs2-peer
  \item Работа с hbs2-git
\end{enumerate}

\subsection{hbs2-peer}

hbs2-git является клиентским приложением для hbs2-peer.
Соответственно, для функционирования необходимо запустить hbs2-peer командой

\begin{verbatim}
hbs2-peer run
\end{verbatim}

Конфигурационный файл по-умолчанию находится в \$XDGDIR/hbs2-peer/

\begin{verbatim}
$(HOME)/.config/hbs2-peer/config
\end{verbatim}

Конфиг по умолчанию будет создан самим hbs2-peer при первом запуске,
если разрешена запись в упомянутую локацию.

Минимальный конфиг:

\begin{verbatim}
$ cat ~/.config/hbs2-peer/config
;; hbs2-peer config file

;; порт для UDP
listen "0.0.0.0:7351"

;; порт для TCP
listen-tcp "0.0.0.0:10351"

; default storage is $HOME/.local/share/hbs2
; storage "./storage"

; edit path to a keyring file
; key    "./key"

; это секретный ключ, и путь относительно конфига
key "./default.key"

; очищать очередь блоков на скачивание при рестарте
; рекомендуется: on
; downloads-del-on-start on

; принимать анонсы блоков
;
; * -- от всех
; от конкретного пира:
; accept-block-announce "PEER-KEY"
;
; рекомедуется включать для конкретных известных пиров
; accept-block-announce *

; поллить ссылки
; poll reflog 5 "BTThPdHKF8XnEq4m6wzbKHKA6geLFK4ydYhBXAqBdHSP"
; poll lwwref 5 "BTThPdHKF8XnEq4m6wzbKHKA6geLFK4ydYhBXAqBdHSP"
; poll refchan 10 ...


; запретить общаться с указанным пиром
; blacklist "5tZfGUoQ79EzFUvyyY5Wh1LzN2oaqhrn9kPnfk6ByHpf"

; порт для http
; рекомендовано: включить
http-port 5000

; логгирование
; trace off
; trace on

; trace1 off
; trace1 on

; debug on
; debug off

; сокет для RPC
; рекомендуется: не трогать
; rpc unix "/tmp/hbs2-rpc.socket"

\end{verbatim}

\subsection{hbs2-git}

\subsubsection{Введение}

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

Таким образом, у каждого участника проекта --- собственный форк
репозитория, куда он пишет.

Каждый участник уведомляет других участников о наличии форка,
они добавляют (или нет) его репозиторий (ссылку) к себе в проект
в качестве \textit{git remote}.

\paragraph{PR}

В git есть собственный механизм pull requests --- \texttt{git-request-pull}.

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

hbs2-git не предлагает никаких собственных механизмов для PR, однако
существует средство fixme

\texttt{hbs2://Fujv1Uy4W5d9Z7REEArMxbXSJ8nLLn4dYuvaAs8b86hr}

которое реализует механизм тикетов и PR с хранением информации непосредственно
в коде проекта, вернее, в объектах git.

Может быть использован и любой другой распределенный трекер.

\subsubsection{Инициализация репозитория}

\paragraph{Создание ключа подписи}

\begin{verbatim}

# сделать конфиг для hbs2-keyman
$ mkdir -p  ~/.config/hbs2-keyman

# сказать hbs2-keyman, где искать ключи
$ cat > ~/.config/hbs2-keyman/config
key-files "/home/hbs2/*.key"
^D

# сделать новый ключ
$ hbs2 keyring-new > newrepo111.key

# обновить индекс
$ hbs2-keyman update

# проверить, что ключ есть
$ hbs2-keyman list
8vFu9S79ysdWag4wek53YWXbC5nCRLF7arGp6181G4js       sign       /home/hbs2/newrepo111.key

\end{verbatim}

Созданный \texttt{newrepo111.key} является \textbf{секретом}, необходимо обеспечить его надежное
хранение без попадания в третьи руки.

\paragraph{Инициализация нового репозитория}

\begin{verbatim}

mkdir newrepo111

cd newrepo111/

git init

echo HI >  README

git add README

git commit -a m 'init'

# инициализировать новый репозиторий

git hbs2 export --new --public 8vFu9S79ysdWag4wek53YWXbC5nCRLF7arGp6181G4js

# добавить его как git remote
git remote add origin hbs21://8vFu9S79ysdWag4wek53YWXbC5nCRLF7arGp6181G4js

git fetch origin

[user@host:~/newrepo111]$ git fetch origin
From hbs21://8vFu9S79ysdWag4wek53YWXbC5nCRLF7arGp6181G4js
 * [new branch]      master     -> origin/master

# дальше работать с remote, как обычно

\end{verbatim}

\subsubsection{Клонировать (чужой) репозиторий}

\begin{verbatim}
git clone hbs2://8vFu9S79ysdWag4wek53YWXbC5nCRLF7arGp6181G4js
Cloning into '8vFu9S79ysdWag4wek53YWXbC5nCRLF7arGp6181G4js'...

\end{verbatim}

Если клонируется зашифрованный репозиторий, то ключ, которым планируется
расшифровка должен быть добавлен в hbs2-keyman ( hbs2-keyman update \&\& hbs2-keyman list )

\subsubsection{Подписка на репозиторий}

Подписаться на репозиторий, но не клонировать его:

\begin{verbatim}
hbs2-git-subscribe <LWWREF>
\end{verbatim}

например:

\begin{verbatim}
hbs2-git-subscribe 8vFu9S79ysdWag4wek53YWXbC5nCRLF7arGp6181G4js

[user@host:~/tmp]$ hbs2-peer poll list | rg  8vFu9S79ysdWag4wek53YWXbC5nCRLF7arGp6181G4js
8vFu9S79ysdWag4wek53YWXbC5nCRLF7arGp6181G4js 17  lwwref
\end{verbatim}

В подписках должна быть и ссылка lwwref и соответствующий ей рефлог

\subsubsection{Разное}

\paragraph{Посмотреть ссылки}

\begin{verbatim}
[user@host:~/newrepo111]$ git hbs21 tools show-remotes
1    8vFu9S79ysdWag4wek53YWXbC5nCRLF7arGp6181G4js 57HBZKQeFgsecCvFYgoZXTDpUdpxqZnfTaWMAL6k5MuH
\end{verbatim}

Версия, ссылка (lwwref), рефлог

\paragraph{Посмотреть ссылку}

\begin{verbatim}
[user@host:~/newrepo111]$ hbs2-peer lwwref get 8vFu9S79ysdWag4wek53YWXbC5nCRLF7arGp6181G4js
(lwwref
  (seq 1)
  (value "BqvS2V3AfakKYwAgTG6fMGW53C6L19YhWaXDY2gdqMkK")
  )
\end{verbatim}

Десериализованный блок значения ссылки: версия, ссылка на блок данных

Получить значение рефлога
\begin{verbatim}
[user@host:~/newrepo111]$ hbs2-peer reflog get 57HBZKQeFgsecCvFYgoZXTDpUdpxqZnfTaWMAL6k5MuH
5wwctwSJkNN3tY4jjr2G2nzutsfzNpwpbDDgG2EJcHxL
\end{verbatim}

\paragraph{Посмотреть транзакции}

На входе -- хэш дерева Меркла (текущее значение рефлога). См. предыдущий шаг

\begin{verbatim}
[user@host:~/newrepo111]$ hbs2 cat -H 5wwctwSJkNN3tY4jjr2G2nzutsfzNpwpbDDgG2EJcHxL
2vFtNUg2qNuSsaZLybL9Zbp2M79G141zJHSudEeEprfA
\end{verbatim}

Ни для чего не нужен в контексте hbs2-git, только для общего развития.

\paragraph{Посмотреть git heads из текущего RepoHead}

\begin{verbatim}
[user@host:~/newrepo111]$ git hbs21 tools show-ref
bdfb845c343eb1da14fe1969219c303c1397980e HEAD
bdfb845c343eb1da14fe1969219c303c1397980e refs/heads/master
\end{verbatim}

\section{Структуры данных}

\subsection{Состояние (State)}

\begin{figure}[h!]
\centering
\begin{tikzpicture}[ every label/.style={font=\scriptsize},
                     every node/.style={font=\scriptsize},
                     handle/.style={ draw=black
                                   , circle
                                   , inner sep=2pt
                                   },
                     box/.style={ draw=black
                                , rounded corners,
                                , anchor=base
                                , font=\scriptsize
                                , minimum height=1.5cm
                                , text width=1.5cm
                                , align=center
                                },
                   ]

  \node[box] (lwwref)    {lwwref};
  \node[box,right=4cm of lwwref] (reflog) {reflog};

  \draw[->] (lwwref.east) -- (reflog.west)
    node[above,midway] {HKDF(SK(lwwref, seed))}
    node [below,midway] {PubKey};

  \node[ rectangle split
       , rectangle split parts=3
       , draw
       , font=\scriptsize
       , text width=3cm
       , below = 0.5cm of lwwref
       ] (merkle) at ($(lwwref)!.5!(reflog)-(0,2)$)
  {
    $T_1 : SequentialRef$
    \nodepart{two}
    ...
    \nodepart{three}
    $T_n : SequentialRef$
  };


  \draw[->] (reflog.south) |- (merkle.east) node [near start, right] {merkle~tree};

  \node[ box
       , below=1cm of merkle, xshift=-1cm, anchor = north east
       , text width=3cm
       , align=left
       , rectangle split
       , rectangle split parts=2] (rhead)
    {\hspace*{.5cm}{RepoHead}\\
     \nodepart{two}
      GK0\\
      time\\
      git refs\\
      manifest\\
    };

  \draw[->] (merkle.south) -- (rhead.north);


  \node[ box
       , below=1cm of merkle, xshift=1cm, anchor = north west
       , text width=3cm
       , align=left
       , rectangle split
       , rectangle split parts=2] (log)
    {\hspace*{.5cm}{log~tree}\\
     \nodepart{two}
    };

  \draw[->] (merkle.south) -- (log.north);


  \node[ box
       , below=1cm of log
       , text width=3cm
       , rectangle split
       , rectangle split parts=3] (logdata)
    {
      $GitObjectPack_1$
     \nodepart{two}
     ...
     \nodepart{three}
      $GitObjectPack_n$
    };


  \draw[->] (log.south) -- (logdata.north) node [midway,right] {merkle~tree};


\end{tikzpicture}
\end{figure}

\textit{Стeйт} состоит из \textit{ссылки} $L_1 : lwwref$ от ключа автора $PK_1(SK_1)$. Ссылка ссылается на

\textit{рефлог} по публичному ключу $PK_2 = PK(SK_2), SK_2 = HKDF(SK_1,seed)$, выводимому из приватного ключа автора
 ( $PK_1 = PK(SK_1)$ ).

 $seed$ содержится в блоке значения ссылки $L_1$.

 $PK_2$ аналогично, содержится в блоке значения ссылки $L_1$.

 Таким образом, все имеют доступ к публичному ключу рефлога $PK_2$ и могут проверять подпись автора
 для даннго рефлога, и только автор имеет доступ к  приватному ключу $SK_2$ и имеет возможность
 подписывать свои транзакции, публикуемые в \textit{рефлоге} для $PK_2$.

 Ранее использовалась прямая ссылка на рефлог для репозитория, что не давало возможность
 поменять структуру данных репозитория, например, с изменением версии hbs2-git без изменения
 самой ссылки.

 Введение еще одного уровня косвенности через lww-ref позволяет не менять исходную (публикуемую)
 ссылку, при этом версионировать сам рефлог. Может быть полезным, например, что бы начать с чистого
 листа, уменьшив количество исторических данных (транзакций, объектов и т.п.).

 Пример: старое значение ссылки на репозиторий hbs2-git выглядело так:

 \begin{verbatim}
BTThPdHKF8XnEq4m6wzbKHKA6geLFK4ydYhBXAqBdHSP
 \end{verbatim}

 Это буквально base-58 от бинарного представления некоторого публичного ключа, ассоциированного с
 рефлогом, владельцем которого является автор hbs2.

 Новое значение ссылки на репозиторий hbs2-git выглядит так:

 \begin{verbatim}
 BTThPdHKF8XnEq4m6wzbKHKA6geLFK4ydYhBXAqBdHSP
 \end{verbatim}

 Однако, теперь это не ссылка типа reflog, а ссылка типа lwwref. Это другой тип данных,
 и значение типа \texttt{lwwref(BTThPdHKF8XnEq4m6wzbKHKA6geLFK4ydYhBXAqBdHSP}
 имеет другой хэш.

 Таким образом, старая версия hbs2-git продолжит работать с рефлогом

 \texttt{BTThPdHKF8XnEq4m6wzbKHKA6geLFK4ydYhBXAqBdHSP},

 новая же версия использует lwwref. Ассоциированный с данным lwwref можно посмотреть, например, так:

 \begin{verbatim}
$ git hbs2 tools show-remotes
4    BTThPdHKF8XnEq4m6wzbKHKA6geLFK4ydYhBXAqBdHSP BKtvRLispCM9UuQqHaNxu4SEUzpQNQ3PeRNknecKGPZ6
 \end{verbatim}

Данная команда покажет, какие lwwref используются в качестве git remote в данном репозитории,
и какие у них версии lwwref и какие значения.

Каждая транзакция $T_n$ содержит полный самодостаточный снимок репозитория, т.е технически
возможно развернуть репозиторий, имея только транзакцию.

Каждая транзакция $T_n$ имеет ссылку на дерево Меркла \textit{паков} объектов git
$GitObjectPack_n$, полученных при помощи команды \texttt{git pack-objects} и индекс,
показывающий, какие объекты входят в каждый \textit{пак}. \textit{Паки объектов} упорядочены,
каждый следующий \textit{пак} в дереве содержит новые по отношению к предыдущим \textit{пакам}
объекты.

Такая структура (а не, например, дерево отдельных объектов) выбрана потому, что:

\begin{enumerate}
  \item git порождает огромное количество слабо различающихся маленьких объектов, следовательно,
    огромную избыточность данных. Лучше всего свои объекты упаковывает сам git, используя, в
    частности, бинарные дельты.
  \item каждый отдельный объект (\textit{блок}) подразумевает, в общем случае, несколько
    сетевых запросов для получения: запрос размера, запрос чанков, ответ. Таким образом,
    повышение количества объектов ведёт к ухудшению скорости синхронизации.
  \item Выше скорость импорта объектов в репозиторий, так как он выполняется стандартной
    командой \texttt{git unpack-objects}
\end{enumerate}

\subsubsection*{RepoHead}

Заголовок транзакции, содержит необходимые метаданные, в частности, ссылки git, соответствующие
объектам, упакованным в паки.

Заметим, что несмотря на то, что у нас каждой операции \textit{PUSH} соответствует транзакция,
которая содержит снимок всего репозитория --- реально передаваться будут только новые блоки
для всех деревьев Меркла. И выкачиваться пирами будут только отсутствующие у них блоки, таким
образом, количество копируемых данных на каждый \textit{PUSH} невелико и соответствует реально
изменившимся данным.


\subsubsection*{Контроль доступа и шифрование}

\texttt{hbs2-git} поддерживает открытые и закрытые репозитории. Закрытые репозитории
реализованы при помощи зашифрованных групповым ключом $GK_0$ деревьев Меркла.

Групповой ключ $GK_0$ представляет собой некоторый секрет для симметричного алгоритма шифрования,
зашифрованный публичными ключами участников.

Групповой ключ можно менять в процессе работы, например, при добавлении/удалении новых участников.

При изменении группового ключа для всех <<старых>> деревьев будет произведено обновление метаданных
и перешифрование секрета для нового ключа.

Для <<новых>> деревьев будет сгенерирован новый секрет.

Нет смысла обновлять <<старые>> секреты, так как уже записанная в HBS2 информация никуда оттуда уже
не денется, будут ли обновлены перегенерированы старые секреты или нет --- данные, зашифрованные
<<старыми>> секретами все равно останутся в системе.

Заметим, что удаление участника из группового ключа лишит его доступа к последующим изменениям, но
не тем, которые у него уже есть.

Метаданные в RepoHead не шифруются, таким образом, публично доступны \textit{манифест} проекта,
название бранчей, тегов и хэши коммитов, на котоыре указывают ссылки. В целом, публичность этих
данных не является острой необходимостью, и их можно в дальнейшем шифровать. Пока выглядит так, что
это не та информация, которую есть большой смысл скрывать.

Система команд спроектирована таким образом, что бы затруднить, или, по крайней мере, не упрощать
раскрытие данных, если репозиторий зашифрован. Таким образом мы пытаемся защититься от случайных
непреднамеренных утечек.


\subsubsection*{Индексация ключей}

Безопасное хранение ключей в настоящий момент возложено на пользователя.

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

hbs2-keyman индексирует ключи в соответствии с настройками, таким образом,
ему известно, в каком файле находится та или иная ключевая пара.

Данная информация используется при криптографических операциях, т.е
hbs2-keyman сообщает компонентам, где искать необходимые ключи.

hbs2-keyman не сохраняет ключи, только индексирует.

hbs2-keyman не отображает секретные ключи, только соответствующие им публичные.

В настоящий момент не все средства используют hbs2-keyman, но в итоге все
будут переведены на него.



\section{Операции}

Основными операциями \texttt{hbs2-git} являются Import и Export.

\subsection{Import}

Настраивает ссылки и импортирует объекты из ссылок hbs2

\begin{figure}[h!]
\centering
\begin{tikzpicture}[ node distance=2cm, auto, thick
                   , every label/.style={font=\scriptsize}
                   , every node/.style={font=\scriptsize}
                   ]
  % Define blocks style
  \tikzstyle{block} = [rectangle
                      , draw
                      , fill=white
                      , text width=5em
                      , text centered
                      , rounded corners
                      , minimum height=2em
                      ]
  \tikzstyle{decision} = [ diamond
                         , draw
                         , fill=white
                         , text width=5em
                         , text centered
                         , node distance=2cm
                         , inner sep=0pt
                         ]

  \tikzstyle{line} = [draw, -Latex]

  \node [block,text width=10em] (init) {Start importRepoWait};
  \node [block, below of=init] (subscribe) {Subscribe to LWWRef};
  \node [block, below of=subscribe] (fetch) {Fetch LWWRef};
  \node [decision, below of=fetch, yshift=-1cm] (checklww) {LWW exists?};
  \node [block, left of=checklww, node distance=5cm] (throwerror) {ThrowError};
  \node [block, right of=checklww, node distance=5cm] (readblock) {Read LWW Block};
  \node [block, below of=readblock] (readreflog) {Read RefLog};
  \node [decision, below of=readreflog] (checkreflog) {RefLog OK?};
  \node [block, right of=checkreflog, node distance=5cm] (processreflog) {Process RefLog};
  \node [block, left of=checkreflog, node distance=5cm] (retryreflog) {Retry fetch RefLog};
  \node [block, below of=checkreflog, node distance=4cm] (continuenext) {Continue Next Steps...};

  \path [line] (init) -- (subscribe);
  \path [line] (subscribe) -- (fetch);
  \path [line] (fetch) -- (checklww);
  \path [line] (checklww) -- node [near start] {no} (throwerror);
  \path [line] (checklww) -- node [near start] {yes} (readblock);
  \path [line] (readblock) -- (readreflog);
  \path [line] (readreflog) -- (checkreflog);
  \path [line] (checkreflog) -- node [near start] {yes} (processreflog);
  \path [line] (checkreflog) -- node [near start] {no} (retryreflog);
  \path [line] (processreflog) |- (continuenext);
  \path [line] (retryreflog) |- (continuenext);
  \path [line] (throwerror) |- (continuenext);


\end{tikzpicture}


\caption{Import}
\end{figure}

\pagebreak

\subsection{Export}

Экспортирует данные в хранилище, обновляет ссылки,
рассылает уведомления.

\begin{figure}[h!]
\centering

\begin{tikzpicture}[ node distance=1.5cm and 1.5cm, auto, thick
                   , every node/.append style={font=\scriptsize}
                   , decision/.style={diamond, draw, fill=white, text width=4em, text badly centered, node distance=2cm, inner sep=0pt}
                   , block/.style={rectangle, draw, fill=white, text width=5em, text centered, rounded corners, minimum height=4em}
                   , line/.style={draw, -Latex}
                   , check/.style={rectangle, draw, fill=white, text width=5em, text centered, minimum height=4em}
                   ]

  % Place nodes
  \node [block] (init) {Start export};
  \node [block, right=of init] (subscribe) {Subscribe to LWWRef};
  \node [decision, right=of subscribe] (newCheck) {New Key?};
  \node [block, right=of newCheck] (waitOrInit) {Wait or Init LWWRef};
  \node [block, below=of waitOrInit] (makeRepoHead) {Make RepoHead};
  \node [block, below=of makeRepoHead] (createTx) {Create Transaction};
  \node [block, left=of createTx] (postTx) {Post Transaction};
  \node [block, left=of postTx] (exit) {Exit};

  % Draw edges
  \path [line] (init) -- (subscribe);
  \path [line] (subscribe) -- (newCheck);
  \path [line] (newCheck) -- node {no} (waitOrInit);
  \path [line] (newCheck) |- node [near start] {yes} (makeRepoHead);
  \path [line] (waitOrInit) -- (makeRepoHead);
  \path [line] (makeRepoHead) -- (createTx);
  \path [line] (createTx) -- (postTx);
  \path [line] (postTx) -- (exit);

\end{tikzpicture}

\caption{Export}
\end{figure}

\pagebreak

\section{Разное}

В документации или где-то еще могут спорадически появляться префиксы hbs21 (hbs21://).

Этот префикс был присвоен новому протоколу hbs2, что бы он не интерферировал
со старым и можно было бы одновременно пользоваться двумя версиями hbs2-git.

После релиза новой версии и прекращении поддержки старой -- данный префикс
не используется, однако должен пониматься hbs2-git (вместо hbs2://)

\section{Ссылки}

\begin{description}
  \item[Блог:] @voidlizard.online
  \item[Канал:]  @hbs2dev \url{https://t.me/hbs2dev}
  \item[Группа:] @hbs2support \url{https://t.me/hbs2_support}
\end{description}

\end{document}


