def gen_mlsag(pk, xx, index): """ Multilayered Spontaneous Anonymous Group Signatures (MLSAG signatures) These are aka MG signatutes in earlier drafts of the ring ct paper c.f. http://eprint.iacr.org/2015/1098 section 2. keyImageV just does I[i] = xx[i] * Hash(xx[i] * G) for each i Gen creates a signature which proves that for some column in the keymatrix "pk" the signer knows a secret key for each row in that column Ver verifies that the MG sig was created correctly :param pk: :param xx: :param index: :return: """ rows = len(xx) cols = len(pk) logger.debug("Generating MG sig of size %s x %s" % (rows, cols)) logger.debug("index is: %s, %s" % (index, pk[index])) c = [None] * cols alpha = scalar_gen_vector(rows) I = key_image_vector(xx) L = key_matrix(rows, cols) R = key_matrix(rows, cols) s = key_matrix(rows, cols) m = "".join(pk[0]) for i in range(1, cols): m = m + "".join(pk[i]) L[index] = [crypto.scalarmult_base(aa) for aa in alpha] # L = aG Hi = hash_key_vector(pk[index]) R[index] = [crypto.scalarmult(Hi[ii], alpha[ii]) for ii in range(0, rows)] # R = aI oldi = index i = (index + 1) % cols c[i] = crypto.cn_fast_hash(m + "".join(L[oldi]) + "".join(R[oldi])) while i != index: s[i] = scalar_gen_vector(rows) L[i] = [ crypto.add_keys2(s[i][j], c[i], pk[i][j]) for j in range(0, rows) ] Hi = hash_key_vector(pk[i]) R[i] = [ crypto.add_keys3(s[i][j], Hi[j], c[i], I[j]) for j in range(0, rows) ] oldi = i i = (i + 1) % cols c[i] = crypto.cn_fast_hash(m + "".join(L[oldi]) + "".join(R[oldi])) s[index] = [ crypto.sc_mulsub(c[index], xx[j], alpha[j]) for j in range(0, rows) ] # alpha - c * x return I, c[0], s
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_point(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.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 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.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
async def mlsag_sign(self): if self.sig_mode == TRANSACTION_CREATE_FAKE: xin = crypto.decodeint(self._fetch()) alpha = crypto.decodeint(self._fetch()) elif self.sig_mode == TRANSACTION_CREATE_REAL: xin = crypto.decodeint(self._fetch_decrypt()) alpha = crypto.decodeint(self._fetch_decrypt()) else: raise ValueError("Invalid mode") ss2 = crypto.sc_mulsub(self.c, xin, alpha) self._insert(crypto.encodeint(ss2)) self._insert_u32(self.sig_mode) return SW_OK
def gen_schnorr_non_linkable(x, P1, P2, index): """ Generates simple Schnorr :param x: :param P1: :param P2: :param index: :return: """ a = crypto.random_scalar() L1 = crypto.scalarmult_base(a) s2 = crypto.random_scalar() c2 = crypto.cn_fast_hash(crypto.encodepoint(L1)) L2 = crypto.point_add( crypto.scalarmult_base(s2), crypto.scalarmult(P2 if index == 0 else P1, crypto.decodeint(c2)), ) c1 = crypto.cn_fast_hash(crypto.encodepoint(L2)) s1 = crypto.sc_mulsub(x, crypto.decodeint(c1), a) return (L1, s1, s2) if index == 0 else (L2, s2, s1)
def generate_ring_signature(prefix_hash, image, pubs, sec, sec_idx, test=False): """ Generates ring signature with key image. void crypto_ops::generate_ring_signature() """ if test: t = crypto.scalarmult_base(sec) if not crypto.point_eq(t, pubs[sec_idx]): raise ValueError("Invalid sec key") k_i = monero.generate_key_image(crypto.encodepoint(pubs[sec_idx]), sec) if not crypto.point_eq(k_i, image): raise ValueError("Key image invalid") for k in pubs: crypto.ge_frombytes_vartime_check(k) image_unp = crypto.ge_frombytes_vartime(image) image_pre = crypto.ge_dsm_precomp(image_unp) buff_off = len(prefix_hash) buff = bytearray(buff_off + 2 * 32 * len(pubs)) memcpy(buff, 0, prefix_hash, 0, buff_off) mvbuff = memoryview(buff) sum = crypto.sc_0() k = crypto.sc_0() sig = [] for i in range(len(pubs)): sig.append([crypto.sc_0(), crypto.sc_0()]) # c, r for i in range(len(pubs)): if i == sec_idx: k = crypto.random_scalar() tmp3 = crypto.scalarmult_base(k) crypto.encodepoint_into(mvbuff[buff_off:buff_off + 32], tmp3) buff_off += 32 tmp3 = crypto.hash_to_point(crypto.encodepoint(pubs[i])) tmp2 = crypto.scalarmult(tmp3, k) crypto.encodepoint_into(mvbuff[buff_off:buff_off + 32], tmp2) buff_off += 32 else: sig[i] = [crypto.random_scalar(), crypto.random_scalar()] tmp3 = crypto.ge_frombytes_vartime(pubs[i]) tmp2 = crypto.ge_double_scalarmult_base_vartime( sig[i][0], tmp3, sig[i][1]) crypto.encodepoint_into(mvbuff[buff_off:buff_off + 32], tmp2) buff_off += 32 tmp3 = crypto.hash_to_point(crypto.encodepoint(tmp3)) tmp2 = crypto.ge_double_scalarmult_precomp_vartime( sig[i][1], tmp3, sig[i][0], image_pre) crypto.encodepoint_into(mvbuff[buff_off:buff_off + 32], tmp2) buff_off += 32 sum = crypto.sc_add(sum, sig[i][0]) h = crypto.hash_to_scalar(buff) sig[sec_idx][0] = crypto.sc_sub(h, sum) sig[sec_idx][1] = crypto.sc_mulsub(sig[sec_idx][0], sec, k) return sig
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 :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.xmr_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.decodeint(kck.digest()) del kck # Second phase computes: s0, s1 c_H = crypto.xmr_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
def generate_ring_signature(prefix_hash, image, pubs, sec, sec_idx, test=False): """ Generates ring signature with key image. void crypto_ops::generate_ring_signature() :param prefix_hash: :param image: :param pubs: :param sec: :param sec_idx: :param test: :return: """ if test: t = crypto.scalarmult_base(sec) if not crypto.point_eq(t, pubs[sec_idx]): raise ValueError("Invalid sec key") k_i = monero.generate_key_image(crypto.encodepoint(pubs[sec_idx]), sec) if not crypto.point_eq(k_i, image): raise ValueError("Key image invalid") for k in pubs: crypto.ge_frombytes_vartime_check(k) image_unp = crypto.ge_frombytes_vartime(image) image_pre = crypto.ge_dsm_precomp(image_unp) buff = b"" + prefix_hash sum = crypto.sc_0() k = crypto.sc_0() sig = [] for i in range(len(pubs)): sig.append([crypto.sc_0(), crypto.sc_0()]) # c, r for i in range(len(pubs)): if i == sec_idx: k = crypto.random_scalar() tmp3 = crypto.scalarmult_base(k) buff += crypto.encodepoint(tmp3) tmp3 = crypto.hash_to_ec(crypto.encodepoint(pubs[i])) tmp2 = crypto.scalarmult(tmp3, k) buff += crypto.encodepoint(tmp2) else: sig[i] = [crypto.random_scalar(), crypto.random_scalar()] tmp3 = crypto.ge_frombytes_vartime(pubs[i]) tmp2 = crypto.ge_double_scalarmult_base_vartime( sig[i][0], tmp3, sig[i][1]) buff += crypto.encodepoint(tmp2) tmp3 = crypto.hash_to_ec(crypto.encodepoint(tmp3)) tmp2 = crypto.ge_double_scalarmult_precomp_vartime( sig[i][1], tmp3, sig[i][0], image_pre) buff += crypto.encodepoint(tmp2) sum = crypto.sc_add(sum, sig[i][0]) h = crypto.hash_to_scalar(buff) sig[sec_idx][0] = crypto.sc_sub(h, sum) sig[sec_idx][1] = crypto.sc_mulsub(sig[sec_idx][0], sec, k) return sig