def ver_borromean(P1, P2, s0, s1, ee): """ Verify range proof signature, Borromean (c.f. gmax/andytoshi's paper) :param P1: :param P2: :param s0: :param s1: :param ee: :return: """ n = len(P1) Lv1 = key_vector(n) for ii in range(n): LL = crypto.add_keys2(s0[ii], ee, P1[ii]) chash = crypto.hash_to_scalar(crypto.encodepoint(LL)) Lv1[ii] = crypto.add_keys2(s1[ii], chash, P2[ii]) kck = crypto.get_keccak() for ii in range(n): kck.update(crypto.encodepoint(Lv1[ii])) # ee_computed = crypto.hash_to_scalar(crypto.encodepoint(Lv1)) ee_computed = crypto.sc_reduce32(crypto.decodeint(kck.digest())) return crypto.sc_eq(ee_computed, ee)
def gen_mlsag_ext(message, pk, xx, kLRki, mscout, index, dsRows): """ Multilayered Spontaneous Anonymous Group Signatures (MLSAG signatures) :param message: :param pk: matrix of points, point form (not encoded) :param xx: :param kLRki: :param mscout: :param index: :param dsRows: :return: """ rows, cols = gen_mlsag_assert(pk, xx, kLRki, mscout, index, dsRows) rv = xmrtypes.MgSig() c, L, R, Hi = 0, None, None, None c_old, Ip, alpha = gen_mlsag_rows(message, rv, pk, xx, kLRki, index, dsRows, rows, cols) i = (index + 1) % cols if i == 0: rv.cc = c_old while i != index: rv.ss[i] = scalar_gen_vector(rows) hasher = hasher_message(message) for j in range(dsRows): L = crypto.add_keys2(rv.ss[i][j], c_old, pk[i][j]) Hi = crypto.hash_to_ec(crypto.encodepoint( pk[i][j])) # originally hashToPoint() R = crypto.add_keys3(rv.ss[i][j], Hi, c_old, Ip[j]) hasher.update(crypto.encodepoint(pk[i][j])) hasher.update(crypto.encodepoint(L)) hasher.update(crypto.encodepoint(R)) for j in range(dsRows, rows): L = crypto.add_keys2(rv.ss[i][j], c_old, pk[i][j]) hasher.update(crypto.encodepoint(pk[i][j])) hasher.update(crypto.encodepoint(L)) c = crypto.sc_reduce32(crypto.decodeint(hasher.digest())) c_old = c i = (i + 1) % cols if i == 0: rv.cc = c_old for j in range(rows): rv.ss[index][j] = crypto.sc_mulsub( c, xx[j], alpha[j]) # alpha[j] - c * xx[j]; sc_mulsub in original does c-ab if mscout: mscout(c) return rv, c
def generate_keys(recovery_key): """ Wallet gen. :param recovery_key: :return: """ sec = crypto.sc_reduce32(recovery_key) pub = crypto.scalarmult_base(sec) return sec, pub
def gen_mlsag_rows(message, rv, pk, xx, kLRki, index, dsRows, rows, cols): """ MLSAG computation - the part with secret keys :param message: :param rv: :param pk: :param xx: :param kLRki: :param index: :param dsRows: :param rows: :param cols: :return: """ Ip = key_vector(dsRows) rv.II = key_vector(dsRows) alpha = key_vector(rows) rv.ss = key_matrix(rows, cols) hasher = hasher_message(message) for i in range(dsRows): hasher.update(crypto.encodepoint(pk[index][i])) if kLRki: alpha[i] = kLRki.k rv.II[i] = kLRki.ki hasher.update(crypto.encodepoint(kLRki.L)) hasher.update(crypto.encodepoint(kLRki.R)) else: Hi = crypto.hash_to_ec(crypto.encodepoint( pk[index][i])) # originally hashToPoint() alpha[i] = crypto.random_scalar() aGi = crypto.scalarmult_base(alpha[i]) aHPi = crypto.scalarmult(Hi, alpha[i]) rv.II[i] = crypto.scalarmult(Hi, xx[i]) hasher.update(crypto.encodepoint(aGi)) hasher.update(crypto.encodepoint(aHPi)) Ip[i] = crypto.precomp(rv.II[i]) for i in range(dsRows, rows): alpha[i] = crypto.random_scalar() aGi = crypto.scalarmult_base(alpha[i]) hasher.update(crypto.encodepoint(pk[index][i])) hasher.update(crypto.encodepoint(aGi)) c_old = hasher.digest() c_old = crypto.sc_reduce32(crypto.decodeint(c_old)) return c_old, Ip, alpha
def ver_mlsag_ext(message, pk, rv, dsRows): """ Multilayered Spontaneous Anonymous Group Signatures (MLSAG signatures) c.f. http://eprint.iacr.org/2015/1098 section 2. keyImageV just does I[i] = xx[i] * Hash(xx[i] * G) for each i :param message: :param pk: matrix of EC points, point form. :param rv: :param dsRows: :return: """ rows, cols = ver_mlsag_assert(pk, rv, dsRows) c_old = rv.cc Ip = key_vector(dsRows) for i in range(dsRows): Ip[i] = crypto.precomp(rv.II[i]) i = 0 while i < cols: c = 0 hasher = hasher_message(message) for j in range(dsRows): L = crypto.add_keys2(rv.ss[i][j], c_old, pk[i][j]) Hi = crypto.hash_to_ec(crypto.encodepoint( pk[i][j])) # originally hashToPoint() R = crypto.add_keys3(rv.ss[i][j], Hi, c_old, Ip[j]) hasher.update(crypto.encodepoint(pk[i][j])) hasher.update(crypto.encodepoint(L)) hasher.update(crypto.encodepoint(R)) for j in range(dsRows, rows): L = crypto.add_keys2(rv.ss[i][j], c_old, pk[i][j]) hasher.update(crypto.encodepoint(pk[i][j])) hasher.update(crypto.encodepoint(L)) c = crypto.sc_reduce32(crypto.decodeint(hasher.digest())) c_old = c i += 1 c = crypto.sc_sub(c_old, rv.cc) return not crypto.sc_isnonzero(c)
def gen_borromean(x, P1, P2, indices): """ Generates Borromean signature for range proofs. :return: """ n = len(P1) alpha = key_zero_vector(n) s1 = key_zero_vector(n) kck = crypto.get_keccak() # ee computation for ii in range(n): alpha[ii] = crypto.random_scalar() L = crypto.scalarmult_base(alpha[ii]) if indices[ii] == 0: s1[ii] = crypto.random_scalar() c = crypto.hash_to_scalar(crypto.encodepoint(L)) L = crypto.add_keys2(s1[ii], c, P2[ii]) kck.update(crypto.encodepoint(L)) else: kck.update(crypto.encodepoint(L)) ee = crypto.sc_reduce32(crypto.decodeint(kck.digest())) del kck s0 = key_zero_vector(n) for jj in range(n): if not indices[jj]: s0[jj] = crypto.sc_mulsub(x[jj], ee, alpha[jj]) else: s0[jj] = crypto.random_scalar() LL = crypto.add_keys2(s0[jj], ee, P1[jj]) cc = crypto.hash_to_scalar(crypto.encodepoint(LL)) s1[jj] = crypto.sc_mulsub(x[jj], cc, alpha[jj]) return s0, s1, ee
def prove_range_mem(amount, last_mask=None): """ Memory optimized range proof. Gives C, and mask such that \sumCi = C c.f. http:#eprint.iacr.org/2015/1098 section 5.1 Ci is a commitment to either 0 or 2^i, i=0,...,63 thus this proves that "amount" is in [0, 2^ATOMS] mask is a such that C = aG + bH, and b = amount :param amount: :param last_mask: ai[ATOMS-1] will be computed as \sum_{i=0}^{ATOMS-2} a_i - last_mask :param use_asnl: use ASNL, used before Borromean :return: sumCi, mask, RangeSig. sumCi is Pedersen commitment on the amount value. sumCi = aG + amount*H mask is "a" from the Pedersent commitment above. """ n = ATOMS bb = d2b(amount, n) # gives binary form of bb in "digits" binary digits ai = [None] * len(bb) Ci = [None] * len(bb) a = crypto.sc_0() C = crypto.identity() alpha = mlsag2.key_zero_vector(n) s1 = mlsag2.key_zero_vector(n) c_H = crypto.gen_H() kck = crypto.get_keccak() # ee computation # First pass, generates: ai, alpha, Ci, ee, s1 for ii in range(n): ai[ii] = crypto.random_scalar() if last_mask is not None and ii == ATOMS - 1: ai[ii] = crypto.sc_sub(last_mask, a) a = crypto.sc_add( a, ai[ii] ) # creating the total mask since you have to pass this to receiver... alpha[ii] = crypto.random_scalar() L = crypto.scalarmult_base(alpha[ii]) if bb[ii] == 0: Ci[ii] = crypto.scalarmult_base(ai[ii]) else: Ci[ii] = crypto.point_add(crypto.scalarmult_base(ai[ii]), c_H) C = crypto.point_add(C, Ci[ii]) if bb[ii] == 0: s1[ii] = crypto.random_scalar() c = crypto.hash_to_scalar(crypto.encodepoint(L)) L = crypto.add_keys2(s1[ii], c, crypto.point_sub(Ci[ii], c_H)) kck.update(crypto.encodepoint(L)) else: kck.update(crypto.encodepoint(L)) c_H = crypto.point_double(c_H) # Compute ee, memory cleanup ee = crypto.sc_reduce32(crypto.decodeint(kck.digest())) del kck # Second phase computes: s0, s1 c_H = crypto.gen_H() s0 = mlsag2.key_zero_vector(n) for jj in range(n): if not bb[jj]: s0[jj] = crypto.sc_mulsub(ai[jj], ee, alpha[jj]) else: s0[jj] = crypto.random_scalar() LL = crypto.add_keys2(s0[jj], ee, Ci[jj]) cc = crypto.hash_to_scalar(crypto.encodepoint(LL)) s1[jj] = crypto.sc_mulsub(ai[jj], cc, alpha[jj]) c_H = crypto.point_double(c_H) A = xmrtypes.BoroSig() A.s0, A.s1, A.ee = s0, s1, ee R = xmrtypes.RangeSig() R.asig = A R.Ci = Ci return C, a, R