Tổng quan về mật mã học trong Bitcoin – phần 3

5 min read

Khóa riêng (Private key)

Khóa riêng là một thuật ngữ khá chung và trong các thuật toán chữ ký điện tử khác nhau, có thể sử dụng các loại khóa riêng khác nhau.

Như bạn có thể đã nhận thấy, Bitcoin sử dụng thuật toán ECDSA(Elliptic Curve Digital Signature Algorithm)— trong trường hợp này, khóa riêng là một số tự nhiên 256 bit, tức là một số nguyên thông thường trong khoảng từ 1 đến 2^256. Về mặt kỹ thuật, ngay cả số 123456 cũng có thể là một khóa riêng hợp lệ, nhưng bạn sẽ sớm hiểu rằng số Bitcoin của bạn “thuộc về bạn” chỉ cho đến khi một kẻ xấu có được khóa riêng của bạn, và các giá trị đơn giản như 123456 thì rất dễ bị dò tìm.

Điều quan trọng cần lưu ý là: cho đến ngày nay, việc thử hết tất cả các khóa là điều không thể, vì 2^256 là một con số khổng lồ đến mức khó tin.

Hãy thử hình dung: theo một bài báo, toàn bộ Trái Đất có chưa đến 10^22 hạt cát. Ta dùng phép xấp xỉ 2^10 ≈ 10^3, tức là 10^22 ≈ 2^80 hạt cát. Trong khi đó, tổng số địa chỉ (khóa riêng) là 2^256, xấp xỉ (2^80)^3.

Nói cách khác, ta có thể lấy toàn bộ cát trên Trái Đất, biến mỗi hạt cát thành một Trái Đất mới, rồi lại biến mỗi hạt cát trên mỗi hành tinh mới thành một Trái Đất nữa — và tổng số hạt cát sau ba vòng như vậy vẫn còn kém xa số lượng khóa riêng có thể có.

Cũng vì lý do đó, hầu hết các phần mềm ví Bitcoin khi tạo khóa riêng chỉ đơn giản là lấy ngẫu nhiên 256 bit — xác suất trùng lặp là cực kỳ nhỏ.

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
L3SPdkFWMnFyDGyV3vkCjroGi4zfD59Wsc5CHdB1LirjN6s2vii9

Khóa công khai (Public key)

Giả sử k là khóa riêng của chúng ta, và G là điểm cơ sở (base point), thì khóa công khai K = G * k. Nói cách khác, khóa công khai chính là một điểm nằm trên đường cong elliptic SECP256k1.

Có hai điểm quan trọng cần lưu ý:

  1. Thứ nhất, có thể dễ dàng thấy rằng phép tính để tạo khóa công khai là xác định duy nhất — tức là, mỗi khóa riêng tương ứng với một và chỉ một khóa công khai duy nhất.
  2. Thứ hai, phép tính ngược lại là cực kỳ khó về mặt tính toán. Nói một cách đơn giản, không thể lấy khóa công khai và tính ngược lại ra khóa riêng, ngoại trừ bằng cách thử hết tất cả các khả năng (brute-force) – đây là bài toán logarit rời rạc trên đường cong elliptic (ECDLP)

Nếu bạn có thể giải được bài toán này nhanh chóng — bạn có thể chiếm đoạt Bitcoin của bất kỳ ai, vì khóa công khai thường được công khai trên mạng.

Ở phần dưới, bạn sẽ thấy rằng cũng có một mối liên hệ tương tự giữa khóa công khai và địa chỉ ví Bitcoin, tuy nhiên ở đó người ta sử dụng tính chất không thể đảo ngược của các hàm băm (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'D5C08F1BFC9C26A5D18FE9254E7923DEBBD34AFB92AC23ABFC6388D2659446C1F04CCDEBB677EAABFED9294663EE79D71B57CA6A6B76BC47E6F8670FE759D746'

Địa chỉ Bitcoin

Địa chỉ Bitcoin là một chuỗi ký tự ngắn gọn, thường bắt đầu bằng chữ 1 hoặc 3 (hoặc bc1 với định dạng mới), được dùng để nhận tiền Bitcoin.
Nó được sinh ra từ khóa công khai (public key) thông qua một chuỗi các bước mã hóa và băm (hash).

Địa chỉ Bitcoin được tính toán một chiều từ khóa công khai, thông qua một chuỗi các hàm băm (hash). Quá trình này không thể đảo ngược, nghĩa là không thể lấy địa chỉ rồi tính ra public key hay private key từ nó.

Các bước chuyển đổi Public Key → Địa chỉ:

Bước 1: Bắt đầu từ khóa riêng (private key)

Ví dụ:

private_key = 45b0c38fa54766354cf3409d38b873255dfa9ed3407a542ba48eb9cab9dfca67

Bước 2: Tính khóa công khai (public key)

Dùng đường cong elliptic SECP256k1 để tính: Ký tự đầu 04 chỉ đây là dạng uncompressed.

public_key = 0416...cb8db   (dài 130 ký tự hex, dạng uncompressed)

Bước 3: Băm công khai (2 lớp hash)

Ta áp dụng liên tiếp 2 hàm băm:

step1=SHA256(public_key)

step2=RIPEMD160(step1)

Kết quả:

step2 = 5879DB1D96FC29B2A6BDC593E67EDD2C5876F64C

📌 Lưu ý: kết quả này là 20 byte (40 ký tự hex) → chính là Bitcoin public key hash.


Bước 4: Thêm prefix và mã hóa Base58Check

  • Prefix 0x00 chỉ loại địa chỉ là “mainnet Bitcoin address”
  • Ghép lại: bashCopyEditversion + hash = 00 + 5879...64C
  • Tính thêm checksum, rồi mã hóa bằng Base58Check, cho ra địa chỉ thân thiện:
Bitcoin address = 17JdJpDyu3tB5GD3jwZP784W5KbRdfb84X

Vì sao không thể đảo ngược địa chỉ thành khóa?

  • Ngay cả khi bạn có địa chỉ, bạn không thể biết public key, chứ chưa nói đến private key
  • Vì sử dụng các hàm băm không thể đảo ngược (SHA256 + RIPEMD160)
  • Vì đã mất thông tin: từ 130 byte xuống chỉ còn 20 byte
Avatar photo

Leave a Reply

Your email address will not be published. Required fields are marked *