Created
November 17, 2020 19:55
-
-
Save bladedoyle/a9b5f986cfaf61962a7b25545ee2a0a1 to your computer and use it in GitHub Desktop.
Grin Wallet Owner API V3 example in Python
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python3 | |
# Start the node: $ grin | |
# Configure Wallet: | |
# owner_api_listen_port = 3420 | |
# api_secret_path = "/home/bdoyle/.grin/main/.owner_api_secret" | |
# Start the wallet owner api: $ grin-wallet owner_api | |
# Install g++ | |
# Install python3 and python3-pip | |
# pip3 install secp256k1 | |
# pip3 install eciespy | |
# pip3 install coincurve | |
# https://pypi.org/project/eciespy/ | |
# See the section "Secp256k1" about half way down the page | |
from coincurve import PrivateKey, PublicKey | |
import requests | |
import json | |
# set grin wallet basicauth credentials | |
wallet_user = "grin" | |
with open('/home/bdoyle/.grin/main/.owner_api_secret','r') as f: | |
wallet_secret = f.read() | |
# We need to call the v3 "init_secure_api" wallet owner api endpoint | |
# https://docs.rs/grin_wallet_api/4.0.0/grin_wallet_api/trait.OwnerRpc.html#tymethod.init_secure_api | |
my_key = PrivateKey.from_int(420) | |
my_public_key = my_key.public_key.format(False).hex() # Generate a public key, uncompressed, in hex | |
#print("my_public_key in hex: {}".format(my_public_key)) | |
# Call init_secure_api | |
http_auth = requests.auth.HTTPBasicAuth(wallet_user, wallet_secret) | |
rpc_data = { "jsonrpc":"2.0", | |
"method":"init_secure_api", | |
"params":{"ecdh_pubkey": my_public_key}, | |
"id":1 | |
} | |
req = requests.post( | |
'http://localhost:3420/v3/owner', | |
json = rpc_data, | |
auth = http_auth, | |
) | |
req_j = req.json() | |
print("init_secure_api response: {}".format(req_j)) | |
api_public_key_hex = req_j["result"]["Ok"] | |
# init_secure_api will return its public key used in the derivation, | |
# which the caller should multiply by its private key to derive the shared key. | |
# The shared key will be derived using ECDH with the provided public key on the secp256k1 curve. | |
api_public_key = PublicKey(bytes.fromhex(api_public_key_hex)) | |
shared_ecdh_key = my_key.ecdh(api_public_key.format()) | |
shared_ecdh_key_hex = shared_ecdh_key.hex() | |
print("shared_ecdh_key_hex: {}".format(shared_ecdh_key_hex)) | |
## - I am very much not sure about what follows ... | |
# all further requests and responses are encrypted and decrypted | |
# See "AES" sectoion at the bottom of: https://github.com/ecies/py | |
from Crypto.PublicKey import RSA | |
from Crypto.Random import get_random_bytes | |
from Crypto.Cipher import AES, PKCS1_OAEP | |
import base64 | |
rpc_data = '{ "jsonrpc": "2.0", "method": "accounts", "params": { "token": "d202964900000000d302964900000000d402964900000000d502964900000000" }, "id": 1 }'.encode("utf-8") | |
cipher_aes = AES.new(shared_ecdh_key, AES.MODE_GCM) | |
ciphertext, tag = cipher_aes.encrypt_and_digest(rpc_data) | |
v3_rpc_payload = { | |
"jsonrpc": "2.0", | |
"method": "encrypted_request_v3", | |
"id": "1", | |
"params": { | |
"nonce": cipher_aes.nonce, | |
"body_enc": base64.b64encode(ciphertext), | |
} | |
} | |
req = requests.post( | |
'http://localhost:3420/v3/owner', | |
json = v3_rpc_payload, | |
auth = http_auth, | |
) | |
print("accounts response: {}".format(req.text)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Any idea if this implementation is actually functional as-is ?