これが Python 向けの俺の手早く雑な参照実装だ。-256〜256 の範囲と、8〜256 ビットでサイズの異なるランダムな数値約 4000個について、Bitcoin の実装と照らし合わせてテスト済みだ。 もっと速く Python らしいバージョンを書くのは簡単なはずだが、今はその気になれない…
import struct
def mpi2num(m):
"""convert MPI string to number"""
datasize = struct.unpack(">I", m[0:4])[0]
r = 0
if datasize:
neg_flag = bool(ord(m[4]) & 0x80)
r = ord(m[4]) & 0x7F
for i in xrange(1, datasize):
r <<= 8
r += ord(m[4+i])
if neg_flag:
r = -r
return r
def num2mpi(n):
"""convert number to MPI string"""
if n == 0:
return struct.pack(">I", 0)
r = ""
neg_flag = bool(n < 0)
n = abs(n)
while n:
r = chr(n & 0xFF) + r
n >>= 8
if ord(r[0]) & 0x80:
r = chr(0) + r
if neg_flag:
r = chr(ord(r[0]) | 0x80) + r[1:]
datasize = len(r)
return struct.pack(">I", datasize) + r
def GetCompact(n):
"""convert number to bc compact uint"""
mpi = num2mpi(n)
nSize = len(mpi) - 4
nCompact = (nSize & 0xFF) << 24
if nSize >= 1:
nCompact |= (ord(mpi[4]) << 16)
if nSize >= 2:
nCompact |= (ord(mpi[5]) << 8)
if nSize >= 3:
nCompact |= (ord(mpi[6]) << 0)
return nCompact
def SetCompact(nCompact):
"""convert bc compact uint to number"""
nSize = (nCompact >> 24) & 0xFF
tbuf = "\x00\x00\x00" + chr(nSize)
if nSize >= 1:
tbuf += chr((nCompact >> 16) & 0xFF)
if nSize >= 2:
tbuf += chr((nCompact >> 8) & 0xFF)
if nSize >= 3:
tbuf += chr((nCompact >> 0) & 0xFF)
tbuf += "\x00" * (nSize - 3)
return mpi2num(tbuf)