def ecdh_encode(unmasked, receiver_pk=None, derivation=None): """ Elliptic Curve Diffie-Helman: encodes and decodes the amount b and mask a where C= aG + bH :param unmasked: :param receiver_pk: :param derivation: :return: """ from apps.monero.xmr.serialize_messages.tx_ecdh import EcdhTuple rv = EcdhTuple() if derivation is None: esk = crypto.random_scalar() rv.senderPk = crypto.scalarmult_base(esk) derivation = crypto.encodepoint(crypto.scalarmult(receiver_pk, esk)) sharedSec1 = crypto.hash_to_scalar(derivation) sharedSec2 = crypto.hash_to_scalar(crypto.encodeint(sharedSec1)) rv.mask = crypto.sc_add(unmasked.mask, sharedSec1) rv.amount = crypto.sc_add(unmasked.amount, sharedSec2) return rv
def generate_mlsag_full(message, pubs, in_sk, out_sk_mask, out_pk_commitments, kLRki, index, txn_fee_key): cols = len(pubs) if cols == 0: raise ValueError("Empty pubs") rows = len(pubs[0]) if rows == 0: raise ValueError("Empty pub row") for i in range(cols): if len(pubs[i]) != rows: raise ValueError("pub is not rectangular") if len(in_sk) != rows: raise ValueError("Bad inSk size") if len(out_sk_mask) != len(out_pk_commitments): raise ValueError("Bad outsk/putpk size") sk = _key_vector(rows + 1) M = _key_matrix(rows + 1, cols) for i in range(rows + 1): sk[i] = crypto.sc_0() for i in range(cols): M[i][rows] = crypto.identity() for j in range(rows): M[i][j] = crypto.decodepoint(pubs[i][j].dest) M[i][rows] = crypto.point_add( M[i][rows], crypto.decodepoint(pubs[i][j].commitment)) sk[rows] = crypto.sc_0() for j in range(rows): sk[j] = in_sk[j].dest sk[rows] = crypto.sc_add(sk[rows], in_sk[j].mask) # add masks in last row for i in range(cols): for j in range(len(out_pk_commitments)): M[i][rows] = crypto.point_sub( M[i][rows], crypto.decodepoint( out_pk_commitments[j])) # subtract output Ci's in last row # Subtract txn fee output in last row M[i][rows] = crypto.point_sub(M[i][rows], txn_fee_key) for j in range(len(out_pk_commitments)): sk[rows] = crypto.sc_sub( sk[rows], out_sk_mask[j]) # subtract output masks in last row return generate_mlsag(message, M, sk, kLRki, index, rows)
def _ecdh_encode(mask, amount, amount_key, v2=False): """ Output recipients need be able to reconstruct the amount commitments. This means the blinding factor `mask` and `amount` must be communicated to the receiver somehow. The mask and amount are stored as: - mask = mask + Hs(amount_key) - amount = amount + Hs(Hs(amount_key)) Because the receiver can derive the `amount_key` they can easily derive both mask and amount as well. """ from apps.monero.xmr.serialize_messages.tx_ecdh import EcdhTuple ecdh_info = EcdhTuple(mask=mask, amount=crypto.sc_init(amount)) if v2: amnt = ecdh_info.amount ecdh_info.mask = crypto.NULL_KEY_ENC ecdh_info.amount = bytearray(32) crypto.encodeint_into(ecdh_info.amount, amnt) crypto.xor8(ecdh_info.amount, _ecdh_hash(amount_key)) return ecdh_info else: amount_key_hash_single = crypto.hash_to_scalar(amount_key) amount_key_hash_double = crypto.hash_to_scalar( crypto.encodeint(amount_key_hash_single)) # Not modifying passed mask, is reused in BP. ecdh_info.mask = crypto.sc_add(ecdh_info.mask, amount_key_hash_single) crypto.sc_add_into(ecdh_info.amount, ecdh_info.amount, amount_key_hash_double) ecdh_info.mask = crypto.encodeint(ecdh_info.mask) ecdh_info.amount = crypto.encodeint(ecdh_info.amount) return ecdh_info
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: """ from apps.monero.xmr.common import memcpy if test: from apps.monero.xmr import monero 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(tmp3, mvbuff[buff_off:buff_off + 32]) buff_off += 32 tmp3 = crypto.hash_to_ec(crypto.encodepoint(pubs[i])) tmp2 = crypto.scalarmult(tmp3, k) crypto.encodepoint_into(tmp2, mvbuff[buff_off:buff_off + 32]) 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(tmp2, mvbuff[buff_off:buff_off + 32]) buff_off += 32 tmp3 = crypto.hash_to_ec(crypto.encodepoint(tmp3)) tmp2 = crypto.ge_double_scalarmult_precomp_vartime( sig[i][1], tmp3, sig[i][0], image_pre) crypto.encodepoint_into(tmp2, mvbuff[buff_off:buff_off + 32]) 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