Finite Prime Fields

Definition

Example

NIST Primes

Why finite fields?

What is an elliptic curve?

Overview

Elliptic Curve Groups

Before getting into the finite fields, let us recall the general group and field definitions from Wikipedia:

A group G is a finite or infinite set of elements together with a binary operation (called the group operation) that together satisfy the four fundamental properties of closure, associativity, the identity property, and the inverse property. The operation with respect to which a group is defined is often called the "group operation," and a set is said to be a group "under" this operation. Elements A, B, C, ... with binary operation between A and B denoted AB form a group if

Closure: If A and B are two elements in G, then the product AB is also in G.

Associativity: The defined multiplication is associative, i.e., for all A,B,C in G, (AB)C=A(BC).

Identity: There is an identity element I (a.k.a. 1, E, or e) such that IA=AI=A for every element A in G.

Inverse: There must be an inverse (a.k.a. reciprocal) of each element. Therefore, for each element A of G, the set contains an element B=A^(-1) such that AA^(-1)=A^(-1)A=I.

Formally, a field is a set

Ftogether with two binary operations onFcalledadditionandmultiplication. A binary operation onFis a mappingFFF, that is, a correspondence that associates with each ordered pair of elements ofFa uniquely determined element ofF.The result of the addition ofaandbis called the sum ofaandb, and is denoteda+b. Similarly, the result of the multiplication ofaandbis called the product ofaandb, and is denotedaborab. These operations are required to satisfy the following properties, referred to asfield axioms(in these axioms,a,b, andcare arbitrary elements of the fieldF):

Associativity of addition and multiplication:

a+ (b+c) = (a+b) +c, anda(bc) = (ab)c.Commutativity of addition and multiplication:

a+b=b+a, andab=ba.Additive and multiplicative identity: there exist two distinct elements 0 and 1 in

Fsuch thata+ 0 =aanda1 =a.Additive inverses: for every

ainF, there exists an element inF, denoteda, called theadditive inverseofa, such thata+ (a) = 0.Multiplicative inverses: for every

a0 inF, there exists an element inF, denoted bya^{1}or 1/a, called themultiplicative inverseofa, such thataa^{1}= 1.Distributivity of multiplication over addition:

a(b+c) = (ab) + (ac).

The most popular field examples are:

\((\mathbb{Q}, +, \cdot)\),

\((\mathbb{R} , +, \cdot)\), and

\((\mathbb{C}, +, \cdot)\) with \(\cdot\) operation is defined as

- \((a+bi) \cdot (c + di) = (ac -bd) + (bc + ad)i\).

Notice that all these fundamental examples are infinite fields. So let's see how finite ones look like!

Let \(p\) be a prime number. The integers modulo \(p\), consisting of integers \(\{ 0, 1, 2, ... , p-1 \}\) with addition and multiplication performed modulo \(p\), is a finite field of order \(p\). We shall denote this field by \(\mathbb{F}_p\).

The elements of \(\mathbb{F}_{29}\) are \(\{ 0, 1, 2, ... , 28 \}\). The followings are some examples of arithmetic operations in \(\mathbb{F}_{29}\):

\(17 + 20 = 8\) since \(37 \ mod \ 29 = 8\).

\(17 - 20 = 26\) since \(-3 \ mod \ 29 = 26\).

\(17 \cdot 20 = 21\) since \(340 \ mod \ 29 = 21.\)

\(17^{-1} = 12\) since \(17 \cdot 12 \ mod \ 29 = 1\).

You can construct a prime field by setting the \(p\) as any prime, but there is a standard recommends elliptic curves over the five prime fields with moduli:

$$p_{192} = 2^{192} - 2^{64} - 1$$

$$ p_{224} = 2^{224} - 2^{96} + 1$$

$$ p_{256} = 2^{256} - 2^{224} + 2^{192} + 2^{96} - 1$$

$$ p_{384} = 2^{384} - 2^{128} - 2^{96} + 2^{32} - 1$$

$$p_{521} = 2^{521} - 1$$

These primes have the property that they can be written as the sum or difference of a small number of powers of 2. Furthermore, except for \(p_{521}\), the powers appearing in these expressions are all multiple of 32. These properties yield reduction algorithms that are especially fast on machines with wordsize 32.

Basis of the security of elliptic curve cryptography is formed by the discrete logarithm problem (DLP), which we will cover in upcoming parts with more details, and DLP is more tractable in finite fields compared to infinite fields. This means that elliptic curve cryptography can achieve high levels of security with relatively smaller key sizes compared to other cryptographic schemes, such as RSA.

Let \(p\) be a prime number and let \(\mathbb{F}_p\) denote the field of integers modulo \(p\). An "elliptic curve" \(E\) over \(\mathbb{F}_p\) is defined by an equation of the form

$$y^2 = x^3 + ax + b,$$

where \(a,b \in \mathbb{F}_p\) satisfy \(4a^3+ 27b^2 \neq 0 \ (mod \ p) \) . A pair \((x, y)\), where \(x,y \in \mathbb{F}_p\) is a point on the curve if it satisfies the curve equation. The *point at infinity*, denoted by \(\infty\), is also said to be on the curve. The set of all points on \(E\) is denoted by \(E(\mathbb{F}_p)\).

For example, if \(E\) is an elliptic curve over \(\mathbb{F}_7\) with defining equation

$$y^2 = x^3 + 2x + 4,$$

then the points on \(E\) are

$$E(\mathbb{F}_7) = \{ \infty, (0,2), (0,5), (1,0), (2,3), (2,4), (3,3), (3,4), (6,1), (6,6) \}.$$

Please see point addition to see how to add 2 points up to obtain another point on the curve.

As we are able to define an addition operation on elliptic curves, we can also construct a group structure on elliptic curves

With the point addition rule, the set of points \(E(\mathbb{F}_p)\) forms a group with \(\infty\) serving as the identity element.

This kind of group structures are called "elliptic curve groups".

In this post, some fundamental concepts and notions are mentioned. In the next post, we will discuss key generation and encryption schemes in elliptic curve cryptography.

]]>Basics of Public-Key Cryptography

What is a key pair?

Private Key

Public Key

How it works?

Real World Applications

Mathematical Foundations

Key Generation Principles & Prime Numbers

Euler's Totient Function

Formula of Secrecy

Encryption / Decryption

From Theory to Hands-on Practice (Rust Code)

Key Generation

Encryption / Decryption

It is time to test!

Conclusion

A key pair consists of two keys:

private key and

public key.

It is available to everyone and used for encryption. It's like a digital address shared openly for others to send encrypted messages. So, anyone can use a recipient's public key to encrypt a message. Once the message is encrypted, it can only be decrypted by the corresponding private key.

It is used for decryption and, as the name suggests, kept secret. The recipient uses their private key to decrypt encrypted messages. The strength of the system lies in the fact that, although the public key is known to all, it is computationally infeasible to derive the private key from it.

Let's consider a scenario where two close friends, Alice and Bob, wish to communicate secretly. In this situation, Alice and Bob can use public-key cryptography (assuming they have securely shared their keys with each other; we will discuss key sharing methods shortly) to maintain the confidentiality of their messages.

Alice encrypts her message using Bob's public key and sends it over to Bob.

Bob receives the encrypted message, decrypts it using his own private key, and finally reads it.

Email encryption serves as a technique to protect the contents of email communications from unauthorized access by external parties. When an email is encrypted, it becomes unreadable to any person. Decryption and restoration of the original message are only possible using your unique private email key.

This encryption process utilizes public-key cryptography.

Social media platforms like WhatsApp and Instagram also use public-key cryptography (sometimes private-key cryptography also) for end-to-end encryption.

In almost all the blockchains, public-key cryptography is extensively used.

Where public keys are used as an account number, private keys are used to sign transactions (I will write a particular blog post on digital signatures) and to prove ownership of an address and the assets contained within it.

In this section, we will discuss the mathematical fundamentals of key generation. You will see that how important prime numbers will be for public-key cryptography.

There is more than one approach to key generation in public-key cryptography. Two of them are:

RSA cryptography,

Elliptic curve cryptography.

Although I'm planning another series of posts regarding elliptic curve cryptography, for the sake of simplicity, we will discuss and practice RSA encryption in this series.

RSA encryption relies on prime factorization of large numbers being computationally difficult. We want the calculation to be easy to perform in one direction, but difficult to invert if you don't have the proper key.

So far, we have discussed how public-key cryptography worked, but we never discussed how were those public and private keys generated.

The main principle in generating public / private key pairs is the use of large prime numbers. Recall from the previous post about prime numbers.

**Unpredictability:**Large primes are not easily guessable, adding a layer of security,**Unique Factorization:**The fact that every natural number can be uniquely factored into primes is crucial in algorithms like RSA, where the security relies on the difficulty of factoring the product of two large prime numbers.

Euler's totient function \(\phi(n)\) is defined as the count of positive integers up to \(n\) that are relatively prime to \(n\). Simply it calculates the number of integers less than \(n\) that do not share any common factors with \(n\), except for the number 1.

**For a Prime Number**\(p\): \(\phi(p) = p - 1.\) This is because all numbers less than a prime number are coprime to it.**For a Product of Two Primes**\(p\) and \(q\): \(\phi(p \ \times \ q) = (p - 1) \ \times \ (q - 1).\) This results from the fact that none of the numbers less than \(p \ \times \ q\) are divisible by either \(p\) or \(q\), except for the multiples of \(p\) and \(q\).**General Case:**If \(n = p_1^{k_1} \times p_2^{k_2} \times \ ... \ \times p_r^{k_r}\), where \(p_1, p_2, ..., p_r\) are distinct prime numbers and \(k_1, k_2, ..., k_r\) are their respective powers, then- \(\phi(n) = n \times (1 - \frac{1}{p_1}) \times (1 - \frac{1}{p_2}) \times \ ... \ \times (1 - \frac{1}{p_r})\).

It is time to construct the key generation algorithm.

For the algorithm to help Bob communicate with Alice, Bob would need to create a public key for Alice to encrypt messages, and a private key to help Bob decrypt Alice's messages. RSA key generation works as follows:

Take two large prime numbers, \(p\) and \(q\), and multiply them to get a number \(N\). Keep \(p\) and \(q\) secret.

Calculate the totient of \(N\): \(\phi(N) = (p-1)(q-1)\).

Find a positive integer \(e\) that is less than \(\phi(N)\) and is coprime with \(\phi(N)\), meaning the greatest common divisor (GCD) between \(e\) and \(\phi(N)\) is 1.

Calculate the number \(d = e^{-1} \ mod \ \phi(N)\). Notice that this means \(e \cdot d \equiv 1 \ mod \ \phi(N)\), so \(d\) and \(e\) are modular inverses of one another.

The pair of integers \((N, e)\) represents Bob's public key and can be shared by everyone who wants to communicate with him. Similarly \((N,d)\) represents Bob's private key that is supposed to be kept as a secret.

Now, if Alice wants to send a message \(m\) and encrypt it into ciphertext \(c\) to send over to Bob, she would perform the following calculation:

$$Enc(m) = m^{e} \ mod \ N = c.$$

Bob receives the encrypted message and decrypts it by performing the following calculation:

$$Dec(c) = c^{d} \ mod \ N = m.$$

Notice that **the aysmmetric encryption correctness property** holds:

$$Dec(Enc(m)) = m^{ed} \ mod \ N \equiv m \ mod \ N$$

as \(e\) and \(d\) are multiplicative inverses of each other.

Before starting to write `generate_keys()`

function, let's recall a slightly modified version of `mod_inverse()`

function we have built in the previous post:

`fn mod_inverse(e: u64, phi: u64) -> Option<u64> { let (mut a, mut b, mut x0, mut x1) = (phi, e, 0u64, 1u64); while b > 0 { let q = a / b; (a, b) = (b, a % b); (x0, x1) = (x1, x0.wrapping_sub(x1.wrapping_mul(q))); } if a > 1 { None // No modular inverse if a is not 1 } else { Some(x0.wrapping_add(phi) % phi) }}`

We will also need a new function to calculate modular exponents (to perform an exponentiation over a modulus):

`fn mod_exp(mut base: u64, mut exp: u64, modulus: u64) -> u64 { if modulus == 1 { return 0 } let mut result = 1; base %= modulus; while exp > 0 { if exp % 2 == 1 { result = result * base % modulus } exp >>= 1; base = base * base % modulus; } result}`

Now, we are ready to construct the key generation function. It will take the tuple\((p, q)\)and will output the triple \((N, e, d)\):

`fn generate_keys(p: u64, q: u64) -> (u64, u64, u64) {}`

Let us start by defining the basic variables like

\(N = p \times q\),

\(\phi = (p-1)(q-1)\):

`let N = p * q;let phi = (p - 1) * (q - 1);`

The most commonly used value for \(e\) in RSA-like systems is 65537 (which is of course a prime number).

`let e = 65537;`

Now that we have everything we need, all we have to do is calculate \(d\) by calculating the modular inverse of \(e\) in mod \(\phi\) by ensuring such a modular inverse exists:

`let d = mod_inverse(e, phi).expect("Modular inverse does not exist!");`

Returning the \((N, e, d)\) triple will complete `generate_keys()`

function:

`fn generate_keys(p: u64, q: u64) -> (u64, u64, u64) { let n = p * q; let phi = (p - 1) * (q - 1); let e = 65537; // Using 65537 as e let d = mod_inverse(e, phi).expect("Modular inverse does not exist."); (n, e, d)}`

Let us recall the encryption and decryption functions:

$$Enc(m) = m^{e} \ mod \ N = c. $$

$$Dec(c) = c^{d} \ mod \ N = m.$$

So, all we need for encryption is to have:

\(m\) (message) as the base,

\(e\) as the exponent, and

\(N\) as the modulus:

`fn encrypt(message: u64, e: u64, n: u64) -> u64 { mod_exp(message, e, n)}`

Similarly, what we need for decryption is to have:

\(c\) (ciphertext) as the base,

\(d\) as the exponent, and

\(N\) as the modulus:

`fn decrypt(ciphertext: u64, d: u64, n: u64) -> u64 { mod_exp(ciphertext, d, n)}`

The code is almost ready. We need to define \(p\), \(q\), and the message \(m\). Normally those primes are extremely large to make the system more complicated. But, for the sake of simplicity, let's choose \(p\) and \(q\) a bit small, for example:

\(p\) = 61,

\(q\) = 53.

Of course, there are some restrictions we need to be mindful of:

They are both prime.

\(\phi = (p-1)(q-1) = 3120\) is coprime to \(e = 65537\).

So, we can proceed with these selections. Let's implement it inside the `main()`

function:

`fn main() { let p: u64 = 61; let q: u64 = 53; let (n, e, d) = generate_keys(p, q); let message = 42; let encrypted = encrypt(message, e, n); let decrypted = decrypt(encrypted, d, n);}`

It is useful to put some **print** lines to check if the code is working properly:

`fn main() { let p: u64 = 61; let q: u64 = 53; let (n, e, d) = generate_keys(p, q); println!("Public Key: (e: {}, n: {})", e, n); println!("Private Key: (d: {}, n: {})", d, n); let message = 42; let encrypted = encrypt(message, e, n); let decrypted = decrypt(encrypted, d, n); println!("Original message: {}", message); println!("Encrypted message: {}", encrypted); println!("Decrypted message: {}", decrypted);}`

Output:

`Public Key: (e: 65537, N: 3233)Private Key: (d: 2753, N: 3233)Original message: 42Encrypted message: 2557Decrypted message: 42`

As you can see, we are able to retrieve the original message after completing the encryption and decryption processes. So our code passed the most fundamental test:

$$Dec(Enc(m)) \equiv m \ mod \ N.$$

You can test this code by yourself on Rust Playground.

Don't forget the

coprimality conditionwhen setting the primes \(p\) and \(q\).

In this post, we have delved deeper into the world of public-key cryptography, exploring the aspects of public and private keys, and how they are used in RSA encryption. We've discussed the importance of prime numbers in generating these keys and touched on Euler's Totient Function, which plays a crucial role in the process. We've also seen how these concepts are applied in real-world scenarios like email, social media, and blockchains. Lastly, we have taken a practical approach by implementing these concepts in Rust code, demonstrating how to generate keys and encrypt and decrypt messages.

I hope this series of posts has been helpful for you. See you in the next post!

]]>In this post, Ill try to explain what zkIgnite is, what has been done so far in the previous cohorts, and finally, what kind of new things we have in this cohort (Cohort 3).

Before starting, it is worth noting that this is NOT a paid content.

What is zkIgnite, exactly?

Overview

zkApp Product Track

Developer Tooling & Infra Track

What happened so far?

Cohort 0

Cohort 1

Cohort 2

What now? | Cohort 3

Who are involved?

Builders

Electors

Technical Committee

And of course, community!

Judging Criteria

Funding

Timeline

How to participate?

Personal Thoughts

First of all, if you are not familiar with the Mina ecosystem and zkApps, you can take a look at my relevant blog post: Exploring Mina Protocol: Building zkApps w/ o1js by Furkan Akal.

zkIgnite is a community-driven builder program to enhance developers and entrepreneurs in the Mina ecosystem. The program provides

technical and non-technical support,

mentorship,

grants.

So far, 50 zkApp and developer tooling projects have been funded.

Participants build applications utilizing zero-knowledge proofs to address practical issues in the real world.

Although there is no restriction to participate as a team or as an individual, teams are encouraged to have 1-2 developers. However, participation is open to everyone, including non-technical builders and community members.

Participants in this track build tools making it easier and more efficient to build on Mina Protocol.

We will discuss these tracks with more details in the upcoming sections.

It was the first edition of zkIgnite back in 2022. It ran from November 22nd, 2022, until the winners were announced on December 22nd, 2022.

**Top 3 Prizes:**

1st prize: 20,000 MINA,

2nd prize: 12,000 MINA,

3rd prize: 8,000 MINA.

**High Quality zkApps:** All high quality zkApps submitted were eligible to receive 5K MINA.

**Bonus Prize:** 1-1.5K MINA to be received by the teams building an oracle to pull on-chain data for zkApps to use.

**Tutorial 4:** The first 1000 participants completing the zkApp Tutorial 4 were eligible to receive 50 MINA.

Technical implementation,

Impact,

Business potential,

Building capacity for next builders.

The second edition of the program, till the winners were announced, took place between February 15th, 2023 and April 3rd, 2023

It is;

250,000 USDC,

150,000 MINA

for the zkApp Track and;

250,000 USDC,

150,000 MINA

for the Dev4Dev (Developer Tooling & Infrastructure) Track. So 500K USDC and 300K MINA in total.

**zkApp Track:**

Business potential,

Impact,

Clarity,

Feasibility.

**Dev4Dev Track:**

Innovation,

Dev experience,

Scalability,

Feasibility.

The third edition of the program took place between June 14th, 2023 and September 11th, 2023.

It is

500,000 MINA and

500,000 USDC

to allocate towards zkApp and Dev Tooling proposals.

Funding allocation decisions were made by electors who are a group of experienced builders and community members within the ecosystem, by considering the similar criteria applied in the previous cohort.

If you are interested in application development to solve a real world problem, then zkApp Product Track is for you. You will be expected to propose a zkApp idea to solve a real world problem and to have a commercial potential.

If not, dont worry. You can go for the Developer Tooling & Infrastructure Track. Every self-sustaining ecosystem in Web3 needs and will always need people to make things more efficient.

They are a group of community members who are experienced in zkApp development or zero-knowledge cryptography. Their main role in this cohort is to provide some feedback for builders and vote for proposals by allocating MINA tokens.

They are a group of ZK experts to provide technical review and feedback on submitted proposals.

The Mina community is one of the largest and most active communities in the Web3 space. They will play the key role to test the products by directly using them. You can join Mina Protocol Discord, if you havent so far.

**Commercial Potential:**Does the zkApp have the potential to generate revenue? How strong is the use case for a sustainable business over time?**Go-to-Market Strategy:**Does the zkApp have the potential to bring on thousands of real users in the next 3-6 months? Has the proposer articulated how they plan to get new users onboard with an MVP?**Vision & Growth Potential:**How compelling is the vision for where this application will exist at scale?**Feasibility:**Will the proposed design support the applications desired scalability? Did the proposer identify key risks or dependencies and articulate how to work around them?**Team:**Based on the information provided, does the proposing team have relevant experience that will help them deliver on their milestones?

**Impact:**Does the proposal solve a real problem or address a gap for developers building on Mina Protocol? How important is the problem to be solved for developers to build quality zkApps?**Scalability & Growth Potential:**Does the proposed solution have the potential to scale and accommodate the growing demand for zkApps in the future? Does the proposal promote reusability and provide benefits to multiple parties within the Mina ecosystem?**Architecture:**Does the proposed architecture design demonstrate that the proposers have a good understanding of Mina Protocol and o1js? Will the proposed architecture support the applications desired impact and scalability?**Feasibility:**Are the proposed milestones feasible to achieve within the current o1js functionality? Did the proposer identify key risks and articulate how to work around them?**Team:**Based on the information provided, does the proposing team have relevant experience that will help them deliver on their milestones?

**zkApp Product:**

**Goal:**To support zkApps with commercial potential to bring more users to Mina Protocol.**Initial Funding:**1,200,000 MINA

**Developer Tooling & Infrastructure:**

**Goal:**To support projects that improve the developer experience on Mina Protocol.**Initial Funding:**300,000 MINA

**Elector:**

**Goal:**To support some community members who allocate funding to project proposals.**Grant:**5,000 MINA per elector

**Technical Committee:**

**Goal:**To support ZK experts who provide technical review on project proposals.**Grant:**15,000 MINA per committee member

**December 22nd, 2023:**Cohort 3 Kick-off Call**January 31st, 2024:**Deadline for first draft project proposals**February 2nd - 10th, 2024:**Technical reviewers and electors provide feedback on proposals**February 17th, 2024:**Deadline for final proposals**February 18th - 28th, 2024:**Electors vote to allocate grant funding**March 1st, 2024:**Cohort 3 grantees are announced**March 2nd - May 31st, 2024:**Grantees build towards their technical milestones

So, there is still a couple of days to submit your proposal.

Create an account on https://zkignite.minaprotocol.com/.

Submit your proposal by visiting the relevant website below:

I really love how O(1) Labs and Mina Foundation are conducting the developer & community marketing efforts. They are doing it using as natural ways as possible and unfortunately this is not an industrial standard for our ecosystem right now.

I find zkIgnite extremely useful and also important to bring a new sort of standard for developer marketing. I hope it will lead many new start-ups to build on Mina Protocol.

]]>What is a prime number, though?

Definition and Basic Properties

Definition

Unique Factorization

Infinitude of Prime Numbers

History

How to find them?

Trial Division

Sieve of Eratosthenes

Probabilistic Tests

Modular Arithmetic

Definition

Example

Modular Inverse

Euclidean Algorithm

Extended Euclidean Algorithm

From Theory to Hands-On Practice

- Rust Code

Conclusion

Definition:A natural number is called aprime number (orprime)if it is greater than 1 and cannot be written as the product of two smaller natural numbers.

For example, 13 is prime because the only way of writing it as a product, 1 13 or 13 1. However, 14 is not prime because it can be written as a product, 7 2 or 2 7.

Writing a natural number as a product of prime numbers is called a **prime factorization** of the number. For example:

The terms in the expression are called **prime factors**.

The fundamental significance of prime numbers to number theory in general comes from the **fundamental theorem of arithmetic**.

Fundamental Theorem of Arithmetic:Every integer larger than 1 can be written as a product of one or more primes.

More strongly, this product is unique in the sense that any two prime factorizations of the same number will have the same numbers of copies of the same primes, although their ordering may differ. So, although there are many different ways of finding a factorization using an integer factorization algorithm, they all must produce the same result. Primes can thus be considered the "basic building blocks" of the natural numbers.

There are infinitely many prime numbers, so the following sequence never ends:

We have many proofs for this statement.

**Euclids Proof:** Euclid proposed a proof published in his well-known *Elements.*

Consider any **finite** list of prime numbers:

Let P be the product of all the prime numbers in this list:

Now, let *q* = *P* + 1. Then *q* is either prime, or not:

If

*q*is prime, then there is at least one more prime that is not in the list,*q*itself.If

*q*is not prime, then some prime factor*p*is supposed to divide*q*. But*p*also divides*P*+ 1 =*q*, as just proposed. If*p*divides*P*and also*q*, then*p*must also divide the difference (that is equal to 1). Since no prime number divides 1,*p*cannot be in the list. This means that at least one more prime number exists beyond those in the list.

The Rhind Mathematical Papyrus, from around 1550 BC, has Egyptian fraction expansions of different forms for prime and composite numbers. However, the earliest surviving records of the study of prime numbers come from the ancient Greek mathematians, who called them *prtos arithms* ( ). Euclid's *Elements* (c. 300 BC) proves the infinitude of primes and the fundamental theorem of arithmetic, and shows how to construct a perfect number from a Mersenne prime.

Around 1000 AD, the Islamic mathematician Ibn al-Haytham (Alhazen) found Wilson's theorem, characterizing the prime numbers as the numbers n that evenly divide

He also conjectured that all even perfect numbers come from Euclid's construction using Mersenne primes, but was unable to prove it.

In 1640, Pierre de Fermat stated Fermats Little Theorem.

Fermats Little Theorem:Ifpis a prime andais any integer not divisible byp, thena^{p}^{ 1}1 is divisible byp.

In 1742, Christian Goldbach formulated Goldbachs conjecture:

Goldbachs Conjecture:Every even natural number greater than 2 is the sum of two prime numbers.

It is the most intuitive and straightforward method to determine if an integer is prime. You basically;

begin with the smallest prime number 2,

divide the given number by the prime number to check if its a divisor,

repeat the process by performing the division by the next prime.

As you may notice, this method is effective for small numbers or numbers with small factors. It becomes impractical for large numbers as the number of divisions (and the time required) increase rapidly.

It is one of the ancient methods to find all prime numbers up to a specified integer. You;

start by listing all the numbers from 2 to the maximum number

*N*you' chose,identify the first prime in the list, which is 2,

remove all multiples of this prime number from the list except the prime itself (2, 4, 6, 8, ),

move to the next number in the list that has not been removed, that is the next prime,

repeat the process.

Definition:Given an integern> 1, called amodulus, two integersaandbare said to becongruent modulo, ifnnis a divisor of their difference; that is, if there is an integerksuch that

Congruence modulo *n* is denoted as

In modulus 17:

Because the difference is 62 - 28 = 34 = 2 17, a multiple of 17.

Equivalently, 62 and 28 have the same remainder when 11 when divided by 17.

Notion of modular inverse and finding the modular inverse of an integer are crucially important in cryptography.

A

modular inverseof an integer a is an integer b such that the product ab is congruent to 1 with respect to the modulus m.

This congruence is written as

Our goal is to find such *b* for an integer *a* for given modulo *m*.

Recall from high school that **greatest common divisor (GCD)** of two integers *x* and *y* is the largest integer that divides both *x* and *y*.

The

Euclidean algorithmis a technique for finding the GCD of two integers.

Given two integers

*a*and*b*, ensure*a*\>*b*. If*a*<*b*, swap them.Divide

*a*by*b*, and take note of the remainder,*r*.Replace

*a*with*b*and*b*with*r*.Repeat steps 2 and 3 until

*b*becomes 0. The non-zero remainder at this point, which will be in the place of*a*, is the GCD of the original*a*and*b*.

**Example:**

To find gcd(48,18)gcd(48,18):

Step 1: 48 divided by 18 gives a remainder of 12 (48=182+12).

Step 2: Replace 48 with 18 and 18 with 12, then divide 18 by 12 giving a remainder of 6 (18=121+6).

Step 3: Replace 18 with 12 and 12 with 6, then divide 12 by 6 giving a remainder of 0 (12=62+0).

Since the remainder is 0, the GCD is the last non-zero remainder, which is 6.

The **Extended Euclidean algorithm** is an extension of the Euclidean Algorithm. It not only finds the GCD of two integers *a* and *b* but also finds integers *x* and *y* (coefficients) such that *ax* + *by* \= gcd(*a*, *b*).

**Algorithm Steps:**

Initialize two pairs of coefficients (

*x*1,*y*1)=(1, 0) and (*x*2,*y*2)=(0, 1). These represent the coefficients for*a*and*b*in the equation*ax*+*by*\= gcd(*a*,*b*).Perform the Euclidean Algorithm steps on

*a*and*b*. Simultaneously, update the coefficients*x*1,*y*1,*x*2, and*y*2 with each division step.After each division

*a*\=*bq*+*r*, update*a*and*b*as in the Euclidean algorithm.Update

*x*1 and*y*1 to*x*2 and*y*2, respectively.Update

*x*2 and*y*2 to*x*1*q**x*2 and*y*1*q**y*2, respectively.

Continue until

*b*becomes 0. At this point,*a*is the GCD, and*x*1 and*y*1 will be the coefficients that satisfy*ax*+*by*\= gcd(*a*,*b*).

**Example:**

To find coefficients *x* and *y* such that 48*x* + 18*y* \= gcd(48, 18):

Following the steps of the algorithm will lead you to calculate the coefficients alongside finding the GCD. For this particular example, you'll end up with specific *x* and *y* values that, when multiplied by 48 and 18 respectively and added, equal 6 (the GCD).

Let us start by initializing our function with some initial variable assignments:

`fn mod_inverse(a: i64, m: i64) -> i64 { let (mut m0, mut x0, mut x1) = (m, 0, 1); let mut a = a;}`

*m0*is set to*m*to remember the original value of*m*throughout the algorithm.*x0*and*x1*are initialized to 0 and 1, respectively. These variables are used to keep track of the coefficients of*a*and*m*in the*Extended Euclidean algorithm*. By the end of the algorithm,*x1*will hold the modular inverse of*a*modulo*m*.

Before diving deeper, we need to handle an edge case.

` if m == 1 { return 0; }`

- If m is 1, the function immediately returns 0 as the modular inverse does not exist in this case.

Now, we can construct the algorithm using a loop:

` while a > 1 { let q = a / m; let t = m; m = a % m; a = t; let t = x0; x0 = x1 - q * x0; x1 = t; }`

The loop will iterate as long as

*a*is greater than 1.*q*is the quotient of the division of*a*by*m*.The algorithm then updates

*a*and*m*using the*Euclidean algorithm*to find the GCD. So*m*becomes*a*%*m*and*a*takes on the old value of*m*.Simultaneously, it updates

*x0*and*x1*, which are tracking the coefficients for*a*and m that would be used to express the GCD as a linear combination of*a*and*m*. The goal here is to keep updating these coefficients until we find the modular inverse.

Before returning the modular inverse, lets be cool and check if the result needs any sign adjustment:

` if x1 < 0 { x1 += m0; }`

- Once the loop exits,
*x1*may hold the modular inverse of*a*modulo*m*, but it might be negative. In such a case, we just add*m0*to ensure the modular inverse is positive.

Now, its time to return the modular inverse, which is completing our function:

` return x1`

OR

` x1`

In Rust, the final expression in the function is used as return value.

So, final version of our code is as follows:

`fn mod_inverse(mut a: i64, mut m: i64) -> i64 { let (m0, mut x0, mut x1) = (m, 0, 1); if m == 1 { return 0; } while a > 1 { let q = a / m; let t = m; m = a % m; a = t; let t = x0; x0 = x1 - q * x0; x1 = t; } if x1 < 0 { x1 += m0; } x1}`

Lets see if its working. We can try to find the modular inverse of 4 modulo 11:

`fn main() { println!("{}", mod_inverse(4, 11));}`

Output:

`3`

Its correct, right? If you multiply 4 by 3, you obtain 12 that is equivalent to 1 in mod 11.

You can test this code by yourself on Rust Playground.

In this post, we've delved into the world of prime numbers and modular arithmetic, exploring their pivotal roles within the historical evolution of mathematics. We've also discussed the Euclidean algorithm, a cornerstone for understanding how to compute the modular inversea critical operation in cryptographic systems. To bridge theory with practice, I've provided a Rust code snippet that demonstrates how to calculate the modular inverse of an integer modulo *m*.

Looking ahead, the next post will shift focus to cryptographic key pairs. We'll explore their significance in securing digital communication and walk through the process of generating them. This upcoming discussion promises to further demystify the complex yet intriguing field of cryptography, equipping you with the knowledge to understand and apply these concepts in real-world scenarios.

https://en.wikipedia.org/wiki/Rhind_Mathematical_Papyrus#/media/File:Rhind_Mathematical_Papyrus.jpg

https://en.wikipedia.org/wiki/Eratosthenes#/media/File:Eratosthenes_profile.png

]]>basic understanding of cryptography,

mathematical fundamentals of public-key cryptography,

a concise Rust code to generate the keys, apply the relevant mathematical operations, and encrypt/decrypt a message.

What is cryptography?

- Terminology

Historical Background

Ancient Origins

Middle Ages to Renaissance

The Age of Mechanical Devices

The Modern Era

Types of Cryptography

Symmetric Cryptography (Private-Key Encryption)

Aysmmetric Cryptography (Public-Key Encryption)

Cryptanalysis

- Methods

Conclusion

Cryptography is a branch of mathematics focusing on the development of techniques for secure communication. Main goal is to protect the privacy and integrity of any information from third parties.

The word comes from Greek *krypts*, meaning "secret," and *graphein*, meaning "to write." It may be translated as secret writing.

**Plaintext:**It is the original, readable, and unencrypted data or message.**Ciphertext:**It refers to the encrypted data or message produced by the encryption process. Its supposed to be unreadable or unintelligible to unauthorized individuals.**Key:**It is a piece of information, usually a string of characters, that determines the functional output of a cryptographic algorithm.**Encryption:**It is the process of converting plaintext into ciphertext. It involves using a cryptographic algorithm and a key to transform the readable data (plaintext) into an unreadable format (ciphertext).**Decryption:**It is the reverse process of encryption. It involves converting ciphertext back into its original plaintext form.

The use of cryptography dates back to ancient civilizations. The earliest known use was in Egypt, around 1900 BCE, where hieroglyphs were used in an unusual way, possibly to hide the actual message.

The Greeks and Romans also advanced some cryptographic techniques. The most popular example is the Caesar cipher which I'll give more details in the upcoming sections of this post.

The Arab mathematician, Al-Kindi, in the 9th century, wrote a manuscript on deciphering encrypted messages, introducing frequency analysis to break substitution ciphers.

During the Renaissance, European cryptographers developed more sophisticated methods for encryption like the [Vigenere cipher](https://en.wikipedia.org/wiki/Vigen%C3%A8re_cipher#:~:text=The%20Vigen%C3%A8re%20cipher%20(French%20pronunciation,of%20another%20text%2C%20the%20key.), a method using a series of different Caesar ciphers based on the letters of a keyword.

The most popular example would be German's Enigma machine that is used during World War II. It employed a complex system of rotors and electrical circuits to encrypt messages.

Following the advancement in computer technology, science of cryptography had also a major transformation. In the 1970s, the Data Encryption Standard (DES) was developed by IBM.

One of the most groundbreaking development was the introduction of public-key cryptography in the 1970s by Whitfield Diffie and Martin Hellman. It solved the problem of secure key distribution which was significant limitation back then.

Cryptography is mainly divided into two paradigms:

Symmetric cryptography (private-key encryption)

Asymmetric cryptography (public-key encryption)

In symmetric cryptography, the same key is used for both encryption and decryption.

Alice encrypts her message (plaintext) using

**the key**and sends it to Bob.Bob receives the encrypted message (ciphertext), decrypts it using the same key, and then reads it.

Caesar cipher, also known as the shift cipher, is one of the simplest and most widely known encryption techniques. Each letter in the plaintext message is shifted forward in the alphabet by the key number of places. If the shift takes you past 'Z', you wrap around to the start of the alphabet. For example, with a shift of 3:

'HELLO' becomes 'KHOOR'.

'CAESAR CIPHER' becomes 'FDHVDU FLSKHU'.

In order to decrypt a ciphertext, the same process is applied backwards.

As you might have noticed;

**Encrypting function:** Shifting the letters forward:

where

x = index of the letter in the alphabet,

n = number of shifting.

**Decrypting function:** Shifting the letters backwards:

where

x = index of the letter in the alphabet,

n = number of shifting.

**Key:** How many times the number will be shifted:

Both parties are responsible with protecting secrecy of the key as well, in addition to the encrypting and decryption functions.

In asymmetric cryptography, different keys are used for encryption and decryption.

**Private Key:** It is used for decryption. Private keys must be kept secure and confidential by its owner.

**Public Key:** It is used for encryption and generated from private keys. Public keys can be distributed widely.

We will dive into more details of these in the 3rd post of this series, *keys*.

Alice encrypts her message (plaintext) using Bobs public key, and sends it to Bob.

Bob receives the encrypted message (ciphertext), decrypts it using his own private key, and then reads it.

Encryption process:

where

**E:**encrypting function,**pub:**public key of the recipient,**m:**message to be encrypted,**c:**encrypted message or ciphertext.

Decryption process:

where

**D:**decrypting function,**priv:**private key of the recipient,**c:**ciphertext to be decrypted,**m:**decrypted message (plaintext).

Crucial point here is that the following equation must be satisfied for all messages:

If this equation holds, then the decrypting function can always be used consistently.

Cryptanalysis is the study of analyzing information systems to understand the hidden aspects. Its primarily used to break cryptographic security systems and gain access to the contents of encrypted messages, even if the cryptographic key is unknown.

**Brute Force Attack:** It involves trying every possible key until the correct one is found. Although its simple, it can be extremely time-consuming for systems with large key spaces.

**Frequency Analysis:** Recall the Caesar cipher, which is a type of substitution ciphers, that the letters in the message were shifted according to the key. This method involves studying the frequency of letters or groups of letters in a ciphertext. I'ts effective against simple substitution ciphers where certain letters or patterns occur more frequently.

**Side-Channel Attacks:** These attacks exploit information gained from the physical implementation of a cryptosystem, such as timing information, power consumption, electromagnetic leaks, or even sound.

In this post, Ive tried to explain some fundamental concepts in basic cryptography and their historical background.

As progress in this series, we will dive deeper into the mathematical underpinnings of public-key cryptography and explore practical implementations using Rust. My aim is not just to understand the theoretical aspects but also to see how these concepts come to life in code.

https://makeameme.org/meme/crypto-means-cryptography

https://en.wikipedia.org/wiki/Enigma_machine#/media/File:Enigma-plugboard.jpg

]]>Before starting, it is worth noting that this is NOT a paid content.

What is Lit Protocol?,

Fundamental Concepts;

Decentralized Access Control,

Programmable Signing,

What are Lit Actions?,

Building Lit Actions.

Lit Protocol is a decentralized network for managing keys that offers developers two primary functions: **encryption** and **programmable signing**. While they seem separate, these capabilities collaborate closely and operate based on a unified foundation known as **threshold cryptography**.

The two main functionality Lit Protocol provides are:

**Encryption and Decentralized Access Control:**Lit Protocol provides data encryption/decryption by utilizing on or off-chain conditions, without relying on a centralized key custodian.

**Programmable Signing:**Lit Protocol can be used to program complex signing automations or provide seamless wallet onboarding experiences using**Programmable Key Pairs (PKPs)**and**Lit Actions**.

Lit enables a decentralized access control layer that developers can use to encrypt some content and store on the open Web. Thanks to **Lit SDK**, builders are able to use some utilities provided by Lit Protocol in their applications. They only need to define the **access control conditions (ACCs)** to determine who will be able to decrypt the encrypted data.

Some other beauty is that Lit supports the use of both on and off-chain data when defining the access control conditions.

Let's see some possible examples:

ownership of a particular fungible token or an NFT,

KYC info from a central exchange (to enable 'once KYC, use everywhere' functionality),

the result of any API call, such as a follow on Twitter,

... and many more.

It is also worth noting that **access control conditions** are compatible with most EVM chains, Cosmos, and Solana. See the full list.

As you may have already noticed, **access control** provides us kind of a reading functionality. Now, let's see the other side of the equation to find out how to write data.

In order to have the signing feature (to write data to distributed systems, e.g. blockchains), Lit Protocol provides two closely-related services:

Programmable Key Pairs (PKP),

Lit Actions.

PKPs, which stand for **programmable key pairs**, are created collaboratively by node operators in the Lit network. These key pairs are stored as distributed key shares. As their name implies, PKPs can be programmed. The set of instructions determining the circumstances under which a PKP will sign, including timing, purpose, and content, is referred to as a **Lit Action**, which we will deeply dive in the next section.

But simply put, **Lit Actions** are *immutable* JavaScript functions. They can be considered as smart contracts.

Lit Actions are JavaScript codes utilized for specifying signing and authentication rules for PKPs. When utilized alongside PKPs, Lit Actions serve as serverless functions equipped with their own private key-pair. This combination of tools enables the writing of data to blockchains and other similar state machines.

Each Lit Action is executed in parallel across Lit's threshold cryptography network, ensuring that the outcome of each program is independently confirmed by each node. Once a sufficient number of nodes (more than two-thirds of the network participants) have validated the result, the designated signing or decryption process can be carried out.

For instance, a simple illustration involves a Lit Action and its related PKP, which checks whether a number is prime and only yields a signature if the number satisfies the prime condition. Each node executes the Lit Action with a provided input and verifies if it fulfills the specified criteria. Upon meeting the conditions, the node generates an independent key share. The complete signature is only formed after collecting more than two-thirds of these shares.

It is worth noting that Lit Actions are chain-agnostic.

Let us start by installing GetLit CLI:

`npm install -g getlit`

Install Lit SDK:

`npm install @lit-protocol/lit-node-client`

As we need our programmable key pair (PKP) to proceed, we will mint a PKP. But to be able to mint a PKP, we need some test LIT tokens. After requesting some test tokens from the Faucet, we can move on:

`getlit action`

`? Where do you want to install the project? ./🎉 The project has been installed at /Users/furkan/lit/lit_actions`

In order to proceed, we need to modify 'NA_E' to 'NAME' in src/foo.action.ts:

`/** * NA_E: foo * * Replace "_" with "M" to pass the schema validation * */const foo = () => { return "bar";};`

Now, we need to mint a PKP:

`getlit setup`

This command redirects us to the browser:

Here we see some PKPs I've already minted, but we will mint a new one. Let us click on the 'Mint PKP!' button:

Confirm the transaction:

As you can see, now we have the minted PKP. After selecting it, we can get back to the terminal:

`🔐 Listening at http://localhost:1210/auth to get your authSig and pkpPublicKeyauthSig: { sig: '0xdb2171826a7d4f9d617e1ae94358f25227ff102b2b0ff7d362a3d95e237a97d11d5aa14075efa7e4bc92f805fb85a444320f4716d834d49cb9fa97de09b28ba21b', derivedVia: 'web3.eth.personal.sign', signedMessage: 'localhost:1210 wants you to sign in with your Ethereum account:\n' + '0x10A7a427aA5644CEc46462092c2e4354fe840dc1\n' + '\n' + '\n' + 'URI: http://localhost:1210/auth\n' + 'Version: 1\n' + 'Chain ID: 1\n' + 'Nonce: 7u1ZmKDg1CwP9NFoA\n' + 'Issued At: 2023-10-31T11:49:22.456Z\n' + 'Expiration Time: 2023-11-01T11:49:15.023Z', address: '0x10a7a427aa5644cec46462092c2e4354fe840dc1'}pkpPublicKey: 0x047b32ee581b66473d342cb3ac71538450e843a876c19e4097e806abbb4ca2ed3ff757f27f05699ea5e22d5fd3b4b87418f3a6ec470a70275a833ad19021ceecff🎉 Success! Your authSig and pkpPublicKey have been saved to your config file. You can view your config file at /Users/furkan/lit/lit_actions/getlit.json`

Before we continue, let's see what we have in src/main.action.ts:

`/** * NAME: hello */// This will exceed the default file size limit// import * as LitJsSdk from "@lit-protocol/lit-node-client-nodejs";type SignData = number[];const helloWorld: SignData = [ 72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100,];(async () => { // this requests a signature share from the Lit Node // the signature share will be automatically returned in the HTTP response from the node const sigShare = await LitActions.signEcdsa({ toSign: new Uint8Array(helloWorld), publicKey, // <-- You should pass this in jsParam sigName, }); console.log('sigShare', sigShare);})();`

This code basically:

defines an array called 'helloWorld' setting the encrypted version of the letters of 'Hello world' string,

signs our encrypted array with the help of our pkpPublicKey, using 'signEcdsa' method,

prints the result.

Now we have two Lit Actions:

foo,

main.

You can test them by running the test command, or create a new lit action by running the 'getlit action' command and continue building.

]]>If not, you can check them out:

Before starting, it is worth noting that this is NOT a paid content.

What is a zero-knowledge proof?

Why are ZK proofs important?,

What is a zkSNARK?,

What is Mina Protocol?

zkBridge,

What is a zkApp?,

General structure of a zkApp,

zkApp CLI,

How do zkApps work?,

Building our first smart contract w/ 'o1js',

How to interact?.

A zero-knowledge proof is a cryptographic method where one party, the prover, can prove to another party, the verifier, that a statement is true, without conveying any additional information beyond the validity of the statement itself.

In other words, it allows one party to prove to another that they know a certain secret or have certain information without actually revealing the secret or information.

They allow private transactions.

They can help to improve blockchain scalability by reducing the computational resources required for verifying transactions.

They let us keep confidential information hidden without sacrificing trustlessness.

... and many more.

zk-SNARKs represent a form of zero-knowledge proof enabling one party, the prover, to demonstrate knowledge of specific information to another party, the verifier, without revealing the actual content.

This mechanism hinges on specialized cryptographic techniques that enable the prover to generate a compact proof swiftly verifiable by the verifier, all the while persuading them of its validity.

In simpler terms, zk-SNARKs permit the prover to authenticate their awareness of something to the verifier without explicitly disclosing the details. It's akin to proving knowledge of a secret recipe ingredient without explicitly unveiling it. The term "zero-knowledge" emphasizes that the prover can establish their knowledge without imparting any supplementary information beyond this fact.

Moreover, zk-SNARKs are referred to as "succinct" because the evidence produced by the prover is concise enough for rapid verification. This feature is crucial in enabling efficient confirmation by the verifier, obviating the need for extensive computations.

Additionally, zk-SNARKs are described as "non-interactive" since the prover and verifier can independently generate and verify the proof without direct communication. This property renders zk-SNARKs a valuable asset for facilitating secure and anonymous transactions within blockchain systems.

Ultimately, zk-SNARKs serve as a potent cryptographic tool for establishing anonymous and secure transactions on the blockchain. Think of it as possessing a magical "proof machine" capable of demonstrating your knowledge without explicitly disclosing the specifics.

Mina is an L1 blockchain based on zero-knowledge proofs (ZKP) with smart contracts written in TypeScript. It is the first cryptocurrency protocol with a succinct blockchain (22KB).

https://docs.minaprotocol.com/

Yes! The entire blockchain state is encapsulated by zkSNARKs. Instead of storing all the data, the network nodes keep this proof. When a new block is generated, a fresh snapshot is created, encompassing the preceding network state and the new block. This lightweight snapshot represents the complete state. This cycle continues with the addition of new blocks. In essence, through the iterative combination of zkSNARKs, the blockchain maintains a consistent size.

No! A Mina node has the option to operate as an archive node, storing past transactions. Archive nodes prove beneficial for service operators, like block explorers. However, this historical data isn't necessary for verifying the current consensus state of the protocol.

zkApps, which stands for zero-knowledge apps, denote smart contracts within the Mina Protocol, leveraging zero-knowledge proofs, particularly relying on zkSNARKs.

zkApps employ an execution method situated off the blockchain and primarily rely on an off-chain state framework. This design facilitates confidential computation and state management that can be either private or public.

Hence, the proof is stored on-chain where verification is executed off-chain.

A zkApp consists of two main ingredients:

front-end,

smart contract.

Smart contracts for zkApps are written in TypeScript, using 'o1js' (evolution of SnarkyJS).

When building zkApps, the o1js library facilitates the creation of a prover function and a corresponding verifier function during the coding process. The prover function executes custom logic within a user's browser, generating a proof of the executed code. Users interact with the zkApp's interface, providing private and public inputs to the prover function, which in turn produces a zero-knowledge proof. While private inputs aren't needed again, the verifier function, responsible for efficiently validating whether a zero-knowledge proof satisfies all constraints defined in the prover function, must be supplied with public inputs during its operation on the Mina network.

On Mina, the verifier function operates as the final check, ensuring that a zero-knowledge proof adheres to all constraints outlined in the prover function. After the development phase, running the 'npm run build' command compiles the TypeScript code into JavaScript, resulting in the creation of the 'smart_contract.js' file. This file allows developers to execute the prover function and generate a verification key for deploying the smart contract.

Although the prover function runs in a user's browser, the verification key resides on-chain within a specific zkApp account, enabling the Mina network to verify whether a zero-knowledge proof meets all the constraints specified in the prover. The verification key serves as a crucial component for establishing a zkApp account and can be utilized off-chain to verify proofs using the verifier function or the verification key itself.

Before starting, please make sure you have already installed the following:

Let us install zkApp CLI now:

`npm install -g zkapp-cli`

To make sure if zkApp CLI is installed successfully, we can check its version:

`zk --version`

Now, it's time to create our first zkApp project:

`zk project fibonacci`

Output:

`? Create an accompanying UI project too? next svelte nuxt empty none`

Let's choose 'none' for now.

`Success!Next steps: cd fibonacci git remote add origin <your-repo-url> git push -u origin main`

Our project directory is ready! Let us see what we have here:

`cd fibonaccils`

`LICENSE babel.config.cjs config.json jest.config.js node_modules package.json tsconfig.jsonREADME.md build jest-resolver.cjs keys package-lock.json src`

Let us rename src/Add.ts to src/Fibonacci.ts and rewrite the code:

`import { Field, SmartContract, state, State, method } from 'o1js';export class Fibonacci extends SmartContract { @state(Field) num1 = State<Field>(); @state(Field) num2 = State<Field>(); @state(Field) result = State<Field>(); init() { super.init(); this.num1.set(Field(0)); this.num2.set(Field(1)); } @method update() { const newResult = this.num1.get().add(this.num2.get()); this.num1.assertEquals(this.num1.get()); this.num2.assertEquals(this.num2.get()); this.result.set(newResult); this.num1.set(this.num2.get()); this.num2.set(newResult); }}`

This is our very first smart contract example and let's dive a bit deeply:

The code begins with the initialization of a smart contract named 'Fibonacci', implemented using the 'o1js' library for blockchain development.

Within the 'Fibonacci' contract, there are three state field variables: 'num1', 'num2', and 'result'. These variables are utilized to maintain the values required for generating the Fibonacci sequence.

The 'init' method is responsible for setting the initial values of 'num1' and 'num2' to 0 and 1, respectively, effectively representing the starting point of the Fibonacci sequence.

The 'update' method is crucial for generating the subsequent number in the Fibonacci sequence. Here's how the method operates:

First, it computes the sum of the current values of 'num1' and 'num2' using the 'add' method.

Next, it validates that the values of 'num1' and 'num2' have not changed during the execution to ensure the consistency and reliability of the sequence.

Once the validation is complete, it updates the 'result' variable with the newly computed sum.

Lastly, it updates the values of 'num1' and 'num2' to prepare for the subsequent iteration. Specifically, 'num1' assumes the value of the prior 'num2', while 'num2' assumes the value of the newly calculated 'result'.

Now let's run the build command:

`npm run build`

This command compiles our smart contract written in TypeScript to JavaScript.

Now, let's configure it before the deployment:

`zk config`

` Deploy aliases in config.json Name URL Smart Contract None found Enter values to create a deploy alias: Create a name (can be anything): fibonacci Set the Mina GraphQL API URL to deploy to: https://proxy.berkeley.minaexplorer.com/graphql Set transaction fee to use when deploying (in MINA): 0.1 Choose an account to pay transaction fees: Create a new fee payer key pair NOTE: The private key is created on this computer and is stored in plain text. Create an alias for this account acc1 Create fee payer key pair at /Users/furkan/.cache/zkapp-cli/keys/acc1.json Create zkApp key pair at keys/add.json Add deploy alias to config.jsonSuccess!Next steps: - If this is a testnet, request tMINA at: https://faucet.minaprotocol.com/?address=<address>&?explorer=minaexplorer - To deploy, run: `zk deploy fibonacci``

Let's cover what we've done above:

We set the name as "fibonacci".

As we will deploy our smart contract to Berkeley testnet, we put its GraphQL API.

We set the transaction fee as 0.1 MINA (could be something else).

We created a new account that will deploy the contract and set an alias for it.

After getting some faucet MINA by visiting the suggested faucet link, we can deploy our smart contract to Berkeley network:

`zk deploy fibonacci`

Output:

` Build project Generate build.json Choose smart contract Only one smart contract exists in the project: Fibonacci Your config.json was updated to always use this smart contract when deploying to this network. Generate verification key (takes 1-2 min) Build transaction Confirm to send transaction Are you sure you want to send (yes/no)? y Send to networkSuccess! Deploy transaction sent.Next step: Your smart contract will be live (or updated) as soon as the transaction is included in a block: https://berkeley.minaexplorer.com/transaction/<txn-hash>`

Let us write a script to check the results:

`touch src/main.ts`

`import { Fibonacci } from './Fibonacci.js';import { Mina, PrivateKey, AccountUpdate,} from 'o1js';console.log('o1js loaded');const useProof = false;const Local = Mina.LocalBlockchain({ proofsEnabled: useProof });Mina.setActiveInstance(Local);const { privateKey: deployerKey, publicKey: deployerAccount } = Local.testAccounts[0];const { privateKey: senderKey, publicKey: senderAccount } = Local.testAccounts[1];// Create a public/private key pair. The public key is your address and where you deploy the zkApp toconst zkAppPrivateKey = PrivateKey.random();const zkAppAddress = zkAppPrivateKey.toPublicKey();// create an instance of Fibonacci - and deploy it to zkAppAddressconst zkAppInstance = new Fibonacci(zkAppAddress);const deployTxn = await Mina.transaction(deployerAccount, () => { AccountUpdate.fundNewAccount(deployerAccount); zkAppInstance.deploy();});await deployTxn.sign([deployerKey, zkAppPrivateKey]).send();// get the initial state of Fibonacci after deploymentconst num0 = zkAppInstance.num1.get();const num1 = zkAppInstance.num2.get();console.log('state after init:', num0.toString());console.log('state after init:', num1.toString());const txn1 = await Mina.transaction(senderAccount, () => { zkAppInstance.update();});await txn1.prove();await txn1.sign([senderKey]).send();const num2 = zkAppInstance.result.get();console.log('state after txn1:', num2.toString());try { const txn2 = await Mina.transaction(senderAccount, () => { zkAppInstance.update(); }); await txn2.prove(); await txn2.sign([senderKey]).send();} catch (ex) { console.log("Error!");}const num3 = zkAppInstance.result.get();console.log('state after txn2:', num3.toString());try { const txn3 = await Mina.transaction(senderAccount, () => { zkAppInstance.update(); }); await txn3.prove(); await txn3.sign([senderKey]).send(); } catch (ex) { console.log("Error!"); } const num4 = zkAppInstance.result.get(); console.log('state after txn2:', num4.toString());const txn4 = await Mina.transaction(senderAccount, () => { zkAppInstance.update();});await txn4.prove();await txn4.sign([senderKey]).send();const num5 = zkAppInstance.result.get();console.log('state after txn3:', num5.toString());console.log('Shutting down');`

This TypeScript code does:

start by importing the necessary modules and the 'Fibonacci' smart contract from './Fibonacci.js'.

set up the 'o1js' library and initializes a local instance of the Mina blockchain for testing purposes, with the option to enable or disable proofs.

define the necessary private and public keys for both the deployer and sender accounts.

generate a new public/private key pair, with the public key representing the address where the 'Fibonacci' smart contract will be deployed.

create an instance of the 'Fibonacci' smart contract and deploy to the specified address.

retrieves and logs the initial state of the 'Fibonacci' contract after deployment, fetching the values of 'num1' and 'num2'.

perform a series of transactions is to execute the 'update' method of the 'Fibonacci' contract, with error handling implemented for potential exceptions.

log the results of the transactions, displaying the state after each update.

finally, log the message 'Shutting down', indicating the end of the script's execution.

Now, let's see what'll happen:

`npm run build && node build/src/main.js`

Output:

`> firstproject@0.1.0 build> tsco1js loadedstate after init: 0state after init: 1state after txn1: 1state after txn2: 2state after txn2: 3state after txn3: 5Shutting down`

Just as expected! It printed the initial values of 0 and 1 first. Then printed the next number in each transaction!

Thanks for reading Furkans Substack! Subscribe for free to receive new posts and support my work.

]]>Before starting, it is worth noting that this is NOT a paid content.

Gno.land is a blockchain L1 solution concentrated on making smart contract development as easy as possible.

Because this way, a lot of web2 developers can easily contribute to web3 and build smart contracts.

Gnolang serves as the programming language for creating Realms, which are Smart Contracts on the Gnoland platform.

It's essentially an interpreted version of Golang, where developers upload their source code onto the blockchain and GnoVM executes the AST interpretation. By doing so, Gnoland emphasizes transparency since developers must share their source code instead of compiled bytecode. Furthermore, Gnolang is designed to support multi-threading, similar to Go routines and channels, for developing smart contracts.

Program code - Solidity

EVM bytecode - another low-level code

EVM implementation - C++, Go, or Rust

Program code - Go

Go AST (abstract syntax tree) - Go

GnoVM implementation - Go

So, you can learn Go once, and then do everything :).

As I mentioned, Realms (smart contracts) are written in Gno.

A public function called `Render(path string) string`

can be implemented by each Realm, which is responsible for generating valid markdown for the given path parameter. This function is aimed at enhancing the interactivity of Realms and simplifying their rendering process.

The *gnodev cli* toolsuite is provided to developers for developing Realms, which includes user-friendly commands for testing and building Realms.

Realms can employ Gno packages from the Gno standard library such as random, maths, avl, etc. or even from the community.

The variables of the Realm's packages are used to store the Realm's state.

In essence, a gno.land Package is a collection of features and capabilities that does not possess any state, which makes it akin to a library. Another significant aspect is that packages can be imported from various Realms and Packages, using the syntax:

`import "gno.land/p/..."`

.

A Realm, written in Gno, is a Smart Contract located on gno.land. Unlike Packages, Realms have the ability to store values or state. To import a Realm, one can use the syntax:

`import "gno.land/r/..."`

.

`package demo// As our function returns a string value, we indicate it while defining the function.func Hello() string { return "Hello, World!"}`

As mentioned earlier, the main difference between packages `/p`

and realms `/r`

is that realms can manage a state.

States are basically defined as global variables (outside of functions) inside the Realm:

`package updatenamevar myName string = "Furkan"func UpdateName(name string) { myName = name}`

The Realm has the ability to define an `init()`

function, which gets executed when the Realm is first called. This can be viewed as a kind of constructor for the Realm, allowing you to establish initial values and logic for the Realm.

`package stakingimport ( "std")var balance_of map[std.Address]uint64var staked_amount map[std.Address]uint64func Stake(pool std.Address, staking_amount uint64) { caller := std.GetOrigCaller() TransferFrom(caller, pool, amount) staked_amount[caller] += stkaing_amount}func TransferFrom(from std.Address, to std.Address, amount uint64) { if (balance_of[from] < amount) { panic("No sufficient balance!") } balance_of[from] -= amount balance_of[to] += amount}func assertAdmin() { if std.GetOrigCaller() != admin { panic("Nobody can call this function, but the admin!") }}`

The `Render`

is a method on a Realm which can return some sort of data to a user browsing the specific Realm using Gno.land website.

When you try to view a Package, you see that the source code is displayed; but when you try to view a Realm, the thing being displayed is the output of its `Render`

method. This is so natural, because recall that Packages cannot hold any state to display.

It does look like as follows:

`func Render(path string) string`

Now, let us write an example for a HelloWorld contract:

`package helloimport ( "strings")func Hello() string { return "Hello World!"}func enterName(name string) string { return "Welcome, " + name + "!"}// Here it comes!func Render(path string) string { if (path == "hello") { return Hello() } else { return "Nothing found!" }}`

Let us clone the official Gno repository and run the build command:

`git clone https://github.com/gnolang/gno.gitcd gnomake build`

Now, we can create the project directories of our Package and Realm:

`mkdir examples/gno.land/p/demo/todomkdir examples/gno.land/r/demo/todo`

Let us start by building the Package and the test files 'task.gno', 'task_test.gno':

`touch examples/gno.land/p/demo/todo/task.gnotouch examples/gno.land/p/demo/todo/task_test.gno`

It is wise to use a struct to introduce the notion of task. 3 variables id, task, and isDone will represent any task. Let's define Task struct to make things easier:

`package todoimport ( "gno.land/p/demo/ufmt")type Task struct { id uint task string isDone bool}`

It's time to define some functions! Let's define NewTask() that users will call when they want to create new tasks for their ToDo:

`func NewTask( id uint, task string, isDone bool,) *Task { return &Task{ id: id, task: task, isDone: isDone, }}`

Now, we can define some useful functions that we can call inside our Realm:

`func (t Task) GetId() uint { return t.id}func (t Task) GetIdString() uint { return ufmt.Sprintf("%d", t.GetId())}func (t Task) GetTask() string { return t.task}func (t Task) GetIsDone() bool { return t.isDone}func (t Task) GetInfo() string { return ufmt.Sprintf( "id: %d\nTask: %d\nisDone", t.id, t.Task, t.isDone, )}`

Our `task.gno`

Package is ready! Let us write a test for it now and see if it is working properly:

`package todoimport ( "testing")func TestNewTask(t *testing.T) { const ( id uint = 1 task string = "Debug the code!" isDone bool = false ) j := NewTask(id, task, isDone) if (j.GetId() != id) { t.Fatalf("Wrong ID!") } if (j.GetTask() != task) { t.Fatalf("Wrong Task!") } if (j.GetIsDone() != isDone) { t.Fatalf("Wrong Status!") }}`

Before running the test command, we need to execute some commands:

`make install gnodevgnodev precompile examples/gno.land/p/demo/todo/task.gnognodev test examples/gno.land/p/demo/todo/task_test.gno`

The terminal output:

`=== RUN TestNewTask--- PASS: TestNewItem (0.00s)ok ./examples/gno.land/p/demo/todo/ 2.01s`

Let us start by creating the Realm:

`touch examples/gno.land/r/demo/todo/todo.gno`

As our contract will have many functions and we want to log if functions will work properly, it is useful to define some messages after importing relevant libraries and also we can initially define a bunch of constants:

`package todoimport ( "bytes" "strings" "std" "gno.land/p/demo/todo" "gno.land/p/demo/avl")const ( successMessage = "New task is added successfully!" markMessage = "Good job!" failMessage = "Unable to add the new task!" noTaskMessage = "There is no task listed!" notFoundMessage = "Not found!")var ( admin std.Address = "?" tasks avl.Tree idCounter uint)`

We will add the admin address later when we generate it :).

Now, let's add some useful functions:

`func isAdmin(address std.Address) bool { return address == admin}func getTaskById(id string) *todo.Task { task, found := task.Get(id) if !found { return nil } return task.(*todo.Task)}`

You can think of `isAdmin()`

as similar as the `onlyOwner`

modifier in Solidity.

It's time to add our Render() method:

`func Render(path string) string { parts: = strings.Split(path, "/") switch { case path == "": return renderTasks() case len(parts) == 2 && parts[0] == "task": task: = getTaskById(parts[1]) if task == nil { return notFoundMessage } return task.GetInfo() default: return notFoundMessage }}func renderTasks() string { if tasks.Size() < 1 { return noTaskMessage } var buffer bytes.Buffer tasks.Iterate("", "", func(t * avl.Node) bool { task, _: = t.Value().( * todo.Task) buffer.WriteString(task.GetInfo()) buffer.WriteString("\n\n") return false }) return buffer.String()}`

Let's define our final two functions: AddTask() and MarkDone(). The first one will be used to add new tasks to the ToDo. The latter will be used to mark tasks to be done.

`func AddTask( task string, isDone bool,) string { if !isAdmin(std.GetOrigCaller()) { return failMessage } newTask: = todo.NewTask( idCounter, task, isDone, ) tasks.Set( newTask.GetIdString(), newTask, ) idCounter++ return successMessage}func MarkDone(id string) string { task: = getTaskById(id) if task == nil { return notFoundMessage } task.isDone = true return markMessage}`

In this page, we will create an account, deploy our code, and finally do some operations. We start by generating a Gno.land account:

`./build/gnokey generate`

The terminal output:

`pupil great rule input annual sunny west quick bunker borrow tomorrow exact couple vital air cluster glare fire nest timber shadow point dilemma sight`

This is the mnemonics that we will use to obtain our account!

Let 's do it:

`./build/gnokey add--recover Admin`

After entering our mnemonics, the terminal output is as follows:

`Admin(local) - addr: g1m2znmyqgd32r9zcts6lp3yapmj4h832fn73n2n pub: gpub1pgfj7ard9eg82cjtv4u4xetrwqer2dntxyfzxz3pqgfsdc7vfka27rget2qxxxrdxs8we3zfu0qm7glkq2lu3hqrt5u6kk5xcst, path: < nil >`

This is the address that we 'd replace in our contract:

`var ( admin std.Address = "g1m2znmyqgd32r9zcts6lp3yapmj4h832fn73n2n" tasks avl.Tree idCounter uint)`

After getting some test tokens from the faucet, we are ready to deploy our code. But first, let's start the local blockchain:

`./build/gnoland`

Now, in another terminal, we can deploy our code:

`./build/gnokey maketx addpkg - deposit "100000000ugnot" - gas - fee "1000000ugnot" - gas - wanted "5000000" - remote "localhost:26657" - chainid "dev" - pkgdir "examples/gno.land/p/demo/todo" - pkgpath "gno.land/p/demo/todo" Admin./build/gnokey maketx addpkg - deposit "100000000ugnot" - gas - fee "1000000ugnot" - gas - wanted "5000000" - remote "localhost:26657" - chainid "dev" - pkgdir "examples/gno.land/r/demo/todo" - pkgpath "gno.land/r/demo/todo" Admin`

The terminal outputs:

`OK!OK!`

The Realm and the Package have been successfully deployed! Now, let's make a contract call:

`./build/gnokey maketx call - func AddTask - args "Deploy your Realm" - args false - deposit "100000000ugnot" - gas - fee "1000000ugnot" - gas - wanted "5000000" - remote "localhost:26657" - chainid "dev" - pkgpath "gno.land/r/demo/todo" Admin`

The terminal output:

`("New task is added successfully!", string)OK!`

Thanks for reading Furkans Substack! Subscribe for free to receive new posts and support my work.

]]>