Pythonのraise ValueError

関数などで例外を発生させたい場合にraiseを使用する。

raise 例外クラス(message):

def process_list(numbers):
    for num in numbers:
        try:
            if num < 0:
                raise ValueError("Negative numbers are not allowed.")
            result = 100 / num
            print(f"Result of division: {result}")
        except ZeroDivisionError:
            print("Error: Division by zero is not allowed.")
        except ValueError as ve:
            print(f"Error: {ve}")
        except Exception as e:
            print(f"Error occurred: {e}")

Pythonの__eq__メソッド

__eq__メソッド は等価の条件を定める

class Person:

    def __init__(self, firstname, lastname, email):
        self.firstname = firstname
        self.lastname = lastname
        self.email = email

    def __eq__(self, other):
        if other is None or not isinstance(other, Person): return False

        return self.firstname == other.firstname and \
            self.lastname == other.lastname and \
            self.email == other.email

    def __ne__(self, other):
        return not self.__eq__(other)
    

mike = Person('Mike', 'Peter', 'mike@gmail.com')
peter = Person('Mike', 'Peter', 'mike@gmail.com')
print(mike)
print(peter)
print(mike == peter)

eqの他にも、lt, ne, le, gt, geなどがある。

class Item(object):

    def __init__(self, price):
        self.price = price

    def __eq__(self, other):
        if not isinstance(other, Item):
            return NotImplemented
        return self.price == other.price

    def __lt__(self, other):
        if not isinstance(other, Item):
            return NotImplemented
        return self.price < other.price
    
    def __ne__(self, other):
        return not self.__eq__(other)

    def __le__(self, other):
        return self.__lt__(other) or self.__eq__(other)
    
    def __gt__(self, other):
        return not self.__le__(other)
    
    def __ge__(self, other):
        return not self.__lt__(other)

Pythonの__rpr__メソッド

__str__, __repr__は特殊メソッドと呼ぶ

initのみの場合

class Person:

    def __init__(self, name: str, age: int) -> None:
        self.name = name
        self.age = age

mike = Person('Mike', 20)
print(mike)
class Person:

    def __init__(self, name: str, age: int) -> None:
        self.name = name
        self.age = age

mike = Person('Mike', 20)
print(f'name: {mike.name}, age: {mike.age}')

classの中に書く

class Person:

    def __init__(self, name: str, age: int) -> None:
        self.name = name
        self.age = age

    def __str__(self) -> str:
        return f'name: {mike.name}, age: {mike.age}'

mike = Person('Mike', 20)
print(mike)

__repr__ は同じ値のオブジェクトを再生成できる文字列を定義。

class Person:

    def __init__(self, name: str, age: int) -> None:
        self.name = name
        self.age = age

    def __repr__(self) -> str:
        return f'name: {mike.name}, age: {mike.age}'

mike = Person('Mike', 20)
print(repr(mike))
class Person:

    def __init__(self, name: str, age: int) -> None:
        self.name = name
        self.age = age

    def __repr__(self) -> str:
        return f'name: {mike.name}, age: {mike.age}'

mike = Person('Mike', 20)
print(repr(mike))

有限体とは

位数が有限である体
四則演算が定義され閉じている有限集

整数の集合は無限の要素だが、有限体は要素が有限で、四則演算(足し算・引き算・掛け算・割り算)が閉じている
=> 閉じているとは、演算結果が、有理数でなくなるということがない
=> 演算を施した結果がふたたびもとの集合に属する
素数 P で割った余り

これ、初手でいきなりつまづくな…

pythonとhmac-sha512

HMACは暗号ハッシュ関数を使用してメッセージ認証を行う仕組み

import hmac
import hashlib

key=b"secret2"
text=b"foo bar"
signature=hmac.new(key,text,hashlib.md5).hexdigest()
print(signature)

b””としないと、エラーになる。
self._hmac = _hashopenssl.hmac_new(key, msg, digestmod=digestmod)
TypeError: Strings must be encoded before hashing

16進数と整数の変換

0xはその文字列が16進数であることを示す

print(format(0xabcd, 'x'))
print(hex(0xabcd))
print('%02x' % 0xabcd)

binasciiはバイト列に変換する

import binascii
print(binascii.unhexlify('abcd'))
print(str(binascii.hexlify(b'\xab\xcd'), 'utf-8'))

blockchain

import hashlib

class Block():
    def __init__(self, data, prev_hash):
        self.index = 0
        self.nonce = 0
        self.prev_hash = prev_hash
        self.data = data

    def blockhash(self):
        blockheader = str(self.index) + str(self.prev_hash) + str(self.data) + str(self.nonce)
        block_hash = hashlib.sha256(blockheader.encode()).hexdigest()
        return block_hash

    def __str__(self):
        return "Block Hash: " + self.blockhash() + "\nPrevious Hash: " + self.prev_hash + "\nindex: " + str(self.index) + "\nData: " + str(self.data) + "\nNonce: " + str(self.nonce) + "\n--------------"

class Hashchain():
    def __init__(self):
        self.chain = ["0000000000000000000000000000000000000000000000000000000000000000"]

    def add(self, hash):
        self.chain.append(hash)

hashchain = Hashchain()
target = 0x777777 * 2**(8*(0x1e - 0x03))

for i in range(30):
    block = Block("Block " + str(i+1), hashchain.chain[-1])
    block.index = block.index + i + 1
    for n in range(4294967296):
        block.nonce = block.nonce + n
        if int(block.blockhash(), 16) < target:
            print(block)
            hashchain.add(block.blockhash())
            break

Proof of work

簡易的なhash計算

import hashlib

input_text = "satoshi"

for nonce in range(20):
    input_data = input_text + str(nonce)
    hash = hashlib.sha256(input_data.encode("UTF-8")).hexdigest()
    print(input_data + " → " + hash)

ブロックヘッダのdifficulty bitsにハッシュ値の条件が書かれている
0x1e777777 のような形式で記述されている。

# difficulty_bits = 0x1e777777
# exponent = 0x1e
# coefficient = 0x777777

target = 0x777777 * 2**(8*(0x1e - 0x03))
print(target)

target_hex = hex(target)[2:].zfill(64)
print(target_hex)
import hashlib

class Block():
    def __init__(self, data, prev_hash):
        self.index = 0
        self.nonce = 0
        self.prev_hash = prev_hash
        self.data = data

    def blockhash(self):
        blockheader = str(self.index) + str(self.prev_hash) + str(self.data) + str(self.nonce)
        block_hash = hashlib.sha256(blockheader.encode()).hexdigest()
        return block_hash

    def __str__(self):
        return "Block Hash: " + self.blockhash() + "\nPrevious Hash: " + self.prev_hash + "\nindex: " + str(self.index) + "\nData: " + str(self.data) + "\nNonce: " + str(self.nonce) + "\n--------------"

class Hashchain():
    def __init__(self):
        self.chain = ["0000000000000000000000000000000000000000000000000000000000000000"]

    def add(self, hash):
        self.chain.append(hash)

hashchain = Hashchain()
target = 0x777777 * 2**(8*(0x1e - 0x03))

for i in range(30):
    block = Block("Block " + str(i+1), hashchain.chain[-1])
    block.index = block.index + i + 1
    for n in range(4294967296):
        block.nonce = block.nonce + n
        if int(block.blockhash(), 16) < target:
            print(block)
            hashchain.add(block.blockhash())
            break

UTXO

import json
import requests

address = "3FkenCiXpSLqD8L79intRNXUgjRoH9sjXa"

res = requests.get("https://blockchain.info/unspent?active=" + address)
utxo_list = json.loads(res.text)["unspent_outputs"]

print(str(len(utxo_list)) + "個のutxoが見つかりました")
for utxo in utxo_list:
    print(utxo["tx_hash"] + ":" + str(utxo["value"]) + " satoshis")

blockcain exploreのtransactionからも確認できる。
https://www.blockchain.com/explorer

$ python3 utxo.py
2個のutxoが見つかりました
0aed6c01112af0a2dd51981e983ce41ef271c3bbec834121a47dbe31c30519d7:548546 satoshis
768b2e91eaa99208d32d3dde2a0f70214940584754b66378a33c9e3bd60136c3:311694 satoshis