def get_proof_recursive( self, a: Vector, b: Vector, P: Point, G: List[Point], H: List[Point], N: int) -> Tuple[Scalar, Scalar, List[Point], List[Point]]: # Can't compress L and R no more if N == 1: # Return tuple a', b', L[], R[] # total size is 2 * scalar_size * log(n) * 2 * point_size return (a[0], b[0], self.L, self.R) aL, aR = split(a) bL, bR = split(b) gL, gR = split(G) hL, hR = split(H) self.L.append( InnerProductCommitment(aL, bR, G=gR, H=hL, U=self.U).get_commitment()) self.R.append( InnerProductCommitment(aR, bL, G=gL, H=hR, U=self.U).get_commitment()) (self.fs_state, _) = fiat_shamir(self.fs_state, [self.L[-1], self.R[-1], P], nret=0) (x, x_sq, xinv, x_sq_inv) = bytes_to_xes(self.fs_state) # Construct change of coordinates for base points, and for vector terms gprime = [] hprime = [] aprime = [] bprime = [] for i in range(int(N / 2)): gprime.append( B.add_pubkeys(B.multiply(G[i], xinv), B.multiply(G[i + int(N / 2)], x))) hprime.append( B.add_pubkeys(B.multiply(H[i], x), B.multiply(H[i + int(N / 2)], xinv))) aprime.append(x * a[i] + xinv * a[i + int(N / 2)] % B.N) bprime.append((xinv * b[i]) + x * b[i + int(N / 2)] % B.N) p_prime = B.add_pubkeys(P, B.multiply(self.L[-1], x_sq)) p_prime = B.add(p_prime, B.multiply(self.R[-1], x_sq_inv)) return self.get_proof_recursive(Vector(aprime), Vector(bprime), p_prime, gprime, hprime, int(N / 2))
def get_commitment(self) -> Point: """ Returns: c * U + v_1 * G_1 + v_2 * G_2 + ... + v_n * G_n + w_1 * H_1 + w_2 * H_2 + ... + w_n + H_n """ P = B.multiply(self.U, self.c) for g_x, a_x in zip(self.G, self.a): P = B.add_pubkeys(P, B.fast_multiply(g_x, a_x)) for h_x, b_x in zip(self.H, self.b): P = B.add_pubkeys(P, B.fast_multiply(h_x, b_x)) return P
def sender_payee_address_from_stealth(sender_prikey, receiver_pubkey): # sender - derive payee address ss1 = btc.multiply(receiver_pubkey, sender_prikey) ss2 = btc.sha256(btc.encode_pubkey((ss1), 'bin_compressed')) addr = btc.pubkey_to_address(btc.add_pubkeys( receiver_pubkey, btc.privtopub(ss2))) return addr
def verify_proof_recursive(self, P: Point, L: Point, R: Point, a: Scalar, b: Scalar, G: List[Point], H: List[Point], N: int): if N == 1: p_prime = InnerProductCommitment(Vector([a]), Vector([b]), G=G, H=H, U=self.U).get_commitment() return P == p_prime (self.fs_state, _) = fiat_shamir(self.fs_state, [L[self.verify_iter], R[self.verify_iter], P], nret=0) (x, x_sq, xinv, x_sq_inv) = bytes_to_xes(self.fs_state) gprime = [] hprime = [] for i in range((int(N / 2))): gprime.append( B.add_pubkeys(B.multiply(G[i], xinv), B.multiply(G[i + int(N / 2)], x))) hprime.append( B.add_pubkeys(B.multiply(H[i], x), B.multiply(H[i + int(N / 2)], xinv))) p_prime1 = B.add_pubkeys(P, B.multiply(L[self.verify_iter], x_sq)) p_prime = B.add_pubkeys(p_prime1, B.multiply(R[self.verify_iter], x_sq_inv)) self.verify_iter = self.verify_iter + 1 return self.verify_proof_recursive(p_prime, L, R, a, b, gprime, hprime, int(N / 2))
def verify(self, Ap, Sp, T1p, T2p, tau_x, mu, t, proof, V): fs_state = b'' # Compute challenges to find x, y, z fs_state, fs_challenge = fiat_shamir(fs_state, [V, Ap, Sp]) y: Scalar = fs_challenge[0] z: Scalar = fs_challenge[1] z2 = pow(z, 2, B.N) fs_state, fs_challenge = fiat_shamir(fs_state, [T1p, T2p], nret=1) x_1 = fs_challenge[0] # Construct verification equation (61) power_of_ones = to_powervector(1, self.bitlength) power_of_twos = to_powervector(2, self.bitlength) yn = to_powervector(y, self.bitlength) k: Scalar = ((yn @ power_of_ones) * (-z2)) % B.N k = (k - (power_of_ones @ power_of_twos) * pow(z, 3, B.N)) % B.N gexp: Scalar = (k + z * (power_of_ones @ yn)) % B.N lhs = PedersonCommitment(t, b=tau_x).get_commitment() rhs = B.multiply(B.G, gexp) rhs = B.add_pubkeys(rhs, B.multiply(V, z2)) rhs = B.add_pubkeys(rhs, B.multiply(T1p, x_1)) rhs = B.add_pubkeys(rhs, B.multiply(T2p, pow(x_1, 2, B.N))) if not lhs == rhs: print('(61) verification check failed') return False # HPrime hprime = [] yinv = modinv(y, B.N) for i in range(1, self.bitlength + 1): hprime.append( B.multiply(getNUMS(self.bitlength + i), pow(yinv, i - 1, B.N))) # Reconstruct P P = B.add_pubkeys(B.multiply(Sp, x_1), Ap) # Add g*^(-z) for i in range(self.bitlength): P = B.add_pubkeys(B.multiply(getNUMS(i + 1), -z % B.N), P) # zynz22n is the exponent of hprime zynz22n = (yn * z) + (power_of_twos * z2) for i in range(self.bitlength): P = B.add_pubkeys(B.multiply(hprime[i], zynz22n[i]), P) fs_state, fs_challenge = fiat_shamir(fs_state, [tau_x, mu, t], nret=1) uchallenge: Scalar = fs_challenge[0] U = B.multiply(B.G, uchallenge) P = B.add_pubkeys(B.multiply(U, t), P) # P should now be : A + xS + -zG* + (zy^n+z^2.2^n)H'* + tU # One can show algebraically (the working is omitted from the paper) # that this will be the same as an inner product commitment to # (lx, rx) vectors (whose inner product is t), thus the variable 'proof' # can be passed into the IPC verify call, which should pass. # input to inner product proof is P.h^-(mu) p_prime = B.add_pubkeys(P, B.multiply(getNUMS(255), -mu % B.N)) a, b, L, R = proof iproof = InnerProductCommitment(power_of_ones, power_of_twos, H=hprime, U=U) return iproof.verify_proof(a, b, p_prime, L, R)
H = getNUMS(255) N = 4 # P -> V: C_0 r = get_blinding_vector(N) x = get_blinding_vector(N) commitments = [ PedersonCommitment(x[i], b=r[i]).get_commitment() for i in range(N) ] # V -> P: e e = get_blinding_value() ev = to_powervector(e, N) # P -> V (z, s) # P P = commitments[0] for i in range(1, N): P = B.add_pubkeys(B.multiply(commitments[i], ev[i]), P) z = ev * x s = ev @ r V = B.multiply(H, s) for i in range(N): V = B.add_pubkeys(B.multiply(B.G, z[i]), V) assert V == P