Skip to content

Instantly share code, notes, and snippets.

@marekyggdrasil
Last active December 20, 2022 15:33
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save marekyggdrasil/7abea82256df50d343a23b97ac0d4b4e to your computer and use it in GitHub Desktop.
Save marekyggdrasil/7abea82256df50d343a23b97ac0d4b4e to your computer and use it in GitHub Desktop.
Example code for the tutorial on Pedersen Commitments and Confidential Transactions available under https://mareknarozniak.com/2021/06/22/ct/
#!/bin/sh
convert -background none inputs_before.png inputs_after.png +append inputs.png
numpy
matplotlib
minicurve
import math
import matplotlib.pyplot as plt
import numpy as np
import hashlib
from minicurve import MiniCurve as mc
from minicurve import Visualizer
from minicurve.helpers import inverse
def add_digits(num, p):
return (num - 1) % p if num > 0 else 0
def hashtard(m, p):
hash = hashlib.sha256(str.encode(m))
num = int.from_bytes(hash.digest(), 'big')
num = add_digits(num, p)
return num
def sign(m, k, d, G, p):
# calculate public key R = k*G
R = k*G
# calculate e = H(M || r) where || is concatenation
e = hashtard(m, p)
# calculate the signature
s = np.mod(k + d*e, p)
# signature is s, R
return s, R
def verify(m, s, G, P, R, p):
# e_v = H(M || r_v)
e = hashtard(m, p)
# calculate the verification
lhs = s*G
rhs = R+e*P
# test if lhs = rhs
if lhs == rhs:
return True, lhs, rhs
return False, lhs, rhs
# n is a group order
def isTransactionValid(G, inputs_data, outputs_data, p):
inp, inputs_signature = inputs_data
out, outputs_signature = outputs_data
# calculate inputs - outputs
P = inp - out
# check if signature matches proving the difference is 0
inp_s, inp_R = inputs_signature
out_s, out_R = outputs_signature
s_comb = np.mod(inp_s - out_s, p)
valid, _, _ = verify('m', s_comb, G, P, inp_R - out_R, p)
return valid
# article URL
url = 'https://mareknarozniak.com/2021/06/22/ct/'
# eliptic curve and finite field parameters
p = 13
a = 1
b = 7
# we need two generator points, G for blinding factors and H for the amounts
G = mc(a, b, p, x=10, y=4, label='G', color='tab:green', tracing=True)
H = mc(a, b, p, x=9, y=11, label='H', color='tab:cyan', tracing=True)
# construct the inputs
# blinding factors
bs = [1, 5]
# amounts
am = [2, 4]
# compute blinded inputs
inputs = []
for bsv, amv in zip(bs, am):
R = bsv*G + amv*H
R.setColor('tab:orange')
inputs.append(R)
# visualize pre-transaction space
inputs[0].setLabel('?')
inputs[1].setLabel('Alice')
vis = Visualizer(a, b, p)
vis.makeField()
vis.points = [G, H] + inputs
vis.generatePlot(title='Inputs before the transaction')
plt.figtext(0.0, 0.01, url, rotation=0)
vis.plot('inputs_before.png')
# perform the transaction
# the payor owns an input of value of 4 coins
# is going to transfer 1 coin to payee and 3 coins
# back to him/herself as a change
inp = inputs[1]
# payor signs input with blinding factor as the private key
k = 9 # random nonce
inp_s, inp_R = sign('m', k, bs[1], G, p)
# calculate the change, sending 3 coins back and choosing
# the blinding factor 6
chn = 6*G + 3*H
chn.setColor('tab:orange')
chn.setLabel('Alice')
# payor signs change with blinding factor as the private key, payor chooses 6
k = 1 # random nonce
chn_s, chn_R = sign('m', k, 6, G, p)
# now the payee creates own output, is receiving 1 coin
# and choses the blinding factor of 7
nout = 7*G + 1*H
nout.setColor('tab:orange')
nout.setLabel('Bob')
# payee signs own output with newly chosen blinding factor
k = 3 # random nonce
out_s, out_R = sign('m', k, 7, G, p)
# gather all the outputs together to form a single output
out = nout + chn
# add output signatures as well
comb_R = out_R + chn_R
comb_s = np.mod(out_s + chn_s, p)
# prepare data for the verifier
inputs_signature = inp_s, inp_R
inputs_data = inp, inputs_signature
outputs_signature = comb_s, comb_R
outputs_data = out, outputs_signature
valid = isTransactionValid(G, inputs_data, outputs_data, p)
print('Is transaction valid?', valid)
# visualize the finite field after the transaction is made
# start by removing the input that was just spent from the
# finite field
del inputs[1]
# include the newly created inputs into the field
inputs.append(chn)
inputs.append(nout)
# plot again
vis = Visualizer(a, b, p)
vis.makeField()
vis.points = [G, H] + inputs
vis.generatePlot(title='Inputs after the transaction')
vis.plot('inputs_after.png')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment