コード例 #1
0
def decode_base58(encoded_str):
    """
    base58 기반 디코딩 함수
    - 비트코인 주소 생성시 Base58로 인코딩
    - 해당 주소로부터 20바이트 해시를 얻는 방법
    :param encoded_str: Base58로 인코딩된 비트코인 주소
    :return: 디코딩된 바이트의 중간 20바이트를 공개키의 hash160 해시값으로 반환
    """
    num = 0

    # 각 자리수 계산
    for c in encoded_str:
        num *= 58
        num += BASE58_ALPHABET.index(c)

    # 25 바이트 빅엔디언으로 변환
    combined = num.to_bytes(25, byteorder="big")

    # 마지막 4바이트는 체크섬
    checksum = combined[-4:]

    # hash256 해시값의 체크섬과 비교
    if hash256(combined[:-4])[:4] != checksum:
        raise ValueError("Bad adress : {} {}".format(
            checksum,
            hash256(combined[:-4])[:4]))

    # 첫 1바이트는 메인넷/테스트넷, 중간 20바이트는 공개키
    return combined[1:-4]
コード例 #2
0
 def hash_prevouts(self):
     if self._hash_prevouts is None:
         all_prevouts = b''
         all_sequence = b''
         for tx_in in self.tx_inputs:
             all_prevouts += tx_in.prev_tx[::-1] + int_to_little_endian(
                 tx_in.prev_index, 4)
             all_sequence += int_to_little_endian(tx_in.sequence, 4)
         self._hash_prevouts = hash256(all_prevouts)
         self._hash_sequence = hash256(all_sequence)
     return self._hash_prevouts
コード例 #3
0
def example1():
    hash0 = bytes.fromhex(
        'c117ea8ec828342f4dfb0ad6bd140e03a50720ece40169ee38bdc15d9eb64cf5')
    hash1 = bytes.fromhex(
        'c131474164b412e3406696da1ee20ab0fc9bf41c8f05fa8ceea7a08d672d7cc5')
    parent = hash256(hash0 + hash1)
    print(parent.hex())
コード例 #4
0
def my_address():
    from ecc.secp256k1 import PrivateKey
    my_message = b'YJ Choi secret'
    secret_key = little_endian_to_int(hash256(my_message))
    private_key = PrivateKey(secret_key)
    address = private_key.public_key.address(testnet=True)
    print(address)
コード例 #5
0
 def hash_outputs(self):
     if self._hash_outputs is None:
         all_outputs = b''
         for tx_out in self.tx_outputs:
             all_outputs += tx_out.serialize()
         self._hash_outputs = hash256(all_outputs)
     return self._hash_outputs
コード例 #6
0
 def sig_hash_bip143(self,
                     input_index,
                     redeem_script=None,
                     witness_script=None):
     '''Returns the integer representation of the hash that needs to get
     signed for index input_index'''
     tx_in = self.tx_inputs[input_index]
     # per BIP143 spec
     s = int_to_little_endian(self.version, 4)
     s += self.hash_prevouts() + self.hash_sequence()
     s += tx_in.prev_tx[::-1] + int_to_little_endian(tx_in.prev_index, 4)
     if witness_script:
         script_code = witness_script.serialize()
     elif redeem_script:
         script_code = p2pkh_script(redeem_script.cmds[1]).serialize()
     else:
         script_code = p2pkh_script(
             tx_in.script_pubkey(self.testnet).cmds[1]).serialize()
     s += script_code
     s += int_to_little_endian(tx_in.value(), 8)
     s += int_to_little_endian(tx_in.sequence, 4)
     s += self.hash_outputs()
     s += int_to_little_endian(self.locktime, 4)
     s += int_to_little_endian(SIGHASH_ALL, 4)
     return int.from_bytes(hash256(s), 'big')
コード例 #7
0
 def hash(self):
     """
     직렬화하여 hash256으로 해시값을 계산한 뒤, 리틀엔디언으로 변환
     - 트랜잭션 ID의 경우, 일반적인 직렬화 사용(?)
     :return: 트랜잭션 자체의 해시
     """
     return hash256(self.serialize_legacy())[::-1]
コード例 #8
0
    def parse(cls, stream, testnet=False):
        # 매직 넘버 : 4바이트
        magic = stream.read(4)

        # 올바른 스트림인지 확인
        if magic == b"":
            raise RuntimeError("Connection Reset")

        if testnet:
            expected_magic = TESTNET_NETWORK_MAGIC
        else:
            expected_magic = NETWORK_MAGIC
        if magic != expected_magic:
            raise RuntimeError("magic is not right {} (expected : {}".format(
                magic, expected_magic))

        # 커맨드 필드 : 12바이트(빈공간 0x00포함)
        command = stream.read(12)
        command = command.strip(b"\x00")

        # 페이로드 길이 : 4바이트 리틀엔디언
        payload_length = little_endian_to_int(stream.read(4))

        # 체크섬 필드 : 4바이트
        checksum = stream.read(4)

        # 페이로드 필드
        payload = stream.read(payload_length)

        # 체크섬을 통한 에러 확인
        payload_checksum = hash256(payload)[:4]
        if payload_checksum != checksum:
            raise RuntimeError("checksum error")

        return cls(command, payload, testnet)
コード例 #9
0
def make_merkle_parent(hash1, hash2):
    """
    두 노드를 이용하여 머클부모를 반환
    - 말단 노드 : 블록의 트랜잭션 해시값
    :param hash1: 왼쪽 자식 노드
    :param hash2: 오른쪽 자식 노드
    :return: 머클 부모(부모 해시값)
    """
    return hash256(hash1 + hash2)
コード例 #10
0
    def sig_hash(self, input_index):
        """
        해제 스크립트에 서명을 포함시켜 트랜잭션을 변형
        step1 : 해제 스크립트 삭제
            - 서명 검증시 트랜잭션의 해제 스크립트 삭제
            - 서명 생성시 동일
            - 입력이 여러 개인 경우, 해당 입력의 해제 스크립트 삭제
        step2 : 이전 트랜잭션 출력의 잠금 스크립트를 입력의 해제 스크립트에 삽입
            - 트랜잭션 입력에 대해 TxIn.script_pubkey를 사용하여 해제 스크립트 입수 가능
        step3 : 해시 유형 추가
            - 서명해시를 구하기 위한 메시지에 포함시킬 필드 결정
            - SIGHASH_ALL : 현재 입력과 다른 모든 입출력을 모두 포함
        step4 : 해시 계산
            - 최종 변경된 트랜잭션의 hash256 해시값 계산
            - 32바이트 빅엔디언 정수로 변환
        :param input_index: 현재 입력에 대한 인덱스
        :return: 변형된 트랜잭션의 서명해시 i.e 서명을 포함시킨 직렬화 정보
        """
        # 버전 : 4바이트 리틀 엔디언
        result = int_to_little_endian(self.version, 4)

        # 이전 트랜잭션 정보 : 이전 트랜잭션 개수 및 이전 트랜잭션들의 정보
        # 서명을 포함시키기 위해 serialize()와 다르게 직렬화
        result += encode_varint(len(self.tx_inputs))
        for idx, tx_in in enumerate(self.tx_inputs):
            # 현재 입력인 경우
            if idx == input_index:
                # 해당 트랜잭션 해시값에 대응되는 트랜잭션의 잠금 스크립트로 스크립트 대체
                tx_in_copy = TxIn(prev_tx=tx_in.prev_tx,
                                  prev_index=tx_in.prev_index,
                                  script_sig=tx_in.script_pubkey(self.testnet),
                                  sequence=tx_in.sequence)
                result += tx_in_copy.serialize()
            # 다른 입력
            else:
                # 해제 스크립트는 포함시키지 않는다
                tx_in_copy = TxIn(prev_tx=tx_in.prev_tx,
                                  prev_index=tx_in.prev_index,
                                  sequence=tx_in.sequence)
                result += tx_in_copy.serialize()

        # 트랜잭션 출력 : 출력 개수 및 출력들의 정보
        result += encode_varint(len(self.tx_outputs))
        for tx_output in self.tx_outputs:
            result += tx_output.serialize()

        # 록타임 : 4바이트의 리틀엔디언
        result += int_to_little_endian(self.locktime, 4)

        # 해시 유형 덧붙임 : SIGHASH_ALL 사용함
        result += int_to_little_endian(SIGHASH_ALL, 4)

        # 서명 해시 생성
        result256 = hash256(result)
        sig_message_hash = int.from_bytes(result256, "big")

        return sig_message_hash
コード例 #11
0
def example1():
    bit_field_size = 10
    bit_field = [0] * bit_field_size

    # 해시 + 나머지연산 이용
    h = hash256(b"hello world")
    bit = int.from_bytes(h, "big") % bit_field_size

    bit_field[bit] = 1
    print(bit_field)
コード例 #12
0
def exercise4():
    from io import BytesIO
    from ecc.secp256k1 import S256Point, Signature
    from ecc.utils import encode_varint, hash256, int_to_little_endian
    from ecc.transaction import Tx, SIGHASH_ALL

    # 문제 : 주어진 p2sh 다중 서명 스크립트와 서명이 주어질 때, 해당 서명 검증
    hex_tx = '0100000001868278ed6ddfb6c1ed3ad5f8181eb0c7a385aa0836f01d5e4789e6bd304d87221a000000db00483045022100dc92655fe37036f47756db8102e0d7d5e28b3beb83a8fef4f5dc0559bddfb94e02205a36d4e4e6c7fcd16658c50783e00c341609977aed3ad00937bf4ee942a8993701483045022100da6bee3c93766232079a01639d07fa869598749729ae323eab8eef53577d611b02207bef15429dcadce2121ea07f233115c6f09034c0be68db99980b9a6c5e75402201475221022626e955ea6ea6d98850c994f9107b036b1334f18ca8830bfff1295d21cfdb702103b287eaf122eea69030a0e9feed096bed8045c8b98bec453e1ffac7fbdbd4bb7152aeffffffff04d3b11400000000001976a914904a49878c0adfc3aa05de7afad2cc15f483a56a88ac7f400900000000001976a914418327e3f3dda4cf5b9089325a4b95abdfa0334088ac722c0c00000000001976a914ba35042cfe9fc66fd35ac2224eebdafd1028ad2788acdc4ace020000000017a91474d691da1574e6b3c192ecfb52cc8984ee7b6c568700000000'
    hex_sec = '03b287eaf122eea69030a0e9feed096bed8045c8b98bec453e1ffac7fbdbd4bb71'
    hex_der = '3045022100da6bee3c93766232079a01639d07fa869598749729ae323eab8eef53577d611b02207bef15429dcadce2121ea07f233115c6f09034c0be68db99980b9a6c5e754022'
    hex_redeem_script = '475221022626e955ea6ea6d98850c994f9107b036b1334f18ca8830bfff1295d21cfdb702103b287eaf122eea69030a0e9feed096bed8045c8b98bec453e1ffac7fbdbd4bb7152ae'
    sec = bytes.fromhex(hex_sec)
    der = bytes.fromhex(hex_der)

    # 해답

    # sec 공개키와 der 서명을 통해 해당 객체 생성
    point = S256Point.parse(sec)
    signature = Signature.parse(der)

    redeem_script = Script.parse(BytesIO(bytes.fromhex(hex_redeem_script)))
    stream = BytesIO(bytes.fromhex(hex_tx))

    tx = Tx.parse(stream)

    # 두번째 서명을 만들기 위한 트랜잭션의 해시 계산
    sig = int_to_little_endian(tx.version, 4)

    # 이전 트랜잭션 정보 : 이전 트랜잭션 개수 및 이전 트랜잭션들의 정보
    sig += encode_varint(len(tx.tx_inputs))

    # 서명 : 트랜잭션 입력의 해제 스크립트를 리딤 스크립트로 대체
    cur_input = tx.tx_inputs[0]
    tx_in_copy = TxIn(prev_tx=cur_input.prev_tx,
                      prev_index=cur_input.prev_index,
                      script_sig=redeem_script,
                      sequence=cur_input.sequence)
    sig += tx_in_copy.serialize()

    # 트랜잭션 출력 : 출력 개수 및 출력들의 정보
    sig += encode_varint(len(tx.tx_outputs))
    for tx_output in tx.tx_outputs:
        sig += tx_output.serialize()
    # 록타임 : 4바이트의 리틀엔디언
    sig += int_to_little_endian(tx.locktime, 4)

    # 해시 유형 덧붙임 : SIGHASH_ALL 사용함
    sig += int_to_little_endian(SIGHASH_ALL, 4)

    # 서명 해시 생성
    result256 = hash256(sig)
    sig_message_hash = int.from_bytes(result256, "big")

    print(point.verify(sig_message_hash, signature))
コード例 #13
0
    def serialize(self):
        # 매직 넘버 : 4바이트
        ret = self.magic

        # 커맨드 필드 : 12바이트(빈공간 0x00포함)
        ret += self.command
        ret += b"\x00" * (12 - len(self.command))

        # 페이로드 길이 : 4바이트 리틀엔디언
        ret += int_to_little_endian(len(self.payload), 4)

        # 체크섬 필드 : 4바이트
        ret += hash256(self.payload)[:4]

        # 페이로드 필드
        ret += self.payload

        return ret
コード例 #14
0
 def check_pow(self):
     """
     작업 증명
     - 작업 증명으로 탈중앙화 방식의 비트코인 채굴이 가능
       => 전체 네트워크 수준에서 비트코인 보안이 유지
     - 특정 조건을 만족하는 작은 값을 찾는 것
         - 특정 조건 : 목표값(target)
         - 작은 값 : 블록 헤더의 해시값
         - 블록의 해시값을 리틀엔디언 정수로 표현하여 비교
     - 블록 헤더의 해시 변경 방법
         - 채굴자가 논스값을 변경
         - 코인베이스 트랜잭션 변경
             => 머클루트가 변경되어 새로운 해시
         - 버전 필드 변경
     :return: 자격 증명 결과
     """
     block_hash = hash256(self.serialize())
     block_hash_int = little_endian_to_int(block_hash)
     return block_hash_int < self.target()
コード例 #15
0
def example4():
    print("목표값 설정 : 블록헤더의 해시값이 목표값보다 작을 때 작업 증명 유효")

    # 목표값 계산
    bits = bytes.fromhex("e93c0118")
    exponent = bits[-1]
    coef = little_endian_to_int(bits[:-1])
    target = coef * 256**(exponent - 3)
    print("exponent: {}, coef: {}".format(exponent, coef))
    print("target: ")
    print("{:x}".format(target).zfill(64))

    # 작업 증명 : 블록 헤더의 해시값을 리틀엔디언으로 표현
    block_hash = hash256(
        bytes.fromhex(
            '020000208ec39428b17323fa0ddec8e887b4a7c53b8c0a0a220cfd0000000000000000005b0750fce0a889502d40508d39576821155e9c9e3f5c3157f961db38fd8b25be1e77a759e93c0118a4ffd71d'
        ))
    block_hash_int = little_endian_to_int(block_hash)
    print("block_hash:")
    print("{:x}".format(block_hash_int).zfill(64))
    print("proof of work : {}".format(block_hash_int < target))
コード例 #16
0
def example2():
    from ecc.secp256k1 import S256Point, Signature
    from ecc.utils import hash256

    modified_tx = bytes.fromhex(
        '0100000001868278ed6ddfb6c1ed3ad5f8181eb0c7a385aa0836f01d5e4789e6bd304d87221a000000475221022626e955ea6ea6d98850c994f9107b036b1334f18ca8830bfff1295d21cfdb702103b287eaf122eea69030a0e9feed096bed8045c8b98bec453e1ffac7fbdbd4bb7152aeffffffff04d3b11400000000001976a914904a49878c0adfc3aa05de7afad2cc15f483a56a88ac7f400900000000001976a914418327e3f3dda4cf5b9089325a4b95abdfa0334088ac722c0c00000000001976a914ba35042cfe9fc66fd35ac2224eebdafd1028ad2788acdc4ace020000000017a91474d691da1574e6b3c192ecfb52cc8984ee7b6c56870000000001000000'
    )
    h256 = hash256(modified_tx)

    z = int.from_bytes(h256, 'big')

    # sec 공개키는 리딤 스크립트에서 구할 수 있음
    sec = bytes.fromhex(
        '022626e955ea6ea6d98850c994f9107b036b1334f18ca8830bfff1295d21cfdb70')
    point = S256Point.parse(sec)

    # der 서명은 해제 스크립트에서 구할 수 있음
    der = bytes.fromhex(
        '3045022100dc92655fe37036f47756db8102e0d7d5e28b3beb83a8fef4f5dc0559bddfb94e02205a36d4e4e6c7fcd16658c50783e00c341609977aed3ad00937bf4ee942a89937'
    )
    sig = Signature.parse(der)

    print(point.verify(z, sig))
コード例 #17
0
 def hash(self):
     """
     직렬화하여 hash256으로 해시값을 계산한 뒤, 리틀엔디언으로 변환
     :return: 블록 ID
     """
     return hash256(self.serialize())[::-1]
コード例 #18
0
def op_hash256(stack):
    if len(stack) < 1:
        return False
    element = stack.pop()
    stack.append(hash256(element))
    return True