package main
import (
"encoding/hex"
"fmt"
"math/big"
)
// ParseBig256 parses s as a 256 bit integer in decimal or hexadecimal syntax.
// Leading zeros are accepted. The empty string parses as zero.
func ParseBig256(s string) (*big.Int, bool) {
if s == "" {
return new(big.Int), true
}
var bigint *big.Int
var ok bool
if len(s) >= 2 && (s[:2] == "0x" || s[:2] == "0X") {
bigint, ok = new(big.Int).SetString(s[2:], 16)
} else {
bigint, ok = new(big.Int).SetString(s, 10)
}
if ok && bigint.BitLen() > 256 {
bigint, ok = nil, false
}
return bigint, ok
}
// has0xPrefix validates str begins with '0x' or '0X'.
func has0xPrefix(str string) bool {
return len(str) >= 2 && str[0] == '0' && (str[1] == 'x' || str[1] == 'X')
}
// Hex2Bytes returns the bytes represented by the hexadecimal string str.
func Hex2Bytes(str string) []byte {
h, _ := hex.DecodeString(str)
return h
}
func BytesToInt(b []byte) *big.Int {
bigNum := new(big.Int).SetBytes(b)
return bigNum
}
func IntToBytes(i *big.Int, numBytes int) []byte {
if i == nil {
return []byte("0x0")
}
return []byte(fmt.Sprintf("%#x", (*big.Int)(i)))
}
func HexStrToInt(strHex string) *big.Int {
return BytesToInt(strToBytes(strHex))
}
func strToBytes(s string) []byte {
if has0xPrefix(s) {
s = s[2:]
}
if len(s)%2 == 1 {
s = "0" + s
}
return Hex2Bytes(s)
}
const (
N_DIVIDED = 8
N_DIVIDED_START = 32
)
var ZERO_MASK = []byte{0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01}
func calcZeroBytes(diffiLevel int) []byte {
boundry := []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}
nBytesToZero, nBitsToZero := diffiLevel/N_DIVIDED, diffiLevel%N_DIVIDED
for i := 0; i < nBytesToZero; i++ {
boundry[i] = 0x00
}
boundry[nBytesToZero] = ZERO_MASK[nBitsToZero]
return boundry
}
func DifficultyToBoundary(difficult int) *big.Int {
var difficultyLevel int
m := 0
n := (difficult - N_DIVIDED_START) / N_DIVIDED
m = (difficult - N_DIVIDED_START) % N_DIVIDED
difficultyLevel = N_DIVIDED_START + n
intBoundry := BytesToInt(calcZeroBytes(difficultyLevel))
rsh := big.NewInt(0).Rsh(intBoundry, 1)
mod := new(big.Int)
step, mod := rsh.DivMod(rsh, big.NewInt(N_DIVIDED), mod)
boundry := intBoundry.Sub(intBoundry, step.Mul(step, big.NewInt(int64(m))))
return boundry
}
func boundryTohashPower(boundry *big.Int) string {
a, ok := new(big.Int).SetString("ffff000000000000000000000000000000000000000000000000000000000000", 16)
if !ok {
return "0"
}
mod, _ := a.DivMod(a, boundry, big.NewInt(0))
return mod.String()
}
func DifficultToHashPower(difficult int) string {
return boundryTohashPower(DifficultyToBoundary(difficult))
}
func main() {
fmt.Println(DifficultToHashPower(101))
fmt.Println(DifficultToHashPower(158))
fmt.Println(DifficultToHashPower(159))
}
import math
import os
import sys
import matplotlib.pyplot as plt
N_DIVIDED = 8
TOKEN_NUM_BYTES = 32
ZERO_MASK = [0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01]
def hex_str_to_bytes(str_hex: str) -> bytes:
if isinstance(str_hex, bytes):
return str_hex
str_hex = str_hex.lower()
if str_hex.startswith("0x"):
str_hex = str_hex[2:]
if len(str_hex) & 1:
str_hex = "0" + str_hex
return bytes.fromhex(str_hex)
def bytes_to_int(bytes_hex: bytes, byteorder="big"):
return int.from_bytes(bytes_hex, byteorder=byteorder)
def int_to_bytes(i: int, n_bytes=TOKEN_NUM_BYTES, byteorder="big") -> bytes:
if n_bytes is None:
n_bytes = (i.bit_length() + 7) // 8 or 1
return i.to_bytes(length=n_bytes, byteorder=byteorder)
def hex_str_to_int(str_hex: str, byteorder: str = "big") -> int:
return bytes_to_int(hex_str_to_bytes(str_hex), byteorder=byteorder)
def calc_zero_bytes(difficulty_level):
boundary = bytearray(b"\xFF" * 32)
n_bytes_to_zero = difficulty_level // 8
n_bits_to_zero = difficulty_level % 8
boundary[0:n_bytes_to_zero] = b"\x00" * n_bytes_to_zero
boundary[n_bytes_to_zero] = ZERO_MASK[n_bits_to_zero]
return bytes(boundary)
def new_difficulty_to_boundary(difficulty: int) -> bytes:
if difficulty < 32:
difficulty_level = difficulty
return calc_zero_bytes(difficulty_level)
else:
n = (difficulty - 32) // N_DIVIDED
m = (difficulty - 32) % N_DIVIDED
difficulty_level = 32 + n
tmp = calc_zero_bytes(difficulty_level)
print(tmp)
int_boundary = bytes_to_int(tmp)
boundary_change_step = (int_boundary >> 1) // N_DIVIDED
# // 822752278660603021077484591278675252491367932816789931674304511
boundary = int_boundary - boundary_change_step * m
return int_to_bytes(boundary, n_bytes=32)
dividend = 0xffff000000000000000000000000000000000000000000000000000000000000 # 2^256
def boundary_to_hashpower(boundary) -> int:
if isinstance(boundary, str):
return dividend // hex_str_to_int(boundary)
elif isinstance(boundary, bytes):
return dividend // bytes_to_int(boundary)
raise TypeError("Type of boundary should be str or bytes")
def new_difficulty_to_hashpower(difficulty: int) -> int:
return boundary_to_hashpower(new_difficulty_to_boundary(difficulty))
def plot_new_diff(diff_list, n_divided=4):
global N_DIVIDED
N_DIVIDED = n_divided
new_hash_list = [new_difficulty_to_hashpower(d) for d in diff_list]
plt.scatter(diff_list, new_hash_list, label=f"Divided 1/{n_divided}")
plt.legend()
return new_hash_list
def convert_hashrate(hashrate, k=1000):
if hashrate <= 0:
return "0 Mh"
rates = ['h', 'Kh', 'Mh', 'Gh', 'Th', 'Ph', 'Eh', 'Zh', 'Yh']
i = math.floor(math.log(hashrate) / math.log(k))
return f"{hashrate / pow(k, i):.2f} {rates[i]}"
print(convert_hashrate(new_difficulty_to_hashpower(100)))
sys.exit()
diff_list = list(range(158, 160))
plt.figure(figsize=(16, 10))
plt.yscale("log")
# new_hash_list_2 = plot_new_diff(diff_list, n_divided=2)
# new_hash_list_4 = plot_new_diff(diff_list, n_divided=4)
# new_hash_list_6 = plot_new_diff(diff_list, n_divided=6)
new_hash_list_8 = plot_new_diff(diff_list, n_divided=8)
print(f"Level",
" ", f"{'1/8':15s}",
)
# for diff, hashpower4, hashpower6, hashpower8 in zip(diff_list,
# new_hash_list_4, new_hash_list_6,
# new_hash_list_8):
for diff, hashpower8 in zip(diff_list, new_hash_list_8):
print(f"{diff:03}",
" -- ", f"{convert_hashrate(hashpower8):15s}",
)