def compute_denominators(k, q): """Computes denominators for Lagrange basis polynomials. Uses distinct points 1, ...,k Arguments: k -- number of basis polynomials q -- the order of the group """ denominators = [] temp = Bn(1) for i in range(1, k + 1): if i == 1: for j in range(2, k + 1): elem = i - j temp = temp.mod_mul(elem, q) elif i == k: elem = 1 - k temp = temp.mod_mul(elem, q) else: inverse = Bn(i - 1 - k) inverse = inverse.mod_inverse(q) elem = i - 1 temp = temp.mod_mul(elem, q) temp = temp.mod_mul(inverse, q) denominators.append(temp) return denominators
def generate_pis(chi, n, q): """Computes vector of elements P_i(chi) for i = 0, ..., n. P_0 is special, defined as ln_plus1(chi) - 1, where ln_plus1 is the (n+1)th Lagrange basis polynomial. The rest P_i are defined as 2*ln_i(ch) + ln_plus1(chi), where ln_i is the ith Lagrange basis polynomial. It returns a list with the values of the n+1 polynomials P_i(chi). Uses Lagrange basis polynomials with distinct points 1, ..., n + 1. Arguments: chi -- point of evaluation, must be a Bn n -- the number of elements, a Python integer q -- the order of the group, must be a Bn """ if chi <= n + 1: raise ValueError("chi should be greater than n + 1, chi=%s n+1=%s" % (chi, n + 1)) pis = [] prod = Bn(1) # prod = (x - w_1) (x - w_2) ... (x - w_{n+1}) for j in range(1, n + 2): prod = prod.mod_mul(chi - j, q) # denoms[0] = 1 / (w_1 - w_2) (w_1 - w_3) ... (w_1 - w_{n + 1}) # denoms[1] = 1 / (w_2 - w_1) (w_2 - w_3) ... (w_2 - w_{n + 1}) # denoms[n] = 1 / (w_{n+1}- w_1) (w_{n+1} - w_2) ... (w_{n+1} - w_n) denoms = compute_denominators(n + 1, q) missing_factor = chi - (n + 1) ln_plus1 = prod.mod_mul(missing_factor.mod_inverse(q), q) ln_plus1 = ln_plus1.mod_mul(denoms[n].mod_inverse(q), q) # P_0 is special pis.append(ln_plus1.mod_sub(Bn(1), q)) two = Bn(2) for i in range(1, n + 1): missing_factor = chi - i l_i = prod.mod_mul(missing_factor.mod_inverse(q), q) l_i = l_i.mod_mul(denoms[i - 1].mod_inverse(q), q) pis.append(two.mod_mul(l_i, q).mod_add(ln_plus1, q)) return pis
def __lagrange(i, index_list, p): ''' Calculate lagrange coefficient ''' top = Bn(1) bottom = Bn(1) for j in index_list: if j != i: top = (top * j) bottom = (bottom * (j-i)) return top.mod_mul(bottom.mod_inverse(p), p)
def lagrangian(i, n, chi, q): """Evaluates Lagrange basis polynomial l_i at point x. Distinct points are 1, 2, ..., n + 1. Returns nonzero field element. Arguments: i -- polynomial index in range 1, 2, ..., n + 1 chi -- input value of the polynomial q -- the order of the group """ numerator = Bn(1) denominator = Bn(1) for j in range(1, n + 2): if i == j: continue numerator = numerator.mod_mul(chi - j, q) elem = i - j denominator = denominator.mod_mul(elem, q) return numerator.mod_mul(denominator.mod_inverse(q), q)
def compute_denominators_slow(k, q): """Computes denominators for Lagrange basis polynomials. This function can be used to test compute_denominators(k, q). Uses distinct points 1, ...,k Arguments: k -- number of basis polynomials q -- the order of the group """ denominators = [] for i in range(1, k + 1): denominator = Bn(1) for j in range(1, k + 1): if i == j: continue elem = i - j denominator = denominator.mod_mul(elem, q) denominators.append(denominator) return denominators
def VerifyOneOfN(ck, cis, proof, message=""): """ Verify the ring signature on message """ n = int(math.ceil(math.log(len(cis)) / math.log(2))) (G, g, h, o) = ck (Celi, Cai, Cbi, cdi, fi, zai, zbi, zd) = proof ## Check all parts of the proof are in the right groups assert 0 <= zd < o for k in range(n): assert 0 <= fi[k] < o assert 0 <= zai[k] < o assert 0 <= zbi[k] < o assert G.check_point(Celi[k]) assert G.check_point(Cai[k]) assert G.check_point(Cbi[k]) assert G.check_point(cdi[k]) # Recompute the challenge x = challenge(list(ck) + cis + Celi + Cai + Cbi + cdi + [message]) ret = True for i in range(n): ret &= x * Celi[i] + Cai[i] == Com(ck, fi[i], zai[i]) ret &= (x - fi[i]) * Celi[i] + Cbi[i] == Com(ck, Bn(0), zbi[i]) # acc = G.infinite() bases = [] expons = [] for idx, ci in enumerate(cis): idx = Bn(idx) idxi = [Bn(int(idx.is_bit_set(i))) for i in range(n)] acc_exp = Bn(1) for k, ij in enumerate(idxi): if ij == 0: acc_exp = acc_exp.mod_mul(x - fi[k], o) else: acc_exp = acc_exp.mod_mul(fi[k], o) bases += [ci] expons += [acc_exp] # acc = acc + acc_exp * ci for k in range(n): expi = (-pow(x, k, o)) # acc = acc + expi * cdi[k] bases += [cdi[k]] expons += [expi] # assert G.wsum(expons, bases) == acc acc = G.wsum(expons, bases) ret &= acc == Com(ck, 0, zd) return ret
def VerifyOneOfN(ck, cis, proof, message = ""): """ Verify the ring signature on message """ n = int(math.ceil(math.log(len(cis)) / math.log(2))) (G, g, h, o) = ck (Celi, Cai, Cbi, cdi, fi, zai, zbi, zd) = proof ## Check all parts of the proof are in the right groups assert 0 <= zd < o for k in range(n): assert 0 <= fi[k] < o assert 0 <= zai[k] < o assert 0 <= zbi[k] < o assert G.check_point(Celi[k]) assert G.check_point(Cai[k]) assert G.check_point(Cbi[k]) assert G.check_point(cdi[k]) # Recompute the challenge x = challenge(list(ck) + cis + Celi + Cai + Cbi + cdi + [ message ]) ret = True for i in range(n): ret &= x * Celi[i] + Cai[i] == Com(ck, fi[i], zai[i]) ret &= (x - fi[i]) * Celi[i] + Cbi[i] == Com(ck, Bn(0), zbi[i]) # acc = G.infinite() bases = [] expons = [] for idx, ci in enumerate(cis): idx = Bn(idx) idxi = [Bn(int(idx.is_bit_set(i))) for i in range(n)] acc_exp = Bn(1) for k, ij in enumerate(idxi): if ij == 0: acc_exp = acc_exp.mod_mul(x - fi[k], o) else: acc_exp = acc_exp.mod_mul(fi[k], o) bases += [ ci ] expons += [ acc_exp ] # acc = acc + acc_exp * ci for k in range(n): expi = (- pow(x,k,o)) # acc = acc + expi * cdi[k] bases += [ cdi[k] ] expons += [ expi ] # assert G.wsum(expons, bases) == acc acc = G.wsum(expons, bases) ret &= acc == Com(ck, 0, zd) return ret