Cryptocurrency Optical Bitcoin, mining using the heavyhash algorithm


Bitcoin in a nutshell – Cryptography

One of the reasons why Bitcoin continues to attract so much attention is its exceptional mathematical nature. Satoshi Nakamoto managed to create a system that is capable of functioning in the complete absence of trust between its participants. All interactions are based on strict mathematics, there is no human factor - that’s what was revolutionary about the idea, and not in a peer-to-peer network, as many people think. Therefore, I decided to devote the first chapter specifically to the mathematical foundations of Bitcoin. Below I will try to explain to you the most basic things - elliptic curves, ECC, private / public keys and so on. Whenever possible, I will illustrate my words with code examples, mainly in Python 2.7; if anything is unclear, ask in the comments.

Book

  • Bitcoin in a nutshell – Cryptography
  • Bitcoin in a nutshell – Transaction
  • Bitcoin in a nutshell - Protocol
  • Bitcoin in a nutshell - Blockchain
  • Bitcoin in a nutshell – Mining

Table of content

  1. Introduction
  2. Elliptic curve
  3. Digital signature
  4. Private key
  5. Public key
  6. Formats & address
  7. Sign
  8. Verify
  9. Formats
  10. Links

Introduction

As I said above, cryptography is a fundamental part of Bitcoin.
Without it, nothing would work at all, so you need to start from here. Bitcoin uses so-called elliptic curve cryptography (ECC). It is based on some special function - an elliptic curve (not to be confused with an ellipse). I will tell you further what this function is and why it is so remarkable.

Elliptic curve

An elliptic curve over a field is a non-singular cubic curve on the projective plane over (the algebraic closure of the field) given by a 3rd degree equation with coefficients from the field and a “point at infinity” - Wikipedia

To put it simply, an elliptic curve is an outwardly quite simple function, usually written in the form of the so-called Weierstrass form:
Depending on the values ​​of the parameters and , the graph of this function may look different:

Script for drawing a graph in Python:

import numpy as np import matplotlib.pyplot as plt def main(): a = -1 b = 1 y, x = np.ogrid[-5:5:100j, -5:5:100j] plt.contour(x. ravel(), y.ravel(), pow(y, 2) - pow(x, 3) - x * a - b, [0]) plt.grid() plt.show() if __name__ == '__main__ ': main() If you believe the wiki, this function first appeared in the works of Diophantus, and later, in the 17th century, Newton himself became interested in it. His research largely led to the formulas for adding points on an elliptic curve, which we will now get acquainted with. Here and further we will consider some elliptic curve.

Let there be two points. Their sum is called the point, which in the simplest case is defined as follows: draw a straight line through and - it will intersect the curve at a single point, call it . By changing the coordinate of the point to the opposite sign, we get a point, which we will call the sum and, that is, .

I consider it necessary to note that we introducing this addition operation - if you add points in the usual sense, that is, adding the corresponding coordinates, you will get a completely different point, which, most likely, has nothing to do with or does not lie on the curve at all .

The smartest ones have already asked the question - what will happen if, for example, we draw a line through two points that have coordinates of the form and , that is, the line passing through them will be parallel to the ordinate axis (third frame in the picture below).

It is easy to see that in this case there is no third intersection with the curve, which we called . In order to avoid this incident, we introduce the so-called point of infinity, usually designated or simply , as in the picture. And we will say that in the absence of intersection .

Of particular interest to us is the case when we want to add a point to itself (frame 2, point). In this case, we simply draw a tangent to the point and reflect the resulting intersection point relative to .

Now, with a slight movement of the hand, you can enter the operation of multiplying a point by some number. As a result, we get a new point, that is, times. With the picture everything should become completely clear:

Elliptic curve over a finite field

ECC uses exactly the same curve, only considered over some finite field - a prime number. That is, all the named properties (addition, multiplication, point at infinity) for such a function remain in force, although if you try to draw this function, it will only vaguely resemble the usual elliptic curve (at best). And the concept of “tangent to a function at a point” generally loses all meaning, but that’s okay. Here is an example function for:

But for , there is generally an almost chaotic set of points. The only thing that still reminds us of the origin of this graph is the symmetry about the axis.

PS If you are interested in how to calculate the coordinates of a point in the case of a curve over a finite field, knowing the coordinates and - you can look through “An Introduction to Bitcoin, Elliptic Curves and the Mathematics of ECDSA” by N. Mistry, everything is described there in detail, you just need to know mathematics at the 8th grade level.

PPS In case my examples did not satisfy your inquisitive mind, here is a site for drawing curves of all kinds, experiment.

SECP256k1

Coming back to Bitcoin, it uses the SECP256k1 curve.
It has the form and is considered over the field , where is a very large prime number, namely . Also for the SECP256k1 a so-called base point is defined, also known as a generator point - this is simply a point, usually designated , lying on a given curve. It is needed to create a public key, which will be discussed below.

A simple example: using Python, let's check if a point belongs to the SECP256k1 curve

>>> p = 115792089237316195423570985008687907853269984665640564039457584007908834671663 >>> x = 550662630222773436695787188951685343 26250603453777594175500187360389116729240 >>> y = 32670510020758816978083085130507043184471273380659243275938904335757337482424 >> > (x**3 + 7) % p == y**2 % p True

Digital signature

Electronic signature (ES), Electronic digital signature (EDS) is a requisite of an electronic document obtained as a result of cryptographic transformation of information using a private signature key and allows you to verify the absence of distortion of information in an electronic document from the moment the signature is formed (integrity), and whether the signature belongs to the owner of the key certificate signatures (authorship), and in case of successful verification, confirm the fact of signing the electronic document (non-repudiation) - Wikipedia

The general idea is this: Alice wants to transfer 1 BTC to Bob.
To do this, she creates a message like: { "from" : 1FXySbm7jpJfHEJRjSNPPUqnpRTcSuS8aN, // Alice's address "to" : 1Eqm3z1yu6D4Y1c1LXKqReqo1gvZNrmfvN, // Bob's address "amount" : 1 // Send 1 BTC } Then Alice takes her private key (for now you can read , that this is a number known only to Alice), the message hash and a function of the form . At the output, it receives the signature of its message - in the case of ECDSA it will be a pair of integers; for other algorithms the signature may look different. After that, she sends out the original message, signature and her public key to all participants in the network.

As a result, each Vasya, if desired, will be able to take this trinity, the type function and check whether the owner of the private key really signed this message or not. And if everyone inside the network knows what belongs to Alice, then you can understand whether she sent the money or whether someone is trying to do it on her behalf.

Moreover, suppose that there is a person who stands between Alice and the rest of the network. Let him intercept Alice's message and change something in it, literally 1 bit out of a billion. But even in this case, checking the signature for validity will show that the message has been changed.

This is a very important feature for Bitcoin, because the network is distributed. We cannot know in advance who our transaction will go to with the requirement to transfer 1000 BTC. But he will not be able to change it (for example, indicate his address as the recipient), because the transaction is signed with your private key, and the rest of the network participants will immediately understand that something is wrong here.

AHTUNG! In reality, the process is quite different from the one described above. Here I simply showed with my fingers what an electronic digital signature is and why it is needed. The actual algorithm is described in the chapter “Bitcoin in a nutshell - Transactions”.

Private key

Private key is a fairly general term and different electronic signature algorithms may use different types of private keys.
As you may have already noticed, Bitcoin uses the ECDSA algorithm - in its case, the private key is some natural 256-bit number, that is, the most common integer from to . Technically, even the number 123456 will be a valid private key, but very soon you will find out that your coins “belong” to you until the moment an attacker gets your private key, and values ​​like 123456 are very easy to tamper with.

It is important to note that today it is impossible to enumerate all the keys due to the fact that this is a fantastically large number.

Let's try to imagine it: according to this article, there are slightly fewer grains of sand on the entire Earth. Let's use what, that is, grains of sand. And we have approximately all addresses.

This means that we can take all the sand on Earth, turn every grain of sand into a new Earth, in the resulting heap of planets, turn every grain of sand on each planet into a new Earth again, and the total number of grains of sand will still be orders of magnitude less than the number of possible private keys.

For the same reason, when creating a private key, most Bitcoin clients simply take 256 random bits - the likelihood of a collision is extremely low.

Python

>>> import random >>> private_key = ".join(['%x' % random.randrange(16) for x in range(0, 64)]) >>> private_key '9ceb87fc34ec40408fd8ab3fa81a93f7b4ebd40bba7811ebef7cbc80252a9815' >>> # or > >> import os >>> private_key = os.urandom(32).encode('hex') >>> private_key '0a56184c7a383d8bcce0c78e6e7a4b4b161b2f80a126caa48bde823a4625521f'

Python, ECDSA

>>> import binascii >>> import ecdsa # sudo pip install ecdsa >>> private_key = ecdsa.SigningKey.generate(curve=ecdsa.SECP256k1) >>> binascii.hexlify(private_key.to_string()).decode('ascii ').upper() u'CE47C04A097522D33B4B003B25DD7E8D7945EA52FA8931FD9AA55B315A39DC62′

Bitcoin-cli

$ bitcoin-cli getnewaddress 14RVpC4su4PzSafjCKVWP2YBHv3f6zNf6U $ bitcoin-cli dumpprivkey 14RVpC4su4PzSafjCKVWP2YBHv3f6zNf6U L3SPdkFWMnFyDGyV3vkCjroGi4zfD59Wsc5CHdB1LirjN6s2vii 9

Public key

Let be our private key, be the base point, then the public key is .
That is, in fact, the public key is a certain point lying on the SECP256k1 curve. Two important nuances. Firstly, it is easy to see that the operation of obtaining a public key is uniquely defined, that is, a specific private key always corresponds to one single public key. Secondly, the reverse operation is computationally difficult and, in the general case, obtaining a private key from a public one can only be done by exhaustive search of the first one.

Below you will find out that exactly the same connection exists between the public key and the address, only it’s all about the irreversibility of hash functions.

Python, ECDSA

>>> import binascii >>> import ecdsa >>> private_key = ecdsa.SigningKey.generate(curve=ecdsa.SECP256k1) >>> public_key = private_key.get_verifying_key() >>> binascii.hexlify(public_key.to_string()) .decode('ascii').upper() u'D5C08F1BFC9C26A5D18FE9254E7923DEBBD34AFB92AC23ABFC6388D2659446C1F04CCDEBB677EAABFED9294663EE79D71B57CA6A6B76BC47E6F8670FE759D7 46′

C++, libbitcoin

#include #include int main() { // Private key bc::ec_secret secret = bc::decode_hash( "038109007313a5807b2eccc082c8c3fbb988a973cacf1a7df9ce725c31b14776"); // Get public key bc::ec_point public_key = bc::secret_to_public_key(secret); std::cout << "Public key: " << bc::encode_hex(public_key) << std::endl; } To compile and run we use (having previously installed libbitcoin): $ g++ -o public_key $$(pkg-config —cflags —libs libbitcoin) $ ./public_key Public key: 0202a406624211f2abbdc68da3df929f938c3399dd79fac1b51b0e4ad1d26a47aa You can see that public key formats in the first and second examples differ (at least in length), I will talk about this in more detail below.

Formats & address

Base58Check encoding

We will encounter this encoding constantly throughout the book, so it is worth understanding how it works and why it is needed at all.
Its essence is to write down a sequence of bytes as briefly as possible in a human-readable format and at the same time make the likelihood of possible typos even less. I think you yourself understand that in the case of Bitcoin there is no such thing as too much security. One wrong symbol and the money will go to an address to which most likely no one will ever find the keys. Here is a comment on this encoding from base58.h:

// Why base-58 instead of standard base-64 encoding? // — Don't want 0OIl characters that look the same in some fonts and // could be used to create visually identical looking account numbers. // — A string with non-alphanumeric characters is not as easily accepted as an account number. // — E-mail usually won't line-break if there's no punctuation to break at. // — Doubleclicking selects the whole number as one word if it's all alphanumeric.

The easiest way to achieve brevity is to use the fairly common Base64 encoding, that is, using a base 64 number system, where the numbers 0,1,...,9, the letters az and AZ are used for recording - this gives 62 characters, the remaining two can be anything , depending on the implementation.
The first difference with Base58Check is that the characters 0,O,l,I have been removed in case someone decides to confuse them. It turns out to be 58 characters, you can check

b58 = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' def base58encode(n): result = " while n > 0: result = b58[n%58] + result n /= 58 return result # print "Base58 encode for '123123':", base58encode(123123 ) # # Base58 encode for '123123': dbp The second difference is the same check. Checksum is added again to the end of the line - the first 4 bytes of SHA256(SHA256(str)). Well, you also need to add as many ones to the beginning as there were leading zeros before encoding in base58, this is a matter of technique. import hashlib def base58encode(n): b58 = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' result = "while n > 0: result = b58 + result n /= 58 return result # Will be used to decode raw bytes and then encode them to the base58 def base256decode( s): result = 0 for c in s: result = result * 256 + ord(c) return result def countLeadingZeroes(s): count = 0 for c in s: if c == '\0': count += 1 else: break return count def base58CheckEncode(prefix, payload): s = chr(prefix) + payload checksum = hashlib.sha256(hashlib.sha256(s).digest()).digest()[0:4] result = s + checksum return '1' * countLeadingZeroes(result) + base58encode(base256decode(result))

Private key formats

The most obvious way to store a private key is to write 256 bits as a bunch of ones and zeros. But, probably, any technically literate person understands that it will be much easier to represent the same sequence in the form of 32 bytes, where each byte corresponds to two characters in hexadecimal notation. Let me remind you that in this case the numbers 0,1,...,9 and the letters A,B,C,D,E,F are used. I used this format in the examples above; for beauty, it is sometimes separated by spaces. E9 87 3D 79 C6 D8 7D C0 FB 6A 57 78 63 33 89 F4 45 32 13 30 3D A6 1F 20 BD 67 FC 23 3A A3 32 62 Another more progressive format is WIF (Wallet Import Format). It is built quite simply:

  1. Take the private key, for example 0C28FCA386C7A227600B2FE50B7CAE11EC86D3BF1FBE471BE89827E19D72AA1D
  2. We write it to Base58Check with the prefix 0x80. All.

private_key = '0a56184c7a383d8bcce0c78e6e7a4b4b161b2f80a126caa48bde823a4625521f' def privateKeyToWif(key_hex): return base58CheckEncode(0x80, key_hex.decode('hex')) # print "Private key in WIF format:", privateKey ToWif(private_key) # # Private key in WIF format: 5HtqcFguVHA22E3bcjJR2p4HHMEGnEXxVL5hnxmPQvRedSQSuT4

Public key formats

Just in case, let me remind you that the public key is just a point on the line SECP256k1.
The first and most common variant of its recording is the uncompressed format, 32 bytes each for X and Y coordinates. To avoid confusion, the prefix 0x04 is used and that is 65 bytes. import ecdsa private_key = '0a56184c7a383d8bcce0c78e6e7a4b4b161b2f80a126caa48bde823a4625521f' def privateKeyToPublicKey(s): sk = ecdsa.SigningKey.from_string(s.decode('hex'), curve=ecdsa.SECP25 6k1) vk = sk.verifying_key return ('\04' + sk. verifying_key.to_string()).encode('hex') uncompressed_public_key = privateKeyToPublicKey(private_key) # print "Uncompressed public key: {}, size: {}". format(uncompressed_public_key, len(uncompressed_public_key) / 2) # # Uncompressed public key: 045fbbe96332b2fc2bcc1b6a267678785401ee3b75674e061ca3616bbb66777b4f946bdd2a6a8ce419eacc5d05718bd718dc8d90c497cee74f5994681af0a1f842, size : 65 However, as the name suggests, this is not the most optimal way to store a public key. You will be surprised, but the second format is called compressed. Its essence is as follows: a public key is a point on the curve, that is, a pair of numbers that satisfies the equation. This means we can only write down the X coordinate, and if we need the Y coordinate, we simply solve the equation. Thus, we reduce the size of the public key by almost 50%!

The only caveat is that if a point lies on a curve, then for its X coordinate there are obviously two solutions to such an equation (look at the graphs above if in doubt). Usually we would simply preserve the sign for the Y coordinate, but when we are talking about a function over a finite field, we need to use the following property: if there are solutions to the equation for the X coordinate, then one of the points will have an even Y coordinate, and the other will have an odd Y coordinate (again Well, you can see for yourself).

In the first case, the prefix 0x02 is used, in the second - 0x03. Here is an illustration of the process:

Address

As already mentioned, the address is obtained from the public key in an unambiguous way. Moreover, it is impossible to carry out the reverse operation, since cryptographically strong hash functions are used - RIPEMD160 and SHA256. Here is the algorithm for translating the public key to the address:

  1. Let's take a private key, for example 45b0c38fa54766354cf3409d38b873255dfa9ed3407a542ba48eb9cab9dfca67
  2. Let's get the public key from it in uncompressed format, in this case it is 04162ebcd38c90b56fbdb4b0390695afb471c944a6003cb334bbf030a89c42b584f089012beb4842483692bdff9fcab8676fed42c47bffb 081001209079bbcb8db.
  3. We count RIPEMD160(SHA256(public_key)), we get 5879DB1D96FC29B2A6BDC593E67EDD2C5876F64C
  4. We translate the result into Base58Check with the prefix 0x00 - 17JdJpDyu3tB5GD3jwZP784W5KbRdfb84X. This is the address.

def pubKeyToAddr(s): ripemd160 = hashlib.new('ripemd160') ripemd160.update(hashlib.sha256(s.decode('hex')).digest()) return base58CheckEncode(0, ripemd160.digest()) def keyToAddr(s): return pubKeyToAddr(privateKeyToPublicKey(s)) # print keyToAddr("45b0c38fa54766354cf3409d38b873255dfa9ed3407a542ba48eb9cab9dfca67") # # '17JdJpDyu3tB5GD3jwZP784W 5KbRdfb84X'

Sign & verify

I don't think you need to necessarily know the technical details of how exactly ECDSA signs and verifies messages, you will still use ready-made libraries everywhere.
The main thing is that you have a general understanding of why this is needed, but if you are still interested, look through Layman's Guide to Elliptic Curve Digital Signatures, there is a beautiful visualization of the whole process below, you can try it yourself. That's all for me, next chapter: Bitcoin in a nutshell - Transaction.

Links

  • “An Introduction to Bitcoin, Elliptic Curves and the Mathematics of ECDSA” by N. Mistry
  • “Secure Implementation of ECDSA Signatures in Bitcoin” by Di Wang
  • Elliptic Curve Cryptography: a gentle introduction
  • Elliptic Cryptography: Theory
  • Generating A Bitcoin Private Key And Address

Who is developing the Optical Bitcoin project?

The founders of the international Optical Bitcoin project are Russian-speaking US citizen Michael Dubrovsky, also known for creating the SiPhox project (YC S20), as well as Bogdan Penkovsky. In addition to them, Marshall Ball, Lucianna Kiffer and others are participating in the development of the project.

Co-founder of the Optical Bitcoin project Mikhail Dubrovsky:

Officially, the development of the Optical Bitcoin (OBTC) project since 2022 has been carried out by a group of developers calling themselves PoWx-Org. The group declares itself as a non-profit organization whose activities are aimed at developing PoW cryptographic solutions compatible with ultra-energy-efficient optical computers. The scientific staff of the Massachusetts Institute of Technology (USA) makes a great contribution to the development of Optical Bitcoin.

Some features of the Optical Bitcoin cryptocurrency:

  • The Optical Bitcoin blockchain operates on PoW consensus with hashing using the economical heavyhash algorithm, which uses the digital hash (SHA3) hash function with a large number of so-called MAC calculations (Multiply-and-Accumulate). It is most effective on special chips with a relatively weak computing core and a low-power specialized photonic co-processor designed specifically for MAC operations (for now, these chips exist only in experimental form);

Prototype hardware silicon chip for oPoW miner:

  • target time between blocks of “Optical Bitcoin” is 600 seconds;
  • The experimental Optical Bitcoin network was launched on March 18, 2021, then on March 28, 2022, it was restarted and the main network was launched. The Genesis block (the first one) did not contain rewards for miners;
  • The current reward for a found block is 50 OBTC;

At the beginning of August, one OBTC is trading at approximately 0.02 USD on the little-known exbitron exchange for USDT, BTC, LTC and DOGE in small volumes and with crazy volatility:

Since the coin is relatively new, the situation can change very quickly. After the creation of special devices for mining on the heavyhash oPoW algorithm, mining on other devices will most likely become unprofitable.

Prototype of an energy-efficient ASIC miner for the heavyhash algorithm:

In this regard, you can try to collect the nth amount of the Optical Bitcoin cryptocurrency in hopes of its growth, or immediately drain the “mined by back-breaking labor” by transferring OBTC into bitcoins on the zergpool.

The wallet for Optical Bitcoin coins can be downloaded from the links on the project website. A desktop version of the wallet for Windows has already been released, and a version for Linux will appear soon. In addition, there is a mobile version of the wallet based on bluewallet for Android.

Rating
( 2 ratings, average 4.5 out of 5 )
Did you like the article? Share with friends:
For any suggestions regarding the site: [email protected]
Для любых предложений по сайту: [email protected]