viewing_key.sage 1.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. from poseidon import poseidon_hash
  2. def xor(text, key):
  3. ciphertext = ""
  4. for i in range(len(text)):
  5. ciphertext += chr(ord(text[i]) ^^ ord(key[i % len(key)]))
  6. return ciphertext
  7. p = 0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001
  8. q = 0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001
  9. Fp = GF(p)
  10. Fq = GF(q)
  11. Ep = EllipticCurve(Fp, (0, 5))
  12. Ep.set_order(q)
  13. nfk_x = 0x25e7aa169ca8198d2e375571faf4c9cf5e7eb192ccb5db9bd36f6aa7e447ca75
  14. nfk_y = 0x155c1f851b1a3384880473442008ff755fe0a49ec1c1b4332db8dce21ae001cc
  15. G = Ep([nfk_x, nfk_y])
  16. # Alice's view key pair
  17. a = Fq.random_element()
  18. A = a * G
  19. # Alice's spend key pair
  20. b = Fq.random_element()
  21. B = b * G
  22. # Each output in a transaction has its own public key
  23. # r is a "transaction secret key, unique to the transaction
  24. # and known only to the sender.
  25. r = Fq.random_element()
  26. R = r * G
  27. # The public key for the output is calculated as such:
  28. rA = r * A
  29. rA_x, rA_y = rA.xy()
  30. P = Fq(int(poseidon_hash([rA_x, rA_y]))) * G + B
  31. # Output value
  32. value = "10000"
  33. # Sender encrypts it
  34. value_enc = xor(value, str(rA))
  35. # A recipient scanning for txs will look at R and calculate
  36. # for themselves what an output would look like if it was
  37. # destined for them:
  38. aR = a * R
  39. aR_x, aR_y = aR.xy()
  40. P_ = Fq(int(poseidon_hash([aR_x, aR_y]))) * G + B
  41. assert P == P_
  42. # Recipient decrypts ciphertext
  43. value_ = xor(value_enc, str(aR))
  44. assert value == value_
  45. # The secret key for spending the output is: H(aR) + b
  46. # And outputs can only be spent by providing a signature
  47. # for the output.