mirror of
https://github.com/monero-project/research-lab.git
synced 2025-01-08 03:49:24 +00:00
769 lines
No EOL
34 KiB
TeX
769 lines
No EOL
34 KiB
TeX
\documentclass[12pt,english]{mrl}
|
|
\usepackage{graphicx}
|
|
\usepackage{listings}
|
|
\usepackage{cite}
|
|
\usepackage{amsthm}
|
|
\newtheorem*{example}{Example}
|
|
|
|
\usepackage[toc,page]{appendix}
|
|
|
|
\renewcommand{\familydefault}{\rmdefault}
|
|
\usepackage[T1]{fontenc}
|
|
\usepackage[latin9]{inputenc}
|
|
\usepackage{color}
|
|
\usepackage{babel}
|
|
\usepackage{verbatim}
|
|
\usepackage{float}
|
|
\usepackage{url}
|
|
\usepackage{amsthm}
|
|
\usepackage{amsmath}
|
|
\usepackage{amssymb}
|
|
\usepackage[unicode=true,pdfusetitle, bookmarks=true,bookmarksnumbered=false,bookmarksopen=false, breaklinks=false,pdfborder={0 0 1},backref=false,colorlinks=true]{hyperref}
|
|
\usepackage{breakurl}
|
|
|
|
|
|
\usepackage{amsmath}
|
|
\usepackage{amsfonts}
|
|
\usepackage{amssymb,enumerate}
|
|
\usepackage{amsthm}
|
|
\usepackage{cite}
|
|
\usepackage{comment}
|
|
\usepackage[all]{xy}
|
|
%\usepackage[notref,notcite]{showkeys}
|
|
\usepackage{hyperref}
|
|
\usepackage{todonotes}
|
|
|
|
% THEOREM ENVIRONMENTS
|
|
|
|
\theoremstyle{definition}
|
|
\newtheorem{lem}{Lemma}[section]
|
|
\newtheorem{cor}[lem]{Corollary}
|
|
\newtheorem{prop}[lem]{Proposition}
|
|
\newtheorem{thm}[lem]{Theorem}
|
|
\newtheorem{soln}[]{Solution}
|
|
\newtheorem{conj}[lem]{Conjecture}
|
|
\newtheorem{Defn}[lem]{Definition}
|
|
\newtheorem{Ex}[lem]{Example}
|
|
\newtheorem{Question}[lem]{Question}
|
|
\newtheorem{Property}[lem]{Property}
|
|
\newtheorem{Properties}[lem]{Properties}
|
|
\newtheorem{Discussion}[lem]{Remark}
|
|
\newtheorem{Construction}[lem]{Construction}
|
|
\newtheorem{Notation}[lem]{Notation}
|
|
\newtheorem{Fact}[lem]{Fact}
|
|
\newtheorem{Notationdefinition}[lem]{Definition/Notation}
|
|
\newtheorem{Remarkdefinition}[lem]{Remark/Definition}
|
|
\newtheorem{rem}[lem]{Remark}
|
|
\newtheorem{Subprops}{}[lem]
|
|
\newtheorem{Para}[lem]{}
|
|
\newtheorem{Exer}[lem]{Exercise}
|
|
\newtheorem{Exerc}{Exercise}
|
|
|
|
\newenvironment{defn}{\begin{Defn}\rm}{\end{Defn}}
|
|
\newenvironment{ex}{\begin{Ex}\rm}{\end{Ex}}
|
|
\newenvironment{question}{\begin{Question}\rm}{\end{Question}}
|
|
\newenvironment{property}{\begin{Property}\rm}{\end{Property}}
|
|
\newenvironment{properties}{\begin{Properties}\rm}{\end{Properties}}
|
|
\newenvironment{notation}{\begin{Notation}\rm}{\end{Notation}}
|
|
\newenvironment{fact}{\begin{Fact}\rm}{\end{Fact}}
|
|
\newenvironment{notationdefinition}{\begin{Notationdefinition}\rm}{\end{Notationdefinition}}
|
|
\newenvironment{remarkdefinition}{\begin{Remarkdefinition}\rm}{\end{Remarkdefinition}}
|
|
\newenvironment{subprops}{\begin{Subprops}\rm}{\end{Subprops}}
|
|
\newenvironment{para}{\begin{Para}\rm}{\end{Para}}
|
|
\newenvironment{disc}{\begin{Discussion}\rm}{\end{Discussion}}
|
|
\newenvironment{construction}{\begin{Construction}\rm}{\end{Construction}}
|
|
\newenvironment{exer}{\begin{Exer}\rm}{\end{Exer}}
|
|
\newenvironment{exerc}{\begin{Exerc}\rm}{\end{Exerc}}
|
|
|
|
\newtheorem{intthm}{Theorem}
|
|
\renewcommand{\theintthm}{\Alph{intthm}}
|
|
|
|
% COMENTS
|
|
|
|
%\newcommand{\ssw}[1]{\footnote{#1}}
|
|
\newcommand{\nt}[2][$^\spadesuit$]{\hspace{0pt}#1\marginpar{\tt\raggedleft
|
|
#1 #2}}
|
|
\newcommand{\dw}[2][$^\spadesuit$]{\nt[#1]{DW:#2}}
|
|
\newcommand{\ssw}[2][$^\spadesuit$]{\nt[#1]{SSW:#2}}
|
|
\newcommand{\ts}[2][$^\spadesuit$]{\nt[#1]{TS:#2}}
|
|
|
|
\newcommand{\ds}{\displaystyle}
|
|
|
|
% CATEGORIES
|
|
|
|
\newcommand{\A}{\mathcal{A}}
|
|
\newcommand{\D}{\mathcal{D}}
|
|
\newcommand{\R}{\mathcal{R}}
|
|
\newcommand{\cat}[1]{\mathcal{#1}}
|
|
\newcommand{\catx}{\cat{X}}
|
|
\newcommand{\caty}{\cat{Y}}
|
|
\newcommand{\catm}{\cat{M}}
|
|
\newcommand{\catv}{\cat{V}}
|
|
\newcommand{\catw}{\cat{W}}
|
|
\newcommand{\catg}{\cat{G}}
|
|
\newcommand{\catp}{\cat{P}}
|
|
\newcommand{\catf}{\cat{F}}
|
|
\newcommand{\cati}{\cat{I}}
|
|
\newcommand{\cata}{\cat{A}}
|
|
\newcommand{\catabel}{\mathcal{A}b}
|
|
\newcommand{\catc}{\cat{C}}
|
|
\newcommand{\catb}{\cat{B}}
|
|
\newcommand{\catgi}{\cat{GI}}
|
|
\newcommand{\catgp}{\cat{GP}}
|
|
\newcommand{\catgf}{\cat{GF}}
|
|
\newcommand{\catgic}{\cat{GI}_C}
|
|
\newcommand{\catgib}{\cat{GI}_B}
|
|
\newcommand{\catib}{\cat{I}_B}
|
|
\newcommand{\catgibdc}{\cat{GI}_{\bdc}}
|
|
\newcommand{\catgicd}{\cat{GI}_{C^{\dagger}}}
|
|
\newcommand{\caticd}{\cat{I}_{C^{\dagger}}}
|
|
\newcommand{\catgc}{\cat{G}_C}
|
|
\newcommand{\catgpc}{\cat{GP}_C}
|
|
\newcommand{\catgpb}{\cat{GP}_B}
|
|
\newcommand{\catgpcd}{\cat{GP}_{C^{\dagger}}}
|
|
\newcommand{\catpcd}{\cat{P}_{C^{\dagger}}}
|
|
\newcommand{\catac}{\cat{A}_C}
|
|
\newcommand{\catab}{\cat{A}_B}
|
|
\newcommand{\catbc}{\cat{B}_C}
|
|
\newcommand{\catabdc}{\cat{A}_{\bdc}}
|
|
\newcommand{\catbbdc}{\cat{B}_{\bdc}}
|
|
\newcommand{\catbb}{\cat{B}_B}
|
|
\newcommand{\catacd}{\cat{A}_{\da{C}}}
|
|
\newcommand{\catbcd}{\cat{B}_{\da{C}}}
|
|
\newcommand{\catgfc}{\cat{GF}_C}
|
|
\newcommand{\catic}{\cat{I}_C}
|
|
\newcommand{\catibdc}{\cat{I}_{\bdc}}
|
|
\newcommand{\catpb}{\cat{P}_B}
|
|
\newcommand{\catpc}{\cat{P}_C}
|
|
\newcommand{\catfc}{\cat{F}'}
|
|
\newcommand{\opg}{\cat{G}}
|
|
\newcommand{\finrescat}[1]{\operatorname{res}\comp{\cat{#1}}}
|
|
\newcommand{\proprescat}[1]{\operatorname{res}\wti{\cat{#1}}}
|
|
\newcommand{\finrescatx}{\finrescat{X}}
|
|
\newcommand{\finrescaty}{\finrescat{Y}}
|
|
\newcommand{\finrescatv}{\finrescat{V}}
|
|
\newcommand{\fincorescatggicd}{\operatorname{cores}\comp{\catg(\caticd)}}
|
|
\newcommand{\finrescatw}{\finrescat{W}}
|
|
\newcommand{\finrescatpc}{\operatorname{res}\comp{\catpc}}
|
|
\newcommand{\finrescatpcr}{\operatorname{res}\comp{\catpc(R)}}
|
|
\newcommand{\finrescatpb}{\operatorname{res}\comp{\catpb}}
|
|
\newcommand{\finrescatpbr}{\operatorname{res}\comp{\catpb(R)}}
|
|
\newcommand{\finrescatgpb}{\operatorname{res}\comp{\catgpb}}
|
|
\newcommand{\finrescatgpbr}{\operatorname{res}\comp{\catgpb(R)}}
|
|
\newcommand{\propcorescatic}{\operatorname{cores}\wti{\catic}}
|
|
\newcommand{\propcorescatgic}{\operatorname{cores}\wti{\catgic}}
|
|
\newcommand{\fincorescatic}{\operatorname{cores}\comp{\catic}}
|
|
\newcommand{\fincorescaticr}{\operatorname{cores}\comp{\catic(R)}}
|
|
\newcommand{\fincorescatir}{\operatorname{cores}\comp{\cati(R)}}
|
|
\newcommand{\finrescatp}{\finrescat{P}}
|
|
\newcommand{\proprescatgpc}{\operatorname{res}\wti{\catgpc}}
|
|
\newcommand{\fincorescaticd}{\operatorname{cores}\comp{\caticd}}
|
|
\newcommand{\finrescatgp}{\finrescat{GP}}
|
|
\newcommand{\finrescatpcd}{\operatorname{res}\comp{\catp_{\da{C}}}}
|
|
\newcommand{\fincorescatggic}{\operatorname{cores}\comp{\catg(\catic)}}
|
|
\newcommand{\fincorescatibdc}{\operatorname{cores}\comp{\catibdc}}
|
|
\newcommand{\fincorescatibdcr}{\operatorname{cores}\comp{\catibdc(R)}}
|
|
\newcommand{\fincorescatgibdc}{\operatorname{cores}\comp{\catgibdc}}
|
|
\newcommand{\fincorescatgibdcr}{\operatorname{cores}\comp{\catgibdc(R)}}
|
|
\newcommand{\fincorescatibr}{\operatorname{cores}\comp{\catib(R)}}
|
|
\newcommand{\finrescatggpc}{\operatorname{res}\comp{\catg(\catpc)}}
|
|
\newcommand{\finrescatg}{\operatorname{res}\comp{\cat{G}}(R)}
|
|
\newcommand{\finrescatgpr}{\operatorname{res}\comp{\cat{GP}(R)}}
|
|
\newcommand{\finrescatpr}{\operatorname{res}\comp{\cat{P}(R)}}
|
|
\newcommand{\finrescatgpc}{\operatorname{res}\comp{\catgp_C(R)}}
|
|
\newcommand{\proprescatpc}{\operatorname{res}\wti{\catp_C(R)}}
|
|
\newcommand{\propcorescatpc}{\operatorname{cores}\wti{\catp_C(R)}}
|
|
\newcommand{\finrescatgpcd}{\operatorname{res}\comp{\catgp_{C^{\dagger}}(R)}}
|
|
\newcommand{\proprescatp}{\proprescat{P}}
|
|
\newcommand{\proprescatgp}{\proprescat{GP}}
|
|
\newcommand{\proprescatx}{\proprescat{X}}
|
|
\newcommand{\proprescaty}{\proprescat{Y}}
|
|
\newcommand{\proprescatv}{\proprescat{V}}
|
|
\newcommand{\proprescatw}{\proprescat{W}}
|
|
\newcommand{\fincorescat}[1]{\operatorname{cores}\comp{\cat{#1}}}
|
|
\newcommand{\propcorescat}[1]{\operatorname{cores}\wti{\cat{#1}}}
|
|
\newcommand{\fincorescatx}{\fincorescat{X}}
|
|
\newcommand{\fincorescati}{\fincorescat{I}}
|
|
\newcommand{\fincorescatgi}{\fincorescat{GI}}
|
|
\newcommand{\fincorescatgir}{\fincorescat{GI(R)}}
|
|
\newcommand{\fincorescatgic}{\operatorname{cores}\comp{\catgi_C(R)}}
|
|
\newcommand{\fincorescatgicd}{\operatorname{cores}\comp{\catgi_{C^{\dagger}}(R)}}
|
|
\newcommand{\propcorescati}{\propcorescat{I}}
|
|
\newcommand{\propcorescatgi}{\propcorescat{GI}}
|
|
\newcommand{\fincorescaty}{\fincorescat{Y}}
|
|
\newcommand{\fincorescatv}{\fincorescat{V}}
|
|
\newcommand{\fincorescatw}{\fincorescat{W}}
|
|
\newcommand{\propcorescatx}{\propcorescat{X}}
|
|
\newcommand{\propcorescaty}{\propcorescat{Y}}
|
|
\newcommand{\propcorescatv}{\propcorescat{V}}
|
|
\newcommand{\propcorescatw}{\propcorescat{W}}
|
|
\newcommand{\cpltrescat}[1]{\operatorname{res}\ol{\cat{#1}}}
|
|
\newcommand{\cpltcorescat}[1]{\operatorname{cores}\ol{\cat{#1}}}
|
|
\newcommand{\cpltrescatw}{\cpltrescat{W}}
|
|
\newcommand{\cpltcorescatw}{\cpltcorescat{W}}
|
|
\newcommand{\gw}{\opg(\catw)}
|
|
\newcommand{\gnw}[1]{\opg^{#1}(\catw)}
|
|
\newcommand{\gnx}[1]{\opg^{#1}(\catx)}
|
|
\newcommand{\gx}{\opg(\catx)}
|
|
\newcommand{\catao}{\cata^o}
|
|
\newcommand{\catxo}{\catx^o}
|
|
\newcommand{\catyo}{\caty^o}
|
|
\newcommand{\catwo}{\catw^o}
|
|
\newcommand{\catvo}{\catv^o}
|
|
|
|
|
|
% DIMENSIONS
|
|
|
|
\newcommand{\pdim}{\operatorname{pd}}
|
|
\newcommand{\pd}{\operatorname{pd}}
|
|
\newcommand{\gdim}{\mathrm{G}\text{-}\!\dim}
|
|
\newcommand{\gkdim}[1]{\mathrm{G}_{#1}\text{-}\!\dim}
|
|
\newcommand{\gcdim}{\gkdim{C}}
|
|
\newcommand{\injdim}{\operatorname{id}}
|
|
\newcommand{\id}{\operatorname{id}}
|
|
\newcommand{\fd}{\operatorname{fd}}
|
|
\newcommand{\fdim}{\operatorname{fd}}
|
|
\newcommand{\catpd}[1]{\cat{#1}\text{-}\pd}
|
|
\newcommand{\xpd}{\catpd{X}}
|
|
\newcommand{\xopd}{\catxo\text{-}\pd}
|
|
\newcommand{\xid}{\catid{X}}
|
|
\newcommand{\wpd}{\catpd{W}}
|
|
\newcommand{\ypd}{\catpd{Y}}
|
|
\newcommand{\gpd}{\catpd{G}}
|
|
\newcommand{\gid}{\catid{G}}
|
|
\newcommand{\catid}[1]{\cat{#1}\text{-}\id}
|
|
\newcommand{\yid}{\catid{Y}}
|
|
\newcommand{\vid}{\catid{V}}
|
|
\newcommand{\wid}{\catid{W}}
|
|
\newcommand{\pdpd}{\catpd\text{-}\pd}
|
|
\newcommand{\idid}{\catid\text{-}\id}
|
|
\newcommand{\pcpd}{\catpc\text{-}\pd}
|
|
\newcommand{\pbpd}{\catpb\text{-}\pd}
|
|
\newcommand{\icdagdim}{\caticd\text{-}\id}
|
|
\newcommand{\icdid}{\caticd\text{-}\id}
|
|
\newcommand{\ibdcid}{\catibdc\text{-}\id}
|
|
\newcommand{\icdim}{\catic\text{-}\id}
|
|
\newcommand{\icid}{\catic\text{-}\id}
|
|
\newcommand{\ibid}{\catib\text{-}\id}
|
|
\newcommand{\pcdim}{\catpc\text{-}\pd}
|
|
\newcommand{\gpcpd}{\catgpc\text{-}\pd}
|
|
\newcommand{\gfpd}{\catgf\text{-}\pd}
|
|
\newcommand{\gppd}{\catgp\text{-}\pd}
|
|
\newcommand{\gfcpd}{\catgfc\text{-}\pd}
|
|
\newcommand{\gpbpd}{\catgpb\text{-}\pd}
|
|
\newcommand{\gicid}{\catgic\text{-}\id}
|
|
\newcommand{\gibid}{\catgib\text{-}\id}
|
|
\newcommand{\gicdagdim}{\catgicd\text{-}\id}
|
|
\newcommand{\gicdid}{\catgicd\text{-}\id}
|
|
\newcommand{\ggpcpd}{\catg(\catpc)\text{-}\pd}
|
|
\newcommand{\ggicdid}{\catg(\caticd)\text{-}\id}
|
|
\newcommand{\ggicid}{\catg(\catic)\text{-}\id}
|
|
\newcommand{\cmdim}{\mathrm{CM}\text{-}\dim}
|
|
\newcommand{\cidim}{\mathrm{CI}\text{-}\!\dim}
|
|
\newcommand{\cipd}{\mathrm{CI}\text{-}\!\pd}
|
|
\newcommand{\cifd}{\mathrm{CI}\text{-}\!\fd}
|
|
\newcommand{\ciid}{\mathrm{CI}\text{-}\!\id}
|
|
|
|
|
|
% OTHER INVARIANTS
|
|
|
|
\newcommand{\Ht}{\operatorname{ht}}
|
|
\newcommand{\col}{\operatorname{col}}
|
|
\newcommand{\depth}{\operatorname{depth}}
|
|
\newcommand{\rank}{\operatorname{rank}}
|
|
\newcommand{\amp}{\operatorname{amp}}
|
|
\newcommand{\edim}{\operatorname{edim}}
|
|
\newcommand{\crs}{\operatorname{crs}}
|
|
\newcommand{\rfd}{\operatorname{Rfd}}
|
|
\newcommand{\ann}{\operatorname{Ann}}
|
|
\newcommand{\mspec}{\mathrm{m}\text{\spec}}
|
|
\newcommand{\soc}{\operatorname{Soc}}
|
|
\newcommand{\len}{\operatorname{length}}
|
|
\newcommand{\type}{\operatorname{type}}
|
|
\newcommand{\dist}{\operatorname{dist}}
|
|
\newcommand{\prox}{\operatorname{\sigma}}
|
|
\newcommand{\curv}{\operatorname{curv}}
|
|
\newcommand{\icurv}{\operatorname{inj\,curv}}
|
|
\newcommand{\grade}{\operatorname{grade}}
|
|
\newcommand{\card}{\operatorname{card}}
|
|
\newcommand{\cx}{\operatorname{cx}}
|
|
\newcommand{\cmd}{\operatorname{cmd}}
|
|
\newcommand{\Span}{\operatorname{Span}}
|
|
\newcommand{\CM}{\operatorname{CM}}
|
|
|
|
% FUNCTORS
|
|
|
|
\newcommand{\cbc}[2]{#1(#2)}
|
|
\newcommand{\ext}{\operatorname{Ext}}
|
|
\newcommand{\rhom}{\mathbf{R}\!\operatorname{Hom}}
|
|
\newcommand{\lotimes}{\otimes^{\mathbf{L}}}
|
|
\newcommand{\HH}{\operatorname{H}}
|
|
\newcommand{\Hom}{\operatorname{Hom}}
|
|
\newcommand{\coker}{\operatorname{Coker}}
|
|
\newcommand{\spec}{\operatorname{Spec}}
|
|
\newcommand{\s}{\mathfrak{S}}
|
|
\newcommand{\tor}{\operatorname{Tor}}
|
|
\newcommand{\im}{\operatorname{Im}}
|
|
\newcommand{\shift}{\mathsf{\Sigma}}
|
|
\newcommand{\othershift}{\mathsf{\Sigma}}
|
|
\newcommand{\da}[1]{#1^{\dagger}}
|
|
\newcommand{\Cl}{\operatorname{Cl}}
|
|
\newcommand{\Pic}{\operatorname{Pic}}
|
|
\newcommand{\proj}{\operatorname{Proj}}
|
|
\newcommand{\End}{\operatorname{End}}
|
|
\newcommand{\cone}{\operatorname{Cone}}
|
|
\newcommand{\Ker}{\operatorname{Ker}}
|
|
\newcommand{\xext}{\ext_{\catx}}
|
|
\newcommand{\yext}{\ext_{\caty}}
|
|
\newcommand{\vext}{\ext_{\catv}}
|
|
\newcommand{\wext}{\ext_{\catw}}
|
|
\newcommand{\aext}{\ext_{\cata}}
|
|
\newcommand{\ahom}{\Hom_{\cata}}
|
|
\newcommand{\aoext}{\ext_{\catao}}
|
|
\newcommand{\aohom}{\Hom_{\catao}}
|
|
\newcommand{\xaext}{\ext_{\catx\!\cata}}
|
|
\newcommand{\axext}{\ext_{\cata\catx}}
|
|
\newcommand{\ayext}{\ext_{\cata\caty}}
|
|
\newcommand{\avext}{\ext_{\cata\catv}}
|
|
\newcommand{\awext}{\ext_{\cata\catw}}
|
|
\newcommand{\Qext}{\ext_{\catw \cata}}
|
|
\newcommand{\pmext}{\ext_{\catp(R)\catm(R)}}
|
|
\newcommand{\miext}{\ext_{\catm(R)\cati(R)}}
|
|
\newcommand{\Qtate}{\comp{\ext}_{\catw \cata}}
|
|
\newcommand{\awtate}{\comp{\ext}_{\cata \catw}}
|
|
\newcommand{\avtate}{\comp{\ext}_{\cata \catv}}
|
|
\newcommand{\pmtate}{\comp{\ext}_{\catp(R) \catm(R)}}
|
|
\newcommand{\mitate}{\comp{\ext}_{\catm(R) \cati(R)}}
|
|
\newcommand{\pcext}{\ext_{\catpc}}
|
|
\newcommand{\pbext}{\ext_{\catpb}}
|
|
\newcommand{\gpcext}{\ext_{\catgpc}}
|
|
\newcommand{\icext}{\ext_{\catic}}
|
|
\newcommand{\gpbext}{\ext_{\catgpb}}
|
|
\newcommand{\gibdcext}{\ext_{\catgibdc}}
|
|
\newcommand{\ibdcext}{\ext_{\catibdc}}
|
|
\newcommand{\gicext}{\ext_{\catgic}}
|
|
\newcommand{\gpext}{\ext_{\catgp}}
|
|
\newcommand{\giext}{\ext_{\catgi}}
|
|
\newcommand{\gicdext}{\ext_{\catgicd}}
|
|
|
|
% IDEALS
|
|
|
|
\newcommand{\ideal}[1]{\mathfrak{#1}}
|
|
\newcommand{\m}{\ideal{m}}
|
|
\newcommand{\n}{\ideal{n}}
|
|
\newcommand{\p}{\ideal{p}}
|
|
\newcommand{\q}{\ideal{q}}
|
|
\newcommand{\fa}{\ideal{a}}
|
|
\newcommand{\fb}{\ideal{b}}
|
|
\newcommand{\fN}{\ideal{N}}
|
|
\newcommand{\fs}{\ideal{s}}
|
|
\newcommand{\fr}{\ideal{r}}
|
|
|
|
% OPERATIONS AND ACCENTS
|
|
|
|
\newcommand{\wt}{\widetilde}
|
|
\newcommand{\ti}{\tilde}
|
|
\newcommand{\comp}[1]{\widehat{#1}}
|
|
\newcommand{\ol}{\overline}
|
|
\newcommand{\wti}{\widetilde}
|
|
|
|
% OPERATORS
|
|
|
|
\newcommand{\ass}{\operatorname{Ass}}
|
|
\newcommand{\supp}{\operatorname{Supp}}
|
|
\newcommand{\minh}{\operatorname{Minh}}
|
|
\newcommand{\Min}{\operatorname{Min}}
|
|
|
|
% MATHBB
|
|
|
|
\newcommand{\bbz}{\mathbb{Z}}
|
|
\newcommand{\bbn}{\mathbb{N}}
|
|
\newcommand{\bbq}{\mathbb{Q}}
|
|
\newcommand{\bbr}{\mathbb{R}}
|
|
\newcommand{\bbc}{\mathbb{C}}
|
|
|
|
% ARROWS
|
|
|
|
\newcommand{\from}{\leftarrow}
|
|
\newcommand{\xra}{\xrightarrow}
|
|
\newcommand{\xla}{\xleftarrow}
|
|
\newcommand{\onto}{\twoheadrightarrow}
|
|
\newcommand{\res}{\xra{\simeq}}
|
|
|
|
|
|
% MAPS
|
|
|
|
\newcommand{\vf}{\varphi}
|
|
\newcommand{\ve}{\varepsilon}
|
|
\newcommand{\Qcomp}{\varepsilon_{\catw \cata}}
|
|
\newcommand{\awcomp}{\varepsilon_{\cata \catw}}
|
|
\newcommand{\avcomp}{\varepsilon_{\cata \catv}}
|
|
\newcommand{\xQcomp}{\vartheta_{\catx \catw \cata}}
|
|
\newcommand{\ayvcomp}{\vartheta_{\cata \caty \catv}}
|
|
\newcommand{\Qacomp}{\varkappa_{\catw \cata}}
|
|
\newcommand{\xaacomp}{\varkappa_{\catx \cata}}
|
|
\newcommand{\aaycomp}{\varkappa_{\cata\caty}}
|
|
\newcommand{\aavcomp}{\varkappa_{\cata\catv}}
|
|
\newcommand{\gpcpccomp}{\vartheta_{\catgpc\catpc}}
|
|
\newcommand{\gpcpbcomp}{\vartheta_{\catgpc\catpb}}
|
|
\newcommand{\gpcgpbcomp}{\vartheta_{\catgpc\catgpb}}
|
|
\newcommand{\gicibcomp}{\vartheta_{\catgic\catib}}
|
|
\newcommand{\gicgibcomp}{\vartheta_{\catgic\catgib}}
|
|
\newcommand{\giciccomp}{\vartheta_{\catgic\catic}}
|
|
\newcommand{\pccomp}{\varkappa_{\catpc}}
|
|
\newcommand{\gpccomp}{\varkappa_{\catgpc}}
|
|
\newcommand{\iccomp}{\varkappa_{\catic}}
|
|
\newcommand{\ibdccomp}{\varkappa_{\catibdc}}
|
|
\newcommand{\icdcomp}{\varkappa_{\caticd}}
|
|
\newcommand{\giccomp}{\varkappa_{\catgic}}
|
|
|
|
% MISCELLANEOUS
|
|
|
|
\newcommand{\y}{\mathbf{y}}
|
|
\newcommand{\te}{\theta}
|
|
\newcommand{\x}{\mathbf{x}}
|
|
\newcommand{\opi}{\operatorname{i}}
|
|
\newcommand{\route}{\gamma}
|
|
\newcommand{\sdc}[1]{\mathsf{#1}}
|
|
\newcommand{\nls}[1]{\mathsf{#1}}
|
|
\newcommand{\cl}{\operatorname{cl}}
|
|
\newcommand{\cls}{\operatorname{cls}}
|
|
\newcommand{\pic}{\operatorname{pic}}
|
|
\newcommand{\pics}{\operatorname{pics}}
|
|
\newcommand{\tri}{\trianglelefteq}
|
|
\newcommand{\Mod}{\operatorname{Mod}}
|
|
\newcommand{\bdc}{B^{\dagger_C}}
|
|
\newcommand{\e}{\mathbf{e}}
|
|
\newcommand{\f}{\mathbf{f}}
|
|
|
|
|
|
% RENEWED COMMANDS
|
|
|
|
\renewcommand{\geq}{\geqslant}
|
|
\renewcommand{\leq}{\leqslant}
|
|
\renewcommand{\ker}{\Ker}
|
|
\renewcommand{\hom}{\Hom}
|
|
|
|
|
|
\newcommand{\normal}{\lhd}
|
|
\newcommand{\normaleq}{\trianglelefteqslant}
|
|
\newcommand{\homrm}[1]{\hom_{_{#1}\catm}}
|
|
\newcommand{\hommr}[1]{\hom_{\catm_{#1}}}
|
|
\newcommand{\cplx}[1]{{#1}_{\bullet}}
|
|
\newcommand{\pext}{\mathrm{P}\!\ext}
|
|
\newcommand{\pextrm}[1]{\pext_{_{#1}\catm}}
|
|
\newcommand{\pextmr}[1]{\pext_{\catm_{#1}}}
|
|
\newcommand{\iext}{\mathrm{I}\!\ext}
|
|
\newcommand{\iextrm}[1]{\iext_{_{#1}\catm}}
|
|
\newcommand{\iextmr}[1]{\iext_{\catm_{#1}}}
|
|
\newcommand{\catmod}[1]{#1\text{-mod}}
|
|
\newcommand{\modcat}[1]{\text{mod-}#1}
|
|
|
|
|
|
\newcommand{\lcm}{\textnormal{lcm}}
|
|
\newcommand{\diff}{\backslash}
|
|
%\setlength{\parindent}{0mm}
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% LyX specific LaTeX commands.
|
|
\floatstyle{ruled}
|
|
\newfloat{algorithm}{tbp}{loa}
|
|
\providecommand{\algorithmname}{Algorithm}
|
|
\floatname{algorithm}{\protect\algorithmname}
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Textclass specific LaTeX commands.
|
|
\numberwithin{equation}{section}
|
|
\numberwithin{figure}{section}
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% User specified LaTeX commands.
|
|
\usepackage{algpseudocode}
|
|
|
|
\usepackage{subcaption}
|
|
|
|
\numberwithin{equation}{section}
|
|
|
|
|
|
\makeatletter
|
|
|
|
|
|
\makeatletter
|
|
|
|
\newcommand{\h}{\mathcal{H}}
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% LyX specific LaTeX commands.
|
|
\floatstyle{ruled}
|
|
\newfloat{algorithm}{tbp}{loa}
|
|
\providecommand{\algorithmname}{Algorithm}
|
|
\floatname{algorithm}{\protect\algorithmname}
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Textclass specific LaTeX commands.
|
|
\numberwithin{equation}{section}
|
|
\numberwithin{figure}{section}
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% User specified LaTeX commands.
|
|
\usepackage{algpseudocode}
|
|
|
|
\makeatother
|
|
|
|
\begin{document}
|
|
\begin{frontmatter}
|
|
|
|
\begin{fmbox}
|
|
\hfill\setlength{\fboxrule}{0px}\setlength{\fboxsep}{5px}\fbox{\includegraphics[width=2in]{moneroLogo.png}}
|
|
\dochead{Research bulletin \hfill MRL-0005}
|
|
\title{Difficulty Adjustment Algorithms in Cryptocurrency Protocols}
|
|
\date{12 October 2014}
|
|
\author[
|
|
addressref={mrl},
|
|
email={lab@monero.cc}
|
|
]{\fnm{Surae} \snm{Noether}}
|
|
\author[
|
|
addressref={mrl}
|
|
email={lab@monero.cc}
|
|
]{\fnm{Sarang} \snm{Noether}}
|
|
|
|
|
|
\address[id=mrl]{
|
|
\orgname{Monero Research Lab}
|
|
}
|
|
\end{fmbox}
|
|
|
|
\begin{abstractbox}
|
|
\begin{abstract}
|
|
|
|
|
|
\end{abstract}
|
|
\end{abstractbox}
|
|
\end{frontmatter}
|
|
|
|
\section{Introduction}\label{intro}
|
|
|
|
For blockchain-based currencies such as Monero and Bitcoin, both transaction verifications and mining rewards occur upon block arrivals. The rate of block arrival is tied to both network hash rate and the block difficulty score. A good block difficulty adjustment method tracks network hash rate such that block arrival rate is kept on target; this ensures that currency rewards for mining are paid on schedule and that transaction verification does not stall. The Monero Research Lab has established that the CryptoNote reference code is suboptimal at tracking network hash rate.
|
|
|
|
As blocks are added to the blockchain, they are assigned a difficulty score; given a state of the blockchain, a new difficulty score is computed, and this is the score to be assigned to the next block. This is the process we refer to as the \textit{difficulty adjustment algorithm}. The new difficulty score depends on the sequence of timestamps of the blocks preceding it, together with those difficulty scores. We have no way of validating a timestamp, and so timestamps are vulnerable to manipulation; the sequence of timestamps need not even be ordered. Hence, mining reward scheduling and transaction verification are vulnerable to manipulation by way of difficulty manipulation.
|
|
|
|
In \cite{kraft2015difficulty}, Kraft presented the first and only formal study regarding difficulty adjustment algorithms. Kraft modeled block arrival rate with a nonhomogeneous Poisson process, established several theorems about such models (including properties of the distributions of block arrival times), computed the expected block arrival time directly utilizing the assumption of exponential growth rate, and derived a difficulty adjustment algorithm utilizing \textit{time-ratio updating}. Kraft also proved these methods converge as a discrete-time linear dynamical system, and used this to develop a stable fixed point iteration scheme as a proposed improvement to the Bitcoin difficulty adjustment algorithm. Kraft established some worst-case scenarios with the idea of quantifying the robustness of the proposal in \cite{kraft2015difficulty} against rapid fluctuations in network hash rate. Lastly, Kraft utilized stochastic simulations of blockchain creation to numerically validate his claim of block arrival rate convergence.
|
|
|
|
In this study, we audit the difficulty adjustment algorithm in the CryptoNote reference code. We establish that the reference code may be exploited by malicious users in several ways. To rectify this, we derive the same model of block arrival rate as Kraft, and we elaborate upon the mechanistic explanation for the model. We re-derive the time-ratio updating first proposed by Kraft. We propose modifications to the Kraft updating, including the usage of a stable nonlinear approach using maximum-likelihood estimates, and we restrict our attention to piecewise constant network hash rates for certain conveniences described in Section \ref{blah}. By choosing a nonlinear updating approach, we guarantee faster-than-exponential convergence and relative insensitivity to small fluctuations in block arrival rate due to noise in the network hash rate. We compare our nonlinear methods with Kraft's linear method, the Bitcoin code, and with the CryptoNote reference code by using stochastic blockchain creation simulations. As a part of our comparison, we investigate a so-called ``timewarp'' attack in which dishonest users manipulate their timestamps according to some predetermined policy.
|
|
|
|
This remainder of this document is arranged in the following manner. In Section \ref{modelBlockChainCreation}, we describe our model of blockchain creation under certain restrictive assumptions, and we note how this model coincides with Kraft's model. Section \ref{referenceCode} describes the difficulty adjustment algorithm of the CryptoNote reference code and the Bitcoin reference code, and compares the resulting blockchain models for each algorithm. In this section, we also investigate how the CryptoNote reference Code may be exploited by attackers who wish to exert disproportionate control over difficulty. In Section \ref{dynamicalSystem}, we verify Kraft's time-ratio updating and derive a nonlinear difficulty adjustment algorithm. In Section \ref{simsAndResults}, we describe the stochastic simulations we use to compare various difficulty adjustment algorithms under a variety of network hash rate scenarios, and we present the results of those simulations.
|
|
|
|
|
|
\section{Our Model of Blockchain Generation}\label{modelBlockChainCreation}
|
|
|
|
In this section, we describe and justify our model of blockchain creation and the assumptions made to generate that model. We also spend some effort to demonstrate how our model coincides with the model presented by Kraft in \cite{kraft2015difficulty}.
|
|
|
|
In order to justify our model, consider the reality of transaction verification in blockchain-based currencies.
|
|
|
|
An unknown (and usually unverifiable) number of nodes agree upon a few particulars about the game, such as a common cryptographic hash function, $\mathcal{H}$, a difficulty adjustment algorithm, a prescribed hash target, $\tau$, and a parent coin selection rule. Nodes bundle ostensibly valid transactions into a block and wish to broadcast these transactions as valid. To prevent malicious users from flooding the network with puppet identities and verifying bad transactions, a moderate cost to broadcasting is implemented by the so-called proof-of-work.
|
|
|
|
If a node wishes to broadcast the validity of a new block, $\mathcal{B}_{new}$, they must discover a nonce, $x$, such that $\mathcal{H}\left(\mathcal{B}_{new} + x\right)\cdot D_{new} < \tau$, where $D_{new}$ is the difficulty of all next blocks (as commonly agreed upon from the start). Since the output of a good cryptographic hash function is practically, if not mathematically, indistinguishable from a uniform random variable, the probability that any given nonce is successful is then inversely proportional to difficulty. That is to say, each hash tested in the proof-of-work game is an independent Bernoulli trial with probability success $p = \tau/D_{new}$. Network hash rate, $H(t)$ (not to be confused with the cryptographic hash function, $\mathcal{H}$), dictates the number of trials run on the network per second.
|
|
|
|
We state the following famous distributional result at our disposal; the proof may be found in \cite{serfozo2009basics} and many other texts on stochastic processes and renewal theory.
|
|
|
|
\begin{thm}[Poisson Law of Rare Events]
|
|
Let $\left\{Y_{n,m}\right\}$ be a countable sequence of independent random variables such that:
|
|
\begin{enumerate}[(i)]
|
|
\item each $Y_{n,m}$ takes on values $0$ or $1$ and
|
|
\item as $n \to \infty$, $\sup_m \mathbb{P}\left\{Y_{n,m} = 1\right\} \to 0$.
|
|
\end{enumerate}
|
|
Then the random variable $Z_n = \sum_m Y_{n,m}$ converges in distribution to a Poisson random variable with mean $\mu = \lim_{n} \sum_{m} \mathbb{P}\left\{Y_{n,m} = 1\right\}$.
|
|
\end{thm}
|
|
|
|
In particular, applying the Poisson Law of Rare Events, we choose $Y_{n,m}$ to be a sequence of independent Bernoulli random variables satisfying both of the following properties
|
|
\begin{enumerate}
|
|
\item for every $n$, there exists some $0 \leq p_n \leq 1$ so that, for every $m = 1, 2, \ldots$, we have $\mathbb{P}\left\{Y_{n,m} = 1\right\} = p_n$ and, furthermore,
|
|
\item there exists some constant $\lambda > 0$ so that $\lim_{n \to \infty} n p_n = \lambda$.
|
|
\end{enumerate}
|
|
We conclude that inter-arrival time is distributionally equivalent to a Poisson process with rate $\lambda$. Here is an example with a few real-life numbers.
|
|
|
|
\begin{Ex}
|
|
Say that the Bitcoin network is currently at $0.35$ exa-hashes per second, difficulty is at $4.8\times 10^{10}$, and we observe the network for two hours, $[0,7200 s]$. Further, say that difficulty is computed as in the original Nakamoto code, where the hash target is a hash with $32$ leading zeros and all remaining digits $1$, i.e.\ our hash target is $\tau = 2^{-32} \approx 2.33 \times 10^{-10}$.
|
|
|
|
Then by subdividing $[0, 7200]$ into $\left(7200\right) \cdot \left(0.35\times 10^{18}\right) = 2.52 \times 10^21$ subintervals of equal length, each subinterval corresponding to a single nonce tested, we shall observe a stochastic process with successes arriving in a distributionally equivalent manner to a Poisson process.
|
|
|
|
In particular, if $n p_n \to \lambda$, then $\lambda$ is the rate of our process. In this case, $n$ is the number of subintervals, i.e.\ the number of hashes that are tested over the time interval $[0,T]$, in this case $2.52 \times 10^{21}$. Also, $p_n$ is the probability that these nonces yield a successful hash. Recall that success occurs if $\mathcal{H}(\cdot) D \leq \tau$, so in our case we have probability of success $2^{-32}/D \approx 4.85 \times 10^{-21}$, and we have block arrival rate $\lambda = (0.35\times 10^{18})\cdot (4.85\times 10^{-21}) \approx 1.70 \times 10^{-3}$. This is arrivals per second; the inverse is about $588$ seconds between arrivals, or $9.8$ minutes per block.
|
|
\end{Ex}
|
|
|
|
\begin{Ex}
|
|
Here is another example from the Monero cryptocurrency, which has a target block arrival rate of $1.0$ minute per block. Presume that we have the same hash target as in the bitcoin code
|
|
\end{Ex}
|
|
|
|
For example, if network hash rate, $H(t)$, is held constant as some $H_0$ hashes per unit time over the time interval, $[0,T]$, then $T\cdot H_0$ nonces were checked on this interval. Subdividing $[0,T]$ into $T\cdot H_0$ equally spaced subintervals, and assigning the result of some Bernoulli trial to each subinterval yields arrival times that are distributionally equivalent
|
|
|
|
|
|
The \textit{a priori}, unobservable network hash rate is not a continuous function, in general; when each new computer joins the network, hash rate increases in a discrete jump. Additionally, network hash rate may be best described as piecewise constant; each node in the network may be presumed to be a CPU, video card, or ASIC that is mining full-bore or is entirely turned off. Smooth increases in network hash rate such as the exponential growth assumed by Kraft may be approximated by piecewise constant with suitably small enough subintervals. On the other hand, a piecewise constant function is also a piecewise exponential function (with zero growth rate) and hence Kraft's results still apply on each subinterval.
|
|
|
|
The \textit{a priori} network graph structure and latency characteristics lead to forking blockchains. In this document, we assume no transmission delay exists in the network so as to study solely the characteristics of the difficulty adjustment algorithm. Under this assumption, all nodes will have equal information at all times, and hence will never disagree on parent coin selection. Violating this assumption with any measure of realism would require some analysis toward various network statistics to capture transmission dynamics. A study would also seem incomplete without investigating alternative parent coin selection rules and the interplay between those rules and various difficulty adjustment algorithms. Kraft implicitly made the same assumption.
|
|
|
|
|
|
|
|
\section{referenceCode}
|
|
|
|
\section{dynamicalSystem}
|
|
|
|
\section{simsAndResults}
|
|
|
|
|
|
%%%%%%%%%%
|
|
|
|
TODO: explain how cn ref code works
|
|
|
|
TODO: show cn ref code can be exploited to amplify or mitigate effect on difficulty by a so-called timewarp attack
|
|
|
|
%%%%%%%%%%%
|
|
|
|
TODO: justify piecewise constant network hash rate, Justify a model of nonhomogeneous Poisson process by Bernoulli,
|
|
|
|
TODO: Re-derive time-ratio updating
|
|
|
|
|
|
TODO: Discuss stability in discrete-time dynamical systems, explain how nonlinear response may yield insensitivity to noise
|
|
|
|
TODO: Derive fixed-point iteration algorithm based on MLE for nonlinear approach, prove convergence.
|
|
|
|
%%%%%%%%%%%
|
|
|
|
TODO: Explain stochastic blockchain creation simulation and how it will be used to test oiur method versus previous methods.
|
|
|
|
TODO: Demonstrate faster-than-exponential convergence in block arrival times to target utilizing our method, compare to previous methods
|
|
|
|
TODO: Demonstrate relative insensitivity to zero-mean noise (up to a certain variance?)
|
|
|
|
TODO: Demonstrate that the strength of an attacker executing a timewarp attack is bounded more strictly in our model than in previous models.
|
|
|
|
%%%%%%%%%%%
|
|
|
|
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
|
|
\newpage
|
|
\begin{appendices}
|
|
\chapter{CryptoNote Difficulty Reference Code}\label{referenceCode}
|
|
|
|
\begin{lstlisting}[language=Python,basicstyle=\small,breaklines=true]
|
|
# DIFFICULTY.py
|
|
# Gives difficulty information over time for blocks with given timestamps
|
|
# Input: block_file WINDOW CUT LAG CHECK_WINDOW [MODE]
|
|
# block_file format: one line per integer timestamp
|
|
# WINDOW: blocks to be used when computing difficulty (720 in practice)
|
|
# CUT: blocks on each side of the block window to exclude (60 in practice)
|
|
# LAG: how far behind we want to be (15 in practice)
|
|
# CHECK_WINDOW: number of blocks to use for median cutoff (60 in practice)
|
|
# [MODE]: 0 = don't sort difficulties (default); 1 = sort difficulties
|
|
# Output: block information, one line per block
|
|
# line format: block_id timestamp next_difficulty cumulative_difficulty
|
|
|
|
import sys
|
|
from math import floor
|
|
|
|
window = int( sys.argv[2] )
|
|
cut = int( sys.argv[3] )
|
|
lag = int( sys.argv[4] )
|
|
check_window = int( sys.argv[5] )
|
|
target = 60
|
|
mode = 0
|
|
try:
|
|
if int( sys.argv[6] ) == 1:
|
|
mode = 1
|
|
except:
|
|
pass
|
|
|
|
print "# window is " + str( window ) + " and cut is " + str( cut )
|
|
|
|
# Read timestamps into an integer array
|
|
block_file = open( sys.argv[1], 'r' )
|
|
timestamps = []
|
|
for line in block_file:
|
|
timestamps.append( floor( float( line.strip() ) ) )
|
|
cumulative_difficulties = []
|
|
|
|
print "# read " + str( len( timestamps ) ) + " blocks"
|
|
|
|
# Apply the median rule
|
|
for i in range( check_window, len( timestamps ) ):
|
|
try:
|
|
median = sum( timestamps[i-check_window:i] )
|
|
if timestamp[i] < median:
|
|
timestamp.pop( i )
|
|
except:
|
|
pass
|
|
|
|
# Compute the difficulty for the next block
|
|
def next_difficulty( timestamps, cumulative_difficulties ):
|
|
if ( len( timestamps ) > window ):
|
|
timestamps = timestamps[0:window]
|
|
cumulative_difficulties = cumulative_difficulties[0:window]
|
|
|
|
length = len( timestamps )
|
|
|
|
# Run some sanity checks
|
|
if len( timestamps ) > window or len( cumulative_difficulties ) > window or len( timestamps ) != len( cumulative_difficulties ):
|
|
raise Exception( "Incorrect number of blocks" )
|
|
if length <= 1:
|
|
return 1
|
|
if window < 2:
|
|
raise Exception( "Window is too small" )
|
|
if ( 2 * cut > window - 2 ):
|
|
raise Exception( "Cut is too large" )
|
|
|
|
timestamps.sort()
|
|
if mode == 1:
|
|
cumulative_difficulties.sort()
|
|
|
|
# Compute the cut indices
|
|
if ( length <= ( window - 2 * cut ) ):
|
|
cut_begin = 0
|
|
cut_end = length
|
|
else:
|
|
cut_begin = int( floor( ( len( timestamps ) - ( window - 2 * cut ) + 1 ) / 2 ) )
|
|
cut_end = cut_begin + window - 2 * cut
|
|
|
|
time_span = timestamps[cut_end-1] - timestamps[cut_begin]
|
|
if time_span == 0:
|
|
time_span = 1
|
|
|
|
total_work = cumulative_difficulties[cut_end-1] - cumulative_difficulties[cut_begin]
|
|
if total_work < 0:
|
|
raise Exception( "Cannot have negative total work" )
|
|
|
|
# Assume high is zero; that is, no overflow
|
|
low = total_work * target
|
|
if low + time_span - 1 < low:
|
|
return 0
|
|
else:
|
|
return int( floor( ( low + time_span - 1 ) / time_span ) )
|
|
|
|
# Start feeding blocks into the difficulty algorithm
|
|
print "# block timestep next_difficulty cumulative_difficulty"
|
|
for i in range( len( timestamps ) ):
|
|
offset = ( i + 1 ) - min( i + 1, window + cut )
|
|
if offset == 0:
|
|
offset = 1
|
|
|
|
difficulty = next_difficulty( timestamps[offset:i], cumulative_difficulties[offset:i] )
|
|
if i == 0:
|
|
cumulative_difficulties.append( 0 )
|
|
else:
|
|
cumulative_difficulties.append( cumulative_difficulties[i-1] + difficulty )
|
|
|
|
# Output
|
|
print ' '.join( map( str, [ i, timestamps[i], difficulty, cumulative_difficulties[i] ] ) )
|
|
\end{lstlisting}
|
|
|
|
|
|
\chapter{New Difficulty Reference Code}\label{referenceCode}
|
|
|
|
\begin{lstlisting}[language=Python,basicstyle=\small,breaklines=true]
|
|
|
|
\end{lstlisting}
|
|
|
|
\end{appendices}
|
|
|
|
\medskip{}
|
|
|
|
\bibliographystyle{plain}
|
|
\bibliography{biblio.bib}
|
|
|
|
\end{document} |