text: ########################################################################
  #     MiniNero.py
  #A miniature, commented
  #port of CryptoNote and 
  #ByteRub: 
  #     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/byterubpay/bitbyterub/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/byterubpay/bitbyterub/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/byterubpay/bitbyterub/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))))
      
  
          
  
  
          
          
  
  