mirror of
https://github.com/monero-project/research-lab.git
synced 2024-12-23 03:59:40 +00:00
262 lines
7.4 KiB
Python
262 lines
7.4 KiB
Python
|
#"MiniNero" by Shen Noether mrl. Use at your own risk.
|
||
|
import hashlib #for signatures
|
||
|
import math
|
||
|
import Crypto.Random.random as rand
|
||
|
import Keccak #cn_fast_hash
|
||
|
import mnemonic #making 25 word mnemonic to remember your keys
|
||
|
import binascii #conversion between hex, int, and binary. Also for the crc32 thing
|
||
|
import ed25519 #Bernsteins python ed25519 code from cr.yp.to
|
||
|
import zlib
|
||
|
|
||
|
b = 256
|
||
|
q = 2**255 - 19
|
||
|
l = 2**252 + 27742317777372353535851937790883648493
|
||
|
|
||
|
def netVersion():
|
||
|
return "12"
|
||
|
|
||
|
def public_key(sk):
|
||
|
#returns point encoded to binary .. sk is just an int..
|
||
|
return ed25519.encodepoint(ed25519.scalarmultbase(sk)) #pub key is not just x coord..
|
||
|
|
||
|
def scalarmult_simple(pk, num):
|
||
|
#returns point encoded to hex.. num is an int, not a hex
|
||
|
return ed25519.encodepoint(ed25519.scalarmult(toPoint(pk), num)) #pub key is not just x coord..
|
||
|
|
||
|
def addKeys(P1, P2):
|
||
|
return binascii.hexlify(ed25519.encodepoint(ed25519.edwards(toPoint(P1), toPoint(P2))))
|
||
|
|
||
|
#aG + bB, G is basepoint..
|
||
|
def addKeys1(a, b, B):
|
||
|
return addKeys(scalarmultBase(a), scalarmultKey(B, b))
|
||
|
|
||
|
#aA + bB
|
||
|
def addKeys2(a, A, b, B):
|
||
|
return addKeys(scalarmultKey(A, a), scalarmultKey(B, b))
|
||
|
|
||
|
def subKeys(P1, P2):
|
||
|
return binascii.hexlify(ed25519.encodepoint(ed25519.edwards_Minus(toPoint(P1), toPoint(P2))))
|
||
|
|
||
|
def randomScalar():
|
||
|
tmp = rand.getrandbits(32 * 8) # 8 bits to a byte ...
|
||
|
return (tmp)
|
||
|
|
||
|
def xor(a, b):
|
||
|
return intToHex(hexToInt(a) ^ hexToInt(b))
|
||
|
|
||
|
def electrumChecksum(wordlist):
|
||
|
wl = wordlist.split(" ") #make an array
|
||
|
if len(wl) > 13:
|
||
|
wl = wl[:24]
|
||
|
else:
|
||
|
wl = wl[:12]
|
||
|
upl = 3 #prefix length
|
||
|
wl2 = ''
|
||
|
for a in wl:
|
||
|
wl2+= a[:upl]
|
||
|
z = ((zlib.crc32(wl2) & 0xffffffff) ^ 0xffffffff ) >> 0
|
||
|
z2 = ((z ^ 0xffffffff) >> 0) % len(wl)
|
||
|
return wl[z2]
|
||
|
|
||
|
__b58chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
|
||
|
__b58base = len(__b58chars)
|
||
|
|
||
|
def b58encode(v):
|
||
|
a = [reverseBytes(v[i:i+16]) for i in range(0, len(v)-16, 16)]
|
||
|
rr = -2*((len(v) /2 )% 16)
|
||
|
|
||
|
res = ''
|
||
|
for b in a:
|
||
|
bb = hexToInt(b)
|
||
|
result = ''
|
||
|
while bb >= __b58base:
|
||
|
div, mod = divmod(bb, __b58base)
|
||
|
result = __b58chars[mod] + result
|
||
|
bb = div
|
||
|
result = __b58chars[bb] + result
|
||
|
res += result
|
||
|
result = ''
|
||
|
if rr < 0:
|
||
|
bf = hexToInt(reverseBytes(v[rr:])) #since we only reversed the ones in the array..
|
||
|
result = ''
|
||
|
while bf >= __b58base:
|
||
|
div, mod = divmod(bf, __b58base)
|
||
|
result = __b58chars[mod] + result
|
||
|
bf = div
|
||
|
result = __b58chars[bf] + result
|
||
|
res += result
|
||
|
return res
|
||
|
|
||
|
|
||
|
def sc_0():
|
||
|
return intToHex(0)
|
||
|
|
||
|
def sc_reduce_key(a):
|
||
|
return intToHex(hexToInt(a) % l)
|
||
|
|
||
|
def sc_unreduce_key(a):
|
||
|
return intToHex(hexToInt(a) % l + l)
|
||
|
|
||
|
def sc_add_keys(a, b):
|
||
|
#adds two private keys mod l
|
||
|
return intToHex((hexToInt(a) + hexToInt(b)) % l)
|
||
|
|
||
|
def sc_add(a, exps):
|
||
|
#adds a vector of private keys mod l and multiplies them by an exponent
|
||
|
ssum = 0
|
||
|
for i in range(0, len(a)):
|
||
|
ssum = (ssum + 10 ** exps[i] * hexToInt(a[i])) % l
|
||
|
return intToHex(ssum)
|
||
|
|
||
|
def sc_check(a):
|
||
|
if hexToInt(a) % l == 0:
|
||
|
return False
|
||
|
return (a == sc_reduce_key(a))
|
||
|
|
||
|
def addScalars(a, b): #to do: remove above and rename to this (so that there is "add keys" and "add scalars")
|
||
|
#adds two private keys mod l
|
||
|
return intToHex((hexToInt(a) + hexToInt(b)) % l)
|
||
|
|
||
|
def sc_sub_keys(a, b):
|
||
|
#subtracts two private keys mod l
|
||
|
return intToHex((hexToInt(a) - hexToInt(b)) % l)
|
||
|
|
||
|
def sc_mul_keys(a, b):
|
||
|
return intToHex((hexToInt(a) * hexToInt(b)) % l)
|
||
|
|
||
|
def sc_sub_keys(a, b):
|
||
|
return intToHex((hexToInt(a) - hexToInt(b)) % l)
|
||
|
|
||
|
def sc_mulsub_keys(a, b, c):
|
||
|
#returns a - b * c (for use in LLW sigs - see MRL notes v 0.3)
|
||
|
return intToHex( (hexToInt(a)- hexToInt(b) * hexToInt(c)) % l)
|
||
|
|
||
|
def add_l(a, n):
|
||
|
return intToHex(hexToInt(a) +n * l )
|
||
|
|
||
|
def sc_muladd_keys(a, b, c):
|
||
|
#returns a + b * c (for use in LLW sigs - see MRL notes v 0.3)
|
||
|
return intToHex((hexToInt(a)+ hexToInt(b) * hexToInt(c) ) % l)
|
||
|
|
||
|
def mul_8(a):
|
||
|
return intToHex(8 * hexToInt(a))
|
||
|
|
||
|
def fe_reduce_key(a):
|
||
|
return intToHex(hexToInt(a) % q)
|
||
|
|
||
|
def recoverSK(seed):
|
||
|
mn2 = seed.split(" ") #make array
|
||
|
if len(mn2) > 13:
|
||
|
mn2 = mn2[:24]
|
||
|
sk = mnemonic.mn_decode(mn2)
|
||
|
else:
|
||
|
mn2 = mn2[:12]
|
||
|
#mn2 += mn2[:]
|
||
|
sk = cn_fast_hash(mnemonic.mn_decode(mn2))
|
||
|
#sk = mnemonic.mn_decode(mn2)
|
||
|
|
||
|
return sk
|
||
|
|
||
|
def cn_fast_hash(s):
|
||
|
k = Keccak.Keccak()
|
||
|
return k.Keccak((len(s) * 4, s), 1088, 512, 32 * 8, False).lower() #r = bitrate = 1088, c = capacity, n = output length in bits
|
||
|
|
||
|
def getView(sk):
|
||
|
a = hexToInt(cn_fast_hash(sc_reduce_key(sk))) % l
|
||
|
return intToHex(a)
|
||
|
|
||
|
def getViewMM(sk):
|
||
|
a = hexToInt(cn_fast_hash(sk))
|
||
|
return intToHex(a)
|
||
|
|
||
|
|
||
|
def reverseBytes(a): #input is byte string, it reverse the endianness
|
||
|
b = [a[i:i+2] for i in range(0, len(a)-1, 2)]
|
||
|
return ''.join(b[::-1])
|
||
|
|
||
|
def encode_addr(version, spendP, viewP):
|
||
|
buf = version + spendP + viewP
|
||
|
h = cn_fast_hash(buf)
|
||
|
buf = buf + h[0:8]
|
||
|
return b58encode(buf)
|
||
|
|
||
|
def hexToInt(h):
|
||
|
s = binascii.unhexlify(h) #does hex to bytes
|
||
|
bb = len(h) * 4 #I guess 8 bits / b
|
||
|
return sum(2**i * ed25519.bit(s,i) for i in range(0,bb)) #does to int
|
||
|
|
||
|
def intToHex(i):
|
||
|
return binascii.hexlify(ed25519.encodeint(i)) #hexlify does bytes to hex
|
||
|
|
||
|
def publicFromSecret(sk):
|
||
|
#returns pubkey in hex, same as scalarmultBase
|
||
|
return binascii.hexlify(public_key(hexToInt(sk)))
|
||
|
|
||
|
def scalarmultBase(sk):
|
||
|
#returns pubkey in hex, expects hex sk
|
||
|
return binascii.hexlify(public_key(hexToInt(sk)))
|
||
|
|
||
|
def identity():
|
||
|
return scalarmultBase(intToHex(0))
|
||
|
|
||
|
def scalarmultKey(pk, num):
|
||
|
return binascii.hexlify(scalarmult_simple(pk, hexToInt(num)))
|
||
|
|
||
|
def scalarmultKeyInt(pk, num):
|
||
|
return binascii.hexlify(scalarmult_simple(pk, num))
|
||
|
|
||
|
def publicFromInt(i):
|
||
|
#returns pubkey in hex, same as scalarmultBase.. should just pick one
|
||
|
return binascii.hexlify(public_key(i))
|
||
|
|
||
|
def toPoint(hexVal):
|
||
|
aa = binascii.unhexlify(hexVal) #to binary (new)
|
||
|
return ed25519.decodepoint(aa) #make to point
|
||
|
|
||
|
def fromPoint(aa): #supposed to reverse toPoint
|
||
|
binvalue = ed25519.encodepoint(aa)
|
||
|
return binascii.hexlify(binvalue)
|
||
|
|
||
|
def hashToPoint_cn(hexVal):
|
||
|
#note this is the monero one, won't work for C.T.
|
||
|
#however there is an alternative which will work for C.T.
|
||
|
#pk = publicFromSecret(hexVal)
|
||
|
HP = cn_fast_hash(hexVal)
|
||
|
return scalarmultBase(HP)
|
||
|
|
||
|
def mul8(point):
|
||
|
return binascii.hexlify(scalarmult_simple(point, 8))
|
||
|
|
||
|
def hashToPoint_ct(hexVal):
|
||
|
#note this is the monero one, won't work for C.T.
|
||
|
#however there is an alternative which will work for C.T.
|
||
|
#returns a hex string, not a point
|
||
|
a = hexVal[:]
|
||
|
i = 0
|
||
|
while True:
|
||
|
worked = 1
|
||
|
a = cn_fast_hash(a)
|
||
|
i += 1
|
||
|
try:
|
||
|
toPoint(a)
|
||
|
except:
|
||
|
worked = 0
|
||
|
if worked == 1:
|
||
|
break
|
||
|
print("found point after "+str(i)+" hashes")
|
||
|
return mul8(a) # needs to be in group of basepoint
|
||
|
|
||
|
def getAddrMM(sk):
|
||
|
vk = getViewMM(sk)
|
||
|
sk = sc_reduce_key(sk)
|
||
|
pk = publicFromSecret(sk)
|
||
|
pvk = publicFromSecret(vk)
|
||
|
return encode_addr(netVersion(), pk, pvk)
|
||
|
|
||
|
def getAddr(sk):
|
||
|
vk = getView(sk)
|
||
|
sk = sc_reduce_key(sk)
|
||
|
pk = publicFromSecret(sk)
|
||
|
pvk = publicFromSecret(vk)
|
||
|
return encode_addr(netVersion(), pk, pvk)
|