Files
semaphore/docs/libsemaphore.html
2020-03-03 23:23:23 +02:00

383 lines
21 KiB
HTML

<!DOCTYPE HTML>
<html lang="en" class="sidebar-visible no-js light">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>libsemaphore - </title>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff" />
<link rel="shortcut icon" href="favicon.png">
<link rel="stylesheet" href="css/variables.css">
<link rel="stylesheet" href="css/general.css">
<link rel="stylesheet" href="css/chrome.css">
<link rel="stylesheet" href="css/print.css" media="print">
<!-- Fonts -->
<link rel="stylesheet" href="FontAwesome/css/font-awesome.css">
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800" rel="stylesheet" type="text/css">
<link href="https://fonts.googleapis.com/css?family=Source+Code+Pro:500" rel="stylesheet" type="text/css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" href="highlight.css">
<link rel="stylesheet" href="tomorrow-night.css">
<link rel="stylesheet" href="ayu-highlight.css">
<!-- Custom theme stylesheets -->
</head>
<body>
<!-- Provide site root to javascript -->
<script type="text/javascript">
var path_to_root = "";
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "light" : "light";
</script>
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script type="text/javascript">
try {
var theme = localStorage.getItem('mdbook-theme');
var sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
</script>
<!-- Set the theme before any content is loaded, prevents flash -->
<script type="text/javascript">
var theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
var html = document.querySelector('html');
html.classList.remove('no-js')
html.classList.remove('light')
html.classList.add(theme);
html.classList.add('js');
</script>
<!-- Hide / unhide sidebar before it is displayed -->
<script type="text/javascript">
var html = document.querySelector('html');
var sidebar = 'hidden';
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
}
html.classList.remove('sidebar-visible');
html.classList.add("sidebar-" + sidebar);
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<div id="sidebar-scrollbox" class="sidebar-scrollbox">
<ol class="chapter"><li class="expanded "><a href="about.html"><strong aria-hidden="true">1.</strong> About</a></li><li class="expanded "><a href="howitworks.html"><strong aria-hidden="true">2.</strong> How it works</a></li><li class="expanded "><a href="quickstart.html"><strong aria-hidden="true">3.</strong> Quick start</a></li><li class="expanded "><a href="usage.html"><strong aria-hidden="true">4.</strong> Usage</a></li><li class="expanded "><a href="api.html"><strong aria-hidden="true">5.</strong> Contract API</a></li><li class="expanded "><a href="libsemaphore.html" class="active"><strong aria-hidden="true">6.</strong> libsemaphore</a></li><li class="expanded "><a href="trustedsetup.html"><strong aria-hidden="true">7.</strong> Trusted setup</a></li><li class="expanded "><a href="audit.html"><strong aria-hidden="true">8.</strong> Security audit</a></li><li class="expanded "><a href="creditsandresources.html"><strong aria-hidden="true">9.</strong> Credits and resources</a></li></ol>
</div>
<div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
</nav>
<div id="page-wrapper" class="page-wrapper">
<div class="page">
<div id="menu-bar" class="menu-bar">
<div id="menu-bar-sticky-container">
<div class="left-buttons">
<button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</button>
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="light">Light (default)</button></li>
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
</ul>
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
<i class="fa fa-search"></i>
</button>
</div>
<h1 class="menu-title"></h1>
<div class="right-buttons">
<a href="print.html" title="Print this book" aria-label="Print this book">
<i id="print-button" class="fa fa-print"></i>
</a>
</div>
</div>
</div>
<div id="search-wrapper" class="hidden">
<form id="searchbar-outer" class="searchbar-outer">
<input type="search" name="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
</form>
<div id="searchresults-outer" class="searchresults-outer hidden">
<div id="searchresults-header" class="searchresults-header"></div>
<ul id="searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script type="text/javascript">
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="content" class="content">
<main>
<h1><a class="header" href="#libsemaphore" id="libsemaphore">libsemaphore</a></h1>
<p><a href="https://www.npmjs.com/package/libsemaphore"><code>libsemaphore</code></a> is a helper
library for Semaphore written in Typescript. Any dApp written in Javascript or
Typescript should use it as it provides useful abstractions over common tasks
and objects, such as identities and proof generation.</p>
<p>Note that only v1.0.14 and above works with the Semaphore code in this
repository. v0.0.x is compatible with the pre-audited Semaphore code.</p>
<h2><a class="header" href="#available-types-interfaces-and-functions" id="available-types-interfaces-and-functions">Available types, interfaces, and functions</a></h2>
<h3><a class="header" href="#types" id="types">Types</a></h3>
<p><strong><code>SnarkBigInt</code></strong></p>
<p>A big integer type compatible with the <code>snarkjs</code> library. Note that it is not
advisable to mix variables of this type with <code>bigNumber</code>s or <code>BigInt</code>s.
Encapsulates <code>snarkjs.bigInt</code>.</p>
<p><strong><code>EddsaPrivateKey</code></strong></p>
<p>An <a href="https://tools.ietf.org/html/rfc8032">EdDSA</a> private key which should be 32
bytes long. Encapsulates a <a href="https://nodejs.org/api/buffer.html"><code>Buffer</code></a>.</p>
<p><strong><code>EddsaPublicKey</code></strong></p>
<p>An EdDSA public key. Encapsulates an array of <code>SnarkBigInt</code>s.</p>
<p><strong><code>SnarkProvingKey</code></strong></p>
<p>A proving key, which when used with a secret <em>witness</em>, generates a zk-SNARK
proof about said witness. Encapsulates a <code>Buffer</code>.</p>
<p><strong><code>SnarkVerifyingKey</code></strong></p>
<p>A verifying key which when used with public inputs to a zk-SNARK and a
<code>SnarkProof</code>, can prove the proof's validity. Encapsulates a <code>Buffer</code>.</p>
<p><strong><code>SnarkWitness</code></strong></p>
<p>The secret inputs to a zk-SNARK. Encapsulates an array of <code>SnarkBigInt</code>s.</p>
<p><strong><code>SnarkPublicSignals</code></strong></p>
<p>The public inputs to a zk-SNARK. Encapsulates an array of <code>SnarkBigInt</code>s.</p>
<h3><a class="header" href="#interfaces" id="interfaces">Interfaces</a></h3>
<p><strong><code>EddsaKeyPair</code></strong></p>
<p>Encapsulates an <code>EddsaPublicKey</code> and an <code>EddsaPrivateKey</code>.</p>
<pre><code class="language-ts">interface EddsaKeyPair {
pubKey: EddsaPublicKey,
privKey: EddsaPrivateKey,
}
</code></pre>
<p><strong><code>Identity</code></strong></p>
<p>Encapsulates all information required to generate an identity commitment, and
is crucial to creating <code>SnarkProof</code>s to broadcast signals.</p>
<pre><code class="language-ts">interface Identity {
keypair: EddsaKeyPair,
identityNullifier: SnarkBigInt,
identityTrapdoor: SnarkBigInt,
}
</code></pre>
<p><strong><code>SnarkProof</code></strong></p>
<p>Note that <code>broadcastSignal()</code> accepts a <code>uint256[8]</code> array for its <code>_proof</code>
parameter. See <code>genBroadcastSignalParams()</code>.</p>
<pre><code class="language-ts">interface SnarkProof {
pi_a: SnarkBigInt[]
pi_b: SnarkBigInt[][]
pi_c: SnarkBigInt[]
}
</code></pre>
<h3><a class="header" href="#functions" id="functions">Functions</a></h3>
<p><strong><code>genPubKey(privKey: EddsaPrivateKey): EddsaPublicKey</code></strong></p>
<p>Generates a public EdDSA key from a supplied private key. To generate a private
key, use <code>crypto.randomBytes(32)</code> where <code>crypto</code> is the built-in Node or
browser module.</p>
<p><strong><code>genIdentity(): Identity</code></strong></p>
<p>This is a convenience function to generate a fresh and random <code>Identity</code>. That
is, the 32-byte private key for the <code>EddsaKeyPair</code> is randomly generated, as
are the distinct 31-byte identity nullifier and the 31-byte identity trapdoor
values.</p>
<p><strong><code>serialiseIdentity(identity: Identity): string</code></strong></p>
<p>Converts an <code>Identity</code> into a JSON string which looks like this:</p>
<pre><code class="language-text">[&quot;e82cc2b8654705e427df423c6300307a873a2e637028fab3163cf95b18bb172e&quot;,&quot;a02e517dfb3a4184adaa951d02bfe0fe092d1ee34438721d798db75b8db083&quot;,&quot;15c6540bf7bddb0616984fccda7e954a0fb5ea4679ac686509dc4bd7ba9c3b&quot;]
</code></pre>
<p>You can also spell this function as <code>serializeIdentity</code>.</p>
<p>To convert this string back into an <code>Identity</code>, use <code>unSerialiseIdentity()</code>.</p>
<p><strong><code>unSerialiseIdentity(string: serialisedId): Identity</code></strong></p>
<p>Converts the <code>string</code> output of <code>serialiseIdentity()</code> to an <code>Identity</code>.</p>
<p>You can also spell this function as <code>unSerializeIdentity</code>.</p>
<p><strong><code>genIdentityCommitment(identity: Identity): SnarkBigInt</code></strong></p>
<p>Generates an identity commitment, which is the hash of the public key, the
identity nullifier, and the identity trapdoor.</p>
<p><strong><code>async genProof(witness: SnarkWitness, provingKey: SnarkProvingKey): SnarkProof</code></strong></p>
<p>Generates a <code>SnarkProof</code>, which can be sent to the Semaphore contract's
<code>broadcastSignal()</code> function. It can also be verified off-chain using
<code>verifyProof()</code> below.</p>
<p><strong><code>genPublicSignals(witness: SnarkWitness, circuit: SnarkCircuit): SnarkPublicSignals</code></strong></p>
<p>Extracts the public signals to be supplied to the contract or <code>verifyProof()</code>.</p>
<p><strong><code>verifyProof(verifyingKey: SnarkVerifyingKey, proof: SnarkProof, publicSignals: SnarkPublicSignals): boolean</code></strong></p>
<p>Returns <code>true</code> if the given <code>proof</code> is valid, given the correct verifying key
and public signals.</p>
<p>Returns <code>false</code> otherwise.</p>
<p><strong><code>signMsg(privKey: EddsaPrivateKey, msg: SnarkBigInt): EdDSAMiMcSpongeSignature)</code></strong></p>
<p>Encapsualtes <code>circomlib.eddsa.signMiMCSponge</code> to sign a message <code>msg</code> using private key <code>privKey</code>.</p>
<p><strong><code>verifySignature(msg: SnarkBigInt, signature: EdDSAMiMcSpongeSignature, pubKey: EddsaPublicKey)</code>: boolean</strong></p>
<p>Returns <code>true</code> if the cryptographic <code>signature</code> of the signed <code>msg</code> is from the
private key associated with <code>pubKey</code>.</p>
<p>Returns <code>false</code> otherwise.</p>
<p><strong><code>setupTree(levels: number, prefix: string): MerkleTree</code></strong></p>
<p>Returns a Merkle tree created using
<a href="https://www.npmjs.com/package/semaphore-merkle-tree"><code>semaphore-merkle-tree</code></a>
with the same number of levels which the Semaphore zk-SNARK circuit expects.
This tree is also configured to use <code>MimcSpongeHasher</code>, which is also what the
circuit expects.</p>
<p><code>levels</code> sets the number of levels of the tree. A tree with 20 levels, for
instance, supports up to 1048576 deposits.</p>
<p><strong><code>genCircuit(circuitDefinition: any)</code></strong></p>
<p>Returns a <code>new snarkjs.Circuit(circuitDefinition)</code>. The <code>circuitDefinition</code>
object should be the <code>JSON.parse</code>d result of the <code>circom</code> command which
converts a <code>.circom</code> file to a <code>.json</code> file.</p>
<p><strong><code>async genWitness(...)</code></strong></p>
<p>This function has the following signature:</p>
<pre><code class="language-ts">const genWitness = async (
signal: string,
circuit: SnarkCircuit,
identity: Identity,
idCommitments: SnarkBigInt[] | BigInt[] | ethers.utils.BigNumber[],
treeDepth: number,
externalNullifier: SnarkBigInt,
)
</code></pre>
<ul>
<li><code>signal</code> is the string you wish to broadcast.</li>
<li><code>circuit</code> is the output of <code>genCircuit()</code>.</li>
<li><code>identity</code> is the <code>Identity</code> whose identity commitment you want to prove is
in the set of registered identities.</li>
<li><code>idCommitments</code> is an array of registered identity commmitments; i.e. the
leaves of the tree.</li>
<li><code>treeDepth</code> is the number of levels which the Merkle tree used has</li>
<li><code>externalNullifier</code> is the current external nullifier</li>
</ul>
<p>It returns an object as such:</p>
<ul>
<li><code>witness</code>: The witness to pass to <code>genProof()</code>.</li>
<li><code>signal</code>: The computed signal for Semaphore. This is the hash of the
recipient's address, relayer's address, and fee.</li>
<li><code>signalHash</code>: The hash of the computed signal.</li>
<li><code>msg</code>: The hash of the external nullifier and the signal hash</li>
<li><code>signature</code>: The signature on the above msg.</li>
<li><code>tree</code>: The Merkle tree object after it has been updated with the identity commitment</li>
<li><code>identityPath</code>: The Merkle path to the identity commmitment</li>
<li><code>identityPathIndex</code>: The leaf index of the identity commitment</li>
<li><code>identityPathElements</code>: The elements along the above Merkle path</li>
</ul>
<p>Only <code>witness</code> is essential to generate the proof; the other data is only
useful for debugging and additional off-chain checks, such as verifying the
signature and the Merkle tree root.</p>
<p><strong><code>formatForVerifierContract = (proof: SnarkProof, publicSignals: SnarkPublicSignals</code></strong></p>
<p>Converts the data in <code>proof</code> and <code>publicSignals</code> to strings and rearranges
elements of <code>proof.pi_b</code> so that <code>snarkjs</code>'s <code>verifier.sol</code> will accept it.
To be specific, it returns an object as such:</p>
<pre><code class="language-ts">{
a: [ proof.pi_a[0].toString(), proof.pi_a[1].toString() ],
b: [
[ proof.pi_b[0][1].toString(), proof.pi_b[0][0].toString() ],
[ proof.pi_b[1][1].toString(), proof.pi_b[1][0].toString() ],
],
c: [ proof.pi_c[0].toString(), proof.pi_c[1].toString() ],
input: publicSignals.map((x) =&gt; x.toString()),
}
</code></pre>
<p><strong><code>stringifyBigInts = (obj: any) =&gt; object</code></strong></p>
<p>Encapsulates <code>snarkjs.stringifyBigInts()</code>. Makes it easy to convert <code>SnarkProof</code>s to JSON. </p>
<p><strong><code>unstringifyBigInts = (obj: any) =&gt; object</code></strong></p>
<p>Encapsulates <code>snarkjs.unstringifyBigInts()</code>. Makes it easy to convert JSON to <code>SnarkProof</code>s.</p>
<p><strong><code>genExternalNullifier = (plaintext: string) =&gt; string</code></strong></p>
<p>Each external nullifier must be at most 29 bytes large. This function
keccak-256-hashes a given <code>plaintext</code>, takes the last 29 bytes, and pads it
(from the start) with 0s, and returns the resulting hex string.</p>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="api.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next" href="trustedsetup.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a href="api.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a href="trustedsetup.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
</div>
<script type="text/javascript">
window.playpen_copyable = true;
</script>
<script src="elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
<script src="mark.min.js" type="text/javascript" charset="utf-8"></script>
<script src="searcher.js" type="text/javascript" charset="utf-8"></script>
<script src="clipboard.min.js" type="text/javascript" charset="utf-8"></script>
<script src="highlight.js" type="text/javascript" charset="utf-8"></script>
<script src="book.js" type="text/javascript" charset="utf-8"></script>
<!-- Custom JS scripts -->
</body>
</html>