mirror of
https://github.com/monero-project/research-lab.git
synced 2025-01-03 09:29:44 +00:00
Added MiniNero and RingCT code
This commit is contained in:
parent
d5b8d275ae
commit
55c92de3bc
64 changed files with 22162 additions and 0 deletions
113
source-code/MiniNero/ASNL.py
Normal file
113
source-code/MiniNero/ASNL.py
Normal file
|
@ -0,0 +1,113 @@
|
|||
#see the aggregate schnorr pdf contained in this repository for an explanation.
|
||||
import MiniNero
|
||||
import MLSAG
|
||||
import LLW_Sigs
|
||||
import PaperWallet
|
||||
import Crypto.Random.random as rand
|
||||
import binascii
|
||||
|
||||
b = 256
|
||||
q = 2**255 - 19
|
||||
l = 2**252 + 27742317777372353535851937790883648493
|
||||
|
||||
|
||||
def GenSchnorr(hash_prefix, pub, sec, k):
|
||||
#modified from original algorithm to match Monero better
|
||||
#see the ag schnorr pdf for original alg.
|
||||
#Note in Monero, hash prefix is always 32 bytes..
|
||||
#hash_prefix = binascii.hexlify(prefix)
|
||||
#k = PaperWallet.skGen() #comment for testing
|
||||
comm = MiniNero.scalarmultBase(k)
|
||||
print("comm", "hash_prefix", comm, hash_prefix)
|
||||
if MiniNero.scalarmultBase(sec) != pub:
|
||||
print"error in genSchnorr"
|
||||
return -1
|
||||
if MiniNero.sc_check(sec) == False:
|
||||
print "fail in geSchnorr"
|
||||
return -1
|
||||
c = MiniNero.sc_reduce_key(MiniNero.cn_fast_hash(hash_prefix + pub + comm))
|
||||
r = MiniNero.sc_sub_keys(k, MiniNero.sc_mul_keys(c, sec))
|
||||
#uncomment to test malleability
|
||||
c = MiniNero.sc_reduce_key(MiniNero.cn_fast_hash(hash_prefix + pub + comm))
|
||||
r = MiniNero.sc_unreduce_key(MiniNero.sc_sub_keys(k, MiniNero.sc_mul_keys(c, sec)))
|
||||
|
||||
return r, c
|
||||
|
||||
def VerSchnorr(hash_prefix, pub, r, c):
|
||||
#hash_prefix = binascii.hexlify(prefix)
|
||||
check1 = MiniNero.toPoint(pub)
|
||||
comm = MiniNero.addKeys(MiniNero.scalarmultKey(pub,c), MiniNero.scalarmultBase(r))
|
||||
c2 = MiniNero.cn_fast_hash(hash_prefix + pub + comm)
|
||||
print(MiniNero.sc_sub_keys(c, c2) == "0000000000000000000000000000000000000000000000000000000000000000")
|
||||
return (MiniNero.sc_sub_keys(c, c2) == "0000000000000000000000000000000000000000000000000000000000000000")
|
||||
|
||||
def GenSchnorrNonLinkable(x, P1, P2, index):
|
||||
if index == 0:
|
||||
a = PaperWallet.skGen()
|
||||
L1 = MiniNero.scalarmultBase(a)
|
||||
s2 = PaperWallet.skGen()
|
||||
c2 = MiniNero.cn_fast_hash(L1)
|
||||
L2 = MiniNero.addKeys(MiniNero.scalarmultBase(s2), MiniNero.scalarmultKey(P2, c2))
|
||||
c1 = MiniNero.cn_fast_hash(L2)
|
||||
s1 = MiniNero.sc_mulsub_keys(a, x, c1)
|
||||
if index == 1:
|
||||
a = PaperWallet.skGen()
|
||||
L2 = MiniNero.scalarmultBase(a)
|
||||
s1 = PaperWallet.skGen()
|
||||
c1 = MiniNero.cn_fast_hash(L2)
|
||||
L1 = MiniNero.addKeys(MiniNero.scalarmultBase(s1), MiniNero.scalarmultKey(P1, c1))
|
||||
c2 = MiniNero.cn_fast_hash(L1)
|
||||
s2 = MiniNero.sc_mulsub_keys(a, x, c2)
|
||||
return L1, s1, s2,
|
||||
|
||||
def VerSchnorrNonLinkable(P1, P2, L1, s1, s2):
|
||||
c2 = MiniNero.cn_fast_hash(L1)
|
||||
L2 = MiniNero.addKeys(MiniNero.scalarmultBase(s2), MiniNero.scalarmultKey(P2, c2))
|
||||
c1 = MiniNero.cn_fast_hash(L2)
|
||||
L1p = MiniNero.addKeys(MiniNero.scalarmultBase(s1), MiniNero.scalarmultKey(P1, c1))
|
||||
if L1 == L1p:
|
||||
print"Verified"
|
||||
return 0
|
||||
else:
|
||||
print "Didn't verify"
|
||||
print(L1,"!=", L1p)
|
||||
return -1
|
||||
|
||||
|
||||
|
||||
def GenASNL(x, P1, P2, indices):
|
||||
#Aggregate Schnorr Non-Linkable
|
||||
#x, P1, P2, are key vectors here, but actually you
|
||||
#indices specifices which column of the given row of the key vector you sign.
|
||||
#the key vector with the first or second key
|
||||
n = len(x)
|
||||
print("Generating Aggregate Schnorr Non-linkable Ring Signature")
|
||||
L1 = [None] * n
|
||||
s1 = [None] * n
|
||||
s2 = [None] * n
|
||||
s = MiniNero.intToHex(0)
|
||||
for j in range(0, n):
|
||||
L1[j], s1[j], s2[j] = GenSchnorrNonLinkable(x[j], P1[j], P2[j], indices[j])
|
||||
s = MiniNero.sc_add_keys(s, s1[j])
|
||||
return L1, s2, s
|
||||
|
||||
def VerASNL(P1, P2, L1, s2, s):
|
||||
#Aggregate Schnorr Non-Linkable
|
||||
print("Verifying Aggregate Schnorr Non-linkable Ring Signature")
|
||||
n = len(P1)
|
||||
LHS = MiniNero.scalarmultBase(MiniNero.intToHex(0))
|
||||
RHS = MiniNero.scalarmultBase(s)
|
||||
for j in range(0, n):
|
||||
c2 = MiniNero.cn_fast_hash(L1[j])
|
||||
L2 = MiniNero.addKeys(MiniNero.scalarmultBase(s2[j]), MiniNero.scalarmultKey(P2[j], c2))
|
||||
LHS = MiniNero.addKeys(LHS, L1[j])
|
||||
c1 = MiniNero.cn_fast_hash(L2)
|
||||
RHS = MiniNero.addKeys(RHS, MiniNero.scalarmultKey(P1[j], c1))
|
||||
if LHS == RHS:
|
||||
print"Verified"
|
||||
return 0
|
||||
else:
|
||||
print "Didn't verify"
|
||||
print(LHS,"!=", RHS)
|
||||
return -1
|
||||
|
5
source-code/MiniNero/AggregateSchnorrCT.hash
Normal file
5
source-code/MiniNero/AggregateSchnorrCT.hash
Normal file
|
@ -0,0 +1,5 @@
|
|||
9
|
||||
0
|
||||
('checksum', '7$Z:')
|
||||
1B2yLX66Q3K49NJnNF9h6Yv4aB4oUxbPC5
|
||||
https://blockchain.info/address/1B2yLX66Q3K49NJnNF9h6Yv4aB4oUxbPC5
|
BIN
source-code/MiniNero/AggregateSchnorrCT_copy.pdf
Normal file
BIN
source-code/MiniNero/AggregateSchnorrCT_copy.pdf
Normal file
Binary file not shown.
6
source-code/MiniNero/Dec23Overleaf.hash
Normal file
6
source-code/MiniNero/Dec23Overleaf.hash
Normal file
|
@ -0,0 +1,6 @@
|
|||
592
|
||||
0
|
||||
(0, 'Yb\x02\xaao\xfca\xd8%\t\x10\xc1M\xbfY\x1b+\xf21F', 'here')
|
||||
('checksum', '\xad\x80?[')
|
||||
199cYxSJyKmkZFET9gtm3WzDHu7MpwHGTU
|
||||
https://blockchain.info/address/199cYxSJyKmkZFET9gtm3WzDHu7MpwHGTU
|
52
source-code/MiniNero/Deterministic.py
Normal file
52
source-code/MiniNero/Deterministic.py
Normal file
|
@ -0,0 +1,52 @@
|
|||
#monero determinstic vk wallet test code, shen noether mrl
|
||||
#use at your own risk
|
||||
import Crypto.Random.random as rand
|
||||
import MiniNero
|
||||
import mnemonic
|
||||
|
||||
def deterministicVK():
|
||||
while True:
|
||||
print('.'),
|
||||
tmp = MiniNero.intToHex(rand.getrandbits(64 * 8)) # 8 bits to a byte ...
|
||||
sk = MiniNero.sc_reduce_key(MiniNero.cn_fast_hash(tmp))
|
||||
|
||||
|
||||
#s = "3c817618dcbfed122a64e592bb441d73300da9123686224a84e0eab1f075117e"; for testing
|
||||
#sk = MiniNero.sc_reduce_key(s)
|
||||
vk = MiniNero.getViewMM(sk) #note this is the sc_reduced version..
|
||||
worked = 1
|
||||
try:
|
||||
MiniNero.toPoint(vk)
|
||||
except:
|
||||
worked =0
|
||||
print("bad vk")
|
||||
if vk == MiniNero.sc_reduce_key(vk) and worked == 1: #already reduced + vk on curve
|
||||
break
|
||||
|
||||
print("found keys")
|
||||
print("secret spend key:", sk)
|
||||
print("secret view key:", vk)
|
||||
vk2 = MiniNero.cn_fast_hash(MiniNero.scalarmultKey(vk, 2))
|
||||
print("secret view key2:", vk2)
|
||||
vk3 = MiniNero.cn_fast_hash(MiniNero.scalarmultKey(vk, 3))
|
||||
print("secret view key3:", vk3)
|
||||
|
||||
pk = MiniNero.publicFromSecret(sk)
|
||||
print("public spend key:", pk)
|
||||
pvk = MiniNero.publicFromSecret(vk)
|
||||
print("public view key:", pvk)
|
||||
pvk2 = MiniNero.publicFromSecret(vk2)
|
||||
print("public view key2:", pvk2)
|
||||
pvk3 = MiniNero.publicFromSecret(vk3)
|
||||
print("public view key3:", pvk3)
|
||||
|
||||
addr = MiniNero.getAddrMM(sk)
|
||||
print("in future this will get all addresses")
|
||||
print("receiving address", addr)
|
||||
wl = mnemonic.mn_encode(s)
|
||||
cks = MiniNero.electrumChecksum(wl)
|
||||
print(cks)
|
||||
print("mnemonic:", wl + " " + cks)
|
||||
|
||||
deterministicVK()
|
||||
|
17
source-code/MiniNero/Ecdh.py
Normal file
17
source-code/MiniNero/Ecdh.py
Normal file
|
@ -0,0 +1,17 @@
|
|||
#Elliptic Curve Diffie Helman with ed25519
|
||||
#ecdhgen and ecdhretrieve translated into MiniNero from implementation by TacoTime
|
||||
import MiniNero
|
||||
import PaperWallet
|
||||
def ecdhGen(P):
|
||||
ephembytes, ephempub = PaperWallet.skpkGen()
|
||||
sspub = MiniNero.scalarmultKey(P, ephembytes) #(receiver pub) * (sender ecdh sk)
|
||||
ss1 = MiniNero.cn_fast_hash(sspub)
|
||||
ss2 = MiniNero.cn_fast_hash(ss1)
|
||||
return ephembytes, ephempub, ss1, ss2
|
||||
|
||||
def ecdhRetrieve(x, pk):
|
||||
sspub = MiniNero.scalarmultKey(pk, x)
|
||||
ss1 = MiniNero.cn_fast_hash(sspub)
|
||||
ss2 = MiniNero.cn_fast_hash(ss1)
|
||||
return ss1, ss2
|
||||
|
2
source-code/MiniNero/FS_Signatures.py
Normal file
2
source-code/MiniNero/FS_Signatures.py
Normal file
|
@ -0,0 +1,2 @@
|
|||
import MiniNero
|
||||
import PaperWallet
|
9
source-code/MiniNero/GenLookup.py
Normal file
9
source-code/MiniNero/GenLookup.py
Normal file
|
@ -0,0 +1,9 @@
|
|||
import MiniNero
|
||||
def getHForCT():
|
||||
A = MiniNero.publicFromInt(123456)
|
||||
return MiniNero.hashToPoint_ct(A)
|
||||
|
||||
H = getHForCT()
|
||||
for i in range(0, 2**14):
|
||||
print(MiniNero.scalarmultKeyInt(H, i))
|
||||
|
348
source-code/MiniNero/Keccak.py
Normal file
348
source-code/MiniNero/Keccak.py
Normal file
|
@ -0,0 +1,348 @@
|
|||
#! /usr/bin/pythonw
|
||||
# The Keccak sponge function, designed by Guido Bertoni, Joan Daemen,
|
||||
# questions, please refer to our website: http://keccak.noekeon.org/
|
||||
#
|
||||
# Implementation by Renaud Bauvin,
|
||||
# hereby denoted as "the implementer".
|
||||
#
|
||||
# To the extent possible under law, the implementer has waived all copyright
|
||||
# and related or neighboring rights to the source code in this file.
|
||||
# http://creativecommons.org/publicdomain/zero/1.0/
|
||||
|
||||
import math
|
||||
|
||||
class KeccakError(Exception):
|
||||
"""Class of error used in the Keccak implementation
|
||||
|
||||
Use: raise KeccakError.KeccakError("Text to be displayed")"""
|
||||
|
||||
def __init__(self, value):
|
||||
self.value = value
|
||||
def __str__(self):
|
||||
return repr(self.value)
|
||||
|
||||
|
||||
class Keccak:
|
||||
"""
|
||||
Class implementing the Keccak sponge function
|
||||
"""
|
||||
def __init__(self, b=1600):
|
||||
"""Constructor:
|
||||
|
||||
b: parameter b, must be 25, 50, 100, 200, 400, 800 or 1600 (default value)"""
|
||||
self.setB(b)
|
||||
|
||||
def setB(self,b):
|
||||
"""Set the value of the parameter b (and thus w,l and nr)
|
||||
|
||||
b: parameter b, must be choosen among [25, 50, 100, 200, 400, 800, 1600]
|
||||
"""
|
||||
|
||||
if b not in [25, 50, 100, 200, 400, 800, 1600]:
|
||||
raise KeccakError.KeccakError('b value not supported - use 25, 50, 100, 200, 400, 800 or 1600')
|
||||
|
||||
# Update all the parameters based on the used value of b
|
||||
self.b=b
|
||||
self.w=b//25
|
||||
self.l=int(math.log(self.w,2))
|
||||
self.nr=12+2*self.l
|
||||
|
||||
# Constants
|
||||
|
||||
## Round constants
|
||||
RC=[0x0000000000000001,
|
||||
0x0000000000008082,
|
||||
0x800000000000808A,
|
||||
0x8000000080008000,
|
||||
0x000000000000808B,
|
||||
0x0000000080000001,
|
||||
0x8000000080008081,
|
||||
0x8000000000008009,
|
||||
0x000000000000008A,
|
||||
0x0000000000000088,
|
||||
0x0000000080008009,
|
||||
0x000000008000000A,
|
||||
0x000000008000808B,
|
||||
0x800000000000008B,
|
||||
0x8000000000008089,
|
||||
0x8000000000008003,
|
||||
0x8000000000008002,
|
||||
0x8000000000000080,
|
||||
0x000000000000800A,
|
||||
0x800000008000000A,
|
||||
0x8000000080008081,
|
||||
0x8000000000008080,
|
||||
0x0000000080000001,
|
||||
0x8000000080008008]
|
||||
|
||||
## Rotation offsets
|
||||
r=[[0, 36, 3, 41, 18] ,
|
||||
[1, 44, 10, 45, 2] ,
|
||||
[62, 6, 43, 15, 61] ,
|
||||
[28, 55, 25, 21, 56] ,
|
||||
[27, 20, 39, 8, 14] ]
|
||||
|
||||
## Generic utility functions
|
||||
|
||||
def rot(self,x,n):
|
||||
"""Bitwise rotation (to the left) of n bits considering the \
|
||||
string of bits is w bits long"""
|
||||
|
||||
n = n%self.w
|
||||
return ((x>>(self.w-n))+(x<<n))%(1<<self.w)
|
||||
|
||||
def fromHexStringToLane(self, string):
|
||||
"""Convert a string of bytes written in hexadecimal to a lane value"""
|
||||
|
||||
#Check that the string has an even number of characters i.e. whole number of bytes
|
||||
if len(string)%2!=0:
|
||||
raise KeccakError.KeccakError("The provided string does not end with a full byte")
|
||||
|
||||
#Perform the modification
|
||||
temp=''
|
||||
nrBytes=len(string)//2
|
||||
for i in range(nrBytes):
|
||||
offset=(nrBytes-i-1)*2
|
||||
temp+=string[offset:offset+2]
|
||||
return int(temp, 16)
|
||||
|
||||
def fromLaneToHexString(self, lane):
|
||||
"""Convert a lane value to a string of bytes written in hexadecimal"""
|
||||
|
||||
laneHexBE = (("%%0%dX" % (self.w//4)) % lane)
|
||||
#Perform the modification
|
||||
temp=''
|
||||
nrBytes=len(laneHexBE)//2
|
||||
for i in range(nrBytes):
|
||||
offset=(nrBytes-i-1)*2
|
||||
temp+=laneHexBE[offset:offset+2]
|
||||
return temp.upper()
|
||||
|
||||
def printState(self, state, info):
|
||||
"""Print on screen the state of the sponge function preceded by \
|
||||
string info
|
||||
|
||||
state: state of the sponge function
|
||||
info: a string of characters used as identifier"""
|
||||
|
||||
print("Current value of state: %s" % (info))
|
||||
for y in range(5):
|
||||
line=[]
|
||||
for x in range(5):
|
||||
line.append(hex(state[x][y]))
|
||||
print('\t%s' % line)
|
||||
|
||||
### Conversion functions String <-> Table (and vice-versa)
|
||||
|
||||
def convertStrToTable(self,string):
|
||||
|
||||
|
||||
#Check that input paramaters
|
||||
if self.w%8!= 0:
|
||||
raise KeccakError("w is not a multiple of 8")
|
||||
if len(string)!=2*(self.b)//8:
|
||||
raise KeccakError.KeccakError("string can't be divided in 25 blocks of w bits\
|
||||
i.e. string must have exactly b bits")
|
||||
|
||||
#Convert
|
||||
output=[[0,0,0,0,0],
|
||||
[0,0,0,0,0],
|
||||
[0,0,0,0,0],
|
||||
[0,0,0,0,0],
|
||||
[0,0,0,0,0]]
|
||||
for x in range(5):
|
||||
for y in range(5):
|
||||
offset=2*((5*y+x)*self.w)//8
|
||||
output[x][y]=self.fromHexStringToLane(string[offset:offset+(2*self.w//8)])
|
||||
return output
|
||||
|
||||
def convertTableToStr(self,table):
|
||||
|
||||
#Check input format
|
||||
if self.w%8!= 0:
|
||||
raise KeccakError.KeccakError("w is not a multiple of 8")
|
||||
if (len(table)!=5) or (False in [len(row)==5 for row in table]):
|
||||
raise KeccakError.KeccakError("table must b")
|
||||
|
||||
#Convert
|
||||
output=['']*25
|
||||
for x in range(5):
|
||||
for y in range(5):
|
||||
output[5*y+x]=self.fromLaneToHexString(table[x][y])
|
||||
output =''.join(output).upper()
|
||||
return output
|
||||
|
||||
def Round(self,A,RCfixed):
|
||||
"""Perform one round of computation as defined in the Keccak-f permutation
|
||||
|
||||
"""
|
||||
|
||||
#Initialisation of temporary variables
|
||||
B=[[0,0,0,0,0],
|
||||
[0,0,0,0,0],
|
||||
[0,0,0,0,0],
|
||||
[0,0,0,0,0],
|
||||
[0,0,0,0,0]]
|
||||
C= [0,0,0,0,0]
|
||||
D= [0,0,0,0,0]
|
||||
|
||||
#Theta step
|
||||
for x in range(5):
|
||||
C[x] = A[x][0]^A[x][1]^A[x][2]^A[x][3]^A[x][4]
|
||||
|
||||
for x in range(5):
|
||||
D[x] = C[(x-1)%5]^self.rot(C[(x+1)%5],1)
|
||||
|
||||
for x in range(5):
|
||||
for y in range(5):
|
||||
A[x][y] = A[x][y]^D[x]
|
||||
|
||||
#Rho and Pi steps
|
||||
for x in range(5):
|
||||
for y in range(5):
|
||||
B[y][(2*x+3*y)%5] = self.rot(A[x][y], self.r[x][y])
|
||||
|
||||
#Chi step
|
||||
for x in range(5):
|
||||
for y in range(5):
|
||||
A[x][y] = B[x][y]^((~B[(x+1)%5][y]) & B[(x+2)%5][y])
|
||||
|
||||
#Iota step
|
||||
A[0][0] = A[0][0]^RCfixed
|
||||
|
||||
return A
|
||||
|
||||
def KeccakF(self,A, verbose=False):
|
||||
"""Perform Keccak-f function on the state A
|
||||
|
||||
verbose: a boolean flag activating the printing of intermediate computations
|
||||
"""
|
||||
|
||||
if verbose:
|
||||
self.printState(A,"Before first round")
|
||||
|
||||
for i in range(self.nr):
|
||||
#NB: result is truncated to lane size
|
||||
A = self.Round(A,self.RC[i]%(1<<self.w))
|
||||
|
||||
if verbose:
|
||||
self.printState(A,"Satus end of round #%d/%d" % (i+1,self.nr))
|
||||
|
||||
return A
|
||||
|
||||
### Padding rule
|
||||
|
||||
def pad10star1(self, M, n):
|
||||
"""Pad M with the pad10*1 padding rule to reach a length multiple of r bits
|
||||
|
||||
M: message pair (length in bits, string of hex characters ('9AFC...')
|
||||
n: length in bits (must be a multiple of 8)
|
||||
Example: pad10star1([60, 'BA594E0FB9EBBD30'],8) returns 'BA594E0FB9EBBD93'
|
||||
"""
|
||||
|
||||
[my_string_length, my_string]=M
|
||||
|
||||
# Check the parameter n
|
||||
if n%8!=0:
|
||||
raise KeccakError.KeccakError("n must be a multiple of 8")
|
||||
|
||||
# Check the length of the provided string
|
||||
if len(my_string)%2!=0:
|
||||
#Pad with one '0' to reach correct length (don't know test
|
||||
#vectors coding)
|
||||
my_string=my_string+'0'
|
||||
if my_string_length>(len(my_string)//2*8):
|
||||
raise KeccakError.KeccakError("the string is too short to contain the number of bits announced")
|
||||
|
||||
nr_bytes_filled=my_string_length//8
|
||||
nbr_bits_filled=my_string_length%8
|
||||
l = my_string_length % n
|
||||
if ((n-8) <= l <= (n-2)):
|
||||
if (nbr_bits_filled == 0):
|
||||
my_byte = 0
|
||||
else:
|
||||
my_byte=int(my_string[nr_bytes_filled*2:nr_bytes_filled*2+2],16)
|
||||
my_byte=(my_byte>>(8-nbr_bits_filled))
|
||||
my_byte=my_byte+2**(nbr_bits_filled)+2**7
|
||||
my_byte="%02X" % my_byte
|
||||
my_string=my_string[0:nr_bytes_filled*2]+my_byte
|
||||
else:
|
||||
if (nbr_bits_filled == 0):
|
||||
my_byte = 0
|
||||
else:
|
||||
my_byte=int(my_string[nr_bytes_filled*2:nr_bytes_filled*2+2],16)
|
||||
my_byte=(my_byte>>(8-nbr_bits_filled))
|
||||
my_byte=my_byte+2**(nbr_bits_filled)
|
||||
my_byte="%02X" % my_byte
|
||||
my_string=my_string[0:nr_bytes_filled*2]+my_byte
|
||||
while((8*len(my_string)//2)%n < (n-8)):
|
||||
my_string=my_string+'00'
|
||||
my_string = my_string+'80'
|
||||
|
||||
return my_string
|
||||
|
||||
def Keccak(self,M,r=1024,c=512,n=1024,verbose=False):
|
||||
"""Compute the Keccak[r,c,d] sponge function on message M
|
||||
|
||||
M: message pair (length in bits, string of hex characters ('9AFC...')
|
||||
r: bitrate in bits (defautl: 1024)
|
||||
c: capacity in bits (default: 576)
|
||||
n: length of output in bits (default: 1024),
|
||||
verbose: print the details of computations(default:False)
|
||||
"""
|
||||
|
||||
#Check the inputs
|
||||
if (r<0) or (r%8!=0):
|
||||
raise KeccakError.KeccakError('r must be a multiple of 8 in this implementation')
|
||||
if (n%8!=0):
|
||||
raise KeccakError.KeccakError('outputLength must be a multiple of 8')
|
||||
self.setB(r+c)
|
||||
|
||||
if verbose:
|
||||
print("Create a Keccak function with (r=%d, c=%d (i.e. w=%d))" % (r,c,(r+c)//25))
|
||||
|
||||
#Compute lane length (in bits)
|
||||
w=(r+c)//25
|
||||
|
||||
# Initialisation of state
|
||||
S=[[0,0,0,0,0],
|
||||
[0,0,0,0,0],
|
||||
[0,0,0,0,0],
|
||||
[0,0,0,0,0],
|
||||
[0,0,0,0,0]]
|
||||
|
||||
#Padding of messages
|
||||
P = self.pad10star1(M, r)
|
||||
|
||||
if verbose:
|
||||
print("String ready to be absorbed: %s (will be completed by %d x '00')" % (P, c//8))
|
||||
|
||||
#Absorbing phase
|
||||
for i in range((len(P)*8//2)//r):
|
||||
Pi=self.convertStrToTable(P[i*(2*r//8):(i+1)*(2*r//8)]+'00'*(c//8))
|
||||
|
||||
for y in range(5):
|
||||
for x in range(5):
|
||||
S[x][y] = S[x][y]^Pi[x][y]
|
||||
S = self.KeccakF(S, verbose)
|
||||
|
||||
if verbose:
|
||||
print("Value after absorption : %s" % (self.convertTableToStr(S)))
|
||||
|
||||
#Squeezing phase
|
||||
Z = ''
|
||||
outputLength = n
|
||||
while outputLength>0:
|
||||
string=self.convertTableToStr(S)
|
||||
Z = Z + string[:r*2//8]
|
||||
outputLength -= r
|
||||
if outputLength>0:
|
||||
S = self.KeccakF(S, verbose)
|
||||
|
||||
# NB: done by block of length r, could have to be cut if outputLength
|
||||
# is not a multiple of r
|
||||
|
||||
if verbose:
|
||||
print("Value after squeezing : %s" % (self.convertTableToStr(S)))
|
||||
|
||||
return Z[:2*n//8]
|
96
source-code/MiniNero/Keccak.txt
Normal file
96
source-code/MiniNero/Keccak.txt
Normal file
|
@ -0,0 +1,96 @@
|
|||
Content
|
||||
-------
|
||||
|
||||
List of files:
|
||||
- Keccak.py : the Keccak and KeccakError classes
|
||||
- demo_KeccakF.py : example of use of Keccak_f function on a 0-filled 5×5 matrix
|
||||
- demo_TestVectors.py : verification of Short/Long test vectors. The test vectors must be copied in the same location as the Python files
|
||||
|
||||
|
||||
Few words of explanation
|
||||
------------------------
|
||||
|
||||
The Keccak module is stateless. It takes your inputs, performs the computation and returns the result.
|
||||
|
||||
|
||||
Typical uses
|
||||
------------
|
||||
|
||||
1) Compute a hash using Keccak[r=1152, c=448] (224 bits of output) on '00112233445566778899AABBCCDDEEFF' (8*16bits=128 bits)
|
||||
|
||||
>>> import Keccak
|
||||
>>> myKeccak=Keccak.Keccak()
|
||||
>>> myKeccak.Keccak((128,'00112233445566778899AABBCCDDEEFF'),1152,448,224,True)
|
||||
|
||||
Create a Keccak function with (r=1152, c=448 (i.e. w=64))
|
||||
|
||||
String ready to be absorbed: 00112233445566778899AABBCCDDEEFF0100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080 (will be completed by 56 x '00')
|
||||
|
||||
Current value of state: Before first round
|
||||
['0x7766554433221100', '0xffeeddccbbaa9988', '0x1', '0x0', '0x0']
|
||||
['0x0', '0x0', '0x0', '0x0', '0x0']
|
||||
['0x0', '0x0', '0x0', '0x0', '0x0']
|
||||
['0x0', '0x0', '0x8000000000000000', '0x0', '0x0']
|
||||
['0x0', '0x0', '0x0', '0x0', '0x0']
|
||||
Current value of state: Satus end of round #1/24
|
||||
['0xdc77ae5456dd06dd', '0x2110377665444332', '0x7e6e5e6e7e6e5e6e', '0x8019e64c44470000', '0xba208b329807a91']
|
||||
['0x5669988982a11005', '0xa8864666600eeaaa', '0xe3304ddaaffcc99e', '0x42206eecc2a88664', '0xb77bbffbb77bbffb']
|
||||
['0x1111111110111117', '0x371dfb48ae8462d1', '0x224555108b45ff10', '0xddba8867553200ef', '0x4c3bf7a26e19d5e']
|
||||
['0xcb3621d00772611c', '0x13f17c0eb95b8bb5', '0x985510cc88440ddd', '0x2cd47cc54bb25aa3', '0x35c1100ff8899883']
|
||||
['0x5deab70448bfe251', '0x88a62388992232cc', '0x7788547722dd0032', '0x8804819c9915908c', '0xdd995510cc88440d']
|
||||
<...>
|
||||
Current value of state: Satus end of round #24/24
|
||||
['0xd89c919ce8078903', '0x92ff885abc7f0af9', '0xa0cdebf3ae8d1078', '0xde568902e183b3ce', '0xe3d1096857dc5b35']
|
||||
['0xc5f432f2633d3da0', '0x6a0094e2d96f8f35', '0xff92be8c648edc5a', '0xb87fe7012b84523a', '0xb8b7e144e77b3096']
|
||||
['0xf4832b396a99f318', '0xd8c10bcbaed2e2cf', '0x7d0f5ff34fc95a2e', '0x404281a6b9b3c2a2', '0xa758a863c74aecbe']
|
||||
['0x5b0f0672fcebc63e', '0xfca88e2204aa233e', '0xb62ef1ba33bc5a69', '0x795abef031f2d7dd', '0x7b7dc16e91fff6cd']
|
||||
['0x677823df6ebd0544', '0xd2a1fc63c7702e0e', '0x49b07e16adc62d95', '0x6bdb0b4f074e8b2b', '0xc27f39383b4799b5']
|
||||
|
||||
Value after absorption : 038907E89C919CD8F90A7FBC5A88FF9278108DAEF3EBCDA0CEB383E1028956DE355BDC576809D1E3A03D3D63F232F4C5358F6FD9E294006A5ADC8E648CBE92FF3A52842B01E77FB896307BE744E1B7B818F3996A392B83F4CFE2D2AECB0BC1D82E5AC94FF35F0F7DA2C2B3B9A6814240BEEC4AC763A858A73EC6EBFC72060F5B3E23AA04228EA8FC695ABC33BAF12EB6DDD7F231F0BE5A79CDF6FF916EC17D7B4405BD6EDF2378670E2E70C763FCA1D2952DC6AD167EB0492B8B4E074F0BDB6BB599473B38397FC2
|
||||
|
||||
Value after squeezing : 038907E89C919CD8F90A7FBC5A88FF9278108DAEF3EBCDA0CEB383E1028956DE355BDC576809D1E3A03D3D63F232F4C5358F6FD9E294006A5ADC8E648CBE92FF3A52842B01E77FB896307BE744E1B7B818F3996A392B83F4CFE2D2AECB0BC1D82E5AC94FF35F0F7DA2C2B3B9A6814240BEEC4AC763A858A73EC6EBFC72060F5B3E23AA04228EA8FC695ABC33BAF12EB6DDD7F231F0BE5A79CDF6FF916EC17D7B4405BD6EDF2378670E2E70C763FCA1D2952DC6AD167EB0492B8B4E074F0BDB6BB599473B38397FC2
|
||||
|
||||
'038907E89C919CD8F90A7FBC5A88FF9278108DAEF3EBCDA0CEB383E1'
|
||||
|
||||
|
||||
2) Computation of the Keccak-f function on an all-zero state
|
||||
|
||||
>>> import Keccak
|
||||
>>> A=[[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0]]
|
||||
>>> myKeccak=Keccak.Keccak(1600)
|
||||
>>> myKeccak.Keccakf(A, True)
|
||||
>>> myKeccak.printState(A,'Final result')
|
||||
|
||||
Current value of state: Before first round
|
||||
['0x0', '0x0', '0x0', '0x0', '0x0']
|
||||
['0x0', '0x0', '0x0', '0x0', '0x0']
|
||||
['0x0', '0x0', '0x0', '0x0', '0x0']
|
||||
['0x0', '0x0', '0x0', '0x0', '0x0']
|
||||
['0x0', '0x0', '0x0', '0x0', '0x0']
|
||||
Current value of state: Satus end of round #1/24
|
||||
['0x1L', '0x0L', '0x0L', '0x0L', '0x0L']
|
||||
['0x0L', '0x0L', '0x0L', '0x0L', '0x0L']
|
||||
['0x0L', '0x0L', '0x0L', '0x0L', '0x0L']
|
||||
['0x0L', '0x0L', '0x0L', '0x0L', '0x0L']
|
||||
['0x0L', '0x0L', '0x0L', '0x0L', '0x0L']
|
||||
<...>
|
||||
Current value of state: Satus end of round #24/24
|
||||
['0xf1258f7940e1dde7L', '0x84d5ccf933c0478aL', '0xd598261ea65aa9eeL', '0xbd1547306f80494dL', '0x8b284e056253d057L']
|
||||
['0xff97a42d7f8e6fd4L', '0x90fee5a0a44647c4L', '0x8c5bda0cd6192e76L', '0xad30a6f71b19059cL', '0x30935ab7d08ffc64L']
|
||||
['0xeb5aa93f2317d635L', '0xa9a6e6260d712103L', '0x81a57c16dbcf555fL', '0x43b831cd0347c826L', '0x1f22f1a11a5569fL']
|
||||
['0x5e5635a21d9ae61L', '0x64befef28cc970f2L', '0x613670957bc46611L', '0xb87c5a554fd00ecbL', '0x8c3ee88a1ccf32c8L']
|
||||
['0x940c7922ae3a2614L', '0x1841f924a2c509e4L', '0x16f53526e70465c2L', '0x75f644e97f30a13bL', '0xeaf1ff7b5ceca249L']
|
||||
|
||||
[[17376452488221285863L, 18417369716475457492L, 16959053435453822517L, 424854978622500449L, 10668034807192757780L], [9571781953733
|
||||
019530L, 10448040663659726788L, 12224711289652453635L, 7259519967065370866L, 1747952066141424100L], [15391093639620504046L, 101139
|
||||
17136857017974L, 9342009439668884831L, 7004910057750291985L, 1654286879329379778L], [13624874521033984333L, 12479658147685402012L,
|
||||
4879704952849025062L, 13293599522548616907L, 8500057116360352059L], [10027350355371872343L, 3500241080921619556L, 140226327413610
|
||||
143L, 10105770293752443592L, 16929593379567477321L]]
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
110
source-code/MiniNero/Knapsack.py
Normal file
110
source-code/MiniNero/Knapsack.py
Normal file
|
@ -0,0 +1,110 @@
|
|||
import Crypto.Random.random as rand
|
||||
import itertools
|
||||
import math #for log
|
||||
import sys
|
||||
def decomposition(i):
|
||||
#from stack exchange, don't think it's uniform
|
||||
while i > 0:
|
||||
n = rand.randint(1, i)
|
||||
yield n
|
||||
i -= n
|
||||
|
||||
def Decomposition(i):
|
||||
while True:
|
||||
l = list(decomposition(i))
|
||||
if len(set(l)) == len(l):
|
||||
return l
|
||||
|
||||
def decomposition2(n, s, d, k):
|
||||
#home-brewed, returns no duplicates, includes the number d
|
||||
s = s - 1
|
||||
n = n
|
||||
while True:
|
||||
a = [d]
|
||||
nn = n
|
||||
#a.append(d)
|
||||
for i in range(0, s):
|
||||
a.append(rand.randint(0, n))
|
||||
a.sort()
|
||||
#print("a", a)
|
||||
b = []
|
||||
c = []
|
||||
while len(a) > 0:
|
||||
t = a.pop()
|
||||
#print(t, a)
|
||||
if t >= d:
|
||||
b.append(nn - t)
|
||||
else:
|
||||
c.append(nn - t)
|
||||
nn = t
|
||||
c.append(nn)
|
||||
tot = b[:] + c[:]
|
||||
#print("b", b)
|
||||
if sum(set(tot)) == n and len(c) > int(k):
|
||||
return sorted(c), sorted(b)
|
||||
|
||||
def decomposition3(n, s, d, k):
|
||||
#a combination of both methods, designed to get some smaller values
|
||||
send, change = decomposition2(n, s, d, k)
|
||||
for i in send:
|
||||
if i > n / s:
|
||||
send.remove(i)
|
||||
send = send + list(Decomposition(i))
|
||||
for i in change:
|
||||
if i > n / (s - 1):
|
||||
change.remove(i)
|
||||
change = change + list(Decomposition(i))
|
||||
return send, change
|
||||
|
||||
def divv(l, m):
|
||||
return [a /float( m) for a in l]
|
||||
|
||||
def frexp10(x):
|
||||
exp = int(math.log10(x))
|
||||
return x / 10**exp, exp
|
||||
|
||||
|
||||
def decideAmounts(totalInputs, toSend, Partitions, k, fuzz):
|
||||
#fuzz is an optional amount to fuzz the transaction by
|
||||
#so if you start with a big obvious number like 2000, it might be fuzzed by up to "fuzz" amount
|
||||
fz = rand.randint(0, int(fuzz * 1000) ) / 1000.0
|
||||
toSend += fz
|
||||
|
||||
|
||||
g, ii =frexp10(totalInputs)
|
||||
ii = 10 ** (-1 * min(ii - 2, 0))
|
||||
print("ii", ii)
|
||||
M = 10 ** (int(math.log(2 ** Partitions) / math.log(10))) * ii
|
||||
#M = 10 ** M
|
||||
print("multiplier:", M)
|
||||
totalInputs = int(totalInputs * M)
|
||||
toSend = int(toSend * M)
|
||||
change = totalInputs - toSend
|
||||
send_amounts, change_amounts = decomposition3(totalInputs, Partitions, toSend, k)
|
||||
all_amounts = send_amounts[:] + change_amounts[:]
|
||||
rand.shuffle(all_amounts)
|
||||
print("")
|
||||
print("change amounts:", divv(change_amounts, M))
|
||||
print("send amounts:", divv(send_amounts, M))
|
||||
print("now from the following, how much is sent?")
|
||||
print("all amounts:", sorted(divv(all_amounts, M)))
|
||||
print("possible sent amounts:")
|
||||
amounts = []
|
||||
for L in range(0, len(all_amounts)+1):
|
||||
for subset in itertools.combinations(all_amounts, L):
|
||||
amounts.append(sum(subset))
|
||||
|
||||
print("number of possible sent amounts:")
|
||||
print(len(amounts))
|
||||
print("2^N:", 2 ** len(all_amounts))
|
||||
print("number of possible sent amounts duplicates removed:")
|
||||
print(len(list(set(amounts))))
|
||||
|
||||
|
||||
|
||||
if len(sys.argv) > 2:
|
||||
kk = 2
|
||||
parts = 7
|
||||
kk = rand.randint(1, int(parts / 4)) #how many sends to demand
|
||||
fuzz = 1
|
||||
decideAmounts(float(sys.argv[1]), float(sys.argv[2]), parts, kk, fuzz)
|
55
source-code/MiniNero/LLW_Sigs.py
Normal file
55
source-code/MiniNero/LLW_Sigs.py
Normal file
|
@ -0,0 +1,55 @@
|
|||
#see mrl_notes .. obv this is a work in progress
|
||||
import MiniNero
|
||||
import PaperWallet
|
||||
|
||||
def keyImage(x):
|
||||
HP = MiniNero.hashToPoint_ct(MiniNero.scalarmultBase(x))
|
||||
return MiniNero.scalarmultKey(HP, x)
|
||||
|
||||
def LLW_Sig(pk, xx, index ):
|
||||
n = len(pk)
|
||||
print("Generating LLW sig of length ", n)
|
||||
L = [None] * n
|
||||
R = [None] * n
|
||||
c= [None] * n
|
||||
s = [PaperWallet.skGen() for i in range(0, n)]
|
||||
HP = [MiniNero.hashToPoint_ct(i) for i in pk]
|
||||
pj = ''.join(pk)
|
||||
keyimage = keyImage(xx) #ok
|
||||
s[index] = MiniNero.mul_8(s[index])
|
||||
L[index] = MiniNero.scalarmultBase(s[index])
|
||||
R[index] = MiniNero.scalarmultKey(HP[index], s[index]) #aH
|
||||
j = (index + 1) % n
|
||||
c[j] = MiniNero.cn_fast_hash(pj+L[index]+R[index])
|
||||
while j != index:
|
||||
L[j] = MiniNero.addKeys(MiniNero.scalarmultBase(s[j]), MiniNero.scalarmultKey(pk[j], c[j])) #Lj = sG + cxG
|
||||
R[j] = MiniNero.addKeys(MiniNero.scalarmultKey(HP[j], s[j]), MiniNero.scalarmultKey(keyimage, c[j])) #Rj = sH + cxH
|
||||
cj = (j + 1) % n
|
||||
c[cj] = MiniNero.cn_fast_hash(pj + L[j] + R[j]) #c j+1 = H(pk + Lj + Rj
|
||||
j = cj #increment j
|
||||
s[index] = MiniNero.sc_mulsub_keys(s[index], c[index], xx) #si = a - c x so a = s + c x
|
||||
print("sigma = ", keyimage, c[0], s[:])
|
||||
return keyimage, c[0], s[:]
|
||||
|
||||
def LLW_Ver(pk, keyimage, c1, s):
|
||||
n= len(pk) #ok
|
||||
print("verifying LLW sig of length", n)
|
||||
L = [None]*n
|
||||
R = [None]*n
|
||||
c= [None]*(n+1)
|
||||
pj = ''.join(pk)
|
||||
HP = [MiniNero.hashToPoint_ct(i) for i in pk]
|
||||
c[0] = c1
|
||||
j = 0
|
||||
while j < n:
|
||||
L[j] = MiniNero.addKeys(MiniNero.scalarmultBase(s[j]), MiniNero.scalarmultKey(pk[j], c[j]))
|
||||
R[j] = MiniNero.addKeys(MiniNero.scalarmultKey(HP[j], s[j]), MiniNero.scalarmultKey(keyimage, c[j]))
|
||||
cj = j + 1
|
||||
c[cj] = MiniNero.cn_fast_hash(pj + L[j] + R[j])
|
||||
j = cj
|
||||
rv = (c[0] == c[n])
|
||||
print("sig verifies complete", rv)
|
||||
print("c", c)
|
||||
print("L", L)
|
||||
print("R", R)
|
||||
return rv
|
16384
source-code/MiniNero/LookupValues.txt
Normal file
16384
source-code/MiniNero/LookupValues.txt
Normal file
File diff suppressed because it is too large
Load diff
85
source-code/MiniNero/MLSAG.py
Normal file
85
source-code/MiniNero/MLSAG.py
Normal file
|
@ -0,0 +1,85 @@
|
|||
#see https://eprint.iacr.org/2015/1098.pdf
|
||||
import MiniNero
|
||||
import PaperWallet
|
||||
|
||||
def keyVector(rows):
|
||||
return [None] * rows
|
||||
|
||||
def keyImage(x, rows):
|
||||
HP = keyVector(rows)
|
||||
KeyImage = keyVector(rows)
|
||||
for i in range(0, rows):
|
||||
HP[i] = MiniNero.hashToPoint_cn(MiniNero.scalarmultBase(x[i]))
|
||||
KeyImage[i] = MiniNero.scalarmultKey(HP[i], x[i])
|
||||
return KeyImage
|
||||
|
||||
def MLSAG_Sign(pk, xx, index):
|
||||
rows = len(xx)
|
||||
cols = len(pk[0])
|
||||
print("Generating MLSAG sig of dimensions ",rows ,"x ", cols)
|
||||
L = [[None] * cols] #list of keyvectors? except it's indexed by cols... it's kind of internal actually
|
||||
R = [[None] * cols]
|
||||
s = [[PaperWallet.skGen() for i in range(0, cols)] ] #first index is rows, second is cols, wonder if I should switch that..
|
||||
HP = [[MiniNero.hashToPoint_cn(i) for i in pk[0]]]
|
||||
|
||||
pj = ''.join(pk[0])
|
||||
for i in range(1, rows):
|
||||
L.append([None] * cols)
|
||||
R.append([None] * cols)
|
||||
s.append([PaperWallet.skGen() for j in range(0, cols)])
|
||||
HP.append([MiniNero.hashToPoint_cn(j) for j in pk[i]])
|
||||
pj = pj + ''.join(pk[i])
|
||||
|
||||
c= [None] * cols #1-dimensional
|
||||
keyimage = keyImage(xx, rows) #ok
|
||||
for i in range(0, rows):
|
||||
L[i][index] = MiniNero.scalarmultBase(s[i][index]) #aG
|
||||
R[i][index] = MiniNero.scalarmultKey(HP[i][index], s[i][index]) #aH
|
||||
j = (index + 1) % cols
|
||||
tohash = pj
|
||||
for i in range(0, rows):
|
||||
tohash = tohash + L[i][index] + R[i][index]
|
||||
c[j] = MiniNero.cn_fast_hash(tohash)
|
||||
while j != index:
|
||||
tohash = pj
|
||||
for i in range(0, rows):
|
||||
L[i][j] = MiniNero.addKeys(MiniNero.scalarmultBase(s[i][j]), MiniNero.scalarmultKey(pk[i][j], c[j])) #Lj = sG + cxG
|
||||
R[i][j] = MiniNero.addKeys(MiniNero.scalarmultKey(HP[i][j], s[i][j]), MiniNero.scalarmultKey(keyimage[i], c[j])) #Rj = sH + cxH
|
||||
tohash = tohash + L[i][j] + R[i][j]
|
||||
j = (j + 1) % cols
|
||||
c[j] = MiniNero.cn_fast_hash(tohash)
|
||||
for i in range(0, rows):
|
||||
s[i][index] = MiniNero.sc_mulsub_keys(s[i][index], c[index], xx[i]) #si = a - c x so a = s + c x
|
||||
return keyimage, c[0], s
|
||||
|
||||
def MLSAG_Ver(pk, keyimage, c1, s ):
|
||||
rows = len(pk)
|
||||
cols = len(pk[0])
|
||||
print("verifying MLSAG sig of dimensions ",rows ,"x ", cols)
|
||||
L = [[None]*cols]
|
||||
R = [[None]*cols]
|
||||
pj = ''.join(pk[0])
|
||||
for i in range(1, rows):
|
||||
L.append([None] * cols)
|
||||
R.append([None] * cols)
|
||||
pj = pj + ''.join(pk[i])
|
||||
c= [None]*(cols+1) #you do an extra one, and then check the wrap around
|
||||
HP = [[MiniNero.hashToPoint_cn(i) for i in pk[0]]]
|
||||
for j in range(1, rows):
|
||||
HP.append([MiniNero.hashToPoint_cn(i) for i in pk[j]])
|
||||
c[0] = c1
|
||||
j = 0
|
||||
while j < cols:
|
||||
tohash = pj
|
||||
for i in range(0, rows):
|
||||
L[i][j] = MiniNero.addKeys(MiniNero.scalarmultBase(s[i][j]), MiniNero.scalarmultKey(pk[i][j], c[j]))
|
||||
R[i][j] = MiniNero.addKeys(MiniNero.scalarmultKey(HP[i][j], s[i][j]), MiniNero.scalarmultKey(keyimage[i], c[j]))
|
||||
tohash = tohash + L[i][j] + R[i][j]
|
||||
j = j + 1
|
||||
c[j] = MiniNero.cn_fast_hash(tohash)
|
||||
|
||||
rv = (c[0] == c[cols])
|
||||
print("c", c)
|
||||
print("sig verifies?", rv)
|
||||
|
||||
return rv
|
100
source-code/MiniNero/MLSAG2.py
Normal file
100
source-code/MiniNero/MLSAG2.py
Normal file
|
@ -0,0 +1,100 @@
|
|||
#see https://eprint.iacr.org/2015/1098.pdf
|
||||
#this one is same as MLSAG.py, I'm just experimenting with
|
||||
#how to best implement it..
|
||||
import MiniNero
|
||||
import PaperWallet
|
||||
|
||||
def keyVector(rows):
|
||||
return [None] * rows
|
||||
|
||||
def keyMatrix(rows, cols):
|
||||
#first index is columns (so slightly backward from math)
|
||||
rv = [None] * cols
|
||||
for i in range(0, cols):
|
||||
rv[i] = keyVector(rows)
|
||||
return rv
|
||||
|
||||
def hashKeyVector(v):
|
||||
return [MiniNero.hashToPoint_cn(vi) for vi in v]
|
||||
|
||||
def vScalarMultBase(v):
|
||||
return [MiniNero.scalarmultBase(a) for a in v]
|
||||
|
||||
def keyImageV(x):
|
||||
#takes as input a keyvector, returns the keyimage-vector
|
||||
return [MiniNero.scalarmultKey(MiniNero.hashToPoint_cn(MiniNero.scalarmultBase(xx)), xx) for xx in x]
|
||||
|
||||
def skvGen(n):
|
||||
return [PaperWallet.skGen() for i in range(0, n)]
|
||||
|
||||
def skmGen(r, c):
|
||||
rv = keyMatrix(r, c)
|
||||
for i in range(0, c):
|
||||
rv[i] = skvGen(r)
|
||||
return rv
|
||||
|
||||
def MLSAG_Gen(pk, xx, index ):
|
||||
rows = len(xx)
|
||||
cols = len(pk)
|
||||
print("Generating MG sig of size ", rows, "x", cols)
|
||||
print("index is:", index)
|
||||
print("checking if I can actually sign")
|
||||
print(pk[index])
|
||||
print([MiniNero.scalarmultBase(x) for x in xx])
|
||||
c= [None] * cols
|
||||
alpha = skvGen(rows)
|
||||
I = keyImageV(xx)
|
||||
L = keyMatrix(rows, cols)
|
||||
R = keyMatrix(rows, cols)
|
||||
s = keyMatrix(rows, cols)
|
||||
m = ''.join(pk[0])
|
||||
for i in range(1, cols):
|
||||
m = m + ''.join(pk[i])
|
||||
L[index] = [MiniNero.scalarmultBase(aa) for aa in alpha] #L = aG
|
||||
Hi = hashKeyVector(pk[index])
|
||||
R[index] = [MiniNero.scalarmultKey(Hi[ii], alpha[ii]) for ii in range(0, rows)] #R = aI
|
||||
oldi = index
|
||||
i = (index + 1) % cols
|
||||
c[i] = MiniNero.cn_fast_hash(m+''.join(L[oldi]) + ''.join(R[oldi]))
|
||||
|
||||
while i != index:
|
||||
s[i] = skvGen(rows)
|
||||
L[i] = [MiniNero.addKeys1(s[i][j], c[i], pk[i][j]) for j in range(0, rows)]
|
||||
|
||||
Hi = hashKeyVector(pk[i])
|
||||
R[i] = [MiniNero.addKeys2( s[i][j], Hi[j], c[i], I[j]) for j in range(0, rows)]
|
||||
oldi = i
|
||||
i = (i + 1) % cols
|
||||
c[i] = MiniNero.cn_fast_hash(m+''.join(L[oldi]) + ''.join(R[oldi]))
|
||||
print("L", L)
|
||||
print("R", R)
|
||||
s[index] = [MiniNero.sc_mulsub_keys(alpha[j], c[index], xx[j]) for j in range(0, rows)] #alpha - c * x
|
||||
return I, c[0], s
|
||||
|
||||
def MLSAG_Ver(pk, I, c0, s ):
|
||||
rows = len(pk[0])
|
||||
cols = len(pk)
|
||||
print("verifying MG sig of dimensions ",rows ,"x ", cols)
|
||||
c= [None] * (cols + 1)
|
||||
c[0] = c0
|
||||
L = keyMatrix(rows, cols)
|
||||
R = keyMatrix(rows, cols)
|
||||
m = ''.join(pk[0])
|
||||
for i in range(1, cols):
|
||||
m = m + ''.join(pk[i])
|
||||
i = 0
|
||||
while i < cols:
|
||||
L[i] = [MiniNero.addKeys1(s[i][j], c[i], pk[i][j]) for j in range(0, rows)]
|
||||
|
||||
Hi = hashKeyVector(pk[i])
|
||||
R[i] = [MiniNero.addKeys2( s[i][j], Hi[j], c[i], I[j]) for j in range(0, rows)]
|
||||
|
||||
oldi = i
|
||||
i = i + 1
|
||||
c[i] = MiniNero.cn_fast_hash(m+''.join(L[oldi]) + ''.join(R[oldi]))
|
||||
print("L", L)
|
||||
print("R", R)
|
||||
print("c", c)
|
||||
|
||||
return (c0 == c[cols])
|
||||
|
261
source-code/MiniNero/MiniNero.py
Normal file
261
source-code/MiniNero/MiniNero.py
Normal file
|
@ -0,0 +1,261 @@
|
|||
#"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)
|
1
source-code/MiniNero/MiniNeroPubKey.py
Normal file
1
source-code/MiniNero/MiniNeroPubKey.py
Normal file
|
@ -0,0 +1 @@
|
|||
MiniNeroPk = 'cd9db8fafbf2b99605cee870ada0dd64ae5a583a4414c3d5d34e8e8072d520b6'
|
50
source-code/MiniNero/MoneroProof.py
Normal file
50
source-code/MiniNero/MoneroProof.py
Normal file
|
@ -0,0 +1,50 @@
|
|||
# shen noether - mrl
|
||||
# this python script computes
|
||||
# a (Keccak) hash of your document
|
||||
# and then turns it into a monero address
|
||||
# for timestamping c.f. github.com/ShenNoether/btcProof
|
||||
#
|
||||
|
||||
import MiniNero #for creating monero address
|
||||
import sys #for getting command line arguments
|
||||
import binascii #for converting binary data
|
||||
import Keccak #for hash, we use this instead of sha256
|
||||
import ed25519
|
||||
import mnemonic
|
||||
|
||||
BLOCKSIZE = 2 **10
|
||||
l = 2**252 + 27742317777372353535851937790883648493
|
||||
def cnHashOfFile(filepath):
|
||||
#c.f. github.com/ShenNoether/btcProof sha256OfFile
|
||||
bin_data = open(filepath, 'rb').read()
|
||||
hex_data = binascii.hexlify(bin_data)
|
||||
print(hex_data)
|
||||
return MiniNero.cn_fast_hash(hex_data)
|
||||
|
||||
def moneroProofOfFile(fi):
|
||||
s = cnHashOfFile(fi)
|
||||
#s = MiniNero.sc_reduce_key(s) #if you are testing, insert
|
||||
#an s below this line
|
||||
|
||||
sk = MiniNero.sc_reduce_key(s)
|
||||
print("secret spend key:", sk)
|
||||
vk = MiniNero.getView(sk)
|
||||
print("secret view key:", vk)
|
||||
pk = MiniNero.publicFromSecret(sk)
|
||||
print("public spend key:", pk)
|
||||
pvk = MiniNero.publicFromSecret(vk)
|
||||
print("public view key:", pvk)
|
||||
wl = mnemonic.mn_encode(s)
|
||||
cks = MiniNero.electrumChecksum(wl)
|
||||
print(cks)
|
||||
print("mnemonic:", wl + " " + cks)
|
||||
|
||||
return MiniNero.encode_addr(MiniNero.netVersion(), pk, pvk)
|
||||
|
||||
if len(sys.argv) > 1:
|
||||
#print("address to send to :", moneroProofOfFile(sys.argv[1]))
|
||||
cnHashOfFile(sys.argv[1])
|
||||
else:
|
||||
print("provide filename as argument")
|
||||
print("example: MoneroProof.py Keccak.txt")
|
||||
|
19
source-code/MiniNero/MyMoneroImport.py
Normal file
19
source-code/MiniNero/MyMoneroImport.py
Normal file
|
@ -0,0 +1,19 @@
|
|||
#use at your own risk
|
||||
#Note, this is not quite working apparently,
|
||||
#apparently the viewkeys from the main client and mymonero
|
||||
#although, if they were derived consistently
|
||||
#(which seems reasonable) then it should work
|
||||
import MiniNero
|
||||
import mnemonic
|
||||
|
||||
def importMM(wordlist):
|
||||
print("for testing purposes only!")
|
||||
sk = MiniNero.recoverSK(wordlist)
|
||||
print("vk", vk)
|
||||
print("pvk", MiniNero.publicFromSecret(vk))
|
||||
key = mnemonic.mn_encode(sk)
|
||||
cks = MiniNero.electrumChecksum(key)
|
||||
print(key + " "+cks)
|
||||
|
||||
seed = raw_input("12 words?")
|
||||
print(importMM(seed))
|
97
source-code/MiniNero/Old_Ring_CT.py
Normal file
97
source-code/MiniNero/Old_Ring_CT.py
Normal file
|
@ -0,0 +1,97 @@
|
|||
#Work in progress obvously. This will implement the modified version of gmaxwells Confidential Transactions so that they work with ring signatures.
|
||||
#The math is outlined in mrl_notes v4 (v3 is same but sign of z should be - in an equation) which can be found in this repository.
|
||||
import MiniNero
|
||||
import LLW_Sigs
|
||||
import PaperWallet
|
||||
|
||||
def getHForCT():
|
||||
A = MiniNero.publicFromInt(1)
|
||||
return MiniNero.hashToPoint_ct(A)
|
||||
|
||||
def binary(n):
|
||||
b = []
|
||||
while n:
|
||||
b = [n & 1] + b
|
||||
n >>= 1
|
||||
return b or [0]
|
||||
|
||||
def out_commitments(values):
|
||||
#do this first
|
||||
n = len(values)
|
||||
values2 = [None] * n
|
||||
for i in range(0, n):
|
||||
values2[i] = [MiniNero.intToHex(j) for j in binary(MiniNero.hexToInt(values[i]))]
|
||||
#returns a list of commitments C_i = y_iG + value_i * H for outputs (these masks are created randomly)
|
||||
masks = [None] * n
|
||||
sumMasks = [None] * n
|
||||
for i in range(0, n):
|
||||
masks[i] = [PaperWallet.skGen() for jj in values2[i]] #binary decomposition for range proofs (could also use another base)
|
||||
sumMasks[i] = MiniNero.intToHex(sum([MiniNero.hexToInt(a) for a in masks[i]])) #sum is what actually goes into the ring..
|
||||
C = [None] * n
|
||||
for i in range(0, n):
|
||||
C[i] = MiniNero.addKeys(MiniNero.scalarmultBase(sumMasks[i]), MiniNero.scalarmultKey(H_ct, values[i]))
|
||||
return C, masks, sumMasks, values2
|
||||
|
||||
def in_commitments(input_value, sk, masks):
|
||||
#for now, assume there is one input, generalized after get that working
|
||||
sum_masks = MiniNero.intToHex(sum([MiniNero.hexToInt(a) for a in masks]))
|
||||
z = MiniNero.sc_sub_keys(sk, sum_masks) # z + sum of input mask values = sk
|
||||
C = MiniNero.addKeys(MiniNero.scalarmultBase(sk), MiniNero.scalarmultKey(H_ct, input_value)) #input_value = sum output values
|
||||
return C, z #z is the sk you need to sign for this commitment
|
||||
|
||||
def CT_ring_sig(pk, C_in, C_out, xz, index):
|
||||
print("Generating Ct ring sig")
|
||||
n = len(pk)
|
||||
pk2 = [None] * 2
|
||||
for i in range(0, n):
|
||||
pk2[i] = MiniNero.addKeys(pk[i], C_in)
|
||||
for j in C_out:
|
||||
pk2[i] = MiniNero.subKeys(pk2[i], j)
|
||||
print("check validity", pk2[index], MiniNero.scalarmultBase(xz))
|
||||
if pk2[index] != MiniNero.scalarmultBase(xz):
|
||||
print("stop lying, you don't know a key")
|
||||
exit()
|
||||
I, c0, s = LLW_Sigs.LLW_Sig(pk2, xz, index)
|
||||
print("Ct ring sig generated")
|
||||
return I, c0, s, pk2
|
||||
|
||||
def rangeProof(C_out_i, masks_i):
|
||||
n = len(masks_i)
|
||||
I_Proofs = [None] * n
|
||||
c0s = [None] * n
|
||||
ss = [None] * n
|
||||
C_is = [None] * n
|
||||
for i in range(0, n):
|
||||
C_i = MiniNero.addKeys(MiniNero.scalarmultBase(masks_i[i]), MiniNero.scalarmultKey(H_ct, C_out_i[i])) # masks_i * G + C_out_i * H
|
||||
C_i_prime = MiniNero.subKeys(C_i, H_ct) #C_i - H
|
||||
C_is[i] = [C_i_prime, C_i]
|
||||
print("generating LLWsig for range proof from Cis, masks, couts", C_is[i], masks_i[i], C_out_i[i])
|
||||
I_Proofs[i], c0s[i], ss[i] = LLW_Sigs.LLW_Sig(C_is[i], masks_i[i], MiniNero.hexToInt(C_out_i[i]))
|
||||
#ring sig on the above, with sk masks_i
|
||||
return I_Proofs, c0s, ss, C_is
|
||||
|
||||
H_ct = getHForCT()
|
||||
print("H", H_ct)
|
||||
|
||||
a = MiniNero.intToHex(49)
|
||||
b1 = MiniNero.intToHex(30)
|
||||
b2 = MiniNero.intToHex(20)
|
||||
x_priv = PaperWallet.skGen() #our private key
|
||||
x_commit = PaperWallet.skGen() # our private commitment key
|
||||
#x_commit = x_priv #do with x_priv = x_commit first... , then modify by adding another mask
|
||||
Pk1 = MiniNero.scalarmultBase(x_priv) #our public key
|
||||
Pk2 = MiniNero.scalarmultBase(PaperWallet.skGen()) #other sk (we don't know it
|
||||
print("xpriv, Pk1, Pk2", x_priv, Pk1, Pk2)
|
||||
|
||||
C_out, out_masks, sumMasks, values2 = out_commitments([b1, b2])
|
||||
|
||||
#testing rangeProofs
|
||||
print("testing range proofs")
|
||||
I_proofs, c0s, ss, Ci_s = rangeProof(values2[0], out_masks[0])
|
||||
print("Iproofs, c0s, ss", I_proofs, c0s, ss)
|
||||
|
||||
print("C_out, outmasks", C_out, sumMasks)
|
||||
C_in, z = in_commitments(a, x_commit, sumMasks)
|
||||
print("C_in, z", C_in, z)
|
||||
I, c0, s, PP = CT_ring_sig([Pk1, Pk2], C_in, C_out, MiniNero.sc_add_keys(x_priv,z), 0)
|
||||
LLW_Sigs.LLW_Ver(PP, I, c0, s)
|
60
source-code/MiniNero/PaperWallet.py
Normal file
60
source-code/MiniNero/PaperWallet.py
Normal file
|
@ -0,0 +1,60 @@
|
|||
#monero paper wallet test code, shen noether mrl
|
||||
#use at your own risk
|
||||
import Crypto.Random.random as rand
|
||||
import MiniNero
|
||||
import mnemonic
|
||||
l = 2**252 + 27742317777372353535851937790883648493
|
||||
|
||||
def skGen():
|
||||
return MiniNero.intToHex( 8 * (rand.getrandbits(64 * 8)) % l)
|
||||
|
||||
def pkGen():
|
||||
#The point of this is in testing functions where you need some arbitrary public key to test against
|
||||
return MiniNero.scalarmultBase(MiniNero.intToHex( 8 * (rand.getrandbits(64 * 8)) % l))
|
||||
|
||||
def skpkGen():
|
||||
#The point of this is in testing functions where you need some arbitrary public key to test against
|
||||
sk = skGen()
|
||||
return sk, MiniNero.scalarmultBase(sk)
|
||||
|
||||
|
||||
|
||||
def keysBoth():
|
||||
print("This is for private testing purposes only, use at your own risk!")
|
||||
print("this function will generate an address that is compatible both with the main client and with MyMonero")
|
||||
print("shen noether- mrl")
|
||||
print(" ")
|
||||
while True:
|
||||
print('.'),
|
||||
sk = skGen()
|
||||
|
||||
#s = "3c817618dcbfed122a64e592bb441d73300da9123686224a84e0eab1f075117e"; for testing
|
||||
|
||||
vk = MiniNero.getViewMM(sk) #note this is the sc_reduced version..
|
||||
worked = 1
|
||||
#uncomment below lines to make viewkey a point..
|
||||
try:
|
||||
MiniNero.toPoint(vk)
|
||||
except:
|
||||
worked =0
|
||||
print("bad vk")
|
||||
|
||||
if vk == MiniNero.sc_reduce_key(vk) and worked == 1: #already reduced
|
||||
break
|
||||
print("found key")
|
||||
print("secret spend key:", sk)
|
||||
print("secret view key:", vk)
|
||||
pk = MiniNero.publicFromSecret(sk)
|
||||
print("public spend key:", pk)
|
||||
pvk = MiniNero.publicFromSecret(vk)
|
||||
print("public view key:", pvk)
|
||||
addr = MiniNero.getAddrMM(sk)
|
||||
print("receiving address", addr)
|
||||
wl = mnemonic.mn_encode(sk)
|
||||
cks = MiniNero.electrumChecksum(wl)
|
||||
print(cks)
|
||||
print("mnemonic:", wl + " " + cks)
|
||||
return sk, vk, pk, pvk, addr, wl, cks
|
||||
|
||||
if __name__ == "__main__":
|
||||
keysBoth()
|
143
source-code/MiniNero/RCTUnitTests.py
Normal file
143
source-code/MiniNero/RCTUnitTests.py
Normal file
|
@ -0,0 +1,143 @@
|
|||
#!/usr/bin/python
|
||||
import sys #for arguments
|
||||
import MiniNero
|
||||
import mnemonic
|
||||
import PaperWallet
|
||||
import Ecdh
|
||||
import ASNL
|
||||
import MLSAG
|
||||
import MLSAG2
|
||||
import LLW_Sigs
|
||||
import RingCT
|
||||
import Crypto.Random.random as rand
|
||||
import Translator
|
||||
import binascii
|
||||
import RingCT2
|
||||
|
||||
#Schnorr NonLinkable true one and false one
|
||||
x, P1 = PaperWallet.skpkGen()
|
||||
P2 = PaperWallet.pkGen()
|
||||
P3 = PaperWallet.pkGen()
|
||||
|
||||
L1, s1, s2 = ASNL.GenSchnorrNonLinkable(x, P1, P2, 0)
|
||||
|
||||
print("Testing Schnorr Non-linkable!")
|
||||
print("This one should verify!")
|
||||
print(ASNL.VerSchnorrNonLinkable(P1, P2, L1, s1, s2))
|
||||
print("")
|
||||
print("This one should NOT verify!")
|
||||
print(ASNL.VerSchnorrNonLinkable(P1, P3, L1, s1, s2))
|
||||
|
||||
#ASNL true one, false one, C != sum Ci, and one out of the range..
|
||||
|
||||
print("\n\n\nTesting ASNL")
|
||||
N = 10
|
||||
x = [None] * N
|
||||
P1 = [None] * N
|
||||
P2 = [None] * N
|
||||
indi = [None] * N
|
||||
for j in range(0, N):
|
||||
indi[j] = rand.getrandbits(1)
|
||||
x[j] = PaperWallet.skGen()
|
||||
if indi[j] == 0:
|
||||
P1[j] = MiniNero.scalarmultBase(x[j])
|
||||
P2[j] = PaperWallet.pkGen()
|
||||
else:
|
||||
P2[j] = MiniNero.scalarmultBase(x[j])
|
||||
P1[j] = PaperWallet.pkGen()
|
||||
L1, s2, s = ASNL.GenASNL(x, P1, P2, indi)
|
||||
#true one
|
||||
print("This one should verify!")
|
||||
|
||||
ASNL.VerASNL(P1, P2, L1, s2, s)
|
||||
#false one
|
||||
indi[3] = (indi[3] + 1) % 2
|
||||
print("")
|
||||
print("This one should NOT verify!")
|
||||
L1, s2, s = ASNL.GenASNL(x, P1, P2, indi)
|
||||
ASNL.VerASNL(P1, P2, L1, s2, s)
|
||||
|
||||
#MG sig: true one
|
||||
print("\n\n\nTesting MG Sig: this one should verify!")
|
||||
N = 3 #cols
|
||||
R = 3 #rows
|
||||
x = [None] * N #just used to generate test public keys
|
||||
sk = [None]* R #vector of secret keys
|
||||
P = [None]*N #stores the public keys
|
||||
|
||||
ind = 2
|
||||
for j in range(0, N):
|
||||
x[j] = [None] * R
|
||||
P[j] = [None] * R
|
||||
for i in range(0, R):
|
||||
x[j][i] = PaperWallet.skGen()
|
||||
P[j][i] = MiniNero.scalarmultBase(x[j][i])
|
||||
for j in range(0, R):
|
||||
sk[j] = x[j][ind]
|
||||
|
||||
print("x", x)
|
||||
II, cc, ss = MLSAG.MLSAG_Sign(P, sk, ind)
|
||||
print("Sig verified?", MLSAG.MLSAG_Ver(P, II, cc, ss) )
|
||||
|
||||
|
||||
#MG sig: false one
|
||||
print("\n\nMG Sig: this one should NOT verify!")
|
||||
N = 3 #cols
|
||||
R = 3 #rows
|
||||
x = [None]*N #just used to generate test public keys
|
||||
sk = [None] * R #vector of secret keys
|
||||
P = [None]*N #stores the public keys
|
||||
ind = 2
|
||||
for j in range(0, N):
|
||||
x[j] = [None] * R
|
||||
P[j] = [None] * R
|
||||
for i in range(0, R):
|
||||
x[j][i] = PaperWallet.skGen()
|
||||
P[j][i] = MiniNero.scalarmultBase(x[j][i])
|
||||
|
||||
for j in range(0, R):
|
||||
sk[j] = x[j][ind]
|
||||
sk[2] = PaperWallet.skGen() #assume we don't know one of the secret keys
|
||||
print("x", x)
|
||||
II, cc, ss = MLSAG.MLSAG_Sign(P, sk, ind)
|
||||
print("Sig verified?", MLSAG.MLSAG_Ver(P, II, cc, ss) )
|
||||
|
||||
|
||||
#rct Sig: range proof true / false, sum Ci true / false, MG sig true / false,
|
||||
|
||||
|
||||
print("\n\n\nTesting Ring CT")
|
||||
|
||||
sc = []
|
||||
pc = []
|
||||
|
||||
sctmp, pctmp = RingCT2.ctskpkGen(60)
|
||||
sc.append(sctmp)
|
||||
pc.append(pctmp)
|
||||
|
||||
sctmp, pctmp = RingCT2.ctskpkGen(70)
|
||||
sc.append(sctmp)
|
||||
pc.append(pctmp)
|
||||
|
||||
#add output 500
|
||||
amounts = []
|
||||
amounts.append(5)
|
||||
destinations = []
|
||||
Sk, Pk = PaperWallet.skpkGen()
|
||||
destinations.append(Pk)
|
||||
|
||||
#add output for 12500
|
||||
amounts.append(125);
|
||||
Sk, Pk = PaperWallet.skpkGen()
|
||||
destinations.append(Pk)
|
||||
|
||||
s = RingCT2.genRct(sc, pc, destinations, amounts, 2)
|
||||
|
||||
print("attempting to verify")
|
||||
print(RingCT2.verRct(s))
|
||||
|
||||
#decode received amount
|
||||
print("decode amounts working?")
|
||||
print(RingCT2.decodeRct(s, Sk, 0))
|
||||
print("decode amounts working?")
|
||||
print(RingCT2.decodeRct(s, Sk, 1))
|
123
source-code/MiniNero/RingCT.py
Normal file
123
source-code/MiniNero/RingCT.py
Normal file
|
@ -0,0 +1,123 @@
|
|||
import MiniNero
|
||||
import MLSAG
|
||||
import LLW_Sigs
|
||||
import PaperWallet
|
||||
import AggregateSchnorr
|
||||
import Ecdh
|
||||
import Translator
|
||||
|
||||
def getHForCT():
|
||||
return "8b655970153799af2aeadc9ff1add0ea6c7251d54154cfa92c173a0dd39c1f94"
|
||||
A = MiniNero.publicFromInt(1)
|
||||
H = MiniNero.hashToPoint_ct(A)
|
||||
Translator.hexToC(H)
|
||||
print(H)
|
||||
return H
|
||||
|
||||
def getH2ForCT():
|
||||
A = MiniNero.publicFromInt(1)
|
||||
HPow2 = MiniNero.hashToPoint_ct(A)
|
||||
two = MiniNero.intToHex(2)
|
||||
H2 = [None] * 64
|
||||
for i in range(0, 64):
|
||||
Translator.hexToCComma(HPow2)
|
||||
H2[i] = HPow2
|
||||
HPow2 = MiniNero.scalarmultKey(HPow2, two)
|
||||
return H2
|
||||
|
||||
def binary(n, digits):
|
||||
b = [0] * digits
|
||||
i = 0
|
||||
while n:
|
||||
b[i] = n & 1
|
||||
i = i + 1
|
||||
n >>= 1
|
||||
return b
|
||||
|
||||
#unused? (Maybe I was just using for testing..)
|
||||
def dec(binArray):
|
||||
s = 0
|
||||
i = 0
|
||||
for a in binArray:
|
||||
s = s + a * 2 ** i
|
||||
i+= 1
|
||||
return s
|
||||
|
||||
def sumCi(Cis):
|
||||
CSum = MiniNero.identity()
|
||||
for i in Cis:
|
||||
CSum = MiniNero.addKeys(CSum, i)
|
||||
return CSum
|
||||
|
||||
def sumCiExp(Cis, Exp):
|
||||
#Cis is a vector
|
||||
#Exp is a vector
|
||||
CSum = MiniNero.identity()
|
||||
for i in range(0, len(Cis)):
|
||||
CSum = MiniNero.addKeys(CSum, MiniNero.scalarmultKey(Cis[i], MiniNero.intToHex(10 ** Exp[i])))
|
||||
return CSum
|
||||
|
||||
|
||||
def genRangeProof(b, digits):
|
||||
bb = binary(b, digits) #gives binary form of bb in "digits" binary digits
|
||||
print("b, b in binary", b, bb)
|
||||
ai = [None] * len(bb)
|
||||
Ci = [None] * len(bb)
|
||||
CiH = [None] * len(bb) #this is like Ci - 2^i H
|
||||
a = MiniNero.intToHex(0)
|
||||
ii = [None] * len(bb)
|
||||
indi = [None] * len(bb)
|
||||
for i in range(0, len(bb)):
|
||||
ai[i] = PaperWallet.skGen()
|
||||
a = MiniNero.addScalars(a, ai[i]) #creating the total mask since you have to pass this to receiver...
|
||||
Ci[i] = MiniNero.addKeys(MiniNero.scalarmultBase(ai[i]), MiniNero.scalarmultKey(getHForCT(), MiniNero.intToHex(bb[i] * 2 ** i)))
|
||||
CiH[i] = MiniNero.subKeys(Ci[i], MiniNero.scalarmultKey(getHForCT(), MiniNero.intToHex(2 ** i)))
|
||||
L1, s2, s = AggregateSchnorr.GenASNL(ai, Ci, CiH, bb)
|
||||
return sumCi(Ci), Ci, L1, s2, s, a
|
||||
|
||||
def verRangeProof(Ci, L1, s2, s):
|
||||
n = len(Ci) #note there will be some fixed length eventually so you can't just get the top digit
|
||||
CiH = [None] * n
|
||||
for i in range(0, n):
|
||||
CiH[i] = MiniNero.subKeys(Ci[i], MiniNero.scalarmultKey(getHForCT(), MiniNero.intToHex(2 ** i)))
|
||||
return AggregateSchnorr.VerASNL(Ci, CiH, L1, s2, s)
|
||||
|
||||
def ComputeReceivedAmount(senderEphemPk, receiverSK, maskedMask, maskedAmount, Ci, exponent):
|
||||
ss1, ss2 = ecdh.ecdhretrieve(receiverSK, senderEphemPk)
|
||||
mask = MiniNero.sc_sub_keys(maskedMask, ss1)
|
||||
CSum = sumCi(Ci)
|
||||
bH = MiniNero.subKeys(CSum, MiniNero.scalarmultBase(mask)) #bH = C - aG
|
||||
b = MiniNero.sc_sub_keys(maskedAmount, ss2)
|
||||
print("received amount:", 10 ** exponent * MiniNero.hexToInt(b))
|
||||
H = getHForCT()
|
||||
bHTent = MiniNero.scalarmultKey(H, b)
|
||||
print(bHTent,"=?", bH)
|
||||
if bHTent != bH:
|
||||
print("wrong amount sent!")
|
||||
return -1
|
||||
return 0
|
||||
|
||||
def genRCTSig(sk_x, sk_in, sk_out, Pk, CIn, COut, ExpIn, ExpOut, index):
|
||||
#sk_x is private keys of addresses (vector)
|
||||
#sk_in is masks of input commitments (vector)
|
||||
#sk_out is masks of output commitments (vector)
|
||||
#Pk is public key list (2d array)
|
||||
#CIn is input commitments (2d array)
|
||||
#COut is output commitments (vector)
|
||||
#ExpIn is exponents for the input commitments (2d array)
|
||||
#so each row of this is going to correspond to a column in the actual mlsag..
|
||||
#ExpOut is exponents for the output commitments
|
||||
#index is the secret index
|
||||
sk = sk_x[:]
|
||||
sk.append(MiniNero.sc_sub_keys(MiniNero.sc_add(sk_in, ExpIn[index]), MiniNero.sc_add(sk_out, ExpOut)))
|
||||
CRow = [None] * len(CIn) #commitments row of public keys Cin - Cout
|
||||
COutSum = sumCiExp(COut, ExpOut) #Cout1*10^i_1 + Cout2 * 10^{i_2}..
|
||||
tmp = MiniNero.identity()
|
||||
pk = [None] * (len(sk_x) + 1) #generalize later...
|
||||
pk[0] = Pk
|
||||
for i in range(0, len(CIn)):
|
||||
CRow[i] = MiniNero.subKeys(sumCiExp(CIn[i], ExpIn[i]), COutSum)
|
||||
pk[1] = CRow
|
||||
II, cc, ssVal = MLSAG.MLSAG_Sign(pk, sk, index)
|
||||
return pk, II, cc, ssVal
|
||||
|
BIN
source-code/MiniNero/RingCT0.1.hash
Normal file
BIN
source-code/MiniNero/RingCT0.1.hash
Normal file
Binary file not shown.
BIN
source-code/MiniNero/RingCT0.1_copy.pdf
Normal file
BIN
source-code/MiniNero/RingCT0.1_copy.pdf
Normal file
Binary file not shown.
5
source-code/MiniNero/RingCT0.2.hash
Normal file
5
source-code/MiniNero/RingCT0.2.hash
Normal file
|
@ -0,0 +1,5 @@
|
|||
724
|
||||
0
|
||||
('checksum', '`\xb1w\xce')
|
||||
1FpHkeBrkjffXd37y7bwa7gBJDUnvSrkS1
|
||||
https://blockchain.info/address/1FpHkeBrkjffXd37y7bwa7gBJDUnvSrkS1
|
BIN
source-code/MiniNero/RingCT0.2_copy.pdf
Normal file
BIN
source-code/MiniNero/RingCT0.2_copy.pdf
Normal file
Binary file not shown.
6
source-code/MiniNero/RingCT0.3.hash
Normal file
6
source-code/MiniNero/RingCT0.3.hash
Normal file
|
@ -0,0 +1,6 @@
|
|||
943
|
||||
0
|
||||
('checksum', 'E\xc1Lg')
|
||||
1N8g2cVBnZvq7GrfvTrmWTqXwPQZhAghf4
|
||||
https://blockchain.info/address/1N8g2cVBnZvq7GrfvTrmWTqXwPQZhAghf4
|
||||
Created new window in existing browser session.
|
BIN
source-code/MiniNero/RingCT0.3.pdf
Normal file
BIN
source-code/MiniNero/RingCT0.3.pdf
Normal file
Binary file not shown.
5
source-code/MiniNero/RingCT0.4.hash
Normal file
5
source-code/MiniNero/RingCT0.4.hash
Normal file
|
@ -0,0 +1,5 @@
|
|||
811
|
||||
0
|
||||
('checksum', '\x9e\xb9\xce\xc4')
|
||||
12ioqmWrLT5rjH3eDcgra2Bog6AfXDd83u
|
||||
https://blockchain.info/address/12ioqmWrLT5rjH3eDcgra2Bog6AfXDd83u
|
BIN
source-code/MiniNero/RingCT0.4_copy.pdf
Normal file
BIN
source-code/MiniNero/RingCT0.4_copy.pdf
Normal file
Binary file not shown.
BIN
source-code/MiniNero/RingCT0.5_copy.pdf
Normal file
BIN
source-code/MiniNero/RingCT0.5_copy.pdf
Normal file
Binary file not shown.
331
source-code/MiniNero/RingCT2.py
Normal file
331
source-code/MiniNero/RingCT2.py
Normal file
|
@ -0,0 +1,331 @@
|
|||
import MiniNero
|
||||
import MLSAG2
|
||||
import PaperWallet
|
||||
import AggregateSchnorr
|
||||
import Ecdh
|
||||
import Crypto.Random.random as rand
|
||||
|
||||
#set 8 atoms, since python is super slow on my laptop - normally this is 64 (note these range sigs are going pretty fast in the c++ version)
|
||||
ATOMS = 8
|
||||
|
||||
#implementing some types
|
||||
class ctkey(object):
|
||||
__slots__ = ['dest', 'mask']
|
||||
|
||||
def ctkeyV(rows):
|
||||
return [ctkey() for i in range(0, rows)]
|
||||
|
||||
class ecdhTuple(object):
|
||||
__slots__ = ['mask', 'amount','senderPk']
|
||||
|
||||
class asnlSig(object):
|
||||
__slots__ = ['L1', 's2','s']
|
||||
|
||||
class mgSig(object):
|
||||
__slots__ = ['ss', 'cc','II']
|
||||
|
||||
class rangeSig(object):
|
||||
__slots__ = ['asig', 'Ci']
|
||||
|
||||
class rctSig(object):
|
||||
__slots__ = ['rangeSigs', 'MG', 'mixRing', 'ecdhInfo','outPk']
|
||||
|
||||
def ctskpkGen(amount):
|
||||
sk = ctkey()
|
||||
pk = ctkey()
|
||||
sk.dest, pk.dest = PaperWallet.skpkGen()
|
||||
sk.mask, pk.mask = PaperWallet.skpkGen()
|
||||
am = MiniNero.intToHex(amount)
|
||||
aH = MiniNero.scalarmultKey(getHForCT(), am)
|
||||
pk.mask = MiniNero.addKeys(pk.mask, aH)
|
||||
return sk, pk
|
||||
|
||||
def getHForCT():
|
||||
return "8b655970153799af2aeadc9ff1add0ea6c7251d54154cfa92c173a0dd39c1f94"
|
||||
A = MiniNero.publicFromInt(1)
|
||||
H = MiniNero.hashToPoint_ct(A)
|
||||
Translator.hexToC(H)
|
||||
print(H)
|
||||
return H
|
||||
|
||||
def getH2ForCT():
|
||||
A = MiniNero.publicFromInt(1)
|
||||
HPow2 = MiniNero.hashToPoint_ct(A)
|
||||
two = MiniNero.intToHex(2)
|
||||
H2 = [None] * ATOMS
|
||||
for i in range(0, ATOMS):
|
||||
#Translator.hexToCComma(HPow2)
|
||||
H2[i] = HPow2
|
||||
HPow2 = MiniNero.scalarmultKey(HPow2, two)
|
||||
return H2
|
||||
|
||||
def d2b(n, digits):
|
||||
b = [0] * digits
|
||||
i = 0
|
||||
while n:
|
||||
b[i] = n & 1
|
||||
i = i + 1
|
||||
n >>= 1
|
||||
return b
|
||||
|
||||
def b2d(binArray):
|
||||
s = 0
|
||||
i = 0
|
||||
for a in binArray:
|
||||
s = s + a * 2 ** i
|
||||
i+= 1
|
||||
return s
|
||||
|
||||
def sumCi(Cis):
|
||||
CSum = MiniNero.identity()
|
||||
for i in Cis:
|
||||
CSum = MiniNero.addKeys(CSum, i)
|
||||
return CSum
|
||||
|
||||
#proveRange and verRange
|
||||
#proveRange gives C, and mask such that \sumCi = C
|
||||
# c.f. http:#eprint.iacr.org/2015/1098 section 5.1
|
||||
# and Ci is a commitment to either 0 or 2^i, i=0,...,63
|
||||
# thus this proves that "amount" is in [0, 2^ATOMS]
|
||||
# mask is a such that C = aG + bH, and b = amount
|
||||
#verRange verifies that \sum Ci = C and that each Ci is a commitment to 0 or 2^i
|
||||
#"prove" returns a rangeSig (list) containing a list [L1, s2, s] and a key64 list [C0, C1, ..., C64] of keys, it also returns C = sum(Ci) and mask, which in the c++ version are returned by reference
|
||||
#inputs key C, key mask, number amount
|
||||
#"ver" returns true or false, and inputs a key, and a rangesig list "as"
|
||||
def proveRange(amount):
|
||||
bb = d2b(amount, ATOMS) #gives binary form of bb in "digits" binary digits
|
||||
print("amount, amount in binary", amount, bb)
|
||||
ai = [None] * len(bb)
|
||||
Ci = [None] * len(bb)
|
||||
CiH = [None] * len(bb) #this is like Ci - 2^i H
|
||||
H2 = getH2ForCT()
|
||||
a = MiniNero.sc_0()
|
||||
ii = [None] * len(bb)
|
||||
indi = [None] * len(bb)
|
||||
for i in range(0, ATOMS):
|
||||
ai[i] = PaperWallet.skGen()
|
||||
a = MiniNero.addScalars(a, ai[i]) #creating the total mask since you have to pass this to receiver...
|
||||
if bb[i] == 0:
|
||||
Ci[i] = MiniNero.scalarmultBase(ai[i])
|
||||
if bb[i] == 1:
|
||||
Ci[i] = MiniNero.addKeys(MiniNero.scalarmultBase(ai[i]), H2[i])
|
||||
CiH[i] = MiniNero.subKeys(Ci[i], H2[i])
|
||||
|
||||
A = asnlSig()
|
||||
A.L1, A.s2, A.s = AggregateSchnorr.GenASNL(ai, Ci, CiH, bb)
|
||||
|
||||
R = rangeSig()
|
||||
R.asig = A
|
||||
R.Ci = Ci
|
||||
|
||||
mask = a
|
||||
C = sumCi(Ci)
|
||||
return C, mask, R
|
||||
|
||||
def verRange(Ci, ags):
|
||||
n = ATOMS
|
||||
CiH = [None] * n
|
||||
H2 = getH2ForCT()
|
||||
for i in range(0, n):
|
||||
CiH[i] = MiniNero.subKeys(ags.Ci[i], H2[i])
|
||||
return AggregateSchnorr.VerASNL(ags.Ci, CiH, ags.asig.L1, ags.asig.s2, ags.asig.s)
|
||||
|
||||
#Ring-ct MG sigs
|
||||
#Prove:
|
||||
# c.f. http:#eprint.iacr.org/2015/1098 section 4. definition 10.
|
||||
# This does the MG sig on the "dest" part of the given key matrix, and
|
||||
# the last row is the sum of input commitments from that column - sum output commitments
|
||||
# this shows that sum inputs = sum outputs
|
||||
#Ver:
|
||||
# verifies the above sig is created corretly
|
||||
def proveRctMG(pubs, inSk, outSk, outPk, index):
|
||||
#pubs is a matrix of ctkeys [P, C]
|
||||
#inSk is the keyvector of [x, mask] secret keys
|
||||
#outMasks is a keyvector of masks for outputs
|
||||
#outPk is a list of output ctkeys [P, C]
|
||||
#index is secret index of where you are signing (integer)
|
||||
#returns a list (mgsig) [ss, cc, II] where ss is keymatrix, cc is key, II is keyVector of keyimages
|
||||
|
||||
#so we are calling MLSAG2.MLSAG_Gen from here, we need a keymatrix made from pubs
|
||||
#we also need a keyvector made from inSk
|
||||
rows = len(pubs[0])
|
||||
cols = len(pubs)
|
||||
print("rows in mg", rows)
|
||||
print("cols in mg", cols)
|
||||
M = MLSAG2.keyMatrix(rows + 1, cols) #just a simple way to initialize a keymatrix, doesn't need to be random..
|
||||
sk = MLSAG2.keyVector(rows + 1)
|
||||
|
||||
for j in range(0, cols):
|
||||
M[j][rows] = MiniNero.identity()
|
||||
sk[rows] = MiniNero.sc_0()
|
||||
for i in range(0, rows):
|
||||
sk[i] = inSk[i].dest #get the destination part
|
||||
sk[rows] = MiniNero.sc_add_keys(sk[rows], inSk[i].mask) #add commitment part
|
||||
for j in range(0, cols):
|
||||
M[j][i] = pubs[j][i].dest # get the destination part
|
||||
M[j][rows] = MiniNero.addKeys(M[j][rows], pubs[j][i].mask) #add commitment part
|
||||
#next need to subtract the commitment part of all outputs..
|
||||
for j in range(0, len(outSk)):
|
||||
sk[rows] = MiniNero.sc_sub_keys(sk[rows], outSk[j].mask)
|
||||
for i in range(0, len(outPk)):
|
||||
M[j][rows] = MiniNero.subKeys(M[j][rows], outPk[i].mask) # subtract commitment part
|
||||
MG = mgSig()
|
||||
MG.II, MG.cc, MG.ss = MLSAG2.MLSAG_Gen(M, sk, index)
|
||||
|
||||
return MG #mgSig
|
||||
|
||||
def verRctMG(MG, pubs, outPk):
|
||||
#mg is an mgsig (list [ss, cc, II] of keymatrix ss, keyvector II and key cc]
|
||||
#pubs is a matrix of ctkeys [P, C]
|
||||
#outPk is a list of output ctkeys [P, C] for the transaction
|
||||
#returns true or false
|
||||
rows = len(pubs[0])
|
||||
cols = len(pubs)
|
||||
M = MLSAG2.keyMatrix(rows + 1, cols) #just a simple way to initialize a keymatrix, doesn't need to be random..
|
||||
for j in range(0, cols):
|
||||
M[j][rows] = MiniNero.identity()
|
||||
for i in range(0, rows):
|
||||
for j in range(0, cols):
|
||||
M[j][i] = pubs[j][i].dest # get the destination part
|
||||
M[j][rows] = MiniNero.addKeys(M[j][rows], pubs[j][i].mask) #add commitment part
|
||||
#next need to subtract the commitment part of all outputs..
|
||||
for j in range(0, cols):
|
||||
for i in range(0, len(outPk)):
|
||||
M[j][rows] = MiniNero.subKeys(M[j][rows], outPk[i].mask) # subtract commitment part
|
||||
return MLSAG2.MLSAG_Ver(M, MG.II, MG.cc, MG.ss)
|
||||
|
||||
#These functions get keys from blockchain
|
||||
#replace these when connecting blockchain
|
||||
#getKeyFromBlockchain grabs a key from the blockchain at "reference_index" to mix with
|
||||
#populateFromBlockchain creates a keymatrix with "mixin" columns and one of the columns is inPk
|
||||
# the return value are the key matrix, and the index where inPk was put (random).
|
||||
def getKeyFromBlockchain(reference_index):
|
||||
#returns a ctkey a (randomly)
|
||||
rv = ctkey()
|
||||
rv.dest = PaperWallet.pkGen()
|
||||
rv.mask = PaperWallet.pkGen()
|
||||
return rv
|
||||
|
||||
def populateFromBlockchain(inPk, mixin):
|
||||
#returns a ckKeyMatrix with your public input keys at "index" which is the second returned parameter.
|
||||
#the returned ctkeyMatrix will have number of columns = mixin
|
||||
rv = [None] * mixin
|
||||
index = rand.getrandbits(mixin - 1)
|
||||
blockchainsize = 10000
|
||||
for j in range(0, mixin):
|
||||
if j != index:
|
||||
rv[j] = [getKeyFromBlockchain(rand.getrandbits(blockchainsize)) for i in range(0, len(inPk))]
|
||||
else:
|
||||
rv[j] = inPk
|
||||
return rv, index
|
||||
|
||||
|
||||
|
||||
#Elliptic Curve Diffie Helman: encodes and decodes the amount b and mask a
|
||||
# where C= aG + bH
|
||||
def ecdhEncode(unmasked, receiverPk):
|
||||
rv = ecdhTuple()
|
||||
#compute shared secret
|
||||
esk, rv.senderPk = PaperWallet.skpkGen()
|
||||
sharedSec1 = MiniNero.cn_fast_hash(MiniNero.scalarmultKey(receiverPk, esk));
|
||||
sharedSec2 = MiniNero.cn_fast_hash(sharedSec1)
|
||||
#encode
|
||||
rv.mask = MiniNero.sc_add_keys(unmasked.mask, sharedSec1)
|
||||
rv.amount = MiniNero.sc_add_keys(unmasked.amount, sharedSec1)
|
||||
return rv
|
||||
|
||||
def ecdhDecode(masked, receiverSk):
|
||||
rv = ecdhTuple()
|
||||
#compute shared secret
|
||||
sharedSec1 = MiniNero.cn_fast_hash(MiniNero.scalarmultKey(masked.senderPk, receiverSk))
|
||||
sharedSec2 = MiniNero.cn_fast_hash(sharedSec1)
|
||||
#encode
|
||||
rv.mask = MiniNero.sc_sub_keys(masked.mask, sharedSec1)
|
||||
rv.amount = MiniNero.sc_sub_keys(masked.amount, sharedSec1)
|
||||
return rv
|
||||
|
||||
#RingCT protocol
|
||||
#genRct:
|
||||
# creates an rctSig with all data necessary to verify the rangeProofs and that the signer owns one of the
|
||||
# columns that are claimed as inputs, and that the sum of inputs = sum of outputs.
|
||||
# Also contains masked "amount" and "mask" so the receiver can see how much they received
|
||||
#verRct:
|
||||
# verifies that all signatures (rangeProogs, MG sig, sum inputs = outputs) are correct
|
||||
#decodeRct: (c.f. http:#eprint.iacr.org/2015/1098 section 5.1.1)
|
||||
# uses the attached ecdh info to find the amounts represented by each output commitment
|
||||
# must know the destination private key to find the correct amount, else will return a random number
|
||||
|
||||
def genRct(inSk, inPk, destinations, amounts, mixin):
|
||||
#inputs:
|
||||
#inSk is signers secret ctkeyvector
|
||||
#inPk is signers public ctkeyvector
|
||||
#destinations is a keyvector of output addresses
|
||||
#amounts is a list of amounts corresponding to above output addresses
|
||||
#mixin is an integer which is the desired mixin
|
||||
#outputs:
|
||||
#rctSig is a list [ rangesigs, MG, mixRing, ecdhInfo, outPk]
|
||||
#rangesigs is a list of one rangeproof for each output
|
||||
#MG is the mgsig [ss, cc, II]
|
||||
#mixRing is a ctkeyMatrix
|
||||
#ecdhInfo is a list of masks / amounts for each output
|
||||
#outPk is a vector of ctkeys (since we have computed the commitment for each amount)
|
||||
rv = rctSig()
|
||||
rv.outPk = ctkeyV( len(destinations))
|
||||
rv.rangeSigs = [None] * len(destinations)
|
||||
outSk = ctkeyV(len(destinations))
|
||||
rv.ecdhInfo = [None] * len(destinations)
|
||||
for i in range(0, len(destinations)):
|
||||
rv.ecdhInfo[i] = ecdhTuple()
|
||||
rv.outPk[i] = ctkey()
|
||||
rv.outPk[i].dest = destinations[i]
|
||||
rv.outPk[i].mask, outSk[i].mask, rv.rangeSigs[i] = proveRange(amounts[i])
|
||||
#do ecdhinfo encode / decode
|
||||
rv.ecdhInfo[i].mask = outSk[i].mask
|
||||
rv.ecdhInfo[i].amount = MiniNero.intToHex(amounts[i])
|
||||
rv.ecdhInfo[i] = ecdhEncode(rv.ecdhInfo[i], destinations[i])
|
||||
rv.mixRing, index = populateFromBlockchain(inPk, mixin)
|
||||
rv.MG = proveRctMG(rv.mixRing, inSk, outSk, rv.outPk, index)
|
||||
return rv
|
||||
|
||||
def verRct(rv):
|
||||
#inputs:
|
||||
#rv is a list [rangesigs, MG, mixRing, ecdhInfo, outPk]
|
||||
#rangesigs is a list of one rangeproof for each output
|
||||
#MG is the mgsig [ss, cc, II]
|
||||
#mixRing is a ctkeyMatrix
|
||||
#ecdhInfo is a list of masks / amounts for each output
|
||||
#outPk is a vector of ctkeys (since we have computed the commitment for each amount)
|
||||
#outputs:
|
||||
#true or false
|
||||
rvb = True
|
||||
tmp = True
|
||||
for i in range(0, len(rv.outPk)):
|
||||
tmp = verRange(rv.outPk[i].mask, rv.rangeSigs[i])
|
||||
print(tmp)
|
||||
rvb = rvb and tmp
|
||||
mgVerd = verRctMG(rv.MG, rv.mixRing, rv.outPk)
|
||||
print(mgVerd)
|
||||
return (rvb and mgVerd)
|
||||
|
||||
def decodeRct(rv, sk, i):
|
||||
#inputs:
|
||||
#rctSig is a list [ rangesigs, MG, mixRing, ecdhInfo, outPk]
|
||||
#rangesigs is a list of one rangeproof for each output
|
||||
#MG is the mgsig [ss, cc, II]
|
||||
#mixRing is a ctkeyMatrix
|
||||
#ecdhInfo is a list of masks / amounts for each output
|
||||
#outPk is a vector of ctkeys (since we have computed the commitment for each amount)
|
||||
#sk is the secret key of the receiver
|
||||
#i is the index of the receiver in the rctSig (in case of multiple destinations)
|
||||
#outputs:
|
||||
#the amount received
|
||||
decodedTuple = ecdhDecode(rv.ecdhInfo[i], sk)
|
||||
mask = decodedTuple.mask
|
||||
amount = decodedTuple.amount
|
||||
C = rv.outPk[i].mask
|
||||
H = getHForCT()
|
||||
Ctmp = MiniNero.addKeys(MiniNero.scalarmultBase(mask), MiniNero.scalarmultKey(H, amount))
|
||||
if (MiniNero.subKeys(C, Ctmp) != MiniNero.identity()):
|
||||
print("warning, amount decoded incorrectly, will be unable to spend")
|
||||
return MiniNero.hexToInt(amount)
|
||||
|
23
source-code/MiniNero/RingCTExampleOutput.txt
Normal file
23
source-code/MiniNero/RingCTExampleOutput.txt
Normal file
|
@ -0,0 +1,23 @@
|
|||
('H', '61fe7f0f5a607a33427d01dd1fded5ffa03fae2e9df9ebccf2e0a2f5bd77a204')
|
||||
inputs
|
||||
('b, b in binary', 10000, [0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1])
|
||||
Generating Aggregate Schnorr Non-linkable Ring Signature
|
||||
outputs
|
||||
('b, b in binary', 7000, [0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0])
|
||||
Generating Aggregate Schnorr Non-linkable Ring Signature
|
||||
('b, b in binary', 3000, [0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0])
|
||||
Generating Aggregate Schnorr Non-linkable Ring Signature
|
||||
verifying range proofs of outputs
|
||||
Verifying Aggregate Schnorr Non-linkable Ring Signature
|
||||
Verified
|
||||
Verifying Aggregate Schnorr Non-linkable Ring Signature
|
||||
Verified
|
||||
('Generating MLSAG sig of dimensions ', 2, 'x ', 2)
|
||||
('verifying MLSAG sig of dimensions ', 2, 'x ', 2)
|
||||
('c', ['80a3cfd06dd2862307cd75c2a1566f20cd743dbb0b9feb22d79dcbecb9023f42', 'a9b7342ba7bf2f102505ca19dab734fde638916c0a29f5b30e49833ab51393ea', '80a3cfd06dd2862307cd75c2a1566f20cd743dbb0b9feb22d79dcbecb9023f42'])
|
||||
('sig verifies?', True)
|
||||
('Sig verified?', True)
|
||||
Finding received amount corresponding to Cib
|
||||
('received ', 7000, 'a488ec68732fb551841c2c6dcc7ffac895d98ec7e9378275ed20ea12805fc18e')
|
||||
Finding received amount corresponding to Cic
|
||||
('received ', 3000, '1b46626858e130a0f3884c74c9fdeabc4d812c519103ea16a35a3f82a3d0ed6d')
|
8
source-code/MiniNero/RingMultisigv1.py
Normal file
8
source-code/MiniNero/RingMultisigv1.py
Normal file
|
@ -0,0 +1,8 @@
|
|||
import MiniNero
|
||||
import MLSAG2
|
||||
import PaperWallet
|
||||
import AggregateSchnorr
|
||||
import Ecdh
|
||||
import Crypto.Random.random as rand
|
||||
|
||||
#def Initiate(skIn, pkIn, pkOut,
|
17
source-code/MiniNero/SimpleBitmonerodTest.py
Normal file
17
source-code/MiniNero/SimpleBitmonerodTest.py
Normal file
|
@ -0,0 +1,17 @@
|
|||
import MiniNero
|
||||
import ed25519
|
||||
import binascii
|
||||
import PaperWallet
|
||||
import cherrypy
|
||||
import os
|
||||
import time
|
||||
import bitmonerod
|
||||
import SimpleXMR2
|
||||
|
||||
|
||||
xmr_addr = "44TVPcCSHebEQp4LnapPkhb2pondb2Ed7GJJLc6TkKwtSyumUnQ6QzkCCkojZycH2MRfLcujCM7QR1gdnRULRraV4UpB5n4"
|
||||
xmr_amount = "0.25"
|
||||
xmr_pid = "d8dd8f42cb13f26dbbf86d2d1da061628cdd17781be95e58a21c845465a2c7f6"
|
||||
|
||||
bitmonerod.send(xmr_addr, float(xmr_amount), xmr_pid, 3)
|
||||
|
35
source-code/MiniNero/SimpleGetTime.py
Normal file
35
source-code/MiniNero/SimpleGetTime.py
Normal file
|
@ -0,0 +1,35 @@
|
|||
import MiniNero
|
||||
import os
|
||||
import ed25519
|
||||
import binascii
|
||||
import PaperWallet
|
||||
|
||||
import json, hmac, hashlib, time, requests
|
||||
|
||||
|
||||
|
||||
def HexSigningPubKey(s):
|
||||
return binascii.hexlify(ed25519.publickey(ed25519.encodeint(MiniNero.hexToInt(s))))
|
||||
|
||||
def Signature(m, sk):
|
||||
sk2 = ed25519.encodeint(MiniNero.hexToInt(sk))
|
||||
pk = ed25519.publickey(sk2)
|
||||
return binascii.hexlify(ed25519.signature(m, sk2, pk))
|
||||
|
||||
def Verify(sig, m, pk):
|
||||
return ed25519.checkvalid(binascii.unhexlify(sig), m, binascii.unhexlify(pk))
|
||||
|
||||
#get saved access pubkey
|
||||
from MiniNeroPubKey import *
|
||||
pubkey = MiniNeroPk
|
||||
|
||||
#ip = raw_input('ip of your server\n')
|
||||
ip = '192.168.2.112:8080' #hopefully you save this in your app...
|
||||
ip = '192.168.137.235:8080'
|
||||
ip = raw_input('your ip?\n')
|
||||
ip = ip + ':8080'
|
||||
#sec = raw_input('you secret key?\n')
|
||||
timestamp = str(int(time.time()))
|
||||
r = requests.get("http://"+ip +'/api/mininero/')
|
||||
print r.text
|
||||
print("your time - server time is:", int(time.time()) - int(r.text))
|
57
source-code/MiniNero/SimpleRequester.py
Normal file
57
source-code/MiniNero/SimpleRequester.py
Normal file
|
@ -0,0 +1,57 @@
|
|||
import MiniNero
|
||||
import os
|
||||
import ed25519
|
||||
import binascii
|
||||
import PaperWallet
|
||||
|
||||
import json, hmac, hashlib, time, requests
|
||||
|
||||
|
||||
|
||||
def HexSigningPubKey(s):
|
||||
return binascii.hexlify(ed25519.publickey(ed25519.encodeint(MiniNero.hexToInt(s))))
|
||||
|
||||
def Signature(m, sk):
|
||||
sk2 = ed25519.encodeint(MiniNero.hexToInt(sk))
|
||||
pk = ed25519.publickey(sk2)
|
||||
return binascii.hexlify(ed25519.signature(m, sk2, pk))
|
||||
|
||||
def Verify(sig, m, pk):
|
||||
return ed25519.checkvalid(binascii.unhexlify(sig), m, binascii.unhexlify(pk))
|
||||
|
||||
def offset(ip):
|
||||
timestamp = str(int(time.time()))
|
||||
r = requests.get("http://"+ip +'/api/mininero/')
|
||||
print r.text
|
||||
print("your time - server time is:", int(time.time()) - int(r.text))
|
||||
return int(time.time()) - int(r.text)
|
||||
|
||||
#get saved access pubkey
|
||||
from MiniNeroPubKey import *
|
||||
pubkey = MiniNeroPk
|
||||
|
||||
#ip = raw_input('ip of your server\n')
|
||||
ip = '192.168.2.112:8080' #hopefully you save this in your app...
|
||||
ip = '192.168.137.235:8080'
|
||||
ip = raw_input('your ip?\n')
|
||||
ip = ip + ':8080'
|
||||
sec = raw_input('you secret key?\n')
|
||||
|
||||
timestamp = str(int(time.time()) - offset(ip))
|
||||
Type = "send"
|
||||
amount = "0.1"
|
||||
destination="1em2WCg9QKxRxbo6S3xKF2K4UDvdu6hMc" #just a random one, I think it's the hash of mininero.py
|
||||
|
||||
#this should be base 64...
|
||||
message = Type+amount.replace('.', 'd')+timestamp+destination
|
||||
sig = Signature(message, sec)
|
||||
tx = {
|
||||
'Type': Type,
|
||||
'timestamp' : timestamp,
|
||||
'destination': destination,
|
||||
'signature': sig,
|
||||
'amount': amount,
|
||||
}
|
||||
#print("curl -d Type='"+Type+"' -d signature='"+sig+"' -d timestamp='"+timestamp+"' -d destination='"+destination+"' -d amount='"+amount+"' -X POST '"+ip+"/api/mininero/'")
|
||||
r = requests.post("http://"+ip +'/api/mininero/', data=tx)
|
||||
print r.text
|
88
source-code/MiniNero/SimpleServer.py
Normal file
88
source-code/MiniNero/SimpleServer.py
Normal file
|
@ -0,0 +1,88 @@
|
|||
import MiniNero
|
||||
import ed25519
|
||||
import binascii
|
||||
import PaperWallet
|
||||
import cherrypy
|
||||
import os
|
||||
import time
|
||||
import bitmonerod
|
||||
import SimpleXMR2
|
||||
|
||||
def HexSigningPubKey(s):
|
||||
return binascii.hexlify(ed25519.publickey(ed25519.encodeint(MiniNero.hexToInt(s))))
|
||||
|
||||
def Signature(m, sk):
|
||||
#note this seems to return nicely sized version of the signature
|
||||
#contrast with, i.e. tweetnacl..
|
||||
sk2 = ed25519.encodeint(MiniNero.hexToInt(sk))
|
||||
pk = ed25519.publickey(sk2)
|
||||
return binascii.hexlify(ed25519.signature(m, sk2, pk))
|
||||
|
||||
def Verify(sig, m, pk):
|
||||
return ed25519.checkvalid(binascii.unhexlify(sig), m, binascii.unhexlify(pk))
|
||||
|
||||
class MiniNeroServer:
|
||||
|
||||
exposed = True
|
||||
|
||||
def GET(self, id=None):
|
||||
times = str(int(time.time()))
|
||||
return (times)
|
||||
|
||||
def POST(self, signature, Type, timestamp, amount=None, destination=None, pid=None, mixin=None):
|
||||
times= int(time.time())
|
||||
pubkey = MiniNeroPk
|
||||
message = Type+amount.replace('.', 'd')+timestamp+destination
|
||||
ver = Verify(signature.encode("utf8"), message.encode("utf8"), pubkey)
|
||||
if abs(times - int(timestamp)) > 30:
|
||||
ver = False
|
||||
return ('fail based on timestamp too old')
|
||||
|
||||
if Type == 'address':
|
||||
if (ver):
|
||||
print("do rpc call")
|
||||
#bitmonerod.myAddress()
|
||||
return ("Your Address is ")
|
||||
if Type == 'balance':
|
||||
if (ver):
|
||||
print("do rpc call")
|
||||
#bitmonerod.myAddress()
|
||||
return ('your balance is ??')
|
||||
if Type == 'send':
|
||||
if (ver) :
|
||||
#create xmr2 order async, return uuid
|
||||
uuid, xmr_amount, xmr_addr, xmr_pid = SimpleXMR2.btc2xmr(destination, amount)
|
||||
bitmonerod.send(xmr_addr, float(xmr_amount), xmr_pid, 3)
|
||||
return ('order uuid: '+uuid)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
#check if api pubkey is created, if not create it:
|
||||
if(os.path.isfile('MiniNeroPubKey.py')):
|
||||
from MiniNeroPubKey import *
|
||||
try:
|
||||
MiniNeroPk
|
||||
except NameError:
|
||||
MiniNeroSk= PaperWallet.skGen()
|
||||
MiniNeroPk= HexSigningPubKey(MiniNeroSk)
|
||||
print("Your new api secret key is:")
|
||||
print(MiniNeroSk)
|
||||
print("You should save this in a password manager")
|
||||
print("Your pubkey will be stored in MiniNeroPubKey.py")
|
||||
f = open('MiniNeroPubKey.py', 'w')
|
||||
f.write("MiniNeroPk = \'"+MiniNeroPk+"\'")
|
||||
print("Your MiniNeroServer PubKey is:")
|
||||
print(MiniNeroPk)
|
||||
|
||||
#Launch Cherry Server
|
||||
cherrypy.tree.mount(
|
||||
MiniNeroServer(), '/api/mininero',
|
||||
{'/':
|
||||
{'request.dispatch': cherrypy.dispatch.MethodDispatcher()}
|
||||
}
|
||||
)
|
||||
|
||||
cherrypy.server.socket_host = '0.0.0.0' #run on metal
|
||||
cherrypy.engine.start()
|
||||
cherrypy.engine.block()
|
16
source-code/MiniNero/SimpleSign.py
Normal file
16
source-code/MiniNero/SimpleSign.py
Normal file
|
@ -0,0 +1,16 @@
|
|||
import MiniNero
|
||||
import ed25519
|
||||
import binascii
|
||||
import PaperWallet
|
||||
import cherrypy
|
||||
import os
|
||||
import time
|
||||
import bitmonerod
|
||||
import SimpleXMR2
|
||||
import SimpleServer
|
||||
|
||||
message = "send0d000114545737471em2WCg9QKxRxbo6S3xKF2K4UDvdu6hMc"
|
||||
message = "send0d0114545747771em2WCg9QKxRxbo6S3xKF2K4UDvdu6hMc"
|
||||
sec = raw_input("sec?")
|
||||
print(SimpleServer.Signature(message, sec))
|
||||
|
3
source-code/MiniNero/SimpleWallet.py
Normal file
3
source-code/MiniNero/SimpleWallet.py
Normal file
|
@ -0,0 +1,3 @@
|
|||
import os
|
||||
sec = raw_input("wallet pass?")
|
||||
os.system(" ~/bitmonero/build/release/bin/simplewallet --wallet-file ~/wallet/testwallet1 --password "+sec+" --rpc-bind-port 18082")
|
48
source-code/MiniNero/SimpleXMR2.py
Normal file
48
source-code/MiniNero/SimpleXMR2.py
Normal file
|
@ -0,0 +1,48 @@
|
|||
import MiniNero
|
||||
import os
|
||||
import ed25519
|
||||
import binascii
|
||||
import PaperWallet
|
||||
|
||||
import json, hmac, hashlib, time, requests
|
||||
|
||||
#gets xmr address, xmr amount, and pid for xmr2 order
|
||||
#inputs are btc destination, and amount in btc
|
||||
#also will return the order id, so you can track the order
|
||||
def btc2xmr(dest, amount):
|
||||
#First create the order..
|
||||
url = 'https://xmr.to/api/v1/xmr2btc/order_create/'
|
||||
payload = {'btc_dest_address' : dest, 'btc_amount' : amount}
|
||||
headers = {'content-type': 'application/json'}
|
||||
r = requests.post(url, data=json.dumps(payload), headers=headers)
|
||||
data = json.loads(r.content)
|
||||
uuid = data['uuid']
|
||||
print("uuid=", uuid)
|
||||
|
||||
#wait a few seconds
|
||||
print("waiting a few seconds for order to be created")
|
||||
for i in range(0, 5):
|
||||
print(".")
|
||||
time.sleep(1)
|
||||
|
||||
#get amount, address, pid
|
||||
ipStatus = 'https://xmr.to/api/v1/xmr2btc/order_status_query/'
|
||||
dat = {
|
||||
'uuid' : uuid
|
||||
}
|
||||
r2 = requests.post(ipStatus, data=json.dumps(dat), headers = headers)
|
||||
#print(r2.text)
|
||||
data2 = json.loads(r2.content)
|
||||
xmr_amount = data2['xmr_required_amount']
|
||||
xmr_addr = data2['xmr_receiving_address']
|
||||
xmr_pid = data2['xmr_required_payment_id']
|
||||
print("send ", str(xmr_amount), " xmr to", xmr_addr, "with pid", xmr_pid)
|
||||
return uuid, xmr_amount, xmr_addr, xmr_pid
|
||||
|
||||
|
||||
|
||||
#dest = "1em2WCg9QKxRxbo6S3xKF2K4UDvdu6hMc" #your dest address here
|
||||
#amount = "0.1" #your amount here...
|
||||
|
||||
#uuid, xmr_amount, xmr_addr, xmr_pid = btc2xmr(dest, amount)
|
||||
|
22
source-code/MiniNero/TacoTimeExample.py
Normal file
22
source-code/MiniNero/TacoTimeExample.py
Normal file
|
@ -0,0 +1,22 @@
|
|||
q = 2**255 - 19
|
||||
l = 2**252 + 27742317777372353535851937790883648493
|
||||
import MiniNero
|
||||
import PaperWallet
|
||||
|
||||
a = 3655169758690262480859172686034352748701568204867449275194046101565641063400
|
||||
b = 2196281112309589493539510630657048805544016132079821556435431458072258858680
|
||||
c = 1680308020000391016811131033972168547846809685867129675902005632340344199616
|
||||
d = 3102886190919558838979092227453570755967767872654511102581747930112259050736
|
||||
e = a + b + c + d
|
||||
print(e, e % l)
|
||||
pk = MiniNero.publicFromSecret(MiniNero.intToHex(e))
|
||||
pka = MiniNero.publicFromSecret(MiniNero.intToHex(a))
|
||||
pkb = MiniNero.publicFromSecret(MiniNero.intToHex(b))
|
||||
pkc = MiniNero.publicFromSecret(MiniNero.intToHex(c))
|
||||
pkd = MiniNero.publicFromSecret(MiniNero.intToHex(d))
|
||||
A = MiniNero.addKeys(pka, pkb)
|
||||
B = MiniNero.addKeys(A, pkc)
|
||||
C = MiniNero.addKeys(B, pkd)
|
||||
print(C)
|
||||
print(pk)
|
||||
|
19
source-code/MiniNero/TactoTimeKeyChains.py
Normal file
19
source-code/MiniNero/TactoTimeKeyChains.py
Normal file
|
@ -0,0 +1,19 @@
|
|||
#you += hash(pubkey || index) to both the private scalar and public point
|
||||
#<tacotime> [02:35:38] so to get priv_i and pub_i
|
||||
#<tacotime> [02:36:06] priv_i = (priv + hash) mod N
|
||||
#<tacotime> [02:37:17] pub_i = (pub + scalarbasemult(hash))
|
||||
import MiniNero
|
||||
import PaperWallet
|
||||
|
||||
sk, vk, pk, pvk, addr, wl, cks = PaperWallet.keysBoth()
|
||||
|
||||
print("making keychain")
|
||||
for i in range(1, 600):
|
||||
index = MiniNero.intToHex(i)
|
||||
has = MiniNero.cn_fast_hash(pk + index)
|
||||
sk1 = MiniNero.sc_add_keys(sk, has)
|
||||
pk1 = MiniNero.addKeys(pk, MiniNero.scalarmultBase(has))
|
||||
pk1_check = MiniNero.publicFromSecret(sk1)
|
||||
print("Check", pk1== pk1_check)
|
||||
print(sk1)
|
||||
#print("i, sk, pk", i, sk1, pk1)
|
377
source-code/MiniNero/Test.py
Normal file
377
source-code/MiniNero/Test.py
Normal file
|
@ -0,0 +1,377 @@
|
|||
#!/usr/bin/python
|
||||
import sys #for arguments
|
||||
import MiniNero
|
||||
import mnemonic
|
||||
import PaperWallet
|
||||
import Ecdh
|
||||
import ASNL
|
||||
import MLSAG
|
||||
import MLSAG2
|
||||
import LLW_Sigs
|
||||
import RingCT
|
||||
import Crypto.Random.random as rand
|
||||
import Translator
|
||||
import binascii
|
||||
|
||||
|
||||
b = 256
|
||||
q = 2**255 - 19
|
||||
l = 2**252 + 27742317777372353535851937790883648493
|
||||
|
||||
|
||||
if len(sys.argv) >= 2:
|
||||
if sys.argv[1] == "id":
|
||||
Translator.hexToC(MiniNero.identity())
|
||||
|
||||
if sys.argv[1] == "smult":
|
||||
a= "87a61352d86f5cb0e9d227542b6b4870b9a327d082d15ea64e0494b9a896c1ac"
|
||||
aG = MiniNero.scalarmultBase(a)
|
||||
print(aG)
|
||||
print(MiniNero.scalarmultKey(aG, a))
|
||||
if sys.argv[1] == "add":
|
||||
#once it's good
|
||||
A = PaperWallet.pkGen()
|
||||
A = "75819750158570adc58ad6f932c3704661d6cd8eafd3a14818293a17790fbf71"
|
||||
B = PaperWallet.pkGen()
|
||||
B = "5fbc56c82c6e40596c673e301b63e100f08b97723ead425ed38f2b55c7a6454f"
|
||||
AB = MiniNero.addKeys(A, B)
|
||||
Translator.hexToC(A)
|
||||
Translator.hexToC(B)
|
||||
print(AB)
|
||||
AAB = MiniNero.addKeys(AB, A)
|
||||
print("AAB", AAB)
|
||||
print("hash")
|
||||
print(MiniNero.sc_reduce_key(MiniNero.cn_fast_hash(A)))
|
||||
aAbB = MiniNero.addKeys(MiniNero.scalarmultKey(A, A), MiniNero.scalarmultKey(B, B))
|
||||
print("testing addKeys3")
|
||||
print(aAbB)
|
||||
|
||||
if sys.argv[1] == "rs":
|
||||
#once it's good
|
||||
sk = MiniNero.randomScalar()
|
||||
if sys.argv[1] == "mn":
|
||||
#checking decoding mnemonic
|
||||
#seed = "code elope foiled knapsack abyss fishing wayside also joining auburn robot sonic inquest obnoxious pact gave smash itches fierce darted owed queen pool fruit auburn"
|
||||
seed = "down hairy tattoo ointment austere lush fossil symptoms vary sonic ultimate onslaught pioneer aerial kept linen unnoticed ahead weavers injury buzzer inquest justice nightly symptoms"
|
||||
seed = "unzip festival cease fences value anchor waking tomorrow ritual hookup guarded antics cease"
|
||||
sk = MiniNero.recoverSK(seed)
|
||||
print("sk", sk)
|
||||
print("addr my monero", MiniNero.getAddr(sk))
|
||||
if sys.argv[1] == "vk":
|
||||
#check making viewkey
|
||||
sk = "86c5616d91c7e7d96ec8220b15a5d441526ecc09f76347a40ab3a67373f8ba03"
|
||||
sk = "7eb3f0d43fbe9caee69215fbc360f49ce545d0dfae71390d531c9723cb25e904"
|
||||
vk = MiniNero.getView(sk)
|
||||
vk = "bb36fe9e852f617093a1634626268b61c5e5e065f503cbdd105877a0a54c3a02"
|
||||
print(vk)
|
||||
if sys.argv[1] == "addr":
|
||||
sk = "b6aafbbb9a6ee768bf292f7ebf977b6a31f51d4ecbf59186dd8367a3012f640f"
|
||||
sk = "7eb3f0d43fbe9caee69215fbc360f49ce545d0dfae71390d531c9723cb25e904"
|
||||
sk = "7c404922198b99c08020468c896f13df4f6e2ff1b5ab3c528e014cc9836ce80b"
|
||||
pk = MiniNero.publicFromSecret(sk)
|
||||
print("pk", pk)
|
||||
vk = "9e71628d6db09405a1267550b902299ed5cd004653e52d0a12129a21ab69900d"
|
||||
vk = "bb36fe9e852f617093a1634626268b61c5e5e065f503cbdd105877a0a54c3a02"
|
||||
vk = "7c404922198b99c08020468c896f13df4f6e2ff1b5ab3c528e014cc9836ce80b"
|
||||
vk = "c1c9e45989cc5fbfe828400886c50b4f58da40692d0f6ce6b3d483c4f1bf4b05"
|
||||
pvk = MiniNero.publicFromSecret(vk)
|
||||
print("pvk", pvk)
|
||||
vers = "12"
|
||||
print(MiniNero.encode_addr(vers, pk, pvk))
|
||||
if sys.argv[1] == "sp":
|
||||
a = "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"
|
||||
a = "c8d603858291b23c42695fec0b3db1b7fcb961e63d885a89c6ef70507a0b3204"
|
||||
a = "7c404922198b99c08020468c896f13df4f6e2ff1b5ab3c528e014cc9836ce80b"
|
||||
b = MiniNero.publicFromSecret(a)
|
||||
print(b)
|
||||
if sys.argv[1] == "crc":
|
||||
#test vectors
|
||||
t = "salads wipeout algebra knife awakened jewels uneven tender nearby worry ferry macro uneven"
|
||||
t = "sadness uneven boil mammal highway zinger enmity inkling coal essential teeming vibrate drunk drowning sulking unnoticed muffin swagger quick musical aquarium equip gather linen quick"
|
||||
t = "tyrant bailed lynx symptoms winter pirate yanks jagged dawn germs daily left hull pedantic puppy dilute dash adventure pigment nodes hockey yodel across richly adventure"
|
||||
t = "irony leopard emotion bovine veteran spout weird soccer adventure jeopardy negative rabbits otter boyfriend jackets boil richly apricot cake hydrogen luggage menu muffin sushi menu"
|
||||
t = "ivory koala decay whole segments cement natural pact omega asylum onslaught pinched jive thumbs nouns pimple baffles uptight okay itself unmask ruthless asked fossil pact"
|
||||
t = "oneself zodiac aimless october comb egotistic vastness otherwise nobody shelter amidst nexus costume dash rotate evenings zones hope aimless jury onslaught copy excess unzip october"
|
||||
t = "fifteen eels reorder sneeze fidget inbound onboard tufts lifestyle rounded lilac opened ascend fonts recipe copy android launching unquoted doctor lids reinvest syllabus five sneeze"
|
||||
t = "vinegar bubble bobsled southern godfather toolbox online hoax error pegs dice pamphlet knapsack erase lottery aside myth surfer exotic wipeout idled pelican cell tiger aside"
|
||||
t = "aquarium safety null huddle vastness ruined taken hamburger rhythm costume lion cupcake pouch auburn hashing vulture vitals pigment dangerous possible each salads segments fazed vulture"
|
||||
t = "aquarium safety null huddle vastness ruined taken hamburger rhythm costume lion cupcake pouch auburn hashing vulture vitals pigment dangerous possible each salads segments fazed vulture"
|
||||
|
||||
t = raw_input("13 or 25 words?")
|
||||
a = MiniNero.electrumChecksum(t)
|
||||
print(a)
|
||||
if sys.argv[1] == "1224":
|
||||
#sohuld turn 12 word key to 24
|
||||
print("tbd")
|
||||
sk = "536313cc0a88457e3d3e5aadda8d204af20e480416cc522ebd5a67df00ce2503"
|
||||
print(MiniNero.getAddr(sk))
|
||||
if sys.argv[1] == "seed":
|
||||
seed = "3c817618dcbfed122a64e592bb441d73300da9123686224a84e0eab1f075117e";
|
||||
a = MiniNero.hexToInt(seed)
|
||||
b = a // l
|
||||
print(b)
|
||||
if sys.argv[1] == "HCT":
|
||||
for i in [1, 12, 123, 1234, 12345, 123456]:
|
||||
A = MiniNero.publicFromInt(i)
|
||||
print(i, MiniNero.hashToPoint_ct(A))
|
||||
if sys.argv[1] == "RingCTSimple":
|
||||
#see below for ring ct with sliding exponents
|
||||
exponent = 9
|
||||
H_ct = RingCT.getHForCT()
|
||||
print("H", H_ct)
|
||||
sr, Pr = PaperWallet.skpkGen() #receivers private/ public
|
||||
se, pe, ss1, ss2 = Ecdh.ecdhGen(Pr) #compute shared secret ss
|
||||
digits = 32 #in practice it could will be 32 (from .0001 monero to ~400k monero) all other amounts can be represented by full 64 if necessary, otherwise you can use the sliding implementation of RingCT given below.
|
||||
print("inputs")
|
||||
a = 10000
|
||||
Cia, L1a, s2a, sa, ska = RingCT.genRangeProof(10000, digits)
|
||||
print("outputs")
|
||||
b = 7000
|
||||
Cib, L1b, s2b, sb, skb = RingCT.genRangeProof(7000, digits)
|
||||
c = 3000
|
||||
Cic, L1c, s2c, sc, skc = RingCT.genRangeProof(3000, digits)
|
||||
print("verifying range proofs of outputs")
|
||||
RingCT.verRangeProof(Cib, L1b, s2b, sb)
|
||||
RingCT.verRangeProof(Cic, L1c, s2c, sc)
|
||||
x, P1 = PaperWallet.skpkGen()
|
||||
P2 = PaperWallet.pkGen()
|
||||
C2 = PaperWallet.pkGen() #some random commitment grabbed from the blockchain
|
||||
ind = 0
|
||||
Ca = RingCT.sumCi(Cia)
|
||||
Cb = RingCT.sumCi(Cib)
|
||||
Cc = RingCT.sumCi(Cic)
|
||||
sk = [x, MiniNero.sc_sub_keys(ska, MiniNero.sc_add_keys(skb, skc))]
|
||||
pk = [[P1, P2], [MiniNero.subKeys(Ca, MiniNero.addKeys(Cb, Cc)), MiniNero.subKeys(C2, MiniNero.addKeys(Cb, Cc)) ] ]
|
||||
II, cc, ssVal = MLSAG.MLSAG_Sign(pk, sk, ind)
|
||||
print("Sig verified?", MLSAG.MLSAG_Ver(pk, II, cc, ssVal) )
|
||||
print("Finding received amount corresponding to Cib")
|
||||
RingCT.ComputeReceivedAmount(pe, sr, MiniNero.addScalars(ss1, skb),MiniNero.addScalars(ss2, MiniNero.intToHex(b)), Cib, 9)
|
||||
print("Finding received amount corresponding to Cic")
|
||||
RingCT.ComputeReceivedAmount(pe, sr, MiniNero.addScalars(ss1, skc), MiniNero.addScalars(ss2, MiniNero.intToHex(c)), Cic, 9)
|
||||
if sys.argv[1] == "MLSAG":
|
||||
#below is example usage. Uncomment each line for testing
|
||||
N = 3 #cols
|
||||
R = 3 #rows
|
||||
x = [[None]*N] #just used to generate test public keys
|
||||
sk = [None] * R #vector of secret keys
|
||||
P = [[None]*N] #stores the public keys
|
||||
|
||||
ind = 2
|
||||
for j in range(0, R):
|
||||
if j > 0:
|
||||
x.append([None]*N)
|
||||
P.append([None]*N)
|
||||
for i in range(0, N):
|
||||
x[j][i] = PaperWallet.skGen()
|
||||
P[j][i] = MiniNero.scalarmultBase(x[j][i])
|
||||
sk[j] = x[j][ind]
|
||||
print("x", x)
|
||||
II, cc, ss = MLSAG.MLSAG_Sign(P, sk, ind)
|
||||
print("Sig verified?", MLSAG.MLSAG_Ver(P, II, cc, ss) )
|
||||
if sys.argv[1] == "MLSAG2":
|
||||
#below is example usage. Uncomment each line for testing
|
||||
rows = 3 #cols
|
||||
cols = 3 #rows
|
||||
ind = 1
|
||||
|
||||
x = MLSAG2.skmGen(rows, cols)
|
||||
sk = x[ind]
|
||||
P = MLSAG2.keyMatrix(rows, cols)
|
||||
for i in range(0, cols):
|
||||
P[i] = MLSAG2.vScalarMultBase(x[i])
|
||||
|
||||
II, cc, ss = MLSAG2.MLSAG_Gen(P, sk, ind)
|
||||
print("I", II)
|
||||
print("c0", cc)
|
||||
print("s", ss)
|
||||
print("Sig verified?", MLSAG2.MLSAG_Ver(P, II, cc, ss) )
|
||||
if sys.argv[1]== "MLSAGc":
|
||||
P = [["4a199991d80915f99870b702fb6b3fa7b127853c4ed12ac2bb071534b9b5dee6","86e2c2ec0262c465749fdb1940de954d87d1e6b96beda093bc185f329e157c53","e9e83e74299bd3cdad4c87c6548dba859680000740660d1f783486d4cafef79f"],["78656dbba0fdfd14fc99b4da8b73c81314b9e65eeaa4eac510ca4dd28bae63a0","987f7b1b498e6ec25ad2ce304300388396a374721a24602b16905eeeb9a42fb0","b1a9c583747a8815fa7a80452efb4f93042dc64db08b3d2f7ac5016ea2b882eb"],["d3ef77673ee441b2ca3b1f9e7f628df9f6306d89d8c5155c3c6ee4c9f5f51408","5423f77332aa6a015ddc70a82e27fe52c68ab47e08b5c07d03641194de4ea1fb","ec564efa1511f73f91649d942fff0921763e4be37ee114036bd584f7a8fb9fd9"]]
|
||||
cc = "cd12f7147c6c01dee58be3338244b6f386806020e2d266a6aac68a4ab4bfb28b"
|
||||
II = ["352d19bc0ab8b45241dc23c27c4598791d4e23cd370198aea8eee8c7b5eb7b1d","8e2bca011d5b1fadde79dee44329545ca903b7bd299c4719e7593ad096e96141","5c6fad47d9ec734dab1139c40d4f11482e3d1f76585643520697a17f687a5962"]
|
||||
ss = [["e26f3115a50a2a25f1ec9582a4f4058f7f5c1b3f467cc38b0e882df7f93d6d0a","6b20f43b1f3c56ff3070b1a9a4612c808c35787a26243f5c046e283ff1b68f09","5091182154ad97d33c8210954b0570ccf95e8bedc5c6c193bde7d562bd9dc20a"],["ac297d01a6923e1c79d0fff82ecbfe0ae6ce515ef2b0dbc7e6b2f6542b99a404","c5371c10d7e7071ce3b3016db65bb29194e91a09cf428237fcf4037de74b5d03","a357b1453acd01fa101593994f60014f8ee7657921690bb4dfb0cfc41ef20802"],["a4a6ceb8454754ad32c987bcc56a03432155b47315f8805a3577a0470b0b330d","0ec6b71c2c6ba34d34bc3ea27e6813091fb3a90dc261a77fc9f46068bb1a3b09","41417b047353352e145fd3e65fe1e51e95081a64e9fda561060167e132c5e602"]]
|
||||
|
||||
rows = 3 #cols
|
||||
cols = c #rows
|
||||
print("I", II)
|
||||
print("c0", cc)
|
||||
print("s", ss)
|
||||
print("Sig verified?", MLSAG2.MLSAG_Ver(P, II, cc, ss) )
|
||||
|
||||
|
||||
|
||||
if sys.argv[1] == "LLW":
|
||||
#below is example usage
|
||||
N = 3
|
||||
x = [None]*N
|
||||
P = [None]*N
|
||||
HP = [None]*N
|
||||
for i in range(0, N):
|
||||
x[i] = PaperWallet.skGen()
|
||||
P[i] = MiniNero.scalarmultBase(x[i])
|
||||
print("x", x)
|
||||
pjoin = ''.join(P)
|
||||
ind = 0
|
||||
II, cc, ss = LLW_Sigs.LLW_Sig(P[:], x[ind], ind )
|
||||
print("Sig verified?", LLW_Sigs.LLW_Ver(P[:], II, cc, ss[:]) )
|
||||
if sys.argv[1] == "Ecdh":
|
||||
x1, pk1 = PaperWallet.skpkGen() #receiver secret key / public key
|
||||
ephem, ephempub, ss = Ecdh.ecdhGen(pk1) #ephempub is public key to create shared key
|
||||
ss2 = Ecdh.ecdhRetrieve(x1, ephempub)
|
||||
print "shared secret from sender: "
|
||||
print ss
|
||||
print "shared secret calculated by receiver: "
|
||||
print ss2
|
||||
if sys.argv[1] == "Schnorr":
|
||||
#test basic schnorr
|
||||
mes = "a very long test message asdflgkjnasdbfblkjnsdfblkjnsdfbklmnsdfbkl;jnsdfblkjsndfgblkjnserfvliksjndcmblkjxncvblikjhnwersfiodusjbsndlfigb7uvy3qo890eruiyghsblfduihjbo 9sruifjtyghbnqliownfghjbdlfkjvnb"
|
||||
sec = "7c404922198b99c08020468c896f13df4f6e2ff1b5ab3c528e014cc9836ce80b"
|
||||
pub = MiniNero.scalarmultBase(sec)
|
||||
r, c = ASNL.GenSchnorr(mes, sec, pub)
|
||||
print("sig verifies?",ASNL.VerSchnorr(mes, pub, r, c))
|
||||
print("sig verifies?",ASNL.VerSchnorr(mes, pub, r, PaperWallet.skGen()))
|
||||
if sys.argv[1] == "SchnorrNL":
|
||||
#test schnorr nonlinkable
|
||||
x, P2 = PaperWallet.skpkGen()
|
||||
P1 = PaperWallet.pkGen()
|
||||
L1, s1, s2 = ASNL.GenSchnorrNonLinkable(x, P1, P2, 1)
|
||||
ASNL.VerSchnorrNonLinkable(P1, P2, L1, s1, s2)
|
||||
if sys.argv[1] == "ASNL":
|
||||
#below tests ASNL code
|
||||
N = 10
|
||||
x = [None] * N
|
||||
P1 = [None] * N
|
||||
P2 = [None] * N
|
||||
indi = [None] * N
|
||||
for j in range(0, N):
|
||||
indi[j] = rand.getrandbits(1)
|
||||
x[j] = PaperWallet.skGen()
|
||||
if indi[j] == 0:
|
||||
P1[j] = MiniNero.scalarmultBase(x[j])
|
||||
P2[j] = PaperWallet.pkGen()
|
||||
else:
|
||||
P2[j] = MiniNero.scalarmultBase(x[j])
|
||||
P1[j] = PaperWallet.pkGen()
|
||||
L1, s2, s = ASNL.GenASNL(x, P1, P2, indi)
|
||||
ASNL.VerASNL(P1, P2, L1, s2, s)
|
||||
if sys.argv[1] == "brief":
|
||||
#shows compatibility with Ref10 (c.f. with sh runtest.sh in brief directory
|
||||
sec = "77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a"
|
||||
P = MiniNero.scalarmultBase(sec)
|
||||
print(P)
|
||||
if sys.argv[1] == "RingCT":
|
||||
#global stuff, i.e. inputs
|
||||
exponent = 9
|
||||
H_ct = RingCT.getHForCT()
|
||||
sr, Pr = PaperWallet.skpkGen() #receivers private/ public
|
||||
digits = 14 #in practice you can either specify it as part of the protocol, or allow a sliding value
|
||||
a = 10
|
||||
b = 7
|
||||
c = 3
|
||||
P2 = PaperWallet.pkGen()
|
||||
C2 = PaperWallet.pkGen() #some random commitment grabbed from the blockchain
|
||||
x, P1 = PaperWallet.skpkGen()
|
||||
ind = 0
|
||||
|
||||
#From the previous transaction
|
||||
print("inputs")
|
||||
Ca, Cia, L1a, s2a, sa, ska = RingCT.genRangeProof(a, digits)
|
||||
|
||||
#Actions performed by sender
|
||||
se, pe, ss1, ss2 = Ecdh.ecdhGen(Pr) #compute shared secret ss
|
||||
print("outputs")
|
||||
Cb, Cib, L1b, s2b, sb, skb = RingCT.genRangeProof(b, digits)
|
||||
Cc, Cic, L1c, s2c, sc, skc = RingCT.genRangeProof(c, digits)
|
||||
print("verifying range proofs of outputs")
|
||||
RingCT.verRangeProof(Cib, L1b, s2b, sb) #only need these for outputs (the input above is assumed in a previous transaction..
|
||||
RingCT.verRangeProof(Cic, L1c, s2c, sc)
|
||||
pk, II, cc, ssVal = RingCT.genRCTSig([x], [ska], [skb, skc], [P1, P2], [[Ca], [C2]], [Cb, Cc], [[exponent],[3]], [exponent, exponent], 0)
|
||||
|
||||
#Actions performed by the Miner
|
||||
print("Sig verified?", MLSAG.MLSAG_Ver(pk, II, cc, ssVal) )
|
||||
|
||||
#Actions performed by receiver(s)
|
||||
print("Finding received amount corresponding to Cib")
|
||||
RingCT.ComputeReceivedAmount(pe, sr, MiniNero.addScalars(ss1, skb),MiniNero.addScalars(ss2, MiniNero.intToHex(b)), Cib, 9)
|
||||
print("Finding received amount corresponding to Cic")
|
||||
RingCT.ComputeReceivedAmount(pe, sr, MiniNero.addScalars(ss1, skc), MiniNero.addScalars(ss2, MiniNero.intToHex(c)), Cic, 9)
|
||||
if sys.argv[1] == "ctest":
|
||||
sk, Pk= PaperWallet.skpkGen()
|
||||
print("running scalarmult base on ", sk, Pk)
|
||||
Translator.t_header()
|
||||
Translator.hexToC(sk, "sec")
|
||||
Translator.t_scalarmultBase("sec", "pub")
|
||||
Translator.t_footer()
|
||||
if sys.argv[1] == "chash":
|
||||
#pk = "ff33f4df1f8f44bfed3572134814f83c890495bd4714a0aaff0e0239c1acc927"
|
||||
sk, Pk= PaperWallet.skpkGen()
|
||||
#h = MiniNero.cn_fast_hash(pk)
|
||||
#print("pk", pk)
|
||||
#Translator.hexToC(pk, "pub")
|
||||
#print("hash", h)
|
||||
Translator.t_header()
|
||||
Translator.hexToC(sk, "sec")
|
||||
Translator.t_scalarmultBase("sec", "pub")
|
||||
Translator.t_cn_fast_hash("pub", "h")
|
||||
Translator.t_footer()
|
||||
if sys.argv[1] == "cSchnorr":
|
||||
prefix = "a very long test message asdflgkjnasdbfblkjnsdfblkjnsdfbklmnsdfbkl;jnsdfblkjsndfgblkjnserfvliksjndcmblkjxncvblikjhnwersfiodusjbsndlfigb7uvy3qo890eruiyghsblfduihjbo 9sruifjtyghbnqliownfghjbdlfkjvnb"
|
||||
hash_prefix = MiniNero.cn_fast_hash(binascii.hexlify(prefix))
|
||||
|
||||
h="247a9b60e8a31c18bfab9f6bf7b5079bc8c1955ea6726ea3f2bc38a3ec1bc658"
|
||||
pubb="ff33f4df1f8f44bfed3572134814f83c890495bd4714a0aaff0e0239c1acc927"
|
||||
sec="9d5f81503e5280cd8fdcd12c94bea81bdf4c2f87ebc0992ab177fba51db92c0a"
|
||||
r, c = ASNL.GenSchnorr(h,pubb, sec, PaperWallet.skGen())
|
||||
Translator.sigToC(r, c)
|
||||
print("verd?", ASNL.VerSchnorr(h, pubb, r, c))
|
||||
if sys.argv[1] == "data":
|
||||
skv = ["ae5934fe1e8065ec19afc80f2f06fc3f36730405a022813e2b18dc9da929da02", "2a9f99b0313157ba599bde727e04d6bfe87163f1d7dc93a352b1a648d7178205", "f0fb4504b06785caac17f4c554526685eed71d21b9b542f50c6e396b6152a403", "e5f7c934aa59c2ea21efeb4695d09bb95402d0dcc92d5bbec59eb1fc5912cf0f", "795f05824fb9e4a0808a523ecc9fefcb9e563e152d9b101224cb18169d3a4a05"]
|
||||
pkv = MLSAG2.vScalarMultBase(skv)
|
||||
print(pkv)
|
||||
if sys.argv[1] == "addKeys":
|
||||
a, A = ('13e467e9c0034e6878af5c801a81ee0543b1096b5ab01356b349cc3235cd1909', 'a50e5e751a9906f9ff086c734591d0ee87be6ca58fe7208b8e070e54d2eda0da')
|
||||
b, B = ('cd43ec6b80dd5ea2668e141fc6dc1191258b5eb58bf7dbef9e647aca3ba09707', '4f31e64eb9017ac02c6313294d0554d4532fbd6ffd15bc175422060867ab33f4')
|
||||
Translator.hexToC(a)
|
||||
Translator.hexToC(b)
|
||||
print(MiniNero.addKeys1(a, b, B))
|
||||
print(MiniNero.addKeys2(a, A, b, B))
|
||||
if sys.argv[1] == "bighash":
|
||||
from bighash import *
|
||||
print(MiniNero.cn_fast_hash(a))
|
||||
b = "d99e55005f1736e5d843dd11ce80e3e989f3eea52a42e14f6c541620568569ed"
|
||||
if sys.argv[1] == "ch":
|
||||
a = "18a5f3cf50ae2207d8ccd70179a13b4fc339d0cd6d9138c6d764f8e4cef8f006c87b1367fef3f02ed5ffd42a7ea212c2b8899af3af8f4b1e34139e1e390f3af1"
|
||||
print(MiniNero.cn_fast_hash(a))
|
||||
if sys.argv[1] == "fastbin":
|
||||
b = "0123456789abcdef"
|
||||
c = MiniNero.hexToInt(b)
|
||||
c = 6000
|
||||
print(b, c)
|
||||
Translator.hexToC(b)
|
||||
b = RingCT.binary(c, 64)
|
||||
b2 = ''.join([str(a) for a in b])
|
||||
print(b2)
|
||||
if sys.argv[1] == "HPow2":
|
||||
A = MiniNero.publicFromInt(1)
|
||||
HPow2 = MiniNero.hashToPoint_ct(A)
|
||||
two = MiniNero.intToHex(2)
|
||||
for j in range(1, 64):
|
||||
key = HPow2
|
||||
while len(key) < 64:
|
||||
key = key + "0"
|
||||
k2 = [key[i:i+2] for i in range(0, len(key), 2)]
|
||||
ar = "{0x"+(", 0x".join(k2))+"}, "
|
||||
print(ar)
|
||||
HPow2 = MiniNero.scalarmultKey(HPow2, two)
|
||||
print("};")
|
||||
if sys.argv[1] == "h2":
|
||||
A = MiniNero.publicFromInt(1)
|
||||
H = MiniNero.hashToPoint_ct(A)
|
||||
print(MiniNero.addKeys(H, H))
|
||||
print(MiniNero.scalarmultKey(H, MiniNero.intToHex(2)))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
54
source-code/MiniNero/Translator.py
Normal file
54
source-code/MiniNero/Translator.py
Normal file
|
@ -0,0 +1,54 @@
|
|||
#the goal with this is to automagically Convert MiniNero Code to ref10 C equivalent
|
||||
import MiniNero
|
||||
|
||||
def t_header():
|
||||
print("#include <stdlib.h>")
|
||||
print("#include <stdio.h>")
|
||||
print("#include <string.h>")
|
||||
print("#include <stdint.h>")
|
||||
print("#include \"crypto-ops.h\"")
|
||||
print("#include \"crypto.h\"\n\n")
|
||||
print("#include \"keccak.h\"")
|
||||
print("#define BYTES 64\n\n")
|
||||
print("int main(int argc, char *argv[]) {\n\n")
|
||||
|
||||
def t_footer():
|
||||
print("return 0;\n}\n\n")
|
||||
|
||||
def hexToC(key):
|
||||
while len(key) < 64:
|
||||
key = key + "0"
|
||||
k2 = [key[i:i+2] for i in range(0, len(key), 2)]
|
||||
ar = "{{0x"+(", 0x".join(k2))+"}}"
|
||||
print(ar)
|
||||
|
||||
def sigToC(r, c):
|
||||
r2 = [r[i:i+2] for i in range(0, len(r), 2)]
|
||||
ar = "{0x"+(", 0x".join(r2))+"}"
|
||||
c2 = [c[i:i+2] for i in range(0, len(c), 2)]
|
||||
ac = "{0x"+(", 0x".join(c2))+"}"
|
||||
print("signature sig = {"+ac+", "+ar+"};\n\n")
|
||||
|
||||
|
||||
def t_scalarmultBase(name_in, name_out):
|
||||
print("//Running scalarmult Base on "+name_in)
|
||||
print("ge_p3 point;")
|
||||
print("ge_scalarmult_base(&point, "+name_in+");")
|
||||
print("unsigned char "+name_out+"[32];")
|
||||
print("ge_p3_tobytes("+name_out+", &point);\n\n")
|
||||
|
||||
def t_cn_fast_hash(name_in, name_out):
|
||||
print("\n//running cn_fast_hash on "+name_in)
|
||||
print("uint8_t md2[32];")
|
||||
print("unsigned char "+name_out+"[32] = {0};")
|
||||
print("int j = 0;")
|
||||
print("keccak((uint8_t *) "+name_in+", 32, md2, 32);")
|
||||
print("for (j= 0 ; j < 32 ; j++) {")
|
||||
print("h[j] = (unsigned char)md2[j];")
|
||||
print("}")
|
||||
print("printf(\"\\nhash:\\n\");")
|
||||
print("for (j = 0 ; j < 32 ; j++) {")
|
||||
print("printf(\"%02x\", "+name_out+"[j]);")
|
||||
print("}")
|
||||
|
||||
|
179
source-code/MiniNero/bitmonerod.py
Normal file
179
source-code/MiniNero/bitmonerod.py
Normal file
|
@ -0,0 +1,179 @@
|
|||
#The following code is taken for the most part from
|
||||
#https://github.com/moneroexamples/python-json-rpc.git
|
||||
#I've slightly modified it to fit the cherry py server better
|
||||
|
||||
import requests
|
||||
import json
|
||||
import os
|
||||
import binascii
|
||||
|
||||
def send(destination_address, amount, payment_id, mixin):
|
||||
# simple wallet is running on the localhost and port of 18082
|
||||
url = "http://localhost:18082/json_rpc"
|
||||
# standard json header
|
||||
headers = {'content-type': 'application/json'}
|
||||
# cryptonote amount format is different then
|
||||
# that normally used by people.
|
||||
# thus the float amount must be changed to
|
||||
# something that cryptonote understands
|
||||
int_amount = int(get_amount(amount))
|
||||
|
||||
# just to make sure that amount->coversion->back
|
||||
# gives the same amount as in the initial number
|
||||
assert amount == float(get_money(str(int_amount))), "Amount conversion failed"
|
||||
|
||||
|
||||
# send specified xmr amount to the given destination_address
|
||||
recipents = [{"address": destination_address,
|
||||
"amount": int_amount}]
|
||||
|
||||
# simplewallet' procedure/method to call
|
||||
rpc_input = {
|
||||
"method": "transfer",
|
||||
"params": {"destinations": recipents,
|
||||
"mixin": mixin,
|
||||
"payment_id" : payment_id}
|
||||
}
|
||||
|
||||
# add standard rpc values
|
||||
rpc_input.update({"jsonrpc": "2.0", "id": "0"})
|
||||
|
||||
# execute the rpc request
|
||||
response = requests.post(
|
||||
url,
|
||||
data=json.dumps(rpc_input),
|
||||
headers=headers)
|
||||
|
||||
# print the payment_id
|
||||
print("#payment_id: ", payment_id)
|
||||
|
||||
# pretty print json output
|
||||
print(json.dumps(response.json(), indent=4))
|
||||
|
||||
|
||||
def get_amount(amount):
|
||||
"""encode amount (float number) to the cryptonote format. Hope its correct.
|
||||
|
||||
Based on C++ code:
|
||||
https://github.com/monero-project/bitmonero/blob/master/src/cryptonote_core/cryptonote_format_utils.cpp#L211
|
||||
"""
|
||||
|
||||
CRYPTONOTE_DISPLAY_DECIMAL_POINT = 12
|
||||
|
||||
str_amount = str(amount)
|
||||
|
||||
fraction_size = 0
|
||||
|
||||
if '.' in str_amount:
|
||||
|
||||
point_index = str_amount.index('.')
|
||||
|
||||
fraction_size = len(str_amount) - point_index - 1
|
||||
|
||||
while fraction_size < CRYPTONOTE_DISPLAY_DECIMAL_POINT and '0' == str_amount[-1]:
|
||||
print(44)
|
||||
str_amount = str_amount[:-1]
|
||||
fraction_size = fraction_size - 1
|
||||
|
||||
if CRYPTONOTE_DISPLAY_DECIMAL_POINT < fraction_size:
|
||||
return False
|
||||
|
||||
str_amount = str_amount[:point_index] + str_amount[point_index+1:]
|
||||
|
||||
if not str_amount:
|
||||
return False
|
||||
|
||||
if fraction_size < CRYPTONOTE_DISPLAY_DECIMAL_POINT:
|
||||
str_amount = str_amount + '0'*(CRYPTONOTE_DISPLAY_DECIMAL_POINT - fraction_size)
|
||||
|
||||
return str_amount
|
||||
|
||||
|
||||
def get_money(amount):
|
||||
"""decode cryptonote amount format to user friendly format. Hope its correct.
|
||||
|
||||
Based on C++ code:
|
||||
https://github.com/monero-project/bitmonero/blob/master/src/cryptonote_core/cryptonote_format_utils.cpp#L751
|
||||
"""
|
||||
|
||||
CRYPTONOTE_DISPLAY_DECIMAL_POINT = 12
|
||||
|
||||
s = amount
|
||||
|
||||
if len(s) < CRYPTONOTE_DISPLAY_DECIMAL_POINT + 1:
|
||||
# add some trailing zeros, if needed, to have constant width
|
||||
s = '0' * (CRYPTONOTE_DISPLAY_DECIMAL_POINT + 1 - len(s)) + s
|
||||
|
||||
idx = len(s) - CRYPTONOTE_DISPLAY_DECIMAL_POINT
|
||||
|
||||
s = s[0:idx] + "." + s[idx:]
|
||||
|
||||
return s
|
||||
|
||||
|
||||
def balance():
|
||||
|
||||
# simple wallet is running on the localhost and port of 18082
|
||||
url = "http://localhost:18082/json_rpc"
|
||||
|
||||
# standard json header
|
||||
headers = {'content-type': 'application/json'}
|
||||
|
||||
# simplewallet' procedure/method to call
|
||||
rpc_input = {
|
||||
"method": "getbalance"
|
||||
}
|
||||
|
||||
# add standard rpc values
|
||||
rpc_input.update({"jsonrpc": "2.0", "id": "0"})
|
||||
|
||||
# execute the rpc request
|
||||
response = requests.post(
|
||||
url,
|
||||
data=json.dumps(rpc_input),
|
||||
headers=headers)
|
||||
|
||||
# amounts in cryptonote are encoded in a way which is convenient
|
||||
# for a computer, not a user. Thus, its better need to recode them
|
||||
# to something user friendly, before displaying them.
|
||||
#
|
||||
# For examples:
|
||||
# 4760000000000 is 4.76
|
||||
# 80000000000 is 0.08
|
||||
#
|
||||
# In example 3 "Basic example 3: get incoming transfers" it is
|
||||
# shown how to convert cryptonote values to user friendly format.
|
||||
|
||||
# pretty print json output
|
||||
print(json.dumps(response.json(), indent=4))
|
||||
|
||||
def myAddress():
|
||||
# simple wallet is running on the localhost and port of 18082
|
||||
url = "http://localhost:18082/json_rpc"
|
||||
|
||||
# standard json header
|
||||
headers = {'content-type': 'application/json'}
|
||||
|
||||
"""return the wallet's address"""
|
||||
|
||||
rpc_input = {
|
||||
"method": "getaddress"
|
||||
}
|
||||
|
||||
response = do_rpc(url, headers, rpc_input)
|
||||
|
||||
return response.json()
|
||||
|
||||
def do_rpc(url,headers, rpc_input):
|
||||
"""does the rpc calls"""
|
||||
|
||||
# add standard rpc values
|
||||
rpc_input.update({"jsonrpc": "2.0", "id": "0"})
|
||||
|
||||
# execute the rpc requrest
|
||||
response = requests.post(
|
||||
url,
|
||||
data=json.dumps(rpc_input),
|
||||
headers=headers)
|
||||
|
||||
return response
|
17
source-code/MiniNero/brief/MakeClass.lua
Normal file
17
source-code/MiniNero/brief/MakeClass.lua
Normal file
|
@ -0,0 +1,17 @@
|
|||
--for quick conversion of the MiniNero python code to c++
|
||||
--
|
||||
if #arg > 0 then
|
||||
class = string.lower(arg[1]) --asdf
|
||||
object = arg[1] --Asdf
|
||||
deff = string.upper(arg[1]) --ASDF
|
||||
hfile = io.input("TemplateHead"):read("*a")
|
||||
cppfile = io.input("TemplateBody"):read("*a")
|
||||
hfile = string.gsub(hfile, "asdf", class)
|
||||
hfile = string.gsub(hfile, "Asdf", object)
|
||||
hfile = string.gsub(hfile, "ASDF", deff)
|
||||
cppfile = string.gsub(cppfile, "asdf", class)
|
||||
cppfile = string.gsub(cppfile, "Asdf", object)
|
||||
cppfile = string.gsub(cppfile, "ASDF", deff)
|
||||
io.output(object..".h"):write(hfile)
|
||||
io.output(object..".cpp"):write(cppfile)
|
||||
end
|
4
source-code/MiniNero/brief/runtest.bat
Normal file
4
source-code/MiniNero/brief/runtest.bat
Normal file
|
@ -0,0 +1,4 @@
|
|||
gtags.exe
|
||||
mingw32-make.exe clean
|
||||
mingw32-make.exe
|
||||
a.exe > .results
|
4
source-code/MiniNero/brief/runtest.sh
Normal file
4
source-code/MiniNero/brief/runtest.sh
Normal file
|
@ -0,0 +1,4 @@
|
|||
gtags.exe
|
||||
make clean
|
||||
make
|
||||
./a.exe
|
3
source-code/MiniNero/brief/runtest2.sh
Normal file
3
source-code/MiniNero/brief/runtest2.sh
Normal file
|
@ -0,0 +1,3 @@
|
|||
rm.exe a.exe
|
||||
g++ bits.cpp
|
||||
./a.exe
|
1
source-code/MiniNero/brief/tasks.bat
Normal file
1
source-code/MiniNero/brief/tasks.bat
Normal file
|
@ -0,0 +1 @@
|
|||
%1
|
132
source-code/MiniNero/btcProof.py
Normal file
132
source-code/MiniNero/btcProof.py
Normal file
|
@ -0,0 +1,132 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
#Some code to do the same thing as btcproof (since I think there may be an error in their file hashing?)
|
||||
#some of this code is taken from KeyUtils.py on a random github, so if you made that, then thanks
|
||||
import sys
|
||||
import ecdsa
|
||||
import ecdsa.der
|
||||
import ecdsa.util
|
||||
import hashlib
|
||||
import os
|
||||
import re
|
||||
import struct
|
||||
|
||||
import webbrowser #for qr code of address
|
||||
|
||||
b58 = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
|
||||
VERSION = 0x00
|
||||
|
||||
def base58encode(n):
|
||||
result = ''
|
||||
while n > 0:
|
||||
result = b58[n%58] + result
|
||||
n /= 58
|
||||
return result
|
||||
|
||||
def base256decode(s):
|
||||
result = 0
|
||||
for c in s:
|
||||
result = result * 256 + ord(c)
|
||||
return result
|
||||
|
||||
def countLeadingChars(s, ch):
|
||||
count = 0
|
||||
for c in s:
|
||||
if c == ch:
|
||||
count += 1
|
||||
else:
|
||||
break
|
||||
return count
|
||||
|
||||
# https://en.bitcoin.it/wiki/Base58Check_encoding
|
||||
def base58CheckEncode(version, payload):
|
||||
s = chr(version) + payload #concat version
|
||||
checksum = hashlib.sha256(hashlib.sha256(s).digest()).digest()[0:4]
|
||||
print("checksum", checksum)
|
||||
result = s + checksum #concat checksum to end
|
||||
leadingZeros = countLeadingChars(result, '\0')
|
||||
#return base58encode(base256decode(result))
|
||||
return '1' * leadingZeros + base58encode(base256decode(result))
|
||||
|
||||
def privateKeyToWif(key_hex):
|
||||
return base58CheckEncode(VERSION, key_hex.decode('hex'))
|
||||
|
||||
def privateKeyToPublicKey(s):
|
||||
sk = ecdsa.SigningKey.from_string(s.decode('hex'), curve=ecdsa.SECP256k1)
|
||||
vk = sk.verifying_key
|
||||
return ('\04' + sk.verifying_key.to_string()).encode('hex')
|
||||
|
||||
def pubKeyToAddr(s):
|
||||
ripemd160 = hashlib.new('ripemd160')
|
||||
ripemd160.update(hashlib.sha256(s.decode('hex')).digest())
|
||||
return base58CheckEncode(0, ripemd160.digest())
|
||||
|
||||
def keyToAddr(s):
|
||||
return pubKeyToAddr(privateKeyToPublicKey(s))
|
||||
|
||||
## below tto create digest of file, result should not vary with blocksize
|
||||
BLOCKSIZE = 2 **10
|
||||
|
||||
def sha256OfFile(filepath):
|
||||
sha = hashlib.sha256()
|
||||
with open(filepath, 'rb') as f:
|
||||
while True:
|
||||
block = f.read(BLOCKSIZE)
|
||||
if len(block) < BLOCKSIZE:
|
||||
print(len(block))
|
||||
block = block[:-1]
|
||||
if not block: break
|
||||
sha.update(block)
|
||||
return sha.hexdigest()
|
||||
|
||||
|
||||
##proofs, c.f.
|
||||
#https://www.btproof.com/technical.html
|
||||
# hash = SHA256(DATA) // or the supplied hash
|
||||
#vhash = CONCAT(VERSION_BYTE, RIPEMD160(hash)) // VERSION_BYTE is 0x00 for main net
|
||||
#address = BASE58(CONCAT(vhash, SHA256(SHA256(vhash))[0..3]))
|
||||
|
||||
def btcProofOfFile(fi):
|
||||
has = sha256OfFile(fi)
|
||||
ripemd160 = hashlib.new('ripemd160')
|
||||
ripemd160.update(has)
|
||||
address = base58CheckEncode(0, ripemd160.digest())
|
||||
return address
|
||||
|
||||
def btcProofOfString(strin):
|
||||
sha = hashlib.sha256()
|
||||
sha.update(strin)
|
||||
has = sha.digest()
|
||||
ripemd160 = hashlib.new('ripemd160')
|
||||
ripemd160.update(has)
|
||||
address = base58CheckEncode(0, ripemd160.digest())
|
||||
return address
|
||||
|
||||
|
||||
|
||||
# Generate a random private key
|
||||
#private_key = os.urandom(32).encode('hex')
|
||||
#address = base58CheckEncode(version, payload)
|
||||
|
||||
#this works (check sha test vectors at http://www.di-mgt.com.au/sha_testvectors.html) indicating I am hashing the file correctly
|
||||
#print(sha256OfFile("a.txt"))
|
||||
#print("should be: cdc76e5c 9914fb92 81a1c7e2 84d73e67 f1809a48 a497200e 046d39cc c7112cd0")
|
||||
|
||||
|
||||
#this works
|
||||
#print("address for abc")
|
||||
#print(btcProofOfString("abc"))
|
||||
#this does not agree with btcproof.com, indicating they are hashing file wrong
|
||||
#print("address for a.txt")
|
||||
#print(btcProofOfFile("a.txt"))
|
||||
|
||||
#print("bitcoin:"+btcProofOfFile(sys.argv[1])+"?amount=0.0001")
|
||||
a = btcProofOfFile(sys.argv[1])
|
||||
print(a)
|
||||
#bitcoin:1PZmMahjbfsTy6DsaRyfStzoWTPppWwDnZ?amount=0.1
|
||||
#url = "https://chart.googleapis.com/chart?chs=250x250&cht=qr&chl="+a
|
||||
url2 = "https://blockchain.info/address/"+a
|
||||
#print(url)
|
||||
print(url2)
|
||||
#webbrowser.open(url)
|
||||
webbrowser.open(url2)
|
129
source-code/MiniNero/ed25519.py
Normal file
129
source-code/MiniNero/ed25519.py
Normal file
|
@ -0,0 +1,129 @@
|
|||
#ed25519.cr.yp.to/python/ed25519.py
|
||||
import hashlib
|
||||
|
||||
b = 256
|
||||
q = 2**255 - 19
|
||||
l = 2**252 + 27742317777372353535851937790883648493
|
||||
|
||||
def H(m):
|
||||
return hashlib.sha512(m).digest()
|
||||
|
||||
def expmod(b,e,m):
|
||||
if e == 0: return 1
|
||||
t = expmod(b,e/2,m)**2 % m
|
||||
if e & 1: t = (t*b) % m
|
||||
return t
|
||||
|
||||
def inv(x):
|
||||
return expmod(x,q-2,q)
|
||||
|
||||
d = -121665 * inv(121666)
|
||||
I = expmod(2,(q-1)/4,q)
|
||||
|
||||
def xrecover(y):
|
||||
xx = (y*y-1) * inv(d*y*y+1)
|
||||
x = expmod(xx,(q+3)/8,q)
|
||||
if (x*x - xx) % q != 0: x = (x*I) % q
|
||||
if x % 2 != 0: x = q-x
|
||||
return x
|
||||
|
||||
By = 4 * inv(5)
|
||||
Bx = xrecover(By)
|
||||
B = [Bx % q,By % q]
|
||||
|
||||
def edwards(P,Q):
|
||||
x1 = P[0]
|
||||
y1 = P[1]
|
||||
x2 = Q[0]
|
||||
y2 = Q[1]
|
||||
x3 = (x1*y2+x2*y1) * inv(1+d*x1*x2*y1*y2)
|
||||
y3 = (y1*y2+x1*x2) * inv(1-d*x1*x2*y1*y2)
|
||||
return [x3 % q,y3 % q]
|
||||
|
||||
def edwards_Minus(P, Q): #added
|
||||
x1 = P[0]
|
||||
y1 = P[1]
|
||||
x2 = (-1 * Q[0]) % q
|
||||
y2 = Q[1]
|
||||
x3 = (x1*y2+x2*y1) * inv(1+d*x1*x2*y1*y2)
|
||||
y3 = (y1*y2+x1*x2) * inv(1-d*x1*x2*y1*y2)
|
||||
return [x3 % q,y3 % q]
|
||||
|
||||
|
||||
def scalarmult(P,e):
|
||||
if e == 0: return [0,1]
|
||||
Q = scalarmult(P,e/2)
|
||||
Q = edwards(Q,Q)
|
||||
if e & 1: Q = edwards(Q,P)
|
||||
return Q
|
||||
|
||||
#added scalarmultbase
|
||||
def scalarmultbase(e):
|
||||
if e == 0: return [0,1]
|
||||
Q = scalarmult(B,e/2)
|
||||
Q = edwards(Q,Q)
|
||||
if e & 1: Q = edwards(Q,B)
|
||||
return Q
|
||||
|
||||
def encodeint(y):
|
||||
bits = [(y >> i) & 1 for i in range(b)]
|
||||
return ''.join([chr(sum([bits[i * 8 + j] << j for j in range(8)])) for i in range(b/8)])
|
||||
|
||||
def encodepoint(P):
|
||||
x = P[0]
|
||||
y = P[1]
|
||||
bits = [(y >> i) & 1 for i in range(b - 1)] + [x & 1]
|
||||
return ''.join([chr(sum([bits[i * 8 + j] << j for j in range(8)])) for i in range(b/8)])
|
||||
|
||||
def bit(h,i):
|
||||
return (ord(h[i/8]) >> (i%8)) & 1
|
||||
|
||||
def publickey(sk):
|
||||
h = H(sk)
|
||||
a = 2**(b-2) + sum(2**i * bit(h,i) for i in range(3,b-2))
|
||||
A = scalarmult(B,a)
|
||||
return encodepoint(A)
|
||||
|
||||
def Hint(m):
|
||||
h = H(m)
|
||||
return sum(2**i * bit(h,i) for i in range(2*b))
|
||||
|
||||
def signature(m,sk,pk):
|
||||
h = H(sk)
|
||||
a = 2**(b-2) + sum(2**i * bit(h,i) for i in range(3,b-2))
|
||||
r = Hint(''.join([h[i] for i in range(b/8,b/4)]) + m)
|
||||
R = scalarmult(B,r)
|
||||
S = (r + Hint(encodepoint(R) + pk + m) * a) % l
|
||||
return encodepoint(R) + encodeint(S)
|
||||
|
||||
def isoncurve(P):
|
||||
x = P[0]
|
||||
y = P[1]
|
||||
return (-x*x + y*y - 1 - d*x*x*y*y) % q == 0
|
||||
|
||||
def decodeint(s):
|
||||
return sum(2**i * bit(s,i) for i in range(0,b))
|
||||
|
||||
def decodepoint(s):
|
||||
y = sum(2**i * bit(s,i) for i in range(0,b-1))
|
||||
x = xrecover(y)
|
||||
if x & 1 != bit(s,b-1): x = q-x
|
||||
P = [x,y]
|
||||
if not isoncurve(P): raise Exception("decoding point that is not on curve")
|
||||
return P
|
||||
|
||||
def checkvalid(s,m,pk):
|
||||
if len(s) != b/4:
|
||||
raise Exception("signature length is wrong")
|
||||
return False
|
||||
if len(pk) != b/8:
|
||||
raise Exception("public-key length is wrong")
|
||||
return False
|
||||
R = decodepoint(s[0:b/8])
|
||||
A = decodepoint(pk)
|
||||
S = decodeint(s[b/8:b/4])
|
||||
h = Hint(encodepoint(R) + pk + m)
|
||||
if scalarmult(B,S) != edwards(R,scalarmult(A,h)):
|
||||
raise Exception("signature does not pass verification")
|
||||
return False
|
||||
return True
|
1704
source-code/MiniNero/mnemonic.py
Normal file
1704
source-code/MiniNero/mnemonic.py
Normal file
File diff suppressed because it is too large
Load diff
6
source-code/MiniNero/mrl_notes0.4.hash
Normal file
6
source-code/MiniNero/mrl_notes0.4.hash
Normal file
|
@ -0,0 +1,6 @@
|
|||
> python btcProof.py mrl_notes0.4_copy.pdf
|
||||
779
|
||||
0
|
||||
('checksum', '\xd3DC~')
|
||||
15jVTLpbuU6cH39aqDxWWSb1UnKS2J7MbT
|
||||
https://blockchain.info/address/15jVTLpbuU6cH39aqDxWWSb1UnKS2J7MbT
|
BIN
source-code/MiniNero/mrl_notes0.4_copy.pdf
Normal file
BIN
source-code/MiniNero/mrl_notes0.4_copy.pdf
Normal file
Binary file not shown.
8
source-code/MiniNero/mrl_notes_v0.3.hash
Normal file
8
source-code/MiniNero/mrl_notes_v0.3.hash
Normal file
|
@ -0,0 +1,8 @@
|
|||
15
|
||||
0
|
||||
('checksum', '\xe2\xee\x11O')
|
||||
bitcoin:12axbjZYAasGTnC9ADsaQfmAjEBYpWf82z?amount=0.0001
|
||||
15
|
||||
0
|
||||
('checksum', '\xe2\xee\x11O')
|
||||
12axbjZYAasGTnC9ADsaQfmAjEBYpWf82z
|
BIN
source-code/MiniNero/mrl_notes_v0.3.pdf
Normal file
BIN
source-code/MiniNero/mrl_notes_v0.3.pdf
Normal file
Binary file not shown.
1
source-code/MiniNero/nOfNMultisig.py
Normal file
1
source-code/MiniNero/nOfNMultisig.py
Normal file
|
@ -0,0 +1 @@
|
|||
import MiniNero
|
708
source-code/MiniNero/oldMiniNero.py
Normal file
708
source-code/MiniNero/oldMiniNero.py
Normal file
|
@ -0,0 +1,708 @@
|
|||
########################################################################
|
||||
# MiniNero.py
|
||||
#A miniature, commented
|
||||
#port of CryptoNote and
|
||||
#Monero:
|
||||
# crypto.cpp / crypto-ops.cpp
|
||||
#
|
||||
#Using Bernstein's ed25519.py for the curve stuff.
|
||||
#The main point is to have a model what's happening in CryptoNote
|
||||
# -Shen.Noether
|
||||
#
|
||||
#Note: The ring image function seems
|
||||
# to take a lot of memory to run
|
||||
# it will throw strange errors if
|
||||
# your computer doesn't have
|
||||
# enough
|
||||
#Note2:
|
||||
# As of yet, slightly incompatible, although mathematically equivalent.
|
||||
# The discrepancies are some differences in packing and hashing.
|
||||
#
|
||||
# To the extent possible under law, the implementer has waived all copyright
|
||||
# and related or neighboring rights to the source code in this file.
|
||||
# http://creativecommons.org/publicdomain/zero/1.0/
|
||||
#
|
||||
#The parts of code from Bernstein(?)'s library possibly has it's own license
|
||||
# which you can dig up from http://cr.yp.to/djb.html
|
||||
########################################################################
|
||||
|
||||
|
||||
|
||||
import hashlib
|
||||
import struct
|
||||
import base64
|
||||
import binascii
|
||||
import sys
|
||||
from Crypto.Util import number
|
||||
import Crypto.Random.random as rand
|
||||
import Keccak
|
||||
from collections import namedtuple
|
||||
import copy
|
||||
|
||||
KEK=Keccak.Keccak(1600)
|
||||
CURVE_P = (2**255 - 19)
|
||||
b = 256
|
||||
q = 2**255 - 19
|
||||
l = 2**252 + 27742317777372353535851937790883648493
|
||||
BASEPOINT = "0900000000000000000000000000000000000000000000000000000000000000"
|
||||
|
||||
#####################################
|
||||
#Bernstein(?) Eddie Library in python
|
||||
#####################################
|
||||
|
||||
def H(m):
|
||||
return hashlib.sha512(m).digest()
|
||||
|
||||
def expmod(b,e,m):
|
||||
if e == 0: return 1
|
||||
t = expmod(b,e/2,m)**2 % m
|
||||
if e & 1: t = (t*b) % m
|
||||
return t
|
||||
|
||||
def inv(x):
|
||||
return expmod(x,q-2,q)
|
||||
|
||||
d = -121665 * inv(121666)
|
||||
I = expmod(2,(q-1)/4,q)
|
||||
|
||||
def xrecover(y):
|
||||
xx = (y*y-1) * inv(d*y*y+1)
|
||||
x = expmod(xx,(q+3)/8,q)
|
||||
if (x*x - xx) % q != 0: x = (x*I) % q
|
||||
if x % 2 != 0: x = q-x
|
||||
return x
|
||||
|
||||
By = 4 * inv(5)
|
||||
Bx = xrecover(By)
|
||||
B = [Bx % q,By % q]
|
||||
|
||||
def edwards(P,Q):
|
||||
x1 = P[0]
|
||||
y1 = P[1]
|
||||
x2 = Q[0]
|
||||
y2 = Q[1]
|
||||
x3 = (x1*y2+x2*y1) * inv(1+d*x1*x2*y1*y2)
|
||||
y3 = (y1*y2+x1*x2) * inv(1-d*x1*x2*y1*y2)
|
||||
return [x3 % q,y3 % q]
|
||||
|
||||
def scalarmult(P, e):
|
||||
if e == 0: return [0,1]
|
||||
Q = scalarmult(P,e/2)
|
||||
Q = edwards(Q,Q)
|
||||
if e & 1: Q = edwards(Q,P)
|
||||
return Q
|
||||
|
||||
def encodeint(y):
|
||||
bits = [(y >> i) & 1 for i in range(b)]
|
||||
return ''.join([chr(sum([bits[i * 8 + j] << j for j in range(8)])) for i in range(b/8)])
|
||||
|
||||
def encodepoint(P):
|
||||
x = P[0]
|
||||
y = P[1]
|
||||
bits = [(y >> i) & 1 for i in range(b - 1)] + [x & 1]
|
||||
return ''.join([chr(sum([bits[i * 8 + j] << j for j in range(8)])) for i in range(b/8)])
|
||||
|
||||
def bit(h,i):
|
||||
return (ord(h[i/8]) >> (i%8)) & 1
|
||||
|
||||
def public_key(sk):
|
||||
A = scalarmult(B,sk)
|
||||
return encodepoint(A)
|
||||
|
||||
|
||||
def Hint(m):
|
||||
h = H(m)
|
||||
return sum(2**i * bit(h,i) for i in range(2*b))
|
||||
|
||||
def signature(m,sk,pk):
|
||||
h = H(sk)
|
||||
a = 2**(b-2) + sum(2**i * bit(h,i) for i in range(3,b-2))
|
||||
r = Hint(''.join([h[i] for i in range(b/8,b/4)]) + m)
|
||||
R = scalarmult(B,r)
|
||||
S = (r + Hint(encodepoint(R) + pk + m) * a) % l
|
||||
return encodepoint(R) + encodeint(S)
|
||||
|
||||
def isoncurve(P):
|
||||
x = P[0]
|
||||
y = P[1]
|
||||
return (-x*x + y*y - 1 - d*x*x*y*y) % q == 0
|
||||
|
||||
def decodeint(s):
|
||||
return sum(2**i * bit(s,i) for i in range(0,b))
|
||||
|
||||
def decodepoint(s):
|
||||
y = sum(2**i * bit(s,i) for i in range(0,b-1))
|
||||
x = xrecover(y)
|
||||
if x & 1 != bit(s,b-1): x = q-x
|
||||
P = [x,y]
|
||||
if not isoncurve(P): raise Exception("decoding point that is not on curve")
|
||||
return P
|
||||
|
||||
def checkvalid(s,m,pk):
|
||||
if len(s) != b/4: raise Exception("signature length is wrong")
|
||||
if len(pk) != b/8: raise Exception("public-key length is wrong")
|
||||
R = decodepoint(s[0:b/8])
|
||||
A = decodepoint(pk)
|
||||
S = decodeint(s[b/8:b/4])
|
||||
h = Hint(encodepoint(R) + pk + m)
|
||||
if scalarmult(B,S) != edwards(R,scalarmult(A,h)):
|
||||
raise Exception("signature does not pass verification")
|
||||
|
||||
#################################
|
||||
#curve stuff,
|
||||
#mostly from https://github.com/monero-project/bitmonero/blob/1b8a68f6c1abcf481652c2cfd87300a128e3eb32/src/crypto/crypto-ops.c
|
||||
#partial reference for fe things https://godoc.org/github.com/agl/ed25519/edwards25519
|
||||
#note ge is the edwards version of the curve
|
||||
#fe is the monty version of the curve
|
||||
#################################
|
||||
|
||||
|
||||
#NOT USED IN MININERO - Use ge_scalarmult_base
|
||||
def ge_fromfe_frombytesvartime(s):
|
||||
#inputs something s (I assume in bytes)
|
||||
#inputs into montgomery form (fe)
|
||||
#then, turns it into edwards form (ge)
|
||||
#then r is the edwards curve point r->
|
||||
#reference 1: http://crypto.stackexchange.com/questions/9536/converting-ed25519-public-key-to-a-curve25519-public-key?rq=1
|
||||
#reference 2: https://github.com/orlp/ed25519/blob/master/src/key_exchange.c
|
||||
#best reference https://www.imperialviolet.org/2013/12/25/elligator.html
|
||||
|
||||
#the point of this function is to return a ge_p2 from an int s
|
||||
#whereas, the similar function ge_frombytes_vartime returns a gep3
|
||||
return
|
||||
|
||||
def ge_double_scalarmult_base_vartime(aa, AA, bb):
|
||||
#a very nice comment in the CN code for this one!
|
||||
#r = a * A + b * B
|
||||
#where a = a[0]+256*a[1]+...+256^31 a[31].
|
||||
#and b = b[0]+256*b[1]+...+256^31 b[31].
|
||||
#B is the Ed25519 base point (x,4/5) with x positive.
|
||||
#cf also https://godoc.org/github.com/agl/ed25519/edwards25519
|
||||
tmpa = ge_scalarmult(aa, AA)
|
||||
tmpb = ge_scalarmult(bb, BASEPOINT)
|
||||
return toHex(edwards(toPoint(tmpa), toPoint(tmpb)))
|
||||
|
||||
def ge_double_scalarmult_vartime(aa, AA, bb, BB):
|
||||
#a very nice comment in the CN code for this one!
|
||||
#r = a * A + b * B
|
||||
#where a = a[0]+256*a[1]+...+256^31 a[31].
|
||||
#and b = b[0]+256*b[1]+...+256^31 b[31].
|
||||
#B is the Ed25519 base point (x,4/5) with x positive.
|
||||
#cf also https://godoc.org/github.com/agl/ed25519/edwards25519
|
||||
tmpa = ge_scalarmult(aa, AA)
|
||||
tmpb = ge_scalarmult(bb, BB)
|
||||
return toHex(edwards(toPoint(tmpa), toPoint(tmpb)))
|
||||
|
||||
|
||||
def toPoint(pubkey):
|
||||
#turns hex key into x, y field coords
|
||||
return decodepoint(pubkey.decode("hex"))
|
||||
|
||||
def toHex(point):
|
||||
#turns point into pubkey (reverse of toPoint)
|
||||
return encodepoint(point).encode("hex")
|
||||
|
||||
def ge_scalarmult(a, A):
|
||||
#so I guess given any point A, and an integer a, this computes aA
|
||||
#so the seecond arguement is definitely an EC point
|
||||
# from http://cr.yp.to/highspeed/naclcrypto-20090310.pdf
|
||||
# "Alice's secret key a is a uniform random 32-byte string then
|
||||
#clampC(a) is a uniform random Curve25519 secret key
|
||||
#i.e. n, where n/8 is a uniform random integer between
|
||||
#2^251 and 2^252-1
|
||||
#Alice's public key is n/Q compressed to the x-coordinate
|
||||
#so that means, ge_scalarmult is not actually doing scalar mult
|
||||
#clamping makes the secret be between 2^251 and 2^252
|
||||
#and should really be done
|
||||
#print(toPoint(A))
|
||||
return encodepoint(scalarmult(toPoint(A), a)).encode("hex") # now using the eddie function
|
||||
|
||||
def ge_scalarmult_base(a):
|
||||
#in this function in the original code, they've assumed it's already clamped ...
|
||||
#c.f. also https://godoc.org/github.com/agl/ed25519/edwards25519
|
||||
#it will return h = a*B, where B is ed25519 bp (x,4/5)
|
||||
#and a = a[0] + 256a[1] + ... + 256^31 a[31]
|
||||
#it assumes that a[31 <= 127 already
|
||||
return ge_scalarmult(8*a, BASEPOINT)
|
||||
|
||||
#NOT USED IN MININERO - use ge_scalarmult_base
|
||||
def ge_frombytes_vartime(key):
|
||||
#https://www.imperialviolet.org/2013/12/25/elligator.html
|
||||
#basically it takes some bytes of data
|
||||
#converts to a point on the edwards curve
|
||||
#if the bytes aren't on the curve
|
||||
#also does some checking on the numbers
|
||||
#ex. your secret key has to be at least >=4294967277
|
||||
#also it rejects certain curve points, i.e. "if x = 0, sign must be positive
|
||||
return 0
|
||||
|
||||
#NOT USED IN MININERO - unecessary as all operations are from hex
|
||||
def ge_p1p1_to_p2(p):
|
||||
#there are two ways of representing the points
|
||||
##http://code.metager.de/source/xref/lib/nacl/20110221/crypto_sign/edwards25519sha512batch/ref/ge25519.c
|
||||
#http://www.hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html
|
||||
return
|
||||
|
||||
#NOT USED IN MININERO -unnecessary as operations are from hex
|
||||
def ge_p2_dbl():
|
||||
#basically it doubles a point and doubles it
|
||||
#c.f. Explicit Formulas for Doubling (towards bottom)
|
||||
#Explicit formulas for doubling
|
||||
#http://www.hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html
|
||||
return
|
||||
|
||||
#NOT USED IN MININERO - unnecessary as operations are from hex
|
||||
def ge_p3_to_p2():
|
||||
#basically, it copies a point in 3 coordinates to another point
|
||||
#c.f. Explicit Formulas for Doubling (towards bottom)
|
||||
#Explicit formulas for doubling
|
||||
#http://www.hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html
|
||||
return
|
||||
|
||||
def ge_mul8(P):
|
||||
#ok, the point of this is to double three times
|
||||
#and the point is that the ge_p2_dbl returns a point in the p1p1 form
|
||||
#so that's why have to convert it first and then double
|
||||
return ge_scalarmult(8, P)
|
||||
|
||||
def sc_reduce(s):
|
||||
#inputs a 64 byte int and outputs the lowest 32 bytes
|
||||
#used by hash_to_scalar, which turns cn_fast_hash to number..
|
||||
r = longToHex(s)
|
||||
r = r[64::]
|
||||
#print("before mod p", r)
|
||||
return hexToLong(r) % CURVE_P
|
||||
|
||||
def sc_reduce32(data):
|
||||
#ok, the code here is exactly the same as sc_reduce
|
||||
#(which is default lib sodium)
|
||||
#except it is assumed that your input
|
||||
#s is alread in the form:
|
||||
# s[0]+256*s[1]+...+256^31*s[31] = s
|
||||
#and the rest is just reducing mod l
|
||||
#so basically take a 32 byte input, and reduce modulo the prime
|
||||
return data % CURVE_P
|
||||
|
||||
def sc_mulsub(a, b, c):
|
||||
#takes in a, b, and c
|
||||
#This is used by the regular sig
|
||||
#i.e. in generate_signature
|
||||
#returns c-ab mod l
|
||||
a = number.bytes_to_long(a[::-1])
|
||||
b = number.bytes_to_long(b[::-1])
|
||||
c = number.bytes_to_long(c[::-1])
|
||||
return (c - a * b) % CURVE_P
|
||||
|
||||
|
||||
##########################################
|
||||
#Hashing
|
||||
#this is where keccak, H_p, and H_s come in..
|
||||
######################################
|
||||
|
||||
def cn_fast_hash(key, size):
|
||||
#see ReadMeKeccak.txt
|
||||
return KEK.Keccak((size,key.encode("hex")),1088,512,256,False)
|
||||
|
||||
|
||||
###################################################
|
||||
#CryptoNote Things
|
||||
#Mainly from https://github.com/monero-project/bitmonero/blob/1b8a68f6c1abcf481652c2cfd87300a128e3eb32/src/crypto/crypto.cpp
|
||||
###################################################
|
||||
|
||||
def random_scalar():
|
||||
tmp = rand.getrandbits(64 * 8) # 8 bits to a byte ...
|
||||
tmp = sc_reduce(tmp) #-> turns 64 to 32 (note sure why don't just gt 32 in first place ... )
|
||||
return tmp
|
||||
|
||||
def hash_to_scalar(data, length):
|
||||
#this one is H_s(P)
|
||||
#relies on cn_fast_hash and sc_reduce32 (which makes an int smaller)
|
||||
#the input here is not necessarily a 64 byte thing, and that's why sc_reduce32
|
||||
res = hexToLong(cn_fast_hash(data, length))
|
||||
return sc_reduce32(res)
|
||||
|
||||
|
||||
def generate_keys():
|
||||
#should return a secret key and public key pair
|
||||
#once you have the secret key,
|
||||
#then the public key be gotten from 25519 function
|
||||
#so just need to generate random
|
||||
#first generate random 32-byte(256 bit) integer, copy to result
|
||||
#ok, just sc_reduce, what that does is takes 64 byte int, turns into 32 byte int...
|
||||
#so sc_reduce is legit and comes from another library http://hackage.haskell.org/package/ed25519-0.0.2.0/src/src/cbits/sc_reduce.c
|
||||
#as far as I can tell, sc
|
||||
#basically this gets you an int which is sufficiently large
|
||||
#import Crypto.Random.random as rand
|
||||
rng = random_scalar()
|
||||
#sec = hex(rng).rstrip("L").lstrip("0x") or "0"
|
||||
sec = sc_reduce32(rng)
|
||||
pub = public_key(sec).encode("hex")
|
||||
#pub = ge_scalarmult_base(sec)
|
||||
#print(rng.decode("hex"))
|
||||
#sec = curve25519_mult(rng, basepoint)
|
||||
|
||||
#the point of ge_p3_tobytes here is just store as bytes...
|
||||
#and p3 is a way to store points on the ge curve
|
||||
return sec, pub
|
||||
|
||||
def check_key(key):
|
||||
#inputs a public key, and outputs if point is on the curve
|
||||
return isoncurve(toPoint(key))
|
||||
|
||||
def secret_key_to_public_key(secret_key):
|
||||
#the actual function returns as bytes since they mult the fast way.
|
||||
if sc_check(secret_key) != 0:
|
||||
print "error in sc_check"
|
||||
quit()
|
||||
return public_key(secret_key)
|
||||
|
||||
def hash_to_ec(key):
|
||||
#takes a hash and turns into a point on the curve
|
||||
#In MININERO, I'm not using the byte representation
|
||||
#So this function is superfluous
|
||||
h = hash_to_scalar(key, len(key))
|
||||
point = ge_scalarmult_base(h)
|
||||
return ge_mul8(point)
|
||||
|
||||
|
||||
def generate_key_image(public_key, secret_key):
|
||||
#should return a key image as defined in whitepaper
|
||||
if sc_check(secret_key) != 0:
|
||||
print"sc check error in key image"
|
||||
point = hash_to_ec(public_key)
|
||||
point2 = ge_scalarmult(secret_key, point)
|
||||
return point2
|
||||
|
||||
def generate_ring_signature(prefix, image, pubs, pubs_count, sec, sec_index):
|
||||
#returns a ring signature
|
||||
if sec_index >= pubs_count:
|
||||
print "bad index of secret key!"
|
||||
quit()
|
||||
if ge_frombytes_vartime(image) != 0:
|
||||
print"bad image!"
|
||||
quit()
|
||||
summ = 0
|
||||
aba = [0 for xx in range(pubs_count)]
|
||||
abb = [0 for xx in range(pubs_count)]
|
||||
sigc = [0 for xx in range(pubs_count)] #these are the c[i]'s from the whitepaper
|
||||
sigr =[0 for xx in range(pubs_count)] #these are the r[i]'s from the whitepaper
|
||||
for ii in range(0, pubs_count):
|
||||
if (ii == sec_index):
|
||||
kk = random_scalar()
|
||||
tmp3 = ge_scalarmult_base(kk) #L[i] for i = s
|
||||
aba[ii] = tmp3
|
||||
tmp3 = hash_to_ec(pubs[ii]) #R[i] for i = s
|
||||
abb[ii] = ge_scalarmult(kk, tmp3)
|
||||
else:
|
||||
k1 = random_scalar() #note this generates a random scalar in the correct range...
|
||||
k2 = random_scalar()
|
||||
if ge_frombytes_vartime(pubs[ii]) != 0:
|
||||
print "error in ring sig!!!"
|
||||
quit()
|
||||
tmp2 = ge_double_scalarmult_base_vartime(k1, pubs[ii], k2) #this is L[i] for i != s
|
||||
aba[ii] = tmp2
|
||||
tmp3 = hash_to_ec(pubs[ii])
|
||||
abb[ii] = ge_double_scalarmult_vartime(k2, tmp3, k1, image) #R[i] for i != s
|
||||
sigc[ii] = k1 #the random c[i] for i != s
|
||||
sigr[ii] = k2 #the random r[i] for i != s
|
||||
summ = sc_add(summ, sigc[ii]) #summing the c[i] to get the c[s] via page 9 whitepaper
|
||||
|
||||
buf = struct.pack('64s', prefix)
|
||||
for ii in range(0, pubs_count):
|
||||
buf += struct.pack('64s', aba[ii])
|
||||
buf += struct.pack('64s', abb[ii])
|
||||
hh = hash_to_scalar(buf,len(buf))
|
||||
sigc[sec_index] = sc_sub(hh, summ) # c[s] = hash - sum c[i] mod l
|
||||
sigr[sec_index] = sc_mulsub(sigc[sec_index], sec, kk) # r[s] = q[s] - sec * c[index]
|
||||
return image, sigc, sigr
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def check_ring_signature(prefix, key_image, pubs, pubs_count, sigr, sigc):
|
||||
#from https://github.com/monero-project/bitmonero/blob/6a70de32bf872d97f9eebc7564f1ee41ff149c36/src/crypto/crypto.cpp
|
||||
#this is the "ver" algorithm
|
||||
aba = [0 for xx in range(pubs_count)]
|
||||
abb = [0 for xx in range(pubs_count)]
|
||||
|
||||
if ge_frombytes_vartime(key_image) != 0:
|
||||
print "ring image error in checking sigs"
|
||||
quit()
|
||||
summ = 0
|
||||
buf = struct.pack('64s', prefix)
|
||||
for ii in range(0, pubs_count):
|
||||
if ((sc_check(sigc[ii]) != 0) or (sc_check(sigr[ii]) != 0)):
|
||||
print "failed sc_check in check ring sigs"
|
||||
quit()
|
||||
if ge_frombytes_vartime(pubs[ii]) != 0:
|
||||
print "public key is a bad point in ring sigs"
|
||||
quit()
|
||||
|
||||
tmp2 = ge_double_scalarmult_base_vartime(sigc[ii], pubs[ii], sigr[ii])
|
||||
aba[ii] = tmp2
|
||||
tmp3 = hash_to_ec(pubs[ii])
|
||||
tmp2 = ge_double_scalarmult_vartime(sigr[ii], tmp3, sigc[ii], key_image)
|
||||
abb[ii] = tmp2
|
||||
summ = sc_add(summ, sigc[ii])
|
||||
for ii in range(0, pubs_count):
|
||||
buf += struct.pack('64s', aba[ii])
|
||||
buf += struct.pack('64s', abb[ii])
|
||||
|
||||
hh = hash_to_scalar(buf,len(buf))
|
||||
hh = sc_sub(hh, summ)
|
||||
return sc_isnonzero(hh) == 0
|
||||
|
||||
def generate_key_derivation(key1, key2):
|
||||
#key1 is public key of receiver Bob (see page 7)
|
||||
#key2 is Alice's private
|
||||
#this is a helper function for the key-derivation
|
||||
#which is the generating one-time key's thingy
|
||||
if sc_check(key2) != 0:
|
||||
#checks that the secret key is uniform enough...
|
||||
print"error in sc_check in keyder"
|
||||
quit()
|
||||
if ge_frombytes_vartime(key1) != 0:
|
||||
print "didn't pass curve checks in keyder"
|
||||
quit()
|
||||
|
||||
point = key1 ## this ones the public
|
||||
point2 = ge_scalarmult( key2, point)
|
||||
#print("p2", encodepoint(point2).encode("hex"))
|
||||
point3 = ge_mul8(point2) #This has to do with n==0 mod 8 by dedfinition, c.f. the top paragraph of page 5 of http://cr.yp.to/ecdh/curve25519-20060209.pdf
|
||||
#and also c.f. middle of page 8 in same document (Bernstein)
|
||||
return point3
|
||||
|
||||
def derivation_to_scalar(derivation, output_index):
|
||||
#this function specifically hashes your
|
||||
#output index (for the one time keys )
|
||||
#in order to get an int, so we can do ge_mult_scalar
|
||||
#buf = s_comm(d = derivation, o = output_index)
|
||||
buf2 = struct.pack('64sl', derivation, output_index)
|
||||
#print(buf2)
|
||||
return hash_to_scalar(buf2, len(buf2))
|
||||
|
||||
def derive_public_key(derivation, output_index, base ):
|
||||
if ge_frombytes_vartime(base) != 0: #check some conditions on the point
|
||||
print"derive pub key bad point"
|
||||
quit()
|
||||
point1 = base
|
||||
scalar = derivation_to_scalar(derivation, output_index)
|
||||
point2 = ge_scalarmult_base(scalar)
|
||||
point3 = point2 #I think the cached is just for the sake of adding
|
||||
#because the CN code adds using the monty curve
|
||||
point4 = edwards(toPoint(point1), toPoint(point3))
|
||||
return point4
|
||||
|
||||
def sc_add(aa, bb):
|
||||
return (aa + bb ) %CURVE_P
|
||||
def sc_sub(aa, bb):
|
||||
return (aa - bb ) %CURVE_P
|
||||
|
||||
def sc_isnonzero(c):
|
||||
return (c %CURVE_P != 0 )
|
||||
|
||||
def sc_mulsub(aa, bb, cc):
|
||||
return (cc - aa * bb ) %CURVE_P
|
||||
|
||||
def derive_secret_key(derivation, output_index, base):
|
||||
#outputs a derived key...
|
||||
if sc_check(base) !=0:
|
||||
print"cs_check in derive_secret_key"
|
||||
scalar = derivation_to_scalar(derivation, output_index)
|
||||
return base + scalar
|
||||
|
||||
class s_comm:
|
||||
def __init__(self, **kwds):
|
||||
self.__dict__.update(kwds)
|
||||
|
||||
def generate_signature(prefix_hash, pub, sec):
|
||||
#gets the "usual" signature (not ring sig)
|
||||
#buf = s_comm(h=prefix_hash, key=pub, comm=0) #see the pack below
|
||||
k = random_scalar()
|
||||
tmp3 = ge_scalarmult_base(k)
|
||||
buf2 = struct.pack('64s64s64s', prefix_hash, pub, tmp3)
|
||||
sigc = hash_to_scalar(buf2, len(buf2))
|
||||
return sc_mulsub(sigc, sec, k), sigc
|
||||
|
||||
def check_signature(prefix_hash, pub, sigr, sigc):
|
||||
#checking the normal sigs, not the ring sigs...
|
||||
if ge_frombytes_vartime(pub) !=0:
|
||||
print "bad point, check sig!"
|
||||
quit()
|
||||
if (sc_check(sigc) != 0) or (sc_check(sigr) != 0):
|
||||
print"sc checksig error!"
|
||||
quit()
|
||||
tmp2 = ge_double_scalarmult_base_vartime(sigc, pub, sigr)
|
||||
buf2 = struct.pack('64s64s64s', prefix_hash, pub, tmp2)
|
||||
c = hash_to_scalar(buf2, len(buf2))
|
||||
c = sc_sub(c, sigc)
|
||||
return sc_isnonzero(c) == 0
|
||||
|
||||
def hexToLong(a):
|
||||
return number.bytes_to_long(a.decode("hex"))
|
||||
|
||||
def longToHex(a):
|
||||
return number.long_to_bytes(a).encode("hex")
|
||||
|
||||
def hexToBits(a):
|
||||
return a.decode("hex")
|
||||
|
||||
def bitsToHex(a):
|
||||
return a.encode("hex")
|
||||
|
||||
def sc_check(key):
|
||||
#in other words, keys which are too small are rejected
|
||||
return 0
|
||||
#s0, s1, s2, s3, s4, s5, s6, s7 = load_4(longToHex(key))
|
||||
#return (signum_(1559614444 - s0) + (signum_(1477600026 - s1) << 1) + (signum_(2734136534 - s2) << 2) + (signum_(350157278 - s3) << 3) + (signum_(-s4) << 4) + (signum_(-s5) << 5) + (signum_(-s6) << 6) + (signum_(268435456 - s7) << 7)) >> 8
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if sys.argv[1] == "rs":
|
||||
#test random_scalar
|
||||
print(longToHex(random_scalar()))
|
||||
if sys.argv[1] == "keys":
|
||||
#test generating keys
|
||||
x,P = generate_keys()
|
||||
print"generating keys:"
|
||||
print("secret:")
|
||||
print( x)
|
||||
print("public:")
|
||||
print( P)
|
||||
print("the point P")
|
||||
print(decodepoint(P.decode("hex")))
|
||||
if sys.argv[1] == "fasthash":
|
||||
mysecret = "99b66345829d8c05041eea1ba1ed5b2984c3e5ec7a756ef053473c7f22b49f14"
|
||||
output_index = 2
|
||||
buf2 = struct.pack('64sl', mysecret, output_index)
|
||||
#buf2 = pickle(buf)
|
||||
#print(buf2)
|
||||
print(buf2)
|
||||
print(cn_fast_hash(mysecret, len(mysecret)))
|
||||
print(cn_fast_hash(buf2, len(buf2)))
|
||||
|
||||
if sys.argv[1] == "hashscalar":
|
||||
data = "ILOVECATS"
|
||||
print(cn_fast_hash(data, len(data)))
|
||||
print(hash_to_scalar(data, len(data)))
|
||||
if sys.argv[1] == "hashcurve":
|
||||
data = "ILOVECATS"
|
||||
print(cn_fast_hash(data, len(data)))
|
||||
print(hash_to_ec(data))
|
||||
|
||||
if sys.argv[1] == "checkkey":
|
||||
x, P = generate_keys()
|
||||
print(check_key(P))
|
||||
if sys.argv[1] == "secpub":
|
||||
#testing for secret_key_to_public_key
|
||||
#these test vecs were for the monty implementation
|
||||
mysecret = "99b66345829d8c05041eea1ba1ed5b2984c3e5ec7a756ef053473c7f22b49f14"
|
||||
mypublic = "b1c652786697a5feef36a56f36fde524a21193f4e563627977ab515f600fdb3a"
|
||||
mysecret, P = generate_keys()
|
||||
pub2 = secret_key_to_public_key(mysecret)
|
||||
print(pub2.encode("hex"))
|
||||
if sys.argv[1] == "keyder":
|
||||
#testing for generate_key_derivation
|
||||
x,P = generate_keys()
|
||||
print(x, P)
|
||||
print(generate_key_derivation(P, x))
|
||||
|
||||
if sys.argv[1] == "dersca":
|
||||
#testing for derivation_to_scalar
|
||||
#this is getting a scalar for one-time-keys rH_s(P)
|
||||
aa, AA = generate_keys()
|
||||
bb, BB = generate_keys()
|
||||
for i in range(0,3):
|
||||
rr, ZZ = generate_keys()
|
||||
derivation = generate_key_derivation(BB, aa)
|
||||
s = derivation_to_scalar(derivation, i)
|
||||
print(s)
|
||||
if sys.argv[1] == "derpub":
|
||||
x, P = generate_keys()
|
||||
output_index = 5
|
||||
keyder = generate_key_derivation(P, x)
|
||||
print("keyder", keyder)
|
||||
print(derive_public_key(keyder, output_index, P))
|
||||
if sys.argv[1] == "dersec":
|
||||
x, P = generate_keys()
|
||||
output_index = 5
|
||||
keyder = generate_key_derivation(P, x)
|
||||
print("keyder", keyder)
|
||||
print(derive_secret_key(keyder, output_index, x))
|
||||
if sys.argv[1] == "testcomm":
|
||||
a = "99b66345829d8c05041eea1ba1ed5b2984c3e5ec7a756ef053473c7f22b49f14"
|
||||
co2 = struct.pack('hhl', 1, 2, 3)
|
||||
print(co2.encode("hex")) #sometimes doesn't print if your terminal doesn't have unicode
|
||||
|
||||
if sys.argv[1] == "gensig":
|
||||
#testing generate_signature
|
||||
print""
|
||||
prefix = "destination"
|
||||
sec, pub = generate_keys() # just to have some data to use ..
|
||||
print(generate_signature(prefix, pub, sec))
|
||||
if sys.argv[1] == "checksig":
|
||||
prefix = "destination"
|
||||
sec, pub = generate_keys() # just to have some data to use ..
|
||||
sir, sic = generate_signature(prefix, pub, sec)
|
||||
print(sir, sic)
|
||||
print(check_signature(prefix, pub, sir, sic))
|
||||
if sys.argv[1] == "keyimage":
|
||||
x, P = generate_keys()
|
||||
xb = 14662008266461539177776197088974240017016792645044069572180060425138978088469
|
||||
Pb = "1d0ecd1758a685d88b39567f491bc93129f59c7dae7182bddc4e6f5ad38ba462"
|
||||
|
||||
I = generate_key_image(Pb, xb)
|
||||
print(I)
|
||||
if sys.argv[1] == "ringsig":
|
||||
#these are fixed since my computer runs out of memory
|
||||
xa = 54592381732429499113512315392038591381134951436395595620076310715410049314218
|
||||
Pa = "3c853b5a82912313b179e40d655003c5e3112c041fcf755c3f09d2a8c64d9062"
|
||||
xb = 14662008266461539177776197088974240017016792645044069572180060425138978088469
|
||||
Pb = "1d0ecd1758a685d88b39567f491bc93129f59c7dae7182bddc4e6f5ad38ba462"
|
||||
ima = "0620b888780351a3029dfbf1a5c45a89816f118aa63fa807d51b959cb3c5efc9"
|
||||
ima, sic, sir = generate_ring_signature("dest", ima, [Pa, Pb],2, xb, 1)
|
||||
|
||||
print("ima",ima)
|
||||
print("sic", sir)
|
||||
print("sir", sic)
|
||||
print(check_ring_signature("dest", ima, [Pa, Pb], 2, sir, sic))
|
||||
|
||||
if sys.argv[1] == "conv":
|
||||
#testing reduction
|
||||
a = "99b66345829d8c05041eea1ba1ed5b2984c3e5ec7a756ef053473c7f22b49f14"
|
||||
print(a)
|
||||
r = hexToLong(a)
|
||||
print(r)
|
||||
a = longToHex(r)
|
||||
print(a)
|
||||
if sys.argv[1] == "red":
|
||||
a = "99b66345829d8c05041eea1ba1ed5b2984c3e5ec7a756ef053473c7f22b49f14"
|
||||
tmp = rand.getrandbits(64 * 8)
|
||||
tmp2 = longToHex(tmp)
|
||||
print(tmp2)
|
||||
tmp3 = longToHex(sc_reduce(tmp))
|
||||
print(tmp3)
|
||||
tmp4 = sc_reduce32(CURVE_P + 1)
|
||||
print(tmp4)
|
||||
tmp5 = sc_reduce(CURVE_P + 1)
|
||||
print(tmp5)
|
||||
if sys.argv[1] == "gedb":
|
||||
x, P = generate_keys()
|
||||
print(ge_double_scalarmult_base_vartime(x, P, x))
|
||||
if sys.argv[1] == "sck":
|
||||
#testing sc_check
|
||||
x, P = generate_keys()
|
||||
print(sc_check(x))
|
||||
print("nonreduced", longToHex(x))
|
||||
print("reduced", sc_reduce32_2(x))
|
||||
print("check reduced", sc_check(hexToLong(sc_reduce32_2(x))))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
10
source-code/MiniNero/rct.py
Normal file
10
source-code/MiniNero/rct.py
Normal file
|
@ -0,0 +1,10 @@
|
|||
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
|
||||
|
||||
|
5
source-code/MiniNero/scrap.py
Normal file
5
source-code/MiniNero/scrap.py
Normal file
|
@ -0,0 +1,5 @@
|
|||
import ed25519
|
||||
import MiniNero
|
||||
import binascii
|
||||
|
||||
print(MiniNero.getHForCT())
|
1
source-code/MiniNero/test.hash
Normal file
1
source-code/MiniNero/test.hash
Normal file
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue