Vincenzo Iovino
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
      • Invitee
    • Publish Note

      Publish Note

      Everyone on the web can find and read all notes of this public team.
      Once published, notes can be searched and viewed by anyone online.
      See published notes
      Please check the box to agree to the Community Guidelines.
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Versions and GitHub Sync Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
Invitee
Publish Note

Publish Note

Everyone on the web can find and read all notes of this public team.
Once published, notes can be searched and viewed by anyone online.
See published notes
Please check the box to agree to the Community Guidelines.
Engagement control
Commenting
Permission
Disabled Forbidden Owners Signed-in users Everyone
Enable
Permission
  • Forbidden
  • Owners
  • Signed-in users
  • Everyone
Suggest edit
Permission
Disabled Forbidden Owners Signed-in users Everyone
Enable
Permission
  • Forbidden
  • Owners
  • Signed-in users
Emoji Reply
Enable
Import from Dropbox Google Drive Gist Clipboard
   owned this note    owned this note      
Published Linked with GitHub
Subscribed
  • Any changes
    Be notified of any changes
  • Mention me
    Be notified of mention me
  • Unsubscribe
Subscribe
# How to Build a Time Lock Crypto Service based on League of Entropy (drand) ## Vincenzo Iovino, [Aragon ZK Research](https://research.aragon.org/) ## Setting and motivation We assume the reader to be familiar with the League of Entropy (a.k.a. [drand](https://drand.love)) system but the presentation of our treatment is self-contained. In the following we denote by $g_1,g_2$ the generators of the groups $G_1,G_2$ of some prime order $p$ used by LOE, and by $PK_L$ the public key of LOE that has the form $PK_L=g_2^{sk_L}$ where $sk_L\in Z_p$ is the corresponding secret key that is shared by the LOE members. For simplicity, in the following we will often say that at time $C$ LOE releases a secret key $SK_C$ whereas we should actually refer to a round number rather than a time. We recall that LOE is a coalition of members who, at each time interval $C$, release a BLS signature $\sigma_C=Hash(C)^{SK_L}$, where $Hash$ is a (standardized hash function) that maps bit strings to points in $G_1$ (we skip technical details about the actual encodings of $C$). This signature is jointly computed in a threshold fashion by the LOE members in a way that a minority of the members cannot obtain the secret key $SK_L$ (that is shared by the members). To ease our presentation, henceforth we denote by $SK_C$ the signature $\sigma_C$ for time $C$ and we say that $SK_C$ is the secret key of LOE for time $C$. For the purpose of our treatment, the reader does not need to know the details of the LOE protocol but simply that at each time interval $C$ the afore-mentioned secret key $SK_C$ is publicly available. We want a cryptographic protocol among a set of parties to jointly construct a public key $PK$ whose corresponding secret key $sk$ can be publicly computed only at time greater or equal than $C$ when the secret key $SK_C$ of LOE for time $C$ will be made available; here $C$ is a public input to all parties. The public key $PK$ should have the form $g^{sk}$ where $g$ is the generator of a group of some prime order $q$, so $sk \in Z_q$. We look for generic approaches so we consider any kind of prime order group in which the Dlog Assumption holds: that is elliptic curve groups (both bilinear and non-bilinear groups) and multiplicative groups of prime order; [later on](#Generalization-to-any-homomorphic-OWF-and-thus-to-RSA) we will also cover a specific RSA setting. This public key $PK$ can be then used for encryption using any encryption scheme defined over the group generated by $g$ (later on we will also discuss other applications to digital signatures and zero-knowledge proofs). Observe that this problem, though related, is independent from the recently proposed [timelock encryption](https://eprint.iacr.org/2015/482) primitive. Indeed, a user Alice can use the public key $PK$, that was part of the output of an execution of the TLCS protocol for time $C$, to encrypt measages without specifying any time and only performing cryptographic operations related to the group generated by $g$. After time $C$, using $SK_C$ and the transcript of the TLCS protocol anyone (and thus a smart contract) can compute the secret key $sk$ corresponding to $PK$. Bob can use $sk$ to decrypt Alice's messages. Observe that, unlike timelock encryption, here the computations of Alice and Bob are completely independent from the LOE system. We assume that there is a blockchain on which anyone (or possibly only registered people to avoid DoS) can post data as a mean to generate a public key PK and some related data that can be used by anyone, and so by a smart contract, to obtain the corresponding secret key $sk$ at time $C$. Additionally, we want that there is a committee of members that anyone can freely join, that is the set of participants in a particular execution of the protocol is not fixed, and we want the protocol to require just one message of interaction from each participant (assuming a perfect broadcast channel like a blockchain). ## Warmup: a TLCS protocol from general-purpose NIZK proofs Consider the following protocol. The generic party $i=1,...$ does the following. It computes $PK_i=g^{sk_i}$, where $sk_i$ is randomly chosen in $Z_q$. It chooses random $t_i$ from $Z_p$ and computes $T_i=g_2^{t_i}$, $Z_i=e(H(C),PK_L)^{t_i}$ and $y_i=H(Z_i) \oplus sk_i$. The party $i$ posts on the blokchain: $(T_i, y_i)$. Note that $Z_i$ is not posted, and the honest party is required to delete $Z_i, t_i,sk_i$ from his memory, so that until time $C$ nobody can get $sk_i$. At some point, the public key construction phase terminates and no new party can participate. Then, the public key $PK$ is set to $PK=\prod_i PK_i=g^{sk}$, where $sk=\sum_i sk_i \mod q$. When the secret $SK_C=H(C)^{sk_L}$ of LOE is published at time $C$, anyone can publicly do the following based on the information posted on the blockchain. For any $i$ compute $e(SK_C,T_i)=Z_i$ and then can compute $sk_i=y_i \oplus H(Z_i)$. From all $sk_i$'s, anyone can then recover $sk=\sum_i sk_i \mod q$. The security here guarantees that if only a single party is trusted in having deleted his memory at the of the computation, then the secret key $sk$ corresponding to $PK$ is protected until time $C$ assuming that the majority of LOE members are honest. That is, the only added assumption beyond LOE is that there is a single honest party. Observe that, since anyone can publicly participate in the protocol (that is the committee allows on-fly join), if someone does not trust the system can decide on participating in the protocol freely. To be able to decrypt we need to assume that the values $y_i$'s posted on the blockchain are computed correctly according to the above procedure, so each $y_i$ needs to be accompained with a ZK proof of well-formedness, that is a proof that the tuple $(g_2,PK_L,C,T_i,PK_i,y_i)$ is such that there exist values $t_i\in Z_p$, $sk_i\in Z_q$ such that $T_i=g_2^{t_i}$, $Z_i=e(H(C),PK_L)^{t_i}$, $y_i=H(Z_i) \oplus sk_i$ and $PK_i=g^{sk_i}$. The proof system needs to be non-malleable to prevent attacks in which the last party can induce a public key of which he knows the corresponding secret key; alternatively, a standard non-interactive Schnorr's proof must be attacked to each partial public key $PK_i$. This requires a NIZK proof of computation of exponentiation in the target group. Notice that if a tuple $(PK_i,T_i,y_i)$ does not come with a valid proof, it will not be used for the computation of $PK$. ## The muon protocol: an efficient TLCS protocol that avoids general-purpose NIZK proofs The above NIZK proof could be implemented with general-purpose SNARK for circuits that compute operations in the target group of the LOE's curve. In this section we show how to implement a variant of the above protocol that avoids general-purpose NIZK proofs that we call the *muon* protocol. (In the following we will be focusing on a single party so we will remove the subscript $i$ that refers to the parties. So when you read $PK$, this is actually $PK_i$ of the previous notation and not the public key that is the result of the shares of all committee members. We choose to do that to minimize the number of subscripts to fit better in hackmd.) We will construct an interactive protocol. This can be done non-interactive via the FS transform. There is a security parameter $k$ that affects the soundness error, precisely the soundness error will be $2^{-k}$ so there is a trade-off: we have freedom to choose $k$ as large as possible to reduce the soundness error and as small as possible to make the system more efficient. The generic party (the prover) has a public key $PK=g^{sk}$, where $sk\in Z_q$ is known to the prover but not to the verifier. For $j=1,\ldots,k$ the prover chooses two random values $sk_{j,1},sk_{j,2}$ that sum up to $sk$ and sets $PK_{j,1}=g^{sk_{j,1}},PK_{j,2}=g^{sk_{j,2}}$. For $j=1,\ldots, k$, the prover chooses random $t_{j,1},t_{j,2}$ from $Z_p$ and computes $T_{j,1}=g_2^{t_{j,1}}$, $Z_{j,1}=e(H(C),PK_L)^{t_{j,1}}$ and $y_{j,1}=H(Z_{j,1}) \oplus sk_{j,1}$ and similarly $T_{j,2},Z_{j,2},y_{j,2}$. The prover sends to the verifier the value $PK$ and the list of tuples: $(PK_{j,b},T_{j,b_j},y_{j,b})_{j\in[k],b\in\{1,2\}}$. (Note: as explained before here we removed the subscript $i$ so $PK$ refers to the contribution of a generic party and not to the final public key that is computed as product of the public keys of all members. We do not include the further subscript $i$ to avoid many subscripts like "$PK_{i,j,b_j}$", etc.) The verifier chooses a vector of $k$ random values $b_1,\ldots,b_k$ in $\{1,2\}$ and sends it to the prover. For all $j\in[k]$ the prover sets $t_j=t_{j,b_j}$ and sends back to the verifier the tuple $(t_j)_{j\in[k]}$. The verifier accepts iff all the following checks pass: - 1. For all $j=1,\ldots,k$ check that $PK_{j,1}* PK_{j,2}=PK$. That is, the verifier checks that all the pairs of public keys form a $2$ out of $2$ secret sharing of the same public key $PK$. This also convinces the verifier that the same condition holds with respect to the secret keys, that is that for all $i=1,\ldots,k$, $sk_{j,1}+sk_{j,2}=sk$ modulo $q$, where $PK=g^{sk}$. - 2. The verifier now checks that the tuple $PK_{j,b_j},T_{j,b_j},y_{j,b_j}$ is well-formed in the following way. The verifier computes $Z_j=e(H(C),PK_L)^{t_j}$. If $t_j$ was equal to $t_{j,b_j}$ then it holds that $Z_j=Z_{j,b_j}$. The verifier computes $s_j=H(Z_j) \oplus y_{j,b_j}.$ If $t_j$ was equal to $t_{j,b_j}$ then it holds that $s_j=sk_{j,b_j}$. The verifier checks that $PK_{j,b_j}=g^{s_j}$ and that $T_{j,b_j}=g_2^{t_j}$. This convinces the verifier that $s_j=sk_{j,b_j}$ and that $sk_{j,b_j}$ is the secret key corresponding to $PK_{j,b_j}$. Let $s_{j,1}$ and $s_{j,2}$ be the values induced by $SK_C$ that should be equal to resp. $sk_{j,1}$ and $sk_{j,2}$ if the prover is honest. If $PK$ was not invertible (that is if $sk$ is not equal to $s_{j,1}+s_{j,2}\ mod\ q$ then: if the first check with respect to a generic $j$ passes then the second check with respect to the same $j$ can pass only with prob. at most $1/2$ over the choice of $b_j$. So the prob. that a malicious committee member convinces the verifier is $1/2^k$. If the proof passes the public key $PK$ of the party is accepted and is used to compute the public key for time $C$ by multiplying together all the public keys of all parties whose proofs were accepted. At time $C$, to recover the corresponding secret key $sk$ using the value $SK_C=H(C)^{SK_L}$ released by LOE, one runs the following procedure. - for j=1 to k: - For all $b\in\{1,2\}$ compute $e(H(C)^{SK_L},T_{j,b})=Z_{j,b}$, $s_{j,b}=H(Z_{j,b}) \oplus y_{j,b}$. - If $g^{s_{j,1}}=PK_{j,1}$ and $g^{s_{j,2}}=PK_{j,2}$ and $PK_{j,1} * PK_{j,2}=PK$ then return $sk=s_{j,1}+s_{j,2}\ mod\ q$ else continue; The previous proof can be made non-interactive by having the prover to choose the vector $b_1,...,b_k$ as hash of the string $[PK,(PK_{j,b},T_{j,b_j},y_{j,b})_{j\in[k]}]$. The verifier does the same to recompute the vector $b_1,...,b_k$ in a deterministic way. Under mild conditions the non-interactive variant can be made weak simulation sound extractable (see [here](https://eprint.iacr.org/2012/704)) since the previous TLCS protocol is a sigma protocol. * TODO: check that the conditions are satisfied. ### Variants based on general secret sharing The above system can be modified having in each repetition e.g. a prob. of error of $1/3$ instead of $1/2$ and with overall shorter proofs. The idea is the following. For each $j\in[k]$ we can choose e.g. $3$ secret keys $sk_{j,1},...,sk_{j,3}$ so that they form e.g. a $2$ out of $3$ secret sharing of $sk$. That is, for all $i\in[3]$, $sk_{j,i}=p_j(i)$, where $p_j$ is a random degree one polynomial whose constant term equals $sk$. Thus, by means of the Lagrange coefficients, any subset of size $2$ of such keys can be used to reconstruct $sk$. Then we let as before $PK_{j,1},...,PK_{j,3}$ be the corresponding public keys. The verifier in check 1 is changed as follows. The verifier will verify that any subset $S$ of $\{1,...,3\}$ of cardinality $2$ of such public keys is such that $\prod_{l\in S} PK_{j,l}^{\lambda_{S,l}}=PK$, where the values $\lambda_{S,l},l\in S$ are the Lagrange coefficients for set $S$. Since there are $3$ subsets of $\{1,...,3\}$ of cardinality $2$, check $1$ requires $3*2=6$ exponentiations in the cyclic group. In check $2$ the verifier will do the checks as above except for the following change. Before, the check was with respect to a single random bit. Now the check is with respect to a random index $k$ in $\{1,...,3\}$. Now we notice that if the check $1$ passes the party could cheat only if there exists at most one index $k'$ such that the public key $PK_{j,k'}$ is invertible and the verifier happens to choose $k=k'$ and this occurs with prob. $1/3$. So, with still one exponentiation in the target group per iteration we get error $1/3$ and we decreased the communication (the size of the proof). Experiments show that, though the time performance may not be much better, this approach is preferable when attempting to reduce the communication cost. The time verification cost depends on the ratio of efficiency between exponentiations in target group and exponentiations in the cyclic groups. If for some cyclic group this ratio were high (that is exponentiations in the target group were much more expensive than exponentiations in the cyclic group), the approach on general secret sharing would also be more efficient in terms of time costs for the verifier. For example, in some applications the period between publication of the tlock public key and revealing of the corresponding secret key could be short; in such case it could make sense to use cyclic groups with short security parameters so that the secret sharing variant could improve more on verification time. In most cases this variant improves slightly on proof size. For the concrete case of e.g. a 2 out of 3 SS one can choose the interpolation points so as to make the Lagrange coefficients to be small integers. #### Random check trick Another trick to make the SS variant more efficient is the following. Let us assume a 2 out of 4 SS as above. The verifier can be modified so as to choose random scalars $r_j,j\in[k]$ and to set for each $l\in [4]$: $RPK_{l}=\prod_{j\in[k]}PK_{j,l}^{r_j}$ Then, the verifier can check for each subset $S$ of $[4]$ of cardinality $2$ that: $\prod_{l\in S} RPK_{l}^{\lambda_{S,l}}=PK^{\sum_{j\in[k]} r_j}$ In this way, the verifier would do a number of exponentiations in the cyclic group of the order $4k+13$ rather than $12k$, and this should make the verifier of the 2 out of 4 SS variant more efficient. * TODO: check the soundness of the approach and implement it. ### Generalization to any homomorphic OWF and thus to RSA The previous protocol only uses the following facts: - The exponentiation in a cyclic group is difficult to invert (for security). - The exponentiation in a cyclic group is easy to check, that is given $sk$ and $PK$ it is easy to check if $PK=g^{sk}$. - The exponentiation in a cyclic group is homomorphic, that is the product of two public keys $PK_1,PK_2$ whose secret keys are resp. $sk_1,sk_2$ is a public key $PK$ such that the corresponding secret key $sk$ equals $sk_1+sk_2$ modulo the order of the group. This can be generalized to any homomorphic one-way function (OWF). Exponentiation in cyclic groups are examples of homomorphic OWFs but another notable example is RSA. Given a modulus $N$ product of two safe primes and an exponent $d\in Z_{\phi(\phi(N))}$, the RSA function $f_{RSA}$ is the function that maps $x$ to $x^d\ mod\ N$. This function can be seen to be also homomorphic. Note that we do *not* claim that we can use this directly for OAEP or related RSA-based encryption schemes. Additionally, we have a trapdoor: if a party has the factorization of the modulus, this party is able to invert the evaluation of the function $PK=f_{RSA}(sk)$ before the prescribed time to get the corresponding secret key $sk$. Observe that the variant with general secret sharing does not generalize to RSA and all homomorphic OWF. ### Free joins without spamming the blockchain? Depending on the resources of the blockchain nodes it might be possible only to verify proofs and accept the contribution of a small fraction of the total committee members, especially if huge number of parties want to contribute. For concreteness, it might be that the nodes have resources to work only on $N$ committee members. In that case, the blockchain can do the following. There is a time $d$ before which parties can submit their contribution. At time $d$ one sees the random beacon published by LOE and this value is used to select (e.g., via a cryptographic hash function) a random subset of committee members of size $N$ among all committee members who took part in the protocol. The unpredictability of the random beacon of LOE makes harder to cheat and allows a fairer choice of the committee members in the limit of the resources of the nodes. This can be combined with other anti-spam techniques to prevent an attacker to submit only contributions under its control. ### From TLCS to timed signatures and timed proofs Borrowing ideas from the celebrated Feige-Lapidot-Shamir technique, the Schnorr signature scheme can be modified so that the underlying sigma protocol on which it is based proves knowledge of a witness to the following $NP$ statement: "I know a secret key corresponding to $PK_{A}$ OR I know a secret key corresponding to $PK$", where $PK_A$ is a known public key of a user Alice and $PK$ is a TLCS public key $PK$ for some time $C$. In this way a resulting signature is such that: a valid signature by Alice looks convincing to Bob before time $C$ but if Bob transfers this signature to Peggy after time $C$, such signature will not look convincing to Peggy since it might have been generated by anyone using the simulator algorithm of the sigma protocol using the secret key corresponding to $PK$ (that may be assumed to be known by anyone after time $C$). The same concept can be extended to general-purpose NIZK proofs that can be made to guarantee the following property: they are publicly verifiable until a given time $C$ but after $C$ they will be no longer transferable (that is, they will no longer look convincing to any receiver). ## Implementations An implementation in C/C++ of the efficient TLCS protocol described above is available [here](https://github.com/aragonzkresearch/tlcs-c) and a Rust implementation by Najmeh Sorous can be found [here](https://github.com/aragonzkresearch/tlcs-rust). ## Acks The problem of the existence of a TLCS protocol was first posed by Alex Kampa who also contributed to stabilize the ideas in these notes. Thanks to all the Aragon ZK Research team who provided beneficial comments and the drand community who helped to figure out some inner details of their system. #### Vincenzo Iovino, May 2023, Aragon ZK Research

Import from clipboard

Paste your webpage below. It will be converted to Markdown.

Advanced permission required

Your current role can only read. Ask the system administrator to acquire write and comment permission.

This team is disabled

Sorry, this team is disabled. You can't edit this note.

This note is locked

Sorry, only owner can edit this note.

Reach the limit

Sorry, you've reached the max length this note can be.
Please reduce the content or divide it to more notes, thank you!

Import from Gist

Import from Snippet

or

Export to Snippet

Are you sure?

Do you really want to delete this note?
All users will lose their connection.

Create a note from template

Create a note from template

Oops...
This template is not available.
Upgrade
All
  • All
  • Team
No template found.

Create custom template

Upgrade

Delete template

Do you really want to delete this template?
Turn this template into a regular note and keep its content, versions, and comments.

This page need refresh

You have an incompatible client version.
Refresh to update.
New version available!
See releases notes here
Refresh to enjoy new features.
Your user state has changed.
Refresh to load new user state.

Sign in

Forgot password

or

By clicking below, you agree to our terms of service.

Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
Wallet ( )
Connect another wallet

New to HackMD? Sign up

Help

  • English
  • 中文
  • Français
  • Deutsch
  • 日本語
  • Español
  • Català
  • Ελληνικά
  • Português
  • italiano
  • Türkçe
  • Русский
  • Nederlands
  • hrvatski jezik
  • język polski
  • Українська
  • हिन्दी
  • svenska
  • Esperanto
  • dansk

Documents

Help & Tutorial

How to use Book mode

How to use Slide mode

API Docs

Edit in VSCode

Install browser extension

Get in Touch

Feedback

Discord

Send us email

Resources

Releases

Pricing

Blog

Policy

Terms

Privacy

Cheatsheet

Syntax Example Reference
# Header Header 基本排版
- Unordered List
  • Unordered List
1. Ordered List
  1. Ordered List
- [ ] Todo List
  • Todo List
> Blockquote
Blockquote
**Bold font** Bold font
*Italics font* Italics font
~~Strikethrough~~ Strikethrough
19^th^ 19th
H~2~O H2O
++Inserted text++ Inserted text
==Marked text== Marked text
[link text](https:// "title") Link
![image alt](https:// "title") Image
`Code` Code 在筆記中貼入程式碼
```javascript
var i = 0;
```
var i = 0;
:smile: :smile: Emoji list
{%youtube youtube_id %} Externals
$L^aT_eX$ LaTeX
:::info
This is a alert area.
:::

This is a alert area.

Versions and GitHub Sync
Get Full History Access

  • Edit version name
  • Delete

revision author avatar     named on  

More Less

No updates to save
Compare
    Choose a version
    No search result
    Version not found
Sign in to link this note to GitHub
Learn more
This note is not linked with GitHub
 

Feedback

Submission failed, please try again

Thanks for your support.

On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

Please give us some advice and help us improve HackMD.

 

Thanks for your feedback

Remove version name

Do you want to remove this version name and description?

Transfer ownership

Transfer to
    Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

      Link with GitHub

      Please authorize HackMD on GitHub
      • Please sign in to GitHub and install the HackMD app on your GitHub repo.
      • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
      Learn more  Sign in to GitHub

      Push the note to GitHub Push to GitHub Pull a file from GitHub

        Authorize again
       

      Choose which file to push to

      Select repo
      Refresh Authorize more repos
      Select branch
      Select file
      Select branch
      Choose version(s) to push
      • Save a new version and push
      • Choose from existing versions
      Include title and tags
      Available push count

      Pull from GitHub

       
      File from GitHub
      File from HackMD

      GitHub Link Settings

      File linked

      Linked by
      File path
      Last synced branch
      Available push count

      Danger Zone

      Unlink
      You will no longer receive notification when GitHub file changes after unlink.

      Syncing

      Push failed

      Push successfully