You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: ch01.asciidoc
+15-5Lines changed: 15 additions & 5 deletions
Original file line number
Diff line number
Diff line change
@@ -34,13 +34,23 @@ Mathematically, a Finite Field is defined as follows:
34
34
35
35
A finite set of numbers and two operations *+* (addition) and *⋅* (multiplication) that satisfy the following:
36
36
37
-
1. If *a* and *b* are in the set, *a+b* and *a⋅b* are in the set.
37
+
1.
38
+
If *a* and *b* are in the set, *a+b* and *a⋅b* are in the set.
38
39
We call this property _closed_
39
-
2. The additive identity, *0* exists.
40
+
2.
41
+
The additive identity, *0* exists.
40
42
This means *a + 0 = a*
41
-
3. The multiplicative identity, *1* exists. This means *a ⋅ 1 = a*
42
-
4. If *a* is in the set, *-a* is in the set. *-a* is defined as the value that makes *a + (-a) = 0*. This is what we call the _additive inverse_.
43
-
5. If *a* is in the set and is not 0, *a^-1^* is in the set. *a^-1^* is defined as the value that makes *a ⋅ a^-1^ = 1*. This is what we call the _multiplicative inverse_.
43
+
3.
44
+
The multiplicative identity, *1* exists.
45
+
This means *a ⋅ 1 = a*
46
+
4.
47
+
If *a* is in the set, *-a* is in the set.
48
+
*-a* is defined as the value that makes *a + (-a) = 0*.
49
+
This is what we call the _additive inverse_.
50
+
5.
51
+
If *a* is in the set and is not 0, *a^-1^* is in the set.
52
+
*a^-1^* is defined as the value that makes *a ⋅ a^-1^ = 1*.
53
+
This is what we call the _multiplicative inverse_.
<1> x-coordinate and y-coordinate being `None` is how we signify the point at infinity. Note that the next if statement will fail if we don't return here.
241
+
<1> x-coordinate and y-coordinate being `None` is how we signify the point at infinity.
242
+
Note that the next if statement will fail if we don't return here.
239
243
<2> We overload the `+` operator here
240
-
<3> `self.x` being `None` means that `self` is the point at infinity, or the additive identity. Thus, we return `other`
241
-
<4> `self.x` being `None` means that `other` is the point at infinity, or the additive identity. Thus, we return `self`
244
+
<3> `self.x` being `None` means that `self` is the point at infinity, or the additive identity.
245
+
Thus, we return `other`
246
+
<4> `self.x` being `None` means that `other` is the point at infinity, or the additive identity.
Copy file name to clipboardExpand all lines: ch03.asciidoc
+64-27Lines changed: 64 additions & 27 deletions
Original file line number
Diff line number
Diff line change
@@ -16,11 +16,23 @@ Pi, sqrt(2), e+7th root of 19, etc are all part of real numbers.
16
16
This worked because _real_ numbers are also a field.
17
17
Note unlike a _finite_ field, there are an _infinite_ number of real numbers, but otherwise the same properties hold:
18
18
19
-
1. if *a* and *b* are in the set, *a+b* and *a⋅b* is in the set. We call this property _closed_
20
-
2. The additive identity, *0* exists. This means *a + 0 = a*
21
-
3. The multiplicative identity, *1* exists. This means *a ⋅ 1 = a*
22
-
4. If *a* is in the set, *-a* is in the set. *-a* is defined as the value that makes *a + (-a) = 0*. This is what we call the _additive inverse_.
23
-
5. If *a* is in the set and is not 0, *a^-1^* is in the set. *a^-1^* is defined as the value that makes *a ⋅ a^-1^ = 1*. This is what we call the _multiplicative inverse_.
19
+
1.
20
+
if *a* and *b* are in the set, *a+b* and *a⋅b* is in the set.
21
+
We call this property _closed_
22
+
2.
23
+
The additive identity, *0* exists.
24
+
This means *a + 0 = a*
25
+
3.
26
+
The multiplicative identity, *1* exists.
27
+
This means *a ⋅ 1 = a*
28
+
4.
29
+
If *a* is in the set, *-a* is in the set.
30
+
*-a* is defined as the value that makes *a + (-a) = 0*.
31
+
This is what we call the _additive inverse_.
32
+
5.
33
+
If *a* is in the set and is not 0, *a^-1^* is in the set.
34
+
*a^-1^* is defined as the value that makes *a ⋅ a^-1^ = 1*.
35
+
This is what we call the _multiplicative inverse_.
24
36
25
37
Clearly, all of these are true as normal addition and multiplication apply for the first part, additive and multiplicative identities 0 and 1 exist, -x is the additive inverse and 1/x is the multiplicative inverse.
26
38
@@ -86,7 +98,8 @@ We will do this using the results of Exercise 2.
86
98
----
87
99
include::code-ch03/ecc.py[tag=source2]
88
100
----
89
-
<1> We pass in `FieldElement` objects into the `Point` class for initialization. This will, in turn, use all the overloaded math operations in `FieldElement`
101
+
<1> We pass in `FieldElement` objects into the `Point` class for initialization.
102
+
This will, in turn, use all the overloaded math operations in `FieldElement`
90
103
91
104
We can now run this test like so:
92
105
@@ -362,9 +375,13 @@ class Point:
362
375
...
363
376
include::code-ch03/ecc.py[tag=source3]
364
377
----
365
-
<1> `current` represents the point that's at the current bit. First time through the loop it represents 1*self, the second time, it will be 2*self, third time, 4*self, then 8*self and so on. We double the point each time. In binary the coefficients are 1, 10, 100, 1000, 10000, etc.
378
+
<1> `current` represents the point that's at the current bit.
379
+
First time through the loop it represents 1*self, the second time, it will be 2*self, third time, 4*self, then 8*self and so on.
380
+
We double the point each time.
381
+
In binary the coefficients are 1, 10, 100, 1000, 10000, etc.
366
382
<2> We start the result at 0, or the point at infinity.
367
-
<3> We are looking at whether the right-most bit is a 1. If it is, then we add the value of the current bit.
383
+
<3> We are looking at whether the right-most bit is a 1.
384
+
If it is, then we add the value of the current bit.
368
385
<4> We need to double the point until we're past how big the coefficient can be.
We now have an easier way to initialize a point on the secp256k1 curve, without having to define the a and b every time like we have to with the `Point` class.
479
496
480
-
We can also define `__rmul__` a bit more efficiently since we know the order of the group, `n`. Since we're coding Python, we'll name this with a capital `N` to make it clear that `N` is a constant.
497
+
We can also define `__rmul__` a bit more efficiently since we know the order of the group, `n`.
498
+
Since we're coding Python, we'll name this with a capital `N` to make it clear that `N` is a constant.
481
499
482
500
[source,python]
483
501
----
@@ -487,7 +505,8 @@ class S256Point(Point):
487
505
...
488
506
include::code-ch03/ecc.py[tag=source8]
489
507
----
490
-
<1> We can mod by `n` because nG=0. That is, every `n` times we cycle back to zero or the point at infinity.
508
+
<1> We can mod by `n` because nG=0.
509
+
That is, every `n` times we cycle back to zero or the point at infinity.
491
510
492
511
We can now define G directly and keep it around since we'll be using it a lot going forward.
493
512
@@ -678,10 +697,14 @@ The only way we could know the details of R beforehand is if we know `e`.
678
697
679
698
To whit, here are the steps:
680
699
681
-
1. We are given (r, s) as the signature, `z` as the hash of the thing being signed and P, the public key (or public point) of the signer.
682
-
2. We calculate u = z/s, v = r/s
683
-
3. We calculate uG + vP = R
684
-
4. If R's `x` coordinate equals `r`, the signature is valid.
700
+
1.
701
+
We are given (r, s) as the signature, `z` as the hash of the thing being signed and P, the public key (or public point) of the signer.
702
+
2.
703
+
We calculate u = z/s, v = r/s
704
+
3.
705
+
We calculate uG + vP = R
706
+
4.
707
+
If R's `x` coordinate equals `r`, the signature is valid.
<1> Note that we use Fermat's Little Theorem for 1/s, since `n` is prime.
709
732
<2> u = z/s
710
733
<3> v = r/s
711
-
<4> uG+vP = (r,y). We need to check that the x-coordinate is r
734
+
<4> uG+vP = (r,y).
735
+
We need to check that the x-coordinate is r
712
736
713
737
include::code-ch03/answers.py[tag=exercise6]
714
738
@@ -733,8 +757,10 @@ class S256Point(Point):
733
757
include::code-ch03/ecc.py[tag=source12]
734
758
----
735
759
<1> `s_inv` (1/s) is calculated using Fermat's Little Theorem on the order of the group `n` which is prime.
736
-
<2> u = z/s. Note that we can mod by `n` as that's the order of the group.
737
-
<3> v = r/s. Note that we can mod by `n` as that's the order of the group.
760
+
<2> u = z/s.
761
+
Note that we can mod by `n` as that's the order of the group.
762
+
<3> v = r/s.
763
+
Note that we can mod by `n` as that's the order of the group.
738
764
<4> uG+vP should be R
739
765
<5> We check that the x-coordinate is `r`
740
766
@@ -748,11 +774,17 @@ We do this by choosing a random `k`.
748
774
749
775
Signing Procedure:
750
776
751
-
1. We are given `z`. We know `e` and eG=P.
752
-
2. Choose a random `k`
753
-
3. Calculate R=kG and r=x-coordinate of R
754
-
4. Calculate s = (z+re)/k
755
-
5. Signature is (r,s)
777
+
1.
778
+
We are given `z`.
779
+
We know `e` and eG=P.
780
+
2.
781
+
Choose a random `k`
782
+
3.
783
+
Calculate R=kG and r=x-coordinate of R
784
+
4.
785
+
Calculate s = (z+re)/k
786
+
5.
787
+
Signature is (r,s)
756
788
757
789
Note that the pubkey `P` has to be transmitted to whoever wants to verify and `z` must be known by the verifier.
758
790
We'll see later that `z` is computed and P is sent along with the signature.
@@ -771,11 +803,13 @@ This library is for teaching purposes only, so please don't use any of the code
771
803
----
772
804
include::code-ch03/examples.py[tag=example10]
773
805
----
774
-
<1> This is an example of a "brain wallet" which is a way to keep the private key in your head without having to memorize something too difficult. Please don't use this for a real secret.
806
+
<1> This is an example of a "brain wallet" which is a way to keep the private key in your head without having to memorize something too difficult.
807
+
Please don't use this for a real secret.
775
808
<2> This is the signature hash, or hash of the message that we're signing.
776
809
<3> We're going to use a fixed `k` here for demonstration purposes.
777
810
<4> kG = (r,y) so we take the `x` coordinate only
778
-
<5> s = (z+re)/k. We can mod by `n` because we know this is a cyclical group of order `n`.
811
+
<5> s = (z+re)/k.
812
+
We can mod by `n` because we know this is a cyclical group of order `n`.
779
813
<6> The public point needs to be known by the verifier
780
814
781
815
include::code-ch03/answers.py[tag=exercise7]
@@ -807,11 +841,13 @@ class PrivateKey:
807
841
s = N - s
808
842
return Signature(r, s) # <6>
809
843
----
810
-
<1> `randint` chooses a random integer from `[0,n)`. Please don't use this function in production as the random number from this library is not nearly random enough.
844
+
<1> `randint` chooses a random integer from `[0,n)`.
845
+
Please don't use this function in production as the random number from this library is not nearly random enough.
811
846
<2> `r` is the x-coordinate of kG
812
847
<3> We use Fermat's Little Theorem again and `n`, which is prime
813
848
<4> s = (z+re)/k
814
-
<5> It turns out that using the low-s value will get nodes to relay our transactions easier. This is for malleability reasons
849
+
<5> It turns out that using the low-s value will get nodes to relay our transactions easier.
850
+
This is for malleability reasons
815
851
<6> We return a `Signature` object from above.
816
852
817
853
.Importance of a unique `k`
@@ -844,7 +880,8 @@ class PrivateKey:
844
880
...
845
881
include::code-ch03/ecc.py[tag=source14]
846
882
----
847
-
<1> We are using the deterministic `k` instead of a random one. Everything else about `sign` remains the same.
883
+
<1> We are using the deterministic `k` instead of a random one.
884
+
Everything else about `sign` remains the same.
848
885
<2> This algorithm returns a candidate that's suitable.
849
886
850
887
Deterministic `k` will be unique with very high probability.
Copy file name to clipboardExpand all lines: ch04.asciidoc
+56-25Lines changed: 56 additions & 25 deletions
Original file line number
Diff line number
Diff line change
@@ -21,9 +21,12 @@ There are two forms of SEC format that we need to be concerned with and the firs
21
21
22
22
Here is how the uncompressed SEC format for a given point P=(x,y) is generated:
23
23
24
-
1. Start with the prefix byte which is `0x04`.
25
-
2. Next, append the x-coordinate in 32 bytes as a Big-Endian integer.
26
-
3. Next, append the y-coordinate in 32 bytes as a Big-Endian integer.
24
+
1.
25
+
Start with the prefix byte which is `0x04`.
26
+
2.
27
+
Next, append the x-coordinate in 32 bytes as a Big-Endian integer.
28
+
3.
29
+
Next, append the y-coordinate in 32 bytes as a Big-Endian integer.
27
30
28
31
Here is what the uncompressed SEC format looks like:
29
32
@@ -67,7 +70,8 @@ class S256Point(Point):
67
70
return b'\x04' + self.x.num.to_bytes(32, 'big') \
68
71
+ self.y.num.to_bytes(32, 'big') # <1>
69
72
----
70
-
<1> In Python 3, you can convert a number to `bytes` using the `to_bytes` method. The first argument is how many bytes it should take up and the second argument is the endianness (see _Big and Little Endian_).
73
+
<1> In Python 3, you can convert a number to `bytes` using the `to_bytes` method.
74
+
The first argument is how many bytes it should take up and the second argument is the endianness (see _Big and Little Endian_).
71
75
72
76
include::code-ch04/answers.py[tag=exercise1]
73
77
@@ -95,8 +99,11 @@ We call this the *Compressed SEC format* because of how the y-coordinate is comp
95
99
96
100
Here is the serialization of the Compressed SEC format for a given point P=(x,y):
97
101
98
-
1. Start with the prefix byte. If `y` is even, it's `0x02`, otherwise it's `0x03`.
99
-
2. Next, append the x-coordinate in 32 bytes as a Big-Endian integer.
102
+
1.
103
+
Start with the prefix byte.
104
+
If `y` is even, it's `0x02`, otherwise it's `0x03`.
105
+
2.
106
+
Next, append the x-coordinate in 32 bytes as a Big-Endian integer.
100
107
101
108
The Compressed SEC format looks like this:
102
109
@@ -205,12 +212,22 @@ This was most likely because the standard was already defined in 2008, supported
205
212
206
213
DER Signature format is defined like this:
207
214
208
-
1. Start with the `0x30` byte
209
-
2. Encode the length of the rest of the signature (usually `0x44` or `0x45`) and append
210
-
3. Append the marker byte `0x02`
211
-
4. Encode `r` as a Big-Endian integer, but prepend with `0x00` byte if `r`'s first byte >= `0x80`. Prepend the resulting length to `r`. Add this to the result.
212
-
5. Append the marker byte `0x02`
213
-
6. Encode `s` as a Big-Endian integer, but prepend with `0x00` byte if `s`'s first byte >= `0x80`. Prepend the resulting length to `s`. Add this to the result.
215
+
1.
216
+
Start with the `0x30` byte
217
+
2.
218
+
Encode the length of the rest of the signature (usually `0x44` or `0x45`) and append
219
+
3.
220
+
Append the marker byte `0x02`
221
+
4.
222
+
Encode `r` as a Big-Endian integer, but prepend with `0x00` byte if `r`'s first byte >= `0x80`.
223
+
Prepend the resulting length to `r`.
224
+
Add this to the result.
225
+
5.
226
+
Append the marker byte `0x02`
227
+
6.
228
+
Encode `s` as a Big-Endian integer, but prepend with `0x00` byte if `s`'s first byte >= `0x80`.
229
+
Prepend the resulting length to `s`.
230
+
Add this to the result.
214
231
215
232
The rules for #4 and #6 with the first byte starting with something greater than or equal to `0x80` is because DER is a general encoding and allows for negative numbers to be encoded.
216
233
The first bit being 1 means that the number is negative.
<1> The purpose of this loop is to determine how many of the bytes at the front are 0 bytes. We want to add them back at the end.
304
+
<1> The purpose of this loop is to determine how many of the bytes at the front are 0 bytes.
305
+
We want to add them back at the end.
288
306
<2> This is the loop that figures out what Base58 digit to use.
289
-
<3> Finally, we prepend all the zeros that we counted at the front because otherwise, they wouldn't show up as prefixed 1's. This annoyingly happens with pay-to-pubkey-hash (p2pkh). More on that in <<chapter_script>>.
307
+
<3> Finally, we prepend all the zeros that we counted at the front because otherwise, they wouldn't show up as prefixed 1's.
308
+
This annoyingly happens with pay-to-pubkey-hash (p2pkh).
309
+
More on that in <<chapter_script>>.
290
310
291
311
This function will take any bytes in Python 3 and convert it to Base58.
292
312
@@ -311,11 +331,16 @@ To both shorten and increase security, we can use the ripemd160 hash to compress
311
331
By not using the SEC format directly, we can go from 33 bytes to 20 bytes, shortening the address significantly.
312
332
Here is how a Bitcoin address is created:
313
333
314
-
1. For mainnet addresses, start with the prefix `0x00`, for testnet `0x6f`.
315
-
2. Take the SEC format (compressed or uncompressed) and do a sha256 operation followed by the ripemd160 hash operation, the combination which is called a hash160 operation.
316
-
3. Combine the prefix from #1 and resulting hash from #2
317
-
4. Do a hash256 of the result from #3 and get the first 4 bytes.
318
-
5. Take the combination of #3 and #4 and encode in Base58.
334
+
1.
335
+
For mainnet addresses, start with the prefix `0x00`, for testnet `0x6f`.
336
+
2.
337
+
Take the SEC format (compressed or uncompressed) and do a sha256 operation followed by the ripemd160 hash operation, the combination which is called a hash160 operation.
338
+
3.
339
+
Combine the prefix from #1 and resulting hash from #2
340
+
4.
341
+
Do a hash256 of the result from #3 and get the first 4 bytes.
342
+
5.
343
+
Take the combination of #3 and #4 and encode in Base58.
319
344
320
345
Step 4 of this process is called the checksum.
321
346
We can do steps 4 and 5 in one go this way:
@@ -368,12 +393,18 @@ WIF uses the same Base58 encoding that addresses use.
368
393
369
394
Here is how the WIF format is created:
370
395
371
-
1. For mainnet private keys, start with the prefix `0x80`, for testnet `0xef`.
372
-
2. Encode the secret in 32-byte Big-Endian.
373
-
3. If the SEC format used for the public key address was compressed add a suffix of `0x01`.
374
-
4. Combine the prefix from #1, serialized secret from #2 and suffix from #3
375
-
5. Do a hash256 of the result from #4 and get the first 4 bytes.
376
-
6. Take the combination of #4 and #5 and encode in Base58.
396
+
1.
397
+
For mainnet private keys, start with the prefix `0x80`, for testnet `0xef`.
398
+
2.
399
+
Encode the secret in 32-byte Big-Endian.
400
+
3.
401
+
If the SEC format used for the public key address was compressed add a suffix of `0x01`.
402
+
4.
403
+
Combine the prefix from #1, serialized secret from #2 and suffix from #3
404
+
5.
405
+
Do a hash256 of the result from #4 and get the first 4 bytes.
406
+
6.
407
+
Take the combination of #4 and #5 and encode in Base58.
377
408
378
409
We can now create the `wif` method on the `PrivateKey` class.
0 commit comments