diff --git a/whitepaper/Bath-CS-Dissertation.sty b/whitepaper/Bath-CS-Dissertation.sty new file mode 100644 index 0000000..c06d0b6 --- /dev/null +++ b/whitepaper/Bath-CS-Dissertation.sty @@ -0,0 +1,83 @@ +% Modified by Alessio Guglielmi, 5 October 2020 + +%\NeedsTeXFormat{LaTeX2e}% +\ProvidesPackage{Bath-CS-Dissertation}[2020/10/10 v1.1] + +%% +%% Package includes to provide the basic style +%% +\usepackage[T1]{fontenc} +\usepackage[utf8]{inputenc} +\usepackage{graphicx} % Permits import of various graphics formats +\usepackage{hyperref} % Provides hyperlinks to sections automatically +\usepackage{pdflscape} % Provides landscape mode for end code listings +\usepackage{multicol} % Provides ability to split output into columns +\usepackage{listings} % Provides styled code listings +\usepackage{parskip} % No paragraph indents +\usepackage{pdfpages} % Allows to include PDFs +\usepackage[nottoc,notlot,notlof]{tocbibind} + % Bibliography to appear in TOC +\usepackage{microtype} % Micro typography features +\usepackage[margin=1in]{geometry} + % Margins + +\usepackage{sfmath} % These two lines set the fonts to +\renewcommand{\familydefault}{\sfdefault} % sans-serif + +\usepackage{natbib} % Bibliography and citations +\newcommand*{\urlprefix}{Available from: }% in the Harvard-Bath style +\newcommand*{\urldateprefix}{Accessed } % +\bibliographystyle{bathx} % + +\pagestyle{headings} + +%% +%% Definitions to provide layout in the dissertation title pages +%% + +\newenvironment{spaced}[1] + {\begin{minipage}[c]{\textwidth}\vspace{#1}} + {\end{minipage}} + +\newenvironment{centrespaced}[2] + {\begin{center}\begin{minipage}[c]{#1}\vspace{#2}} + {\end{minipage}\end{center}} + +\newcommand{\consultation}[1]{% +\thispagestyle{empty} +\begin{centrespaced}{0.8\textwidth}{0.4\textheight} +\ifnum #1 = 0 +This dissertation may be made available for consultation within the University Library and may be photocopied or lent to other libraries for the purposes of consultation. +\else +This dissertation may not be consulted, photocopied or lent to other libraries without the permission of the author for #1 +\ifnum #1 = 1 +year +\else +years +\fi +from the date of submission of the dissertation. +\fi +\end{centrespaced} +} + +\newcommand{\declaration}[2]{ + \thispagestyle{empty} + \begin{spaced}{4em} + \begin{center} + \LARGE\textbf{#1} + \end{center} + \end{spaced} + \begin{spaced}{3em} + \begin{center} + Submitted by: #2 + \end{center} + \end{spaced} + \begin{centrespaced}{0.8\textwidth}{0.1\textheight} + \section*{Copyright} +Attention is drawn to the fact that copyright of this dissertation rests with its author. The Intellectual Property Rights of the products produced as part of the project belong to the author unless otherwise specified below, in accordance with the University of Bath's policy on intellectual property (see \url{https://www.bath.ac.uk/publications/university-ordinances/attachments/Ordinances_1_October_2020.pdf}). + +This copy of the dissertation has been supplied on condition that anyone who consults it is understood to recognise that its copyright rests with its author and that no quotation from the dissertation and no information derived from it may be published without the prior written consent of the author. + \section*{Declaration} +This dissertation is submitted to the University of Bath in accordance with the requirements of the degree of Bachelor of Science in the Department of Computer Science. No portion of the work in this dissertation has been submitted in support of an application for any other degree or qualification of this or any other university or institution of learning. Except where specifically acknowledged, it is the work of the author. + \end{centrespaced} + } diff --git a/whitepaper/Dissertation.bib b/whitepaper/Dissertation.bib new file mode 100644 index 0000000..0e10bee --- /dev/null +++ b/whitepaper/Dissertation.bib @@ -0,0 +1,234 @@ +@misc{ + eatsleeput.com_2022, + title={Eatsleeput.com}, + url={https://eatsleeput.com/}, + publisher={EatSleepUT.com}, + year={2022}, + month={Feb}, + note={Archive: https://archive.ph/Gp0Ou} +} + +@misc{cohen_2017, title={BitTorrent.org}, url={https://www.bittorrent.org/beps/bep_0003.html}, journal={bep_0003.rst_post}, author={Cohen, Bram}, year={2017}, month={Feb}} + +@InProceedings{10.1007/3-540-48285-7_24, +author="Benaloh, Josh +and de Mare, Michael", +editor="Helleseth, Tor", +title="One-Way Accumulators: A Decentralized Alternative to Digital Signatures", +booktitle="Advances in Cryptology --- EUROCRYPT '93", +year="1994", +publisher="Springer Berlin Heidelberg", +address="Berlin, Heidelberg", +pages="274--285", +abstract="This paper describes a simple candidate one-way hash function which satisfies a quasi-commutative property that allows it to be used as an accumulator. This property allows protocols to be developed in which the need for a trusted central authority can be eliminated. Space-efficient distributed protocols are given for document time stamping and for membership testing, and many other applications are possible.", +isbn="978-3-540-48285-7" +} + +@INPROCEEDINGS{6956581, +author={Ben Sasson, Eli and Chiesa, Alessandro and Garman, Christina and Green, Matthew and Miers, Ian and Tromer, Eran and Virza, Madars}, +booktitle={2014 IEEE Symposium on Security and Privacy}, +title={Zerocash: Decentralized Anonymous Payments from Bitcoin}, +year={2014}, +volume={}, +number={}, +pages={459-474}, +doi={10.1109/SP.2014.36}} + +@article{doi:10.1137/0220068, + author = {Blum, Manuel and De Santis, Alfredo and Micali, Silvio and Persiano, Giuseppe}, + title = {Noninteractive Zero-Knowledge}, + journal = {SIAM Journal on Computing}, + volume = {20}, + number = {6}, + pages = {1084-1118}, + year = {1991}, + doi = {10.1137/0220068}, + URL = {https://doi.org/10.1137/0220068}, + eprint = {https://doi.org/10.1137/0220068}, + abstract = { This paper investigates the possibility of disposing of interaction between prover and verifier in a zero-knowledge proof if they share beforehand a short random string.Without any assumption, it is proven that noninteractive zero-knowledge proofs exist for some number-theoretic languages for which no efficient algorithm is known.If deciding quadratic residuosity (modulo composite integers whose factorization is not known) is computationally hard, it is shown that the NP-complete language of satisfiability also possesses noninteractive zero-knowledge proofs. } +} + +@article{RABIN1983256, + title = {Transaction protection by beacons}, + journal = {Journal of Computer and System Sciences}, + volume = {27}, + number = {2}, + pages = {256-267}, + year = {1983}, + issn = {0022-0000}, + doi = {https://doi.org/10.1016/0022-0000(83)90042-9}, + url = {https://www.sciencedirect.com/science/article/pii/0022000083900429}, + author = {Michael O. Rabin}, + abstract = {Protocols for implementing contract signing, confidential disclosures, and certified mail in an electronic mail system are proposed. These transactions are provably impossible without a trusted intermediary. However, they can be implemented with just a small probability of a participant cheating his partner, by use of a beacon emitting random integers. Applications include privacy protection of personal information in data banks, as well as the protection of business transactions.} +} + +@InProceedings{merkle, + author="Merkle, Ralph C.", + editor="Pomerance, Carl", + title="A Digital Signature Based on a Conventional Encryption Function", + booktitle="Advances in Cryptology --- CRYPTO '87", + year="1988", + publisher="Springer Berlin Heidelberg", + address="Berlin, Heidelberg", + pages="369--378", + abstract="A new digital signature based only on a conventional encryption function (such as DES) is described which is as secure as the underlying encryption function -- the security does not depend on the difficulty of factoring and the high computational costs of modular arithmetic are avoided. The signature system can sign an unlimited number of messages, and the signature size increases logarithmically as a function of the number of messages signed. Signature size in a `typical' system might range from a few hundred bytes to a few kilobytes, and generation of a signature might require a few hundred to a few thousand computations of the underlying conventional encryption function.", + isbn="978-3-540-48184-3" +} + +@InProceedings{10.1007/978-3-642-02384-2_17, + author="Maurer, Ueli", + editor="Preneel, Bart", + title="Unifying Zero-Knowledge Proofs of Knowledge", + booktitle="Progress in Cryptology -- AFRICACRYPT 2009", + year="2009", + publisher="Springer Berlin Heidelberg", + address="Berlin, Heidelberg", + pages="272--286", + abstract="We present a simple zero-knowledge proof of knowledge protocol of which many protocols in the literature are instantiations. These include Schnorr's protocol for proving knowledge of a discrete logarithm, the Fiat-Shamir and Guillou-Quisquater protocols for proving knowledge of a modular root, protocols for proving knowledge of representations (like Okamoto's protocol), protocols for proving equality of secret values, a protocol for proving the correctness of a Diffie-Hellman key, protocols for proving the multiplicative relation of three commitments (as required in secure multi-party computation), and protocols used in credential systems.", + isbn="978-3-642-02384-2" +} + +@article{10.1145/116825.116852, + author = {Goldreich, Oded and Micali, Silvio and Wigderson, Avi}, + title = {Proofs That Yield Nothing but Their Validity or All Languages in NP Have Zero-Knowledge Proof Systems}, + year = {1991}, + issue_date = {July 1991}, + publisher = {Association for Computing Machinery}, + address = {New York, NY, USA}, + volume = {38}, + number = {3}, + issn = {0004-5411}, + url = {https://doi.org/10.1145/116825.116852}, + doi = {10.1145/116825.116852}, + journal = {J. ACM}, + month = {jul}, + pages = {690–728}, + numpages = {39}, + keywords = {interactive proofs, methodological design of protocols, graph isomorphism, zero-knowledge, one-way functions, proof systems, cryptographic protocols, NP, fault tolerant distributed computing} +} + +@article{mohr2007survey, + title={A survey of zero-knowledge proofs with applications to cryptography}, + author={Mohr, Austin}, + journal={Southern Illinois University, Carbondale}, + pages={1--12}, + year={2007} +} + +@Inbook{Shamir1981, + author="Shamir, Adi + and Rivest, Ronald L. + and Adleman, Leonard M.", + editor="Klarner, David A.", + title="Mental Poker", + bookTitle="The Mathematical Gardner", + year="1981", + publisher="Springer US", + address="Boston, MA", + pages="37--43", + abstract="Can two potentially dishonest players play a fair game of poker without using any cards---for example, over the phone? This paper provides the following answers:1No. (Rigorous mathematical proof supplied.)2Yes. (Correct and complete protocol given.)", + isbn="978-1-4684-6686-7", + doi="10.1007/978-1-4684-6686-7_5", + url="https://doi.org/10.1007/978-1-4684-6686-7_5" +} + +@article{blum1983coin, + title={Coin flipping by telephone a protocol for solving impossible problems}, + author={Blum, Manuel}, + journal={ACM SIGACT News}, + volume={15}, + number={1}, + pages={23--27}, + year={1983}, + publisher={ACM New York, NY, USA} +} + +@InProceedings{blindsig, + author="Chaum, David", + editor="Chaum, David + and Rivest, Ronald L. + and Sherman, Alan T.", + title="Blind Signatures for Untraceable Payments", + booktitle="Advances in Cryptology", + year="1983", + publisher="Springer US", + address="Boston, MA", + pages="199--203", + abstract="Automation of the way we pay for goods and services is already underway, as can be seen by the variety and growth of electronic banking services available to consumers. The ultimate structure of the new electronic payments system may have a substantial impact on personal privacy as well as on the nature and extent of criminal use of payments. Ideally a new payments system should address both of these seemingly conflicting sets of concerns.", + isbn="978-1-4757-0602-4" +} + +@article{bellare2003one, + title={The One-More-RSA-Inversion Problems and the Security of Chaum's Blind Signature Scheme.}, + author={Bellare, Mihir and Namprempre, Chanathip and Pointcheval, David and Semanko, Michael}, + journal={Journal of Cryptology}, + volume={16}, + number={3}, + year={2003}, + publisher={Springer} +} + +@inproceedings{sander1999auditable, + title={Auditable, anonymous electronic cash}, + author={Sander, Tomas and Ta-Shma, Amnon}, + booktitle={Annual International Cryptology Conference}, + pages={555--572}, + year={1999}, + organization={Springer} +} + +@InProceedings{10.1007/978-3-540-89255-7_15, + author="Camenisch, Jan + and Chaabouni, Rafik + and shelat, abhi", + editor="Pieprzyk, Josef", + title="Efficient Protocols for Set Membership and Range Proofs", + booktitle="Advances in Cryptology - ASIACRYPT 2008", + year="2008", + publisher="Springer Berlin Heidelberg", + address="Berlin, Heidelberg", + pages="234--252", + abstract="We consider the following problem: Given a commitment to a value $\sigma$, prove in zero-knowledge that $\sigma$ belongs to some discrete set $\Phi$. The set $\Phi$ can perhaps be a list of cities or clubs; often $\Phi$ can be a numerical range such as [1,220]. This problem arises in e-cash systems, anonymous credential systems, and various other practical uses of zero-knowledge protocols.", + isbn="978-3-540-89255-7" +} + +@inproceedings{paillier1999public, + title={Public-key cryptosystems based on composite degree residuosity classes}, + author={Paillier, Pascal}, + booktitle={International conference on the theory and applications of cryptographic techniques}, + pages={223--238}, + year={1999}, + organization={Springer} +} + +@article{damgaard2010generalization, + title={A generalization of Paillier’s public-key system with applications to electronic voting}, + author={Damg{\aa}rd, Ivan and Jurik, Mads and Nielsen, Jesper Buus}, + journal={International Journal of Information Security}, + volume={9}, + number={6}, + pages={371--385}, + year={2010}, + publisher={Springer} +} + +@phdthesis{groth2004honest, + title={Honest verifier zero-knowledge arguments applied}, + author={Groth, Jens}, + year={2004}, + school={BRICS} +} + +@InProceedings{fiatshamir, + author="Fiat, Amos + and Shamir, Adi", + editor="Odlyzko, Andrew M.", + title="How To Prove Yourself: Practical Solutions to Identification and Signature Problems", + booktitle="Advances in Cryptology --- CRYPTO' 86", + year="1987", + publisher="Springer Berlin Heidelberg", + address="Berlin, Heidelberg", + pages="186--194", + abstract="In this paper we describe simple identification and signature schemes which enable any user to prove his identity and the authenticity of his messages to any other user without shared or public keys. The schemes are provably secure against any known or chosen message attack if factoring is difficult, and typical implementations require only 1{\%} to 4{\%} of the number of modular multiplications required by the RSA scheme. Due to their simplicity, security and speed, these schemes are ideally suited for microprocessor-based devices such as smart cards, personal computers, and remote control systems.", + isbn="978-3-540-47721-1" +} diff --git a/whitepaper/Dissertation.pdf b/whitepaper/Dissertation.pdf new file mode 100644 index 0000000..7723ded Binary files /dev/null and b/whitepaper/Dissertation.pdf differ diff --git a/whitepaper/Dissertation.tex b/whitepaper/Dissertation.tex new file mode 100644 index 0000000..334d6b7 --- /dev/null +++ b/whitepaper/Dissertation.tex @@ -0,0 +1,233 @@ +\documentclass[12pt,a4paper]{report} + +\usepackage{Bath-CS-Dissertation} +\usepackage{amsmath} +\usepackage{amssymb} + + +\title{\textbf{Cryptographic protocol for dishonest players to play Risk} \\ Literature and technology survey and review} +\author{Jude Southworth} +\date{Bachelor of Science in Computer Science and Mathematics \\ + The University of Bath \\ + 2023 \\} + +\begin{document} + +\hypersetup{pageanchor=false} +\renewcommand{\thesection}{\arabic{section}} + +\setcounter{page}{0} +\pagenumbering{arabic} + +\maketitle + +\section{Existing solutions} + +For playing games over an internet connection, multiple solutions already exist. These can roughly be broken down into those that are centralised and those that are decentralised, although many decentralised systems rely on federated or centralised communications for peer discovery. + +\subsection{Centralised} + +In highly centralised networks, traffic is routed to a number of servers that are operated by the same organisation who maintains the game or service. This is the current standard for the majority of the internet: in fact, this is the methodology used by the official version of Risk, playable as an app. + +Without patching the executables, there is no way for a user to run their own servers, or to connect to a third party's server. This has two main advantages: \begin{itemize} + \item \textbf{Moderation.} The developers can enforce their own rules through some form of EULA, and this would be properly enforceable, as if a user is banned from the official servers, there is no alternative. + + \item \textbf{Security.} The server acts as a trusted party, and validates all communications from players. Hence, players cannot subvert a (properly implemented) service's protocol. +\end{itemize} + +\subsection{Peer-to-peer networks} + +In peer-to-peer (P2P) networks, traffic may be routed directly to other peers, or servers may be operated by third parties (sometimes called "federated networks"). This form of communication is still popular in certain games or services, for example BitTorrent is primarily a P2P service; and titles from the Counter-Strike series are federated, with a wide selection of third party hosts. + +The main advantage of peer-to-peer networks over centralised networks is longevity. Games such as Unreal Tournament 99 (which is federated) still have playable servers, as the servers are community-run, and so as long as people still wish to play the game, they will remain online (despite the original developers no longer making any profit from the title) \citep{eatsleeput.com_2022}. + +However, security can often be worse in fully peer-to-peer networks than that of fully centralised networks. Peers may send malicious communications, or behave in ways that violate the general rules of the service. As there is no trusted server, there is no easy way to validate communications to prevent peers from cheating. + +Some peer-to-peer services try to address issues with security. In file-sharing protocols such as BitTorrent, a tracker supplies hashes of the file pieces to validate the file being downloaded \citep{cohen_2017}. However, the downside of this approach is that a trusted party (in this case the tracker) is still required. A malicious tracker could supply bad hashes, or an outdated tracker may expose the peer to security vulnerabilities. + +\subsection{Untrusted setups} + +Currently, there exists an online centralised version of the board game Risk. + +We aim to apply bit-commitment schemes and zero-knowledge proof protocols to an online P2P variant of Risk, to allow peers to play the game whilst preventing cheating and needing no trusted parties. The variant of interest is the "fog of war" variant, where a player cannot see the unit counts of regions besides those that they own or are neighbouring. + +\section{Literature review} + +Centralised systems can securely perform the generation of random values, through using a cryptographically secure random number generator on the server-side, and distributing the values to the clients. This is how dice rolls are processed in centralised online games. However, in a P2P system, something else must be done to simulate the randomness. + +For dice rolling, we want that \begin{itemize} + \item No peer can change the probable outcome of the dice (random), + \item No peer can deny having rolled the dice (non-repudiation). +\end{itemize} +We apply the concept of bit commitment schemes to form these guarantees. + +\subsection{Bit commitment schemes} + +Bit commitment schemes provide a mechanism for one party to commit to some hidden value and reveal it later. This can be achieved through the use of commutative cryptographic algorithms and with one-way functions. + +\subsubsection{Commutative cryptography} + +\cite{Shamir1981} provides a protocol using bit commitment to play poker. They offer a bit commitment scheme using commutative encryption algorithms based on modular arithmetic. This scheme works by each player encrypting cards, and decrypting in a different order as to obscure the value of the actual cards until all players have decrypted. + +Many encryption schemes are not commutative however. One alternative is to use some well-known one-way function, such as SHA, with randomly generated salts. + +\subsubsection{Bit commitment with one-way functions} + +Bit commitment schemes can also be implemented using one-way functions: \begin{enumerate} + \item The first party decides on the value $m$ to be committed to. + \item The first party generates some random value $r$. + \item The first party generates and publishes some value $c = H(m, r)$, where $H$ is an agreed-upon public one-way function. + \item The first party publishes $m$ and $r$ to the second party some time later. + \item The second party computes $c' = H(m, r)$ and validates that $c = c'$. +\end{enumerate} + +\cite{blum1983coin} provides a protocol for flipping fair coins across a telephone, which is isomorphic to selecting a random value from a set of two values. This cannot be simply repeated though to generate numbers in the range of 1-6, as 6 is not a power of 2. + +However, a similar protocol can be used where each player commits to a single value $x \in \mathbb{Z}_6$. As the distribution of outcomes of addition in the group $\mathbb{Z}_n$ is fair, we can then sum the values of $x$ committed to by both players to deduce a final value for the roll. To decrease the amount of communications required for rolling a number of dice, a vector of values can be used. + +This protocol relies only on the ability for one party to produce random numbers. We can consider the $\mathbb{Z}_6$-set on $\mathbb{Z}_6$: upon one party selecting $x \in \mathbb{Z}_6$, the other party's selection is from the group $x \cdot \mathbb{Z}_6 = \{ x + 0, \dots, x + 5 \} \cong \mathbb{Z}_6$. So, the potential outcomes only require one party to select randomly. + +If both parties were to collude and generate non-randomly, this protocol falls through. A potential way around this is to involve other players in the protocol: the same rule applies of only a single player needs to be selecting randomly to produce random outputs. Therefore, so long as there are non-colluding players, this would protect against basic collusion. + +\subsection{Zero-knowledge proofs} + +Zero-knowledge proofs form a subset of minimum disclosure proofs, and beyond that, a subset of interactive proofs. Zero-knowledge proofs are defined by three axioms: \begin{itemize} %todo ref + \item \textbf{Completeness.} If the conjecture is true, an honest verifier will be convinced of its truth by a prover. + \item \textbf{Soundness.} If the conjecture is false, a cheating prover cannot convince an honest verifier (except with some small probability). + \item \textbf{Zero-knowledge.} This is the condition for a minimum disclosure proof to be considered zero-knowledge. If the conjecture is true, the verifier cannot learn any other information besides the truthfulness. +\end{itemize} + +Zero-knowledge proofs are particularly applicable to the presented problem. They primarily solve two problems: \begin{itemize} + \item The disclosure of some information without leaking other information, + \item The proof presented can only be trusted by the verifier, and not by other parties. +\end{itemize} + +We can further formalise the general description of a zero-knowledge proof. \cite{mohr2007survey} provides a common formalisation of the concept of a zero-knowledge proof system for a language $L$ by stating that \begin{itemize} + \item For every $x \in L$, the verifier will accept $x$ following interaction with a prover. + \item For some polynomial $p$ and any $x \notin S$, the verifier will reject $x$ with probability at least $\frac{1}{p(|x|)}$. + \item A verifier can produce a simulator $S$ such that for all $x \in L$, the outputs of $S(x)$ are indistinguishable from a transcript of the proving steps taken with the prover on $x$. +\end{itemize} + +The final point describes a proof as being \textit{computationally zero-knowledge}. Some stronger conditions exist, which describe the distributions of the outputs of the simulator versus the distributions of the outputs of interaction with the prover. \begin{itemize} + \item \textbf{Perfect.} A simulator produced by a verifier produces outputs that are distributed identically to real transcripts. + \item \textbf{Statistical.} A simulator produced by a verifier gives transcripts distributed identically, except for some constant number of exceptions. +\end{itemize} + +Some proofs described are \emph{honest-verifier} zero-knowledge proofs. In these circumstances, the verifier is required to act in accordance with the protocol for the simulator distribution to behave as expected. We consider verifiers as honest, as it appears they may only impede themselves by acting dishonestly. + +\subsubsection{Games as graphs} + +The board used to play Risk can be viewed as an undirected graph. Each region is a node, with edges connecting it to the adjacent regions. For convenience, we also consider the player's hand to be a node, which has all units not in play placed upon it. + +Furthermore, the actions taken when playing the game can be seen as constructing new edges on a directed weighted graph. This makes us interested in the ability to prove that the new edges conform to certain rules. + +The main game protocol can be considered as the following graph mutations for a player $P$: \begin{itemize} + \item \textbf{Reinforcement.} A player updates the weight on some edges of the graph that lead from the hand node $H_P$ to region nodes $R_1, \dots, R_n$ in their control. \begin{itemize} + \item Any adjacent players will then need to undergo proving the number of units on neighbouring regions. + \end{itemize} + + \item \textbf{Attack.} Player $P$ attacks $R_B$ from $R_A$. In the event of losing units, the player updates the edge on the graph from $R_A$ to the hand node $H_P$. + + In the event of winning the attack, the player updates the edge from $R_A$ to $R_B$ to ensure some non-zero amount of units is located in the region. + + \item \textbf{Unit movement.} The player updates an edge from one region $R_1$ to another neighbouring region $R_2$. +\end{itemize} + +The goal is then to identify ways to secure this protocol by obscuring the edges and weights, whilst preventing the ability for the player to cheat. + +\subsubsection{Graphs \& ZKPs} + +\cite{10.1145/116825.116852} identifies methods to construct zero-knowledge proofs for two graphs being isomorphic or non-isomorphic. + +Identifying Risk as a graph therefore enables us to construct isomorphisms as part of the proof protocol. For example, when a player wishes to commit to a movement, it is important to prove that the initial node and the new node are adjacent. This can be proven by communicating isomorphic graphs, and constructing challenges based on the edges of the original graph. + +\subsubsection{Adjacency proofs} + +Proving adjacency of two nodes is akin to proving isomorphism of two graphs. A protocol using challenges could be constructed as follows: \begin{enumerate} + \item The prover commits a new edge between two nodes. + \item The prover constructs an isomorphic graph to the game, and encrypts the edges. + \item The verified challenges either: \begin{itemize} + \item That the graphs are isomorphic. + \item That the new edge is valid. + \end{itemize} + \item The prover sends a total decryption key for the graph's nodes, to prove isomorphism to the game board; or a decryption key for the new edge to the isomorphism, to prove adjacency. +\end{enumerate} + +These challenges restrict the ability for the prover to cheat: if the two nodes they are committing to are not adjacent, either the prover will need to commit an invalid isomorphism (detected by challenge 1), or lie about the edge they have committed (detected by challenge 2). + +Selection between two challenges is the ideal number of challenges to use, as the probability of cheating being detected is $\frac{1}{2}$. Using more challenge options (e.g, $n$) means the likelihood of the prover cheating a single challenge reduces to $\frac{1}{n}$. This would require much larger numbers of communications to then convince the verifier to the same level of certainty. + +Adjacency proofs are necessary to ensure that players move units fairly. + +\subsubsection{Cheating with negative values} + +Zerocash is a ledger system that uses zero-knowledge proofs to ensure consistency and prevent cheating. Ledgers are the main existing use case of zero-knowledge proofs, and there are some limited similarities between ledgers and Risk in how they wish to obscure values of tokens within the system. + +\emph{Publicly-verifiable preprocessing zero-knowledge succinct non-interactive arguments of knowledge} (zk-SNARKs) are the building blocks of Zerocash \citep{6956581}, and its successor Zcash. A zk-SNARK consists of three algorithms: \texttt{KeyGen}, \texttt{Prove}, \texttt{Verify}. + +These are utilised to construct and verify transactions called \texttt{POUR}s. A \texttt{POUR} takes, as input, a certain "coin", and splits this coin into multiple outputs whose values are non-negative and sum to the same value as the input. The output coins may also be associated with different wallet addresses. + +Zerocash then uses zk-SNARKs as a means to prove that the value of the inputs into a \texttt{POUR} is the same as the value of the outputs. This prevents users from generating "debt", or from generating value without going through a minting process (also defined in the Zerocash spec). + +\subsubsection{Ensuring consistency of weights} + +A similar issue appears in the proposed system: a cheating player could update the weights on their graph to cause a region to be "in debt". Therefore, we need the protocol to ensure players prove that the sum of all edges is equal to how many units the player has in play (a well-known value). + +\subsubsection{Additive homomorphic cryptosystems} + +Some cryptosystems admit an additive homomorphic property: that is, given the public key and two encrypted values $\sigma_1 = E(m_1), \sigma_2 = E(m_2)$, the value $\sigma_1 + \sigma_2 = E(m_1 + m_2)$ is the cyphertext of the underlying operation. + +\cite{paillier1999public} defined a cryptosystem based on residuosity classes, which expresses this property. \cite{damgaard2010generalization} demonstrates an honest-verifier zero-knowledge proof for proving a given value is 0. Hence, clearly, proving a summation $a + b = v$ can be performed by proving $v - a - b = 0$ in an additive homomorphic cryptosystem. + +So, using some such scheme to obscure edge weights should enable verification of the edge values without revealing their actual values. + +\subsubsection{Reducing communication} + +In the presented algorithms, interaction is performed fairly constantly, leading to a large number of communications. This will slow the system considerably, and make proofs longer to perform due to network latency. + +An alternative general protocol is the $\Sigma$-protocol \citep{groth2004honest}. In the $\Sigma$-protocol, three communications occur: \begin{itemize} + \item The prover sends the conjecture. + \item The verifier sends a random string. + \item The prover sends some proofs generated using the random string. +\end{itemize} +This reduces the number of communications to a constant, even for varying numbers of challenges. + +The Fiat-Shamir heuristic \citep{fiatshamir} provides a method to further reduce communication by constructing non-interactive zero-knowledge proofs using a random oracle. For ledgers, non-interactive zero-knowledge proofs are necessary, as the ledger must be resilient to a user going offline. However, in our case, users should be expected to stay online for an entire session of Risk, and each session is self-contained. So this full transformation is not necessary. + +\subsubsection{Set membership proofs} + +Another approach to the problem is to use set membership, which is a widely considered problem in zero-proof literature. In this case, each region would be associated with a set of units from a public "pool" of units. Then, a player needs to prove the cardinality of a set, and the uniqueness/distinctness of its members. A number of constructs exist for analysing and proving in obscured sets. + +\subsubsection{Accumulators} + +Defined by \cite{10.1007/3-540-48285-7_24}, accumulators form a subset of one-way hash functions that satisfy a \textit{quasi-commutative} property: that is, for some hash function $h$, $h(h(x_1, y_1), y_2) = h(h(x_1, y_2), y_1)$. + +\cite{10.1007/3-540-48285-7_24} also proved that such functions exist, by providing an example based on modular arithmetic. They then used these to construct set membership proofs as follows: \begin{itemize} + \item Take $s_1, \dots, s_n$ a set of users who wish to identify each other, and $P_k$ a public key. + \item Each user $s_i$ computes $z = h( h( h(P_k, s_1), \dots), s_n)$ and $z_i = h( h( h(P_k, s_1), \dots), s_n)$ omitting $s_i$. + \item For a user to validate their membership to another user, they publish $(z_i, s_i)$. +\end{itemize} + +\subsubsection{Merkle trees} + +Merkle trees \citep{merkle} provide an alternative way of proving set membership, that is more space efficient than accumulators, and doesn't require special hashing functions (any one-way function will work). A Merkle tree stores the hashes of some data in the leaf nodes, and each node above stores the hash of the two nodes below it. The commitment is then the hash of the topmost node. + +With this scheme, the data stored in the leaf nodes is totally obscured. However, the constructor of the tree can demonstrate to another user the presence of some data in the tree by revealing the hashes of a subset of the other nodes in the tree. They can also reveal the tree's structure without revealing any contents by revealing all hashes constituting the tree. + +Whilst this would be useful in a Risk version in which a player never exposed their unit count, and simply wagered units on an attack; it doesn't apply well to the intended scenario of privately communicating unit counts, as the hash function used is well-known, and so proofs to a single player can easily be replicated by a malicious verifier to other players in the game. + +To overcome this issue we want to devise some zero-knowledge system for proving set size. It is then beneficial to consider a public set $U$ containing all of a player's possible units. + +\subsubsection{Blind signatures} + +\cite{blindsig} describes a process of a blind signature, in which a message is signed without the contents being revealed to the signer. This requires some signing function $S$ which commutes with an encrypting function $E$, i.e $E^{-1}(S^{-1}(E(m))) = S^{-1}(m)$. + +\cite{10.1007/978-3-540-89255-7_15} demonstrates how blind signatures can be used to construct zero-knowledge set membership proofs for some element $\sigma$ in a public set $\Phi$, using pairing-based cryptography. + +Blind signatures can also be performed with RSA \citep{bellare2003one}. In RSA-based blind signatures, the signing party computes primes $p_A, q_A$ and exponents $d, e$ such that $(m^d)^e \equiv m \mod p_Aq_A$. The 2-tuple $(p_Aq_A, e)$ is the public key, and is released publicly. The other party computes a random value $R$, and computes and publishes $B = m \cdot R^e \mod p_Aq_A$ for some message $m$. The signing party then replies with $B^d = (m \cdot R^e)^d \equiv m^d \cdot R \mod p_Aq_A$, so that the other party can then extract $m^d$ as $R$ is known only to them. Due to the discrete logarithm problem, determining the signing key $d$ from this is not computationally feasible. Similarly, it is not feasible for the signer to determine $m$, as $R$ is not known to them. + +RSA blinding can incur a security risk, as by using the same keys to sign and encrypt, a player can be tricked into revealing their private key through a chosen-plaintext attack. + +\bibliography{Dissertation} + +\end{document} diff --git a/whitepaper/bathx.bst b/whitepaper/bathx.bst new file mode 100644 index 0000000..e7f6127 --- /dev/null +++ b/whitepaper/bathx.bst @@ -0,0 +1,2480 @@ +%% +%% This is file `bathx.bst', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% bath-bst.dtx (with options: `bst2') +%% ---------------------------------------------------------------- +%% bath-bst --- Harvard referencing style as recommended by the University of Bath Library +%% Author: Alex Ball +%% E-mail: a.j.ball@bath.ac.uk +%% License: Released under the LaTeX Project Public License v1.3c or later +%% See: http://www.latex-project.org/lppl.txt +%% ---------------------------------------------------------------- +%% +ENTRY + { address + archive + author + booktitle + casenumber + chapter + doi + edition + editor + eid + entrysubtype + eprint + eventyear + howpublished + institution + journal + key + keywords + language + library + month + note + number + options + organization + pages + publisher + pubstate + school + series + sortyear + title + titleaddon + translator + type + url + urldate + urlyear + userb + venue + version + volume + year + } + {} + { label extra.label sort.label short.list } +INTEGERS { output.state before.all mid.clause mid.sentence after.sentence after.block } +FUNCTION {init.state.consts} +{ #0 'before.all := + #1 'mid.clause := + #2 'mid.sentence := + #3 'after.sentence := + #4 'after.block := +} +STRINGS { s t } +FUNCTION {output.nonnull} +{ 's := + output.state mid.sentence = + { ", " * write$ } + { output.state after.sentence = + { add.period$ " " * write$ } + { output.state before.all = + 'write$ + { output.state mid.clause = + { " " * write$ } + { add.period$ write$ + newline$ + "\newblock " write$ + } + if$ + } + if$ + } + if$ + mid.sentence 'output.state := + } + if$ + s +} +FUNCTION {end.clause} +{ output.state mid.clause = + { mid.sentence 'output.state := } + 'skip$ + if$ +} +FUNCTION {output} +{ duplicate$ empty$ + { pop$ end.clause } + 'output.nonnull + if$ +} +FUNCTION {output.check} +{ 't := + duplicate$ empty$ + { pop$ "empty " t * " in " * cite$ * warning$ + end.clause + } + 'output.nonnull + if$ +} +FUNCTION {new.block} +{ output.state before.all = + 'skip$ + { after.block 'output.state := } + if$ +} +FUNCTION {new.sentence} +{ output.state after.block = + 'skip$ + { output.state before.all = + 'skip$ + { after.sentence 'output.state := } + if$ + } + if$ +} +FUNCTION {continue.clause} +{ output.state after.sentence = + 'skip$ + { output.state after.block = + 'skip$ + { output.state before.all = + 'skip$ + { mid.clause 'output.state := } + if$ + } + if$ + } + if$ +} +FUNCTION {date.block} +{ new.block +} +FUNCTION {bibinfo.check} +{ swap$ + duplicate$ missing$ + { pop$ pop$ + "" + } + { duplicate$ empty$ + { swap$ pop$ + } + { swap$ + "\bibinfo{" swap$ * "}{" * swap$ * "}" * + } + if$ + } + if$ +} +FUNCTION {bibinfo.warn} +{ swap$ + duplicate$ missing$ + { swap$ "missing " swap$ * " in " * cite$ * warning$ pop$ + "" + } + { duplicate$ empty$ + { swap$ "empty " swap$ * " in " * cite$ * warning$ + } + { swap$ + "\bibinfo{" swap$ * "}{" * swap$ * "}" * + } + if$ + } + if$ +} +FUNCTION {fin.entry} +{ add.period$ + write$ + newline$ +} + +FUNCTION {not} +{ { #0 } + { #1 } + if$ +} +FUNCTION {and} +{ 'skip$ + { pop$ #0 } + if$ +} +FUNCTION {or} +{ { pop$ #1 } + 'skip$ + if$ +} +FUNCTION {new.block.checkb} +{ empty$ + swap$ empty$ + and + 'skip$ + 'new.block + if$ +} +FUNCTION {field.or.null} +{ duplicate$ empty$ + { pop$ "" } + 'skip$ + if$ +} +FUNCTION {emphasize} +{ duplicate$ empty$ + { pop$ "" } + { "\emph{" swap$ * "}" * } + if$ +} +FUNCTION {tie.or.space.prefix} +{ duplicate$ text.length$ #3 < + { "~" } + { " " } + if$ + swap$ +} +FUNCTION {capitalize} +{ "u" change.case$ "t" change.case$ } +FUNCTION {space.word} +{ " " swap$ * " " * } +FUNCTION {either.or.check} +{ empty$ + 'pop$ + { "can't use both " swap$ * " fields in " * cite$ * warning$ } + if$ +} +FUNCTION {is.online} +{ type$ "software" = + { #0 } + { url empty$ doi empty$ and + { type$ "online" = + { #1 } + { #0 } + if$ + } + { #1 } + if$ + } + if$ +} +FUNCTION {bbl.and} +{ "and"} + +FUNCTION {bbl.etal} +{ "et~al." } + +FUNCTION {bbl.editors} +{ "eds" } + +FUNCTION {bbl.editor} +{ "ed." } + +FUNCTION {bbl.edby} +{ "edited by" } + +FUNCTION {bbl.translator} +{ "Trans." } + +FUNCTION {bbl.edition} +{ "ed." } + +FUNCTION {bbl.volume} +{ "vol." } + +FUNCTION {bbl.of} +{ "of" } + +FUNCTION {bbl.number} +{ "no." } + +FUNCTION {bbl.nr} +{ "no." } + +FUNCTION {bbl.in} +{ "in" } + +FUNCTION {bbl.pages} +{ "pp." } + +FUNCTION {bbl.page} +{ "p." } + +FUNCTION {bbl.chapter} +{ "chap." } + +FUNCTION {bbl.techrep} +{ "Tech. Rep." } + +FUNCTION {bbl.mthesis} +{ "Master's thesis" } + +FUNCTION {bbl.phdthesis} +{ "Ph.D. thesis" } + +FUNCTION {bbl.first} +{ "1st" } + +FUNCTION {bbl.second} +{ "2nd" } + +FUNCTION {bbl.third} +{ "3rd" } + +FUNCTION {bbl.fourth} +{ "4th" } + +FUNCTION {bbl.fifth} +{ "5th" } + +FUNCTION {bbl.st} +{ "st" } + +FUNCTION {bbl.nd} +{ "nd" } + +FUNCTION {bbl.rd} +{ "rd" } + +FUNCTION {bbl.th} +{ "th" } + +FUNCTION {bbl.commission} +{ "Commission Decision" } + +FUNCTION {bbl.online} +{ "[Online]" } + +FUNCTION {bbl.nodate} +{ "n.d." } + +FUNCTION {bbl.inpreparation} +{ "preprint" } + +FUNCTION {bbl.submitted} +{ "preprint" } + +FUNCTION {bbl.inpress} +{ "in press" } + +FUNCTION {bbl.unpublished} +{ "Unpublished" } + +MACRO {jan} {"January"} + +MACRO {feb} {"February"} + +MACRO {mar} {"March"} + +MACRO {apr} {"April"} + +MACRO {may} {"May"} + +MACRO {jun} {"June"} + +MACRO {jul} {"July"} + +MACRO {aug} {"August"} + +MACRO {sep} {"September"} + +MACRO {oct} {"October"} + +MACRO {nov} {"November"} + +MACRO {dec} {"December"} + +FUNCTION {eng.ord} +{ duplicate$ "1" swap$ * + #-2 #1 substring$ "1" = + { bbl.th * } + { duplicate$ #-1 #1 substring$ + duplicate$ "1" = + { pop$ bbl.st * } + { duplicate$ "2" = + { pop$ bbl.nd * } + { "3" = + { bbl.rd * } + { bbl.th * } + if$ + } + if$ + } + if$ + } + if$ +} + +INTEGERS { nameptr namesleft numnames } +STRINGS { bibinfo } +FUNCTION {format.names} +{ 'bibinfo := + duplicate$ empty$ + 'skip$ + { 's := + "" 't := + #1 'nameptr := + s num.names$ 'numnames := + numnames 'namesleft := + { namesleft #0 > } + { s nameptr + "{ll}{, jj}{, f{.}.}{~vv}" + format.name$ + bibinfo bibinfo.check + 't := + nameptr #1 > + { namesleft #1 > + { ", " * t * } + { s nameptr "{ll}" format.name$ duplicate$ "others" = + { 't := } + { pop$ } + if$ + t "others" = + { " " * bbl.etal * + } + { bbl.and + space.word * t * + } + if$ + } + if$ + } + 't + if$ + nameptr #1 + 'nameptr := + namesleft #1 - 'namesleft := + } + while$ + } + if$ +} +FUNCTION {format.names.ed} +{ 'bibinfo := + duplicate$ empty$ + 'skip$ + { 's := + "" 't := + #1 'nameptr := + s num.names$ 'numnames := + numnames 'namesleft := + { namesleft #0 > } + { s nameptr + "{f{.}.~}{vv~}{ll}{ jj}" + format.name$ + bibinfo bibinfo.check + 't := + nameptr #1 > + { namesleft #1 > + { ", " * t * } + { s nameptr "{ll}" format.name$ duplicate$ "others" = + { 't := } + { pop$ } + if$ + t "others" = + { " " * bbl.etal * + } + { bbl.and + space.word * t * + } + if$ + } + if$ + } + 't + if$ + nameptr #1 + 'nameptr := + namesleft #1 - 'namesleft := + } + while$ + } + if$ +} +FUNCTION {format.authors} +{ author "author" format.names +} +FUNCTION {get.bbl.editor} +{ editor num.names$ #1 > 'bbl.editors 'bbl.editor if$ } +FUNCTION {format.editors} +{ editor "editor" format.names duplicate$ empty$ 'skip$ + { "," * + " " * + get.bbl.editor + * + } + if$ +} +FUNCTION {format.translators} +{ translator "translator" format.names.ed duplicate$ empty$ 'skip$ + { "," * + " " * + bbl.translator * + "(" swap$ * + ")" * + } + if$ +} +FUNCTION {format.full.names} +{'s := + "" 't := + #1 'nameptr := + s num.names$ 'numnames := + numnames 'namesleft := + { namesleft #0 > } + { s nameptr + "{vv~}{ll}" format.name$ + 't := + nameptr #1 > + { namesleft #1 > + { ", " * t * } + { s nameptr "{ll}" format.name$ duplicate$ "others" = + { 't := } + { pop$ } + if$ + t "others" = + { " " * bbl.etal * + } + { bbl.and + space.word * t * + } + if$ + } + if$ + } + 't + if$ + nameptr #1 + 'nameptr := + namesleft #1 - 'namesleft := + } + while$ +} +FUNCTION {author.editor.key.full} +{ author empty$ + { editor empty$ + { key empty$ + { cite$ #1 #3 substring$ } + 'key + if$ + } + { editor format.full.names } + if$ + } + { author format.full.names } + if$ +} +FUNCTION {editor.key.full} +{ editor empty$ + { key empty$ + { cite$ #1 #3 substring$ } + 'key + if$ + } + { editor format.full.names } + if$ +} +FUNCTION {author.key.full} +{ author empty$ + { key empty$ + { cite$ #1 #3 substring$ } + 'key + if$ + } + { author format.full.names } + if$ +} +FUNCTION {make.full.names} +{ type$ "book" = + type$ "inbook" = + or + 'author.editor.key.full + { type$ "proceedings" = + 'editor.key.full + 'author.key.full + if$ + } + if$ +} +FUNCTION {output.bibitem} +{ newline$ + "\bibitem[{" write$ + label write$ + ")" make.full.names duplicate$ short.list = + { pop$ } + { * } + if$ + "}]{" * write$ + cite$ write$ + "}" write$ + newline$ + "" + before.all 'output.state := +} +FUNCTION {format.key} +{ empty$ + { key field.or.null } + { "" } + if$ +} +FUNCTION {select.language} +{ duplicate$ empty$ + 'pop$ + { language empty$ + 'skip$ + { "{\selectlanguage{" language * "}" * swap$ * "}" * } + if$ + } + if$ +} +FUNCTION {format.title} +{ title + duplicate$ empty$ 'skip$ + { "t" change.case$ } + if$ + "title" bibinfo.check + duplicate$ empty$ + 'skip$ + { select.language } + if$ +} +FUNCTION {format.btitle} +{ title + duplicate$ empty$ 'skip$ + { "t" change.case$ } + if$ + "title" bibinfo.check + duplicate$ empty$ 'skip$ + { emphasize + select.language + } + if$ +} +FUNCTION {format.titleaddon} +{ titleaddon + duplicate$ empty$ 'skip$ + { "[" swap$ "titleaddon" bibinfo.check * "]" * } + if$ +} +FUNCTION {format.version} +{ version + duplicate$ empty$ 'skip$ + { "(v." swap$ * + "version" bibinfo.check + ")" * + } + if$ +} +FUNCTION {get.title.addenda} +{ continue.clause + format.version output + continue.clause + format.titleaddon output + continue.clause + library empty$ + type$ "image" = + or + is.online + and + journal empty$ + and + type empty$ + type$ "booklet" = not + type$ "audio" = not + and + type$ "video" = not + and + type$ "music" = not + and + type$ "movie" = not + and + or + and + { bbl.online output } + 'skip$ + if$ + continue.clause + format.translators output +} +FUNCTION {word.in} +{ bbl.in capitalize + ":" * + " " * } +FUNCTION {format.booktitle} +{ booktitle + duplicate$ empty$ 'skip$ + { "t" change.case$ } + if$ + "booktitle" bibinfo.check + emphasize +} +FUNCTION {format.in.ed.booktitle} +{ format.booktitle duplicate$ empty$ 'skip$ + { editor "editor" format.names.ed duplicate$ empty$ 'pop$ + { "," * + " " * + get.bbl.editor add.period$ + " " * + * swap$ + * + word.in swap$ * + } + if$ + } + if$ +} +FUNCTION {legal.journal.shape} +{ duplicate$ "OJ" = + 'emphasize + 'skip$ + if$ +} +FUNCTION {nodate.check} +{ +duplicate$ empty$ + sortyear empty$ + and + { options field.or.null "nonodate" = + 'skip$ + { pop$ bbl.nodate } + if$ + } + 'skip$ + if$ +} +FUNCTION {format.date} +{ year "year" bibinfo.check nodate.check + extra.label * +} +FUNCTION {format.date.brackets} +{ format.date + "[" swap$ * "]" * +} +FUNCTION {format.date.parens} +{ format.date + "(" swap$ * ")" * +} +FUNCTION {format.jur.date.essential} +{ options field.or.null "scottish-style" = + keywords field.or.null "sc" = + or + 'format.date + 'format.date.brackets + if$ +} +FUNCTION {format.jur.date} +{ journal field.or.null 's := + s "OJ" = + s "ECR" = + or + 'format.date.brackets + { options field.or.null "year-essential=false" = + 'format.date.parens + { volume empty$ + 'format.jur.date.essential + { options field.or.null "year-essential=true" = + 'format.jur.date.essential + 'format.date.parens + if$ + } + if$ + } + if$ + } + if$ +} +FUNCTION {format.eu.date} +{ journal field.or.null 's := + s "OJ" = + s "ECR" = + or + 'format.date.brackets + 'format.date + if$ +} +FUNCTION {format.bvolume} +{ volume empty$ + { "" } + { bbl.volume volume tie.or.space.prefix + "volume" bibinfo.check * * + series "series" bibinfo.check + duplicate$ empty$ 'pop$ + { emphasize ", " * swap$ * } + if$ + "volume and number" number either.or.check + } + if$ +} +FUNCTION {format.number.series} +{ volume empty$ + { number empty$ + { series field.or.null } + { series empty$ + { number "number" bibinfo.check } + { series "series" bibinfo.check + number tie.or.space.prefix "number" bibinfo.check * * + } + if$ + } + if$ + } + { "" } + if$ +} +FUNCTION {is.num} +{ chr.to.int$ + duplicate$ "0" chr.to.int$ < not + swap$ "9" chr.to.int$ > not and +} +FUNCTION {extract.num} +{ duplicate$ 't := + "" 's := + { t empty$ not } + { t #1 #1 substring$ + t #2 global.max$ substring$ 't := + duplicate$ is.num + { s swap$ * 's := } + { pop$ "" 't := } + if$ + } + while$ + s empty$ + 'skip$ + { pop$ s } + if$ +} +FUNCTION {convert.edition} +{ extract.num "l" change.case$ 's := + s "first" = s "1" = or + { bbl.first 't := } + { s "second" = s "2" = or + { bbl.second 't := } + { s "third" = s "3" = or + { bbl.third 't := } + { s "fourth" = s "4" = or + { bbl.fourth 't := } + { s "fifth" = s "5" = or + { bbl.fifth 't := } + { s #1 #1 substring$ is.num + { s eng.ord 't := } + { edition 't := } + if$ + } + if$ + } + if$ + } + if$ + } + if$ + } + if$ + t +} +FUNCTION {format.edition} +{ edition duplicate$ empty$ 'skip$ + { convert.edition + output.state mid.sentence = + { "l" } + { "t" } + if$ change.case$ + "edition" bibinfo.check + " " * bbl.edition * + } + if$ +} +FUNCTION {format.thesis.type} +{ type duplicate$ empty$ + 'pop$ + { swap$ pop$ + "t" change.case$ "type" bibinfo.check + } + if$ +} +FUNCTION {format.booklet.type} +{ type duplicate$ empty$ + { pop$ "" } + { "type" bibinfo.check + is.online author empty$ and editor empty$ and + { " " * bbl.online * } + 'skip$ + if$ + } + if$ +} +FUNCTION {add.cmd.number} +{ ". " swap$ "number" bibinfo.check * +} +FUNCTION {format.legr.number} +{ series field.or.null 's := + s "C" = + 'add.cmd.number + { s "Cd" = + 'add.cmd.number + { s "Cmd" = + 'add.cmd.number + { s "Cmnd" = + 'add.cmd.number + { s "Cm" = + 'add.cmd.number + { s #1 #3 substring$ 't := + t "HL " = + { ", (" swap$ + "number" bibinfo.check * + ")" * + } + { ", " swap$ + "number" bibinfo.check * + } + if$ + } + if$ + } + if$ + } + if$ + } + if$ + } + if$ +} +FUNCTION {format.tr.number} +{ series duplicate$ empty$ + { pop$ + type duplicate$ empty$ + { pop$ + number duplicate$ empty$ + { pop$ "" + } + { "(" swap$ + "number" bibinfo.check + * ")" * + } + if$ + } + { "(" swap$ + "t" change.case$ "type" bibinfo.check + * + number duplicate$ empty$ + 'pop$ + { tie.or.space.prefix + "number" bibinfo.check + * * + } + if$ + ")" * + } + if$ + } + { "(" swap$ * + type duplicate$ empty$ + { pop$ + number duplicate$ empty$ + 'pop$ + { format.legr.number * } + if$ + } + { "t" change.case$ "type" bibinfo.check + * + number duplicate$ empty$ + 'pop$ + { tie.or.space.prefix + "number" bibinfo.check + * * + } + if$ + } + if$ + ")" * + continue.clause + } + if$ +} +FUNCTION {format.manual.number} +{ series duplicate$ empty$ + { pop$ + type duplicate$ empty$ + { pop$ + number duplicate$ empty$ + { pop$ "" + } + { "number" bibinfo.check + } + if$ + } + { "t" change.case$ "type" bibinfo.check + number duplicate$ empty$ + 'pop$ + { tie.or.space.prefix + "number" bibinfo.check + * * + } + if$ + } + if$ + } + { number duplicate$ empty$ + 'pop$ + { tie.or.space.prefix + "number" bibinfo.check + * * + } + if$ + type duplicate$ empty$ + 'pop$ + { ", " swap$ * + "t" change.case$ "type" bibinfo.check + * + } + if$ + } + if$ +} +FUNCTION {format.chapter} +{ chapter duplicate$ empty$ + { pop$ "" } + { "chapter" bibinfo.check + "c." swap$ * + } + if$ +} +FUNCTION {format.series.number.chapter} +{ series duplicate$ empty$ + { pop$ "(" } + { "series" bibinfo.check + "(" swap$ * + } + if$ + type duplicate$ empty$ + { pop$ + number duplicate$ empty$ + 'pop$ + { "number" bibinfo.check + swap$ duplicate$ "(" = + { swap$ * } + { ", " * swap$ * } + if$ + } + if$ + chapter duplicate$ empty$ + 'pop$ + { "chapter" bibinfo.check + swap$ duplicate$ "(" = + { swap$ * } + { ", c." * swap$ * } + if$ + } + if$ + } + { "type" bibinfo.check + swap$ duplicate$ "(" = + { swap$ * } + { ", " * swap$ * } + if$ + number duplicate$ empty$ + { pop$ + chapter duplicate$ empty$ + 'pop$ + { "chapter" bibinfo.check + " c." swap$ * * + } + if$ + } + { "number" bibinfo.check + " " swap$ * * + chapter duplicate$ empty$ + 'pop$ + { "chapter" bibinfo.check + ", c." swap$ * * + } + if$ + } + if$ + } + if$ + ")" * + duplicate$ "()" = + { pop$ "" } + 'skip$ + if$ +} +FUNCTION {format.case.number} +{ casenumber duplicate$ empty$ + { pop$ + number duplicate$ empty$ + { pop$ "" } + { institution field.or.null "Commission" = + userb empty$ not + and + { userb "userb" bibinfo.check + "(" swap$ * ") " * bbl.commission * " " * + swap$ "number" bibinfo.check * + } + { "number" bibinfo.check + "(" swap$ * ")" * + } + if$ + } + if$ + } + { "casenumber" bibinfo.check + "(" swap$ * ")" * + institution field.or.null "Commission" = + number empty$ not + and + { " " * bbl.commission * " " * + number "number" bibinfo.check * + } + 'skip$ + if$ + } + if$ +} +FUNCTION {eu.case.check} +{ journal field.or.null "OJ" = + number empty$ not + or + casenumber empty$ not + or + 'continue.clause + 'new.block + if$ +} +FUNCTION {format.note} +{ note empty$ + { "" } + { note #1 #1 substring$ + duplicate$ "{" = + 'skip$ + { output.state mid.sentence = + output.state mid.clause = + or + { "l" } + { "u" } + if$ + change.case$ + } + if$ + note #2 global.max$ substring$ * "note" bibinfo.check + } + if$ +} +FUNCTION {format.org.or.pub} +{ 't := + "" + address empty$ t empty$ and + 'skip$ + { address "address" bibinfo.check * + t empty$ + 'skip$ + { address empty$ + 'skip$ + { ": " * } + if$ + t * + } + if$ + } + if$ +} +FUNCTION {format.publisher.address} +{ publisher "publisher" bibinfo.warn format.org.or.pub +} +FUNCTION {format.organization.address} +{ publisher empty$ + { organization "organization" bibinfo.check format.org.or.pub } + { publisher "publisher" bibinfo.warn format.org.or.pub + organization duplicate$ empty$ + 'pop$ + { "organization" bibinfo.check ". " * swap$ * } + if$ + } + if$ +} +FUNCTION {format.institution.address} +{ publisher empty$ + { institution "institution" bibinfo.check format.org.or.pub } + { publisher "publisher" bibinfo.warn format.org.or.pub + institution duplicate$ empty$ + 'pop$ + { "institution" bibinfo.check ". " * swap$ * } + if$ + } + if$ +} +FUNCTION {format.library} +{ library "library" bibinfo.check + emphasize + duplicate$ empty$ not + is.online + and + journal empty$ + and + { " " * bbl.online * } + 'skip$ + if$ +} +FUNCTION {format.img.library} +{ library duplicate$ empty$ + { pop$ "" } + { "library" bibinfo.check + "At: " swap$ * + } + if$ +} +FUNCTION {format.img.library.address} +{ address empty$ library empty$ and institution empty$ and + { "" } + { "At: " + address "address" bibinfo.check * + library duplicate$ empty$ + { institution duplicate$ empty$ + { pop$ "" } + { address empty$ + 'skip$ + { ". " swap$ } + if$ + "institution" bibinfo.check * * + } + if$ + } + { address empty$ + 'skip$ + { ". " swap$ } + if$ + "library" bibinfo.check * * + } + if$ + } + if$ +} +FUNCTION {format.pub.org.lib.address} +{ publisher duplicate$ empty$ + { pop$ + organization duplicate$ empty$ + { pop$ + format.img.library.address } + { "organization" bibinfo.check + library empty$ + { format.org.or.pub } + { ". " * + format.img.library.address * + } + if$ + } + if$ + } + { "publisher" bibinfo.warn format.org.or.pub + library empty$ + 'skip$ + { ". " * + format.img.library * + } + if$ + } + if$ +} + +INTEGERS { multiresult } +FUNCTION {multi.page.check} +{ 't := + #0 'multiresult := + { multiresult not + t empty$ not + and + } + { t #1 #1 substring$ + duplicate$ "-" = + swap$ duplicate$ "," = + swap$ "+" = + or or + { #1 'multiresult := } + { t #2 global.max$ substring$ 't := } + if$ + } + while$ + multiresult +} +FUNCTION {n.dashify} +{ 't := + "" + { t empty$ not } + { t #1 #1 substring$ "-" = + { t #1 #2 substring$ "--" = not + { "--" * + t #2 global.max$ substring$ 't := + } + { { t #1 #1 substring$ "-" = } + { "-" * + t #2 global.max$ substring$ 't := + } + while$ + } + if$ + } + { t #1 #1 substring$ * + t #2 global.max$ substring$ 't := + } + if$ + } + while$ +} +FUNCTION {format.pages} +{ pages duplicate$ empty$ 'skip$ + { duplicate$ multi.page.check + { bbl.pages swap$ + n.dashify + } + { bbl.page swap$ + } + if$ + "pages" bibinfo.check + * + } + if$ +} +FUNCTION {format.journal.pages} +{ pages duplicate$ empty$ 'pop$ + { swap$ duplicate$ empty$ + { pop$ pop$ format.pages } + { ", " * + swap$ + n.dashify + pages multi.page.check + 'bbl.pages + 'bbl.page + if$ + swap$ + "pages" bibinfo.check + * * + } + if$ + } + if$ +} +FUNCTION {format.journal.eid} +{ eid "eid" bibinfo.check + duplicate$ empty$ 'pop$ + { swap$ duplicate$ empty$ 'skip$ + { ", " * + } + if$ + swap$ * + } + if$ +} +FUNCTION {format.vol.num.pages} +{ pubstate field.or.null + duplicate$ "inpress" = + { pop$ bbl.inpress } + { duplicate$ "submitted" = + { pop$ bbl.submitted } + { duplicate$ "inpreparation" = + { pop$ bbl.inpreparation } + { pop$ "" } + if$ + } + if$ + } + if$ + duplicate$ empty$ + { pop$ + volume field.or.null + duplicate$ empty$ 'skip$ + { "volume" bibinfo.check + } + if$ + number "number" bibinfo.check duplicate$ empty$ 'skip$ + { swap$ duplicate$ empty$ + { "there's a number but no volume in " cite$ * warning$ } + 'skip$ + if$ + swap$ + "(" swap$ * ")" * + } + if$ * + eid empty$ + { format.journal.pages } + { format.journal.eid } + if$ + } + 'skip$ + if$ +} +FUNCTION {format.chapter.pages} +{ chapter empty$ + 'format.pages + { type empty$ + { bbl.chapter } + { type "l" change.case$ + "type" bibinfo.check + } + if$ + chapter tie.or.space.prefix + "chapter" bibinfo.check + * * + pages empty$ + 'skip$ + { ", " * format.pages * } + if$ + } + if$ +} +FUNCTION {format.journal.series.vol.pages} +{ journal field.or.null + duplicate$ "OJ" = + { "journal" bibinfo.check + emphasize + series empty$ + volume empty$ + and + pages empty$ + and + 'skip$ + { " " * } + if$ + series "series" bibinfo.check + volume "volume" bibinfo.check * + duplicate$ empty$ + 'skip$ + { pages field.or.null duplicate$ empty$ + 'skip$ + { "/" swap$ * + } + if$ * + } + if$ * + } + { duplicate$ "ECR" = + { "journal" bibinfo.check + volume "volume" bibinfo.check + duplicate$ empty$ + 'skip$ + { " " swap$ * "--" * * } + if$ + } + { "journal" bibinfo.check + is.online + { " " * bbl.online * } + 'skip$ + if$ + volume "volume" bibinfo.check + duplicate$ empty$ + 'pop$ + { " " * swap$ * } + if$ + pages empty$ + eid empty$ + and + 'skip$ + { " " * } + if$ + } + if$ + } + if$ + eid empty$ + { pages "pages" bibinfo.check * } + { eid "eid" bibinfo.check * } + if$ +} +FUNCTION {format.eprint} +{ eprint duplicate$ empty$ + 'skip$ + { "\eprint" + archive empty$ + 'skip$ + { "[" * archive * "]" * } + if$ + "{" * swap$ * "}" * + } + if$ +} +FUNCTION {format.url} +{ doi empty$ + { url } + { "https://doi.org/" doi * } + if$ + duplicate$ empty$ + { pop$ "" } + { "\urlprefix\url{" swap$ * "}" * } + if$ + urlyear empty$ + { urldate empty$ + 'skip$ + { " [\urldateprefix{}" * urldate * "]" * } + if$ + } + { " [\urldateprefix{}" * urlyear * "]" * } + if$ +} +FUNCTION {format.article.crossref} +{ word.in + " \cite{" * crossref * "}" * +} +FUNCTION {format.incoll.inproc.crossref} +{ word.in + " \cite{" * crossref * "}" * +} +FUNCTION {format.book.crossref} +{ volume duplicate$ empty$ + { "empty volume in " cite$ * "'s crossref of " * crossref * warning$ + pop$ word.in + } + { bbl.volume + capitalize + swap$ tie.or.space.prefix "volume" bibinfo.check * * bbl.of space.word * + } + if$ + " \cite{" * crossref * "}" * +} + +FUNCTION {article} +{ output.bibitem + format.authors "author" output.check + author format.key output + format.date "year" output.check + date.block + format.title "title" output.check + get.title.addenda + new.block + crossref missing$ + { journal "t" change.case$ + "journal" bibinfo.check + emphasize + "journal" output.check + is.online + { continue.clause + bbl.online output + } + 'skip$ + if$ + format.vol.num.pages output + } + { format.article.crossref output.nonnull + format.pages output + } + if$ + new.block + format.note output + new.block + format.eprint output + format.url output + fin.entry +} +FUNCTION {book} +{ output.bibitem + author empty$ + { editor empty$ + { format.btitle "title" output.check + format.date "year" output.check + year empty$ 'skip$ { date.block } if$ + get.title.addenda + } + { format.editors "author and editor" output.check + editor format.key output + format.date "year" output.check + date.block + format.btitle "title" output.check + get.title.addenda + } + if$ + } + { format.authors output.nonnull + crossref missing$ + { "author and editor" editor either.or.check } + 'skip$ + if$ + format.date "year" output.check + date.block + format.btitle "title" output.check + get.title.addenda + } + if$ + format.bvolume output + format.number.series output + new.block + format.edition output + crossref missing$ + { new.sentence + format.publisher.address output + } + { new.block + format.book.crossref output.nonnull + } + if$ + new.block + format.note output + new.block + format.eprint output + format.url output + fin.entry +} +FUNCTION {booklet} +{ output.bibitem + author empty$ + { format.btitle "title" output.check + format.date "year" output.check + year empty$ 'skip$ { date.block } if$ + get.title.addenda + } + { format.authors output + author format.key output + format.date "year" output.check + date.block + format.btitle "title" output.check + get.title.addenda + } + if$ + new.block + format.booklet.type output + new.block + howpublished "howpublished" bibinfo.check output + new.block + format.note output + publisher empty$ 'skip$ + { new.block} + if$ + format.publisher.address output + new.block + format.eprint output + format.url output + fin.entry +} +FUNCTION {inbook} +{ output.bibitem + author empty$ + { format.editors "author and editor" output.check + editor format.key output + } + { format.authors output.nonnull + crossref missing$ + { "author and editor" editor either.or.check } + 'skip$ + if$ + } + if$ + format.date "year" output.check + date.block + format.btitle "title" output.check + get.title.addenda + crossref missing$ + { format.publisher.address output + format.bvolume output + format.chapter.pages "chapter and pages" output.check + new.block + format.number.series output + new.sentence + } + { format.chapter.pages "chapter and pages" output.check + new.block + format.book.crossref output.nonnull + } + if$ + format.edition output + new.block + format.note output + new.block + format.eprint output + format.url output + fin.entry +} +FUNCTION {incollection} +{ output.bibitem + format.authors "author" output.check + author format.key output + format.date "year" output.check + date.block + format.title "title" output.check + get.title.addenda + new.block + crossref missing$ + { format.in.ed.booktitle "booktitle" output.check + new.block + format.publisher.address output + format.bvolume output + format.number.series output + format.chapter.pages output + new.sentence + format.edition output + } + { format.incoll.inproc.crossref output.nonnull + format.chapter.pages output + } + if$ + new.block + format.note output + new.block + format.eprint output + format.url output + fin.entry +} +FUNCTION {inproceedings} +{ output.bibitem + format.authors "author" output.check + author format.key output + format.date "year" output.check + date.block + format.title "title" output.check + get.title.addenda + new.block + crossref missing$ + { format.in.ed.booktitle "booktitle" output.check + eventyear output + venue output + new.sentence + publisher empty$ + { format.organization.address output } + { organization "organization" bibinfo.check output + format.publisher.address output + } + if$ + format.bvolume output + format.number.series output + format.pages output + } + { format.incoll.inproc.crossref output.nonnull + format.pages output + } + if$ + new.block + format.note output + new.block + format.eprint output + format.url output + fin.entry +} +FUNCTION {conference} { inproceedings } +FUNCTION {jurisdiction} +{ output.bibitem + author empty$ + { format.btitle "title" output.check + continue.clause + format.case.number output + number empty$ + casenumber empty$ + and + 'new.sentence + 'continue.clause + if$ + format.jur.date "year" output.check + year empty$ 'skip$ { eu.case.check } if$ + get.title.addenda + } + { format.authors output + author format.key output + format.jur.date "year" output.check + date.block + continue.clause + format.btitle "title" output.check + get.title.addenda + } + if$ + eu.case.check + format.note output + note empty$ + 'eu.case.check + 'new.block + if$ + crossref missing$ + { continue.clause + format.journal.series.vol.pages output + } + { format.article.crossref output.nonnull + format.pages output + } + if$ + new.block + format.eprint output + format.url output + fin.entry +} +FUNCTION {uklegislation} +{ output.bibitem + author empty$ + { format.btitle "title" output.check + continue.clause + format.date emphasize "year" output.check + get.title.addenda + } + { format.authors output + author format.key output + format.date "year" output.check + date.block + continue.clause + format.btitle "title" output.check + get.title.addenda + } + if$ + entrysubtype field.or.null "secondary" = + { number "number" bibinfo.check output } + { series empty$ type empty$ and + { number empty$ + { format.chapter output } + { continue.clause + format.series.number.chapter output + } + if$ + } + { chapter empty$ + { new.block } + { continue.clause } + if$ + format.series.number.chapter output + } + if$ + } + if$ + note empty$ + 'skip$ + { new.block + format.note output + new.block + } + if$ + publisher empty$ 'skip$ + { entrysubtype field.or.null "secondary" = + 'skip$ + { new.block } + if$ + format.publisher.address output + } + if$ + new.block + format.eprint output + format.url output + fin.entry +} +FUNCTION {eulegislation} +{ output.bibitem + author empty$ + { format.title "title" output.check + continue.clause + format.eu.date "year" output.check + get.title.addenda + } + { format.authors output + author format.key output + format.eu.date "year" output.check + date.block + continue.clause + format.title "title" output.check + get.title.addenda + } + if$ + eu.case.check + format.note output + note empty$ + 'eu.case.check + 'new.block + if$ + crossref missing$ + { continue.clause + format.journal.series.vol.pages output + } + { format.article.crossref output.nonnull + format.pages output + } + if$ + new.block + format.eprint output + format.url output + fin.entry +} +FUNCTION {legislation} +{ journal empty$ + 'uklegislation + 'eulegislation + if$ +} +FUNCTION {manual} +{ output.bibitem + author empty$ + { format.btitle "title" output.check + format.date "year" output.check + year empty$ 'skip$ { date.block } if$ + get.title.addenda + } + { format.authors output + author format.key output + format.date "year" output.check + date.block + format.btitle "title" output.check + get.title.addenda + } + if$ + format.edition output + new.block + format.manual.number output + new.block + format.library output + organization address new.block.checkb + format.organization.address output + new.block + format.note output + new.block + format.eprint output + format.url output + fin.entry +} +FUNCTION {image} +{ output.bibitem + author empty$ + { format.btitle "title" output.check + format.date "year" output.check + year empty$ 'skip$ { date.block } if$ + get.title.addenda + } + { format.authors output + author format.key output + format.date "year" output.check + date.block + format.btitle "title" output.check + get.title.addenda + } + if$ + format.edition output + new.block + format.manual.number output + new.block + format.pub.org.lib.address output + new.block + format.note output + new.block + format.eprint output + format.url output + fin.entry +} +FUNCTION {mastersthesis} +{ output.bibitem + format.authors "author" output.check + author format.key output + format.date "year" output.check + date.block + format.btitle "title" output.check + get.title.addenda + new.block + bbl.mthesis format.thesis.type output.nonnull + new.block + school "school" bibinfo.warn output + address "address" bibinfo.check output + new.block + format.note output + new.block + format.eprint output + format.url output + fin.entry +} +FUNCTION {misc} +{ output.bibitem + author empty$ + { format.title "title" output.check + format.date "year" output.check + year empty$ 'skip$ { date.block } if$ + get.title.addenda + } + { format.authors output + author format.key output + format.date "year" output.check + date.block + format.title "title" output.check + get.title.addenda + } + if$ + new.block + howpublished "howpublished" bibinfo.check output + new.block + format.note output + new.block + format.eprint output + format.url output + fin.entry +} +FUNCTION {phdthesis} +{ output.bibitem + format.authors "author" output.check + author format.key output + format.date "year" output.check + date.block + format.btitle "title" output.check + get.title.addenda + new.block + bbl.phdthesis format.thesis.type output.nonnull + new.block + school "school" bibinfo.warn output + address "address" bibinfo.check output + new.block + format.note output + new.block + format.eprint output + format.url output + fin.entry +} +FUNCTION {proceedings} +{ output.bibitem + editor empty$ + { format.btitle "title" output.check + format.date "year" output.check + year empty$ 'skip$ { date.block } if$ + get.title.addenda + } + { format.editors output + editor format.key output + format.date "year" output.check + date.block + format.btitle "title" output.check + get.title.addenda + } + if$ + format.bvolume output + format.number.series output + new.sentence + publisher empty$ + { format.organization.address output } + { organization "organization" bibinfo.check output + format.publisher.address output + } + if$ + new.block + format.note output + new.block + format.eprint output + format.url output + fin.entry +} +FUNCTION {techreport} +{ output.bibitem + author empty$ + { format.btitle "title" output.check + format.date "year" output.check + year empty$ 'skip$ { date.block } if$ + get.title.addenda + } + { format.authors output + author format.key output + format.date "year" output.check + date.block + format.btitle "title" output.check + get.title.addenda + } + if$ + new.block + format.tr.number output + new.block + publisher empty$ + { format.institution.address output } + { institution "institution" bibinfo.check output + format.publisher.address output + } + if$ + new.block + format.library output + new.block + format.note output + new.block + format.eprint output + format.url output + fin.entry +} +FUNCTION {unpublished} +{ output.bibitem + author empty$ + { booktitle empty$ 'format.btitle 'format.title if$ "title" output.check + format.date "year" output.check + year empty$ 'skip$ { date.block } if$ + get.title.addenda + } + { format.authors output + author format.key output + format.date "year" output.check + date.block + booktitle empty$ 'format.btitle 'format.title if$ "title" output.check + get.title.addenda + } + if$ + new.block + format.in.ed.booktitle output + new.block + howpublished "howpublished" bibinfo.check output + new.block + bbl.unpublished output + new.block + format.note output + new.block + format.eprint output + format.url output + fin.entry +} + +FUNCTION {letter} +{ journal empty$ + 'unpublished + 'article + if$ +} +FUNCTION {audio} { booklet } +FUNCTION {movie} { booklet } +FUNCTION {music} { booklet } +FUNCTION {video} { booklet } +FUNCTION {dataset} { manual } +FUNCTION {electronic} { manual } +FUNCTION {online} { manual } +FUNCTION {patent} { manual } +FUNCTION {software} { manual } +FUNCTION {standard} { manual } +FUNCTION {www} { manual } +FUNCTION {thesis} { phdthesis } +FUNCTION {report} { techreport } +FUNCTION {default.type} { misc } + +READ +FUNCTION {sortify} +{ purify$ + "l" change.case$ +} +INTEGERS { len } +FUNCTION {chop.word} +{ 's := + 'len := + s #1 len substring$ = + { s len #1 + global.max$ substring$ } + 's + if$ +} +FUNCTION {format.lab.names} +{'s := + "" 't := + #1 'nameptr := + s num.names$ 'numnames := + numnames 'namesleft := + { namesleft #0 > } + { s nameptr + "{vv~}{ll}" format.name$ + 't := + nameptr #1 > + { nameptr #2 = + numnames #3 > and + { "others" 't := + #1 'namesleft := } + 'skip$ + if$ + namesleft #1 > + { ", " * t * } + { s nameptr "{ll}" format.name$ duplicate$ "others" = + { 't := } + { pop$ } + if$ + t "others" = + { " " * bbl.etal * + } + { bbl.and + space.word * t * + } + if$ + } + if$ + } + 't + if$ + nameptr #1 + 'nameptr := + namesleft #1 - 'namesleft := + } + while$ +} +FUNCTION {author.editor.key.label} +{ author empty$ + { editor empty$ + { key empty$ + { title empty$ + { cite$ #1 #3 substring$ } + { title + type$ "book" = + { emphasize } + 'skip$ + if$ + } + if$ + } + 'key + if$ + } + { editor format.lab.names } + if$ + } + { author format.lab.names } + if$ +} +FUNCTION {editor.key.label} +{ editor empty$ + { key empty$ + { title empty$ + { cite$ #1 #3 substring$ } + { title emphasize } + if$ + } + 'key + if$ + } + { editor format.lab.names } + if$ +} +FUNCTION {author.key.label} +{ author empty$ + { key empty$ + { title empty$ + { cite$ #1 #3 substring$ } + { title + type$ "article" = + type$ "incollection" = + or + type$ "inproceedings" = + or + type$ "misc" = + or + 'skip$ + { emphasize } + if$ + } + if$ + } + 'key + if$ + } + { author format.lab.names } + if$ +} +FUNCTION {calc.short.authors} +{ type$ "book" = + type$ "inbook" = + or + 'author.editor.key.label + { type$ "proceedings" = + 'editor.key.label + 'author.key.label + if$ + } + if$ + 'short.list := +} +FUNCTION {calc.label} +{ calc.short.authors + short.list + "(" + * + year nodate.check duplicate$ empty$ + { pop$ "" } + 'skip$ + if$ + * + 'label := +} +FUNCTION {sort.format.names} +{ 's := + #1 'nameptr := + "" + s num.names$ 'numnames := + numnames 'namesleft := + { namesleft #0 > } + { s nameptr + "{ll{ }}{ f{ }}{ jj{ }}{ vv{}}" + format.name$ 't := + nameptr #1 > + { " " * + namesleft #1 = + t "others" = + and + { "zzzzz" 't := } + 'skip$ + if$ + t sortify * + } + { t sortify * } + if$ + nameptr #1 + 'nameptr := + namesleft #1 - 'namesleft := + } + while$ +} +FUNCTION {sort.format.title} +{ 't := + "A " #2 + "An " #3 + "The " #4 t chop.word + chop.word + chop.word + sortify + #1 global.max$ substring$ +} +FUNCTION {author.editor.sort} +{ author empty$ + { editor empty$ + { title empty$ + { key empty$ + { "to sort, need author, editor, title, or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { title sort.format.title } + if$ + } + { editor sort.format.names } + if$ + } + { author sort.format.names } + if$ +} +FUNCTION {editor.sort} +{ editor empty$ + { title empty$ + { key empty$ + { "to sort, need editor, title, or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { title sort.format.title } + if$ + } + { editor sort.format.names } + if$ +} +FUNCTION {author.sort} +{ author empty$ + { title empty$ + { key empty$ + { "to sort, need author, title, or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { title sort.format.title } + if$ + } + { author sort.format.names } + if$ +} + +FUNCTION {presort} +{ calc.label + label sortify + " " + * + type$ "book" = + type$ "inbook" = + or + 'author.editor.sort + { type$ "proceedings" = + 'editor.sort + 'author.sort + if$ + } + if$ + #1 entry.max$ substring$ + 'sort.label := + sort.label + * + " " + * + title field.or.null + sort.format.title + * + #1 entry.max$ substring$ + 'sort.key$ := +} + +ITERATE {presort} +SORT +STRINGS { last.label next.extra } +INTEGERS { last.extra.num last.extra.num.extended last.extra.num.blank number.label } +FUNCTION {initialize.extra.label.stuff} +{ #0 int.to.chr$ 'last.label := + "" 'next.extra := + #0 'last.extra.num := + "a" chr.to.int$ #1 - 'last.extra.num.blank := + last.extra.num.blank 'last.extra.num.extended := + #0 'number.label := +} +FUNCTION {forward.pass} +{ last.label label = + { last.extra.num #1 + 'last.extra.num := + last.extra.num "z" chr.to.int$ > + { "a" chr.to.int$ 'last.extra.num := + last.extra.num.extended #1 + 'last.extra.num.extended := + } + 'skip$ + if$ + last.extra.num.extended last.extra.num.blank > + { last.extra.num.extended int.to.chr$ + last.extra.num int.to.chr$ + * 'extra.label := } + { last.extra.num int.to.chr$ 'extra.label := } + if$ + } + { "a" chr.to.int$ 'last.extra.num := + "" 'extra.label := + label 'last.label := + } + if$ + number.label #1 + 'number.label := +} +FUNCTION {reverse.pass} +{ next.extra "b" = + { "a" 'extra.label := } + 'skip$ + if$ + extra.label 'next.extra := + extra.label + duplicate$ empty$ + 'skip$ + { "{\natexlab{" swap$ * "}}" * } + if$ + 'extra.label := + label extra.label * 'label := +} +EXECUTE {initialize.extra.label.stuff} +ITERATE {forward.pass} +REVERSE {reverse.pass} +FUNCTION {bib.sort.order} +{ sort.label + " " + * + year field.or.null sortify + * + " " + * + title field.or.null + sort.format.title + * + #1 entry.max$ substring$ + 'sort.key$ := +} +ITERATE {bib.sort.order} +SORT +FUNCTION {begin.bib} +{ preamble$ empty$ + 'skip$ + { preamble$ write$ newline$ } + if$ + "\begin{thebibliography}{" number.label int.to.str$ * "}" * + write$ newline$ + "\providecommand{\natexlab}[1]{#1}" + write$ newline$ + "\providecommand{\url}[1]{\texttt{#1}}" + write$ newline$ + "\providecommand{\urlprefix}{Available from: }" + write$ newline$ + "\providecommand{\urldateprefix}{Accessed }" + write$ newline$ + "\providecommand{\selectlanguage}[1]{\relax}" + write$ newline$ + "\providecommand{\bibinfo}[2]{#2}" + write$ newline$ + "\providecommand{\eprint}[2][]{\url{#2}}" + write$ newline$ +} +EXECUTE {begin.bib} +EXECUTE {init.state.consts} +ITERATE {call.type$} +FUNCTION {end.bib} +{ newline$ + "\end{thebibliography}" write$ newline$ +} +EXECUTE {end.bib} +%% +%% Copyright (C) 2020 by University of Bath +%% +%% End of file `bathx.bst'.