def sub_keys(dst, A, B): dst = _ensure_dst_key(dst) crypto.decodepoint_into(tmp_pt_1, A) crypto.decodepoint_into(tmp_pt_2, B) crypto.point_sub_into(tmp_pt_3, tmp_pt_1, tmp_pt_2) crypto.encodepoint_into(dst, tmp_pt_3) return dst
async def _sync_step(s, ctx, tds): if not tds.tdis: raise wire.DataError("Empty") kis = [] buff = bytearray(32 * 3) buff_mv = memoryview(buff) await confirms.keyimage_sync_step(ctx, s.current_output, s.num_outputs) for td in tds.tdis: s.current_output += 1 if s.current_output >= s.num_outputs: raise wire.DataError("Too many outputs") if __debug__: log.debug(__name__, "ki_sync, step i: %d", s.current_output) # Update the control hash s.hasher.update(key_image.compute_hash(td)) # Compute keyimage + signature ki, sig = key_image.export_key_image(s.creds, s.subaddresses, td) # Serialize into buff crypto.encodepoint_into(buff_mv[0:32], ki) crypto.encodeint_into(buff_mv[32:64], sig[0][0]) crypto.encodeint_into(buff_mv[64:], sig[0][1]) # Encrypt with enc_key nonce, ciph, _ = chacha_poly.encrypt(s.enc_key, buff) kis.append(MoneroExportedKeyImage(iv=nonce, blob=ciph)) return MoneroKeyImageSyncStepAck(kis=kis)
def ctest_multiexp(self): scalars = [0, 1, 2, 3, 4, 99] point_base = [0, 2, 4, 7, 12, 18] scalar_sc = [crypto.sc_init(x) for x in scalars] points = [ crypto.scalarmult_base(crypto.sc_init(x)) for x in point_base ] muex = bp.MultiExp( scalars=[crypto.encodeint(x) for x in scalar_sc], point_fnc=lambda i, d: crypto.encodepoint(points[i])) self.assertEqual(len(muex), len(scalars)) res = bp.multiexp(None, muex) res2 = bp.vector_exponent_custom( A=bp.KeyVEval( 3, lambda i, d: crypto.encodepoint_into( crypto.scalarmult_base(crypto.sc_init(point_base[i])), d)), B=bp.KeyVEval( 3, lambda i, d: crypto.encodepoint_into( crypto.scalarmult_base(crypto.sc_init(point_base[3 + i])), d)), a=bp.KeyVEval( 3, lambda i, d: crypto.encodeint_into(crypto.sc_init(scalars[i]), d), ), b=bp.KeyVEval( 3, lambda i, d: crypto.encodeint_into( crypto.sc_init(scalars[i + 3]), d)), ) self.assertEqual(res, res2)
def _set_out_tx_out( state: State, dst_entr: MoneroTransactionDestinationEntry, tx_out_key: crypto.Point, derivation: crypto.Point, ) -> tuple[bytes, bytes]: """ Manually serializes TxOut(0, TxoutToKey(key)) and calculates hmac. """ use_tags = state.hard_fork >= 15 tx_out_bin = bytearray(35 if use_tags else 34) tx_out_bin[0] = 0 # amount varint tx_out_bin[1] = (3 if use_tags else 2 ) # variant code txout_to_tagged_key or txout_to_key crypto.encodepoint_into(tx_out_bin, tx_out_key, 2) if use_tags: view_tag = _derive_view_tags(derivation, state.current_output_index) tx_out_bin[-1] = view_tag[0] state.mem_trace(8, True) # Tx header prefix hashing state.tx_prefix_hasher.buffer(tx_out_bin) state.mem_trace(9, True) # Hmac dst_entr hmac_vouti = offloading_keys.gen_hmac_vouti(state.key_hmac, dst_entr, tx_out_bin, state.current_output_index) state.mem_trace(10, True) return tx_out_bin, hmac_vouti
def scalarmult_key(dst, P, s): dst = _ensure_dst_key(dst) crypto.decodepoint_into(tmp_pt_1, P) crypto.decodeint_into_noreduce(tmp_sc_1, s) crypto.scalarmult_into(tmp_pt_2, tmp_pt_1, tmp_sc_1) crypto.encodepoint_into(dst, tmp_pt_2) return dst
def _add_tx_pub_key_to_extra(tx_extra, pub_key): """ Adds public key to the extra """ to_add = bytearray(33) to_add[0] = 1 # TX_EXTRA_TAG_PUBKEY crypto.encodepoint_into(memoryview(to_add)[1:], pub_key) return tx_extra + to_add
def add_keys2(dst, a, b, B): dst = _ensure_dst_key(dst) crypto.decodeint_into_noreduce(tmp_sc_1, a) crypto.decodeint_into_noreduce(tmp_sc_2, b) crypto.decodepoint_into(tmp_pt_1, B) crypto.add_keys2_into(tmp_pt_2, tmp_sc_1, tmp_sc_2, tmp_pt_1) crypto.encodepoint_into(dst, tmp_pt_2) return dst
def get_exponent(dst, base, idx): dst = _ensure_dst_key(dst) salt = b"bulletproof" idx_size = uvarint_size(idx) final_size = len(salt) + 32 + idx_size buff = tmp_bf_exp_mv memcpy(buff, 0, base, 0, 32) memcpy(buff, 32, salt, 0, len(salt)) dump_uvarint_b_into(idx, buff, 32 + len(salt)) crypto.keccak_hash_into(tmp_bf_1, buff[:final_size]) crypto.hash_to_point_into(tmp_pt_1, tmp_bf_1) crypto.encodepoint_into(dst, tmp_pt_1) return dst
def vector_exponent_custom(A, B, a, b, dst=None): dst = _ensure_dst_key(dst) crypto.identity_into(tmp_pt_2) for i in range(len(a)): crypto.decodeint_into_noreduce(tmp_sc_1, a.to(i)) crypto.decodepoint_into(tmp_pt_3, A.to(i)) crypto.decodeint_into_noreduce(tmp_sc_2, b.to(i)) crypto.decodepoint_into(tmp_pt_4, B.to(i)) crypto.add_keys3_into(tmp_pt_1, tmp_sc_1, tmp_pt_3, tmp_sc_2, tmp_pt_4) crypto.point_add_into(tmp_pt_2, tmp_pt_2, tmp_pt_1) gc_iter(i) crypto.encodepoint_into(dst, tmp_pt_2) return dst
async def get_tx_keys(ctx: wire.Context, msg: MoneroGetTxKeyRequest, keychain: Keychain) -> MoneroGetTxKeyAck: await paths.validate_path(ctx, keychain, msg.address_n) do_deriv = msg.reason == _GET_TX_KEY_REASON_TX_DERIVATION await layout.require_confirm_tx_key(ctx, export_key=not do_deriv) creds = misc.get_creds(keychain, msg.address_n, msg.network_type) tx_enc_key = misc.compute_tx_key( creds.spend_key_private, msg.tx_prefix_hash, msg.salt1, crypto_helpers.decodeint(msg.salt2), ) # the plain_buff first stores the tx_priv_keys as decrypted here # and then is used to store the derivations if applicable plain_buff = chacha_poly.decrypt_pack(tx_enc_key, msg.tx_enc_keys) utils.ensure(len(plain_buff) % 32 == 0, "Tx key buffer has invalid size") msg.tx_enc_keys = b"" # If return only derivations do tx_priv * view_pub if do_deriv: if msg.view_public_key is None: raise wire.DataError("Missing view public key") plain_buff = bytearray(plain_buff) view_pub = crypto_helpers.decodepoint(msg.view_public_key) tx_priv = crypto.Scalar() derivation = crypto.Point() n_keys = len(plain_buff) // 32 for c in range(n_keys): crypto.decodeint_into(tx_priv, plain_buff, 32 * c) crypto.scalarmult_into(derivation, view_pub, tx_priv) crypto.encodepoint_into(plain_buff, derivation, 32 * c) # Encrypt by view-key based password. tx_enc_key_host, salt = misc.compute_enc_key_host(creds.view_key_private, msg.tx_prefix_hash) res = chacha_poly.encrypt_pack(tx_enc_key_host, plain_buff) res_msg = MoneroGetTxKeyAck(salt=salt) if do_deriv: res_msg.tx_derivations = res return res_msg res_msg.tx_keys = res return res_msg
def _set_tx_extra(state: State) -> bytes: """ Sets tx public keys into transaction's extra. Extra field is supposed to be sorted (by sort_tx_extra() in the Monero) Tag ordering: TX_EXTRA_TAG_PUBKEY, TX_EXTRA_TAG_ADDITIONAL_PUBKEYS, TX_EXTRA_NONCE """ from apps.monero.xmr.serialize import int_serialize # Extra buffer length computation # TX_EXTRA_TAG_PUBKEY (1B) | tx_pub_key (32B) extra_size = 33 offset = 0 num_keys = 0 len_size = 0 if state.need_additional_txkeys: num_keys = len(state.additional_tx_public_keys) len_size = int_serialize.uvarint_size(num_keys) # TX_EXTRA_TAG_ADDITIONAL_PUBKEYS (1B) | varint | keys extra_size += 1 + len_size + 32 * num_keys if state.extra_nonce: extra_size += len(state.extra_nonce) extra = bytearray(extra_size) extra[0] = 1 # TX_EXTRA_TAG_PUBKEY crypto.encodepoint_into(memoryview(extra)[1:], state.tx_pub) offset += 33 if state.need_additional_txkeys: extra[offset] = 0x4 # TX_EXTRA_TAG_ADDITIONAL_PUBKEYS int_serialize.dump_uvarint_b_into(num_keys, extra, offset + 1) offset += 1 + len_size for idx in range(num_keys): extra[offset:offset + 32] = state.additional_tx_public_keys[idx] offset += 32 if state.extra_nonce: utils.memcpy(extra, offset, state.extra_nonce, 0, len(state.extra_nonce)) state.extra_nonce = None return extra
async def _set_out_tx_out(state: State, dst_entr, tx_out_key): """ Manually serializes TxOut(0, TxoutToKey(key)) and calculates hmac. """ tx_out_bin = bytearray(34) tx_out_bin[0] = 0 # amount varint tx_out_bin[1] = 2 # variant code TxoutToKey crypto.encodepoint_into(tx_out_bin, tx_out_key, 2) state.mem_trace(8) # Tx header prefix hashing state.tx_prefix_hasher.buffer(tx_out_bin) state.mem_trace(9, True) # Hmac dst_entr hmac_vouti = await offloading_keys.gen_hmac_vouti( state.key_hmac, dst_entr, tx_out_bin, state.current_output_index) state.mem_trace(10, True) return tx_out_bin, hmac_vouti
def _derive_view_tags(derivation: crypto.Point, output_index: int) -> bytes: """ Computes view tags for tx output - speeds up blockchain scanning for wallets view_tag_full = H["view_tag"|derivation|output_index] """ buff = bytearray(32) ctx = crypto_helpers.get_keccak() ctx.update(b"view_tag") crypto.encodepoint_into(buff, derivation) ctx.update(buff) # Correct way of serializing output_index is calling dump_uvarint_b_into, but we # know that output_index is always lower than 127 so we save imports and calls. if output_index > 127: raise ValueError("Output index too big") buff[0] = output_index ctx.update(buff[:1]) full_tag = ctx.digest() return full_tag[:1]
def check_ring_singature(prefix_hash, image, pubs, sig): """ Checks ring signature generated with generate_ring_signature :param prefix_hash: :param image: :param pubs: :param sig: :return: """ from apps.monero.xmr.common import memcpy 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() for i in range(len(pubs)): if crypto.sc_check(sig[i][0]) != 0 or crypto.sc_check(sig[i][1]) != 0: return False 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(pubs[i])) 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) h = crypto.sc_sub(h, sum) return crypto.sc_isnonzero(h) == 0
def _encrypt_payment_id(payment_id, public_key, secret_key): """ Encrypts payment_id hex. Used in the transaction extra. Only recipient is able to decrypt. """ derivation_p = crypto.generate_key_derivation(public_key, secret_key) derivation = bytearray(33) derivation = crypto.encodepoint_into(derivation, derivation_p) derivation[32] = 0x8D # ENCRYPTED_PAYMENT_ID_TAIL hash = crypto.cn_fast_hash(derivation) pm_copy = bytearray(payment_id) return crypto.xor8(pm_copy, hash)
def hadamard_fold(v, a, b, into=None, into_offset=0): """ Folds a curvepoint array using a two way scaled Hadamard product ln = len(v); h = ln // 2 v[i] = a * v[i] + b * v[h + i] """ h = len(v) // 2 crypto.decodeint_into_noreduce(tmp_sc_1, a) crypto.decodeint_into_noreduce(tmp_sc_2, b) into = into if into else v for i in range(h): crypto.decodepoint_into(tmp_pt_1, v.to(i)) crypto.decodepoint_into(tmp_pt_2, v.to(h + i)) crypto.add_keys3_into(tmp_pt_3, tmp_sc_1, tmp_pt_1, tmp_sc_2, tmp_pt_2) crypto.encodepoint_into(tmp_bf_0, tmp_pt_3) into.read(i + into_offset, tmp_bf_0) gc_iter(i) return into
def _encrypt_payment_id(payment_id, public_key, secret_key): """ Encrypts payment_id hex. Used in the transaction extra. Only recipient is able to decrypt. """ derivation_p = crypto.generate_key_derivation(public_key, secret_key) derivation = bytearray(33) derivation = crypto.encodepoint_into(derivation, derivation_p) derivation[32] = 0x8B hash = crypto.cn_fast_hash(derivation) pm_copy = bytearray(payment_id) for i in range(8): pm_copy[i] ^= hash[i] return pm_copy
def _generate_clsag( message: bytes, P: List[bytes], p: Sc25519, C_nonzero: List[bytes], z: Sc25519, Cout: Ge25519, index: int, mg_buff: List[bytes], ) -> List[bytes]: sI = crypto.new_point() # sig.I sD = crypto.new_point() # sig.D sc1 = crypto.new_scalar() # sig.c1 a = crypto.random_scalar() H = crypto.new_point() D = crypto.new_point() Cout_bf = crypto.encodepoint(Cout) tmp_sc = crypto.new_scalar() tmp = crypto.new_point() tmp_bf = bytearray(32) crypto.hash_to_point_into(H, P[index]) crypto.scalarmult_into(sI, H, p) # I = p*H crypto.scalarmult_into(D, H, z) # D = z*H crypto.sc_mul_into(tmp_sc, z, crypto.sc_inv_eight()) # 1/8*z crypto.scalarmult_into(sD, H, tmp_sc) # sig.D = 1/8*z*H sD = crypto.encodepoint(sD) hsh_P = crypto.get_keccak() # domain, I, D, P, C, C_offset hsh_C = crypto.get_keccak() # domain, I, D, P, C, C_offset hsh_P.update(_HASH_KEY_CLSAG_AGG_0) hsh_C.update(_HASH_KEY_CLSAG_AGG_1) def hsh_PC(x): nonlocal hsh_P, hsh_C hsh_P.update(x) hsh_C.update(x) for x in P: hsh_PC(x) for x in C_nonzero: hsh_PC(x) hsh_PC(crypto.encodepoint_into(tmp_bf, sI)) hsh_PC(sD) hsh_PC(Cout_bf) mu_P = crypto.decodeint(hsh_P.digest()) mu_C = crypto.decodeint(hsh_C.digest()) del (hsh_PC, hsh_P, hsh_C) c_to_hash = crypto.get_keccak() # domain, P, C, C_offset, message, aG, aH c_to_hash.update(_HASH_KEY_CLSAG_ROUND) for i in range(len(P)): c_to_hash.update(P[i]) for i in range(len(P)): c_to_hash.update(C_nonzero[i]) c_to_hash.update(Cout_bf) c_to_hash.update(message) chasher = c_to_hash.copy() crypto.scalarmult_base_into(tmp, a) chasher.update(crypto.encodepoint_into(tmp_bf, tmp)) # aG crypto.scalarmult_into(tmp, H, a) chasher.update(crypto.encodepoint_into(tmp_bf, tmp)) # aH c = crypto.decodeint(chasher.digest()) del (chasher, H) L = crypto.new_point() R = crypto.new_point() c_p = crypto.new_scalar() c_c = crypto.new_scalar() i = (index + 1) % len(P) if i == 0: crypto.sc_copy(sc1, c) mg_buff.append(int_serialize.dump_uvarint_b(len(P))) for _ in range(len(P)): mg_buff.append(bytearray(32)) while i != index: crypto.random_scalar(tmp_sc) crypto.encodeint_into(mg_buff[i + 1], tmp_sc) crypto.sc_mul_into(c_p, mu_P, c) crypto.sc_mul_into(c_c, mu_C, c) # L = tmp_sc * G + c_P * P[i] + c_c * C[i] crypto.add_keys2_into(L, tmp_sc, c_p, crypto.decodepoint_into(tmp, P[i])) crypto.decodepoint_into(tmp, C_nonzero[i]) # C = C_nonzero - Cout crypto.point_sub_into(tmp, tmp, Cout) crypto.scalarmult_into(tmp, tmp, c_c) crypto.point_add_into(L, L, tmp) # R = tmp_sc * HP + c_p * I + c_c * D crypto.hash_to_point_into(tmp, P[i]) crypto.add_keys3_into(R, tmp_sc, tmp, c_p, sI) crypto.point_add_into(R, R, crypto.scalarmult_into(tmp, D, c_c)) chasher = c_to_hash.copy() chasher.update(crypto.encodepoint_into(tmp_bf, L)) chasher.update(crypto.encodepoint_into(tmp_bf, R)) crypto.decodeint_into(c, chasher.digest()) P[i] = None C_nonzero[i] = None i = (i + 1) % len(P) if i == 0: crypto.sc_copy(sc1, c) if i & 3 == 0: gc.collect() # Final scalar = a - c * (mu_P * p + mu_c * Z) crypto.sc_mul_into(tmp_sc, mu_P, p) crypto.sc_muladd_into(tmp_sc, mu_C, z, tmp_sc) crypto.sc_mulsub_into(tmp_sc, c, tmp_sc, a) crypto.encodeint_into(mg_buff[index + 1], tmp_sc) mg_buff.append(crypto.encodeint(sc1)) mg_buff.append(sD) return mg_buff
def eval(self, dst, GiHi=False): dst = _ensure_dst_key(dst) return crypto.encodepoint_into(dst, self.acc)
def prove_range_borromean(amount, last_mask): """Calculates Borromean range proof""" # The large chunks allocated first to avoid potential memory fragmentation issues. ai = bytearray(32 * 64) alphai = bytearray(32 * 64) Cis = bytearray(32 * 64) s0s = bytearray(32 * 64) s1s = bytearray(32 * 64) buff = bytearray(32) ee_bin = bytearray(32) a = crypto.sc_init(0) si = crypto.sc_init(0) c = crypto.sc_init(0) ee = crypto.sc_init(0) tmp_ai = crypto.sc_init(0) tmp_alpha = crypto.sc_init(0) C_acc = crypto.identity() C_h = crypto.xmr_H() C_tmp = crypto.identity() L = crypto.identity() kck = crypto.get_keccak() for ii in range(64): crypto.random_scalar(tmp_ai) if last_mask is not None and ii == 63: crypto.sc_sub_into(tmp_ai, last_mask, a) crypto.sc_add_into(a, a, tmp_ai) crypto.random_scalar(tmp_alpha) crypto.scalarmult_base_into(L, tmp_alpha) crypto.scalarmult_base_into(C_tmp, tmp_ai) # if 0: C_tmp += Zero (nothing is added) # if 1: C_tmp += 2^i*H # 2^i*H is already stored in C_h if (amount >> ii) & 1 == 1: crypto.point_add_into(C_tmp, C_tmp, C_h) crypto.point_add_into(C_acc, C_acc, C_tmp) # Set Ci[ii] to sigs crypto.encodepoint_into(Cis, C_tmp, ii << 5) crypto.encodeint_into(ai, tmp_ai, ii << 5) crypto.encodeint_into(alphai, tmp_alpha, ii << 5) if ((amount >> ii) & 1) == 0: crypto.random_scalar(si) crypto.encodepoint_into(buff, L) crypto.hash_to_scalar_into(c, buff) crypto.point_sub_into(C_tmp, C_tmp, C_h) crypto.add_keys2_into(L, si, c, C_tmp) crypto.encodeint_into(s1s, si, ii << 5) crypto.encodepoint_into(buff, L) kck.update(buff) crypto.point_double_into(C_h, C_h) # Compute ee tmp_ee = kck.digest() crypto.decodeint_into(ee, tmp_ee) del (tmp_ee, kck) C_h = crypto.xmr_H() gc.collect() # Second pass, s0, s1 for ii in range(64): crypto.decodeint_into(tmp_alpha, alphai, ii << 5) crypto.decodeint_into(tmp_ai, ai, ii << 5) if ((amount >> ii) & 1) == 0: crypto.sc_mulsub_into(si, tmp_ai, ee, tmp_alpha) crypto.encodeint_into(s0s, si, ii << 5) else: crypto.random_scalar(si) crypto.encodeint_into(s0s, si, ii << 5) crypto.decodepoint_into(C_tmp, Cis, ii << 5) crypto.add_keys2_into(L, si, ee, C_tmp) crypto.encodepoint_into(buff, L) crypto.hash_to_scalar_into(c, buff) crypto.sc_mulsub_into(si, tmp_ai, c, tmp_alpha) crypto.encodeint_into(s1s, si, ii << 5) crypto.point_double_into(C_h, C_h) crypto.encodeint_into(ee_bin, ee) del (ai, alphai, buff, tmp_ai, tmp_alpha, si, c, ee, C_tmp, C_h, L) gc.collect() return C_acc, a, [s0s, s1s, ee_bin, Cis]
def verify_clsag(self, msg, ss, sc1, sI, sD, pubs, C_offset): n = len(pubs) c = crypto.Scalar() D_8 = crypto.Point() tmp_bf = bytearray(32) C_offset_bf = crypto_helpers.encodepoint(C_offset) crypto.sc_copy(c, sc1) point_mul8_into(D_8, sD) hsh_P = crypto_helpers.get_keccak() # domain, I, D, P, C, C_offset hsh_C = crypto_helpers.get_keccak() # domain, I, D, P, C, C_offset hsh_P.update(clsag._HASH_KEY_CLSAG_AGG_0) hsh_C.update(clsag._HASH_KEY_CLSAG_AGG_1) def hsh_PC(x): hsh_P.update(x) hsh_C.update(x) for x in pubs: hsh_PC(x.dest) for x in pubs: hsh_PC(x.commitment) hsh_PC(crypto.encodepoint_into(tmp_bf, sI)) hsh_PC(crypto.encodepoint_into(tmp_bf, sD)) hsh_PC(C_offset_bf) mu_P = crypto_helpers.decodeint(hsh_P.digest()) mu_C = crypto_helpers.decodeint(hsh_C.digest()) c_to_hash = crypto_helpers.get_keccak( ) # domain, P, C, C_offset, message, L, R c_to_hash.update(clsag._HASH_KEY_CLSAG_ROUND) for i in range(len(pubs)): c_to_hash.update(pubs[i].dest) for i in range(len(pubs)): c_to_hash.update(pubs[i].commitment) c_to_hash.update(C_offset_bf) c_to_hash.update(msg) c_p = crypto.Scalar() c_c = crypto.Scalar() L = crypto.Point() R = crypto.Point() tmp_pt = crypto.Point() i = 0 while i < n: crypto.sc_mul_into(c_p, mu_P, c) crypto.sc_mul_into(c_c, mu_C, c) C_P = crypto.point_sub_into( None, crypto.decodepoint_into(tmp_pt, pubs[i].commitment), C_offset) crypto.add_keys2_into( L, ss[i], c_p, crypto.decodepoint_into(tmp_pt, pubs[i].dest)) crypto.point_add_into(L, L, crypto.scalarmult_into(tmp_pt, C_P, c_c)) HP = crypto.hash_to_point_into(None, pubs[i].dest) crypto.add_keys3_into(R, ss[i], HP, c_p, sI) crypto.point_add_into(R, R, crypto.scalarmult_into(tmp_pt, D_8, c_c)) chasher = c_to_hash.copy() chasher.update(crypto.encodepoint_into(tmp_bf, L)) chasher.update(crypto.encodepoint_into(tmp_bf, R)) crypto.decodeint_into(c, chasher.digest()) i += 1 res = crypto.sc_sub_into(None, c, sc1) if not crypto.sc_eq(res, crypto.Scalar(0)): raise ValueError("Signature error")
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
def scalarmult_base(dst, x): dst = _ensure_dst_key(dst) crypto.decodeint_into_noreduce(tmp_sc_1, x) crypto.scalarmult_base_into(tmp_pt_1, tmp_sc_1) crypto.encodepoint_into(dst, tmp_pt_1) return dst
def scalarmultH(dst, x): dst = _ensure_dst_key(dst) crypto.decodeint_into(tmp_sc_1, x) crypto.scalarmult_into(tmp_pt_1, _XMR_HP, tmp_sc_1) crypto.encodepoint_into(dst, tmp_pt_1) return dst
def aci(mv, x, i): crypto.encodepoint_into(x, mv[32 * 64 * 2 + 32 + 32 * i:])
def _hash_point(hasher, point, tmp_buff): crypto.encodepoint_into(tmp_buff, point) hasher.update(tmp_buff)
def generate_ring_signature( prefix_hash: bytes, image: Ge25519, pubs: list[Ge25519], sec: Sc25519, sec_idx: int, test: bool = False, ) -> Sig: """ Generates ring signature with key image. void crypto_ops::generate_ring_signature() """ from trezor.utils import memcpy 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.check_ed25519point(k) 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 _ 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 = pubs[i] tmp2 = crypto.ge25519_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.ge25519_double_scalarmult_vartime2( sig[i][1], tmp3, sig[i][0], image) 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