def _det_mask(self, i, is_sL=True, dst=None): dst = _ensure_dst_key(dst) if self.fnc_det_mask: return self.fnc_det_mask(i, is_sL, dst) self.tmp_det_buff[64] = int(is_sL) memcpy(self.tmp_det_buff, 65, _ZERO, 0, 4) dump_uvarint_b_into(i, self.tmp_det_buff, 65) crypto.hash_to_scalar_into(self.tmp_sc_1, self.tmp_det_buff) crypto.encodeint_into(dst, self.tmp_sc_1) 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 _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
def _add_additional_tx_pub_keys_to_extra(tx_extra, pub_keys): """ Adds all additional tx public keys to the extra buffer """ from apps.monero.xmr.serialize import int_serialize # format: variant_tag (0x4) | array len varint | 32B | 32B | ... num_keys = len(pub_keys) len_size = int_serialize.uvarint_size(num_keys) buffer = bytearray(1 + len_size + 32 * num_keys) buffer[0] = 0x4 # TX_EXTRA_TAG_ADDITIONAL_PUBKEYS int_serialize.dump_uvarint_b_into(num_keys, buffer, 1) # uvarint(num_keys) offset = 1 + len_size for idx in range(num_keys): buffer[offset : offset + 32] = pub_keys[idx] offset += 32 tx_extra += buffer return tx_extra
def generate_mlsag( message: bytes, pk: KeyM, xx: List[Sc25519], index: int, dsRows: int, mg_buff: List[bytes], ) -> List[bytes]: """ Multilayered Spontaneous Anonymous Group Signatures (MLSAG signatures) :param message: the full message to be signed (actually its hash) :param pk: matrix of public keys and commitments :param xx: input secret array composed of a private key and commitment mask :param index: specifies corresponding public key to the `xx`'s private key in the `pk` array :param dsRows: separates pubkeys from commitment :param mg_buff: mg signature buffer """ rows, cols = gen_mlsag_assert(pk, xx, index, dsRows) rows_b_size = int_serialize.uvarint_size(rows) # Preallocation of the chunked buffer, len + cols + cc for _ in range(1 + cols + 1): mg_buff.append(None) mg_buff[0] = int_serialize.dump_uvarint_b(cols) cc = crypto.new_scalar() # rv.cc c = crypto.new_scalar() L = crypto.new_point() R = crypto.new_point() Hi = crypto.new_point() # calculates the "first" c, key images and random scalars alpha c_old, II, alpha = generate_first_c_and_key_images(message, pk, xx, index, dsRows, rows, cols) i = (index + 1) % cols if i == 0: crypto.sc_copy(cc, c_old) ss = [crypto.new_scalar() for _ in range(rows)] tmp_buff = bytearray(32) while i != index: hasher = _hasher_message(message) # Serialize size of the row mg_buff[i + 1] = bytearray(rows_b_size + 32 * rows) int_serialize.dump_uvarint_b_into(rows, mg_buff[i + 1]) for x in ss: crypto.random_scalar(x) for j in range(dsRows): # L = rv.ss[i][j] * G + c_old * pk[i][j] crypto.add_keys2_into(L, ss[j], c_old, crypto.decodepoint_into(Hi, pk[i][j])) crypto.hash_to_point_into(Hi, pk[i][j]) # R = rv.ss[i][j] * H(pk[i][j]) + c_old * Ip[j] crypto.add_keys3_into(R, ss[j], Hi, c_old, II[j]) hasher.update(pk[i][j]) _hash_point(hasher, L, tmp_buff) _hash_point(hasher, R, tmp_buff) for j in range(dsRows, rows): # again, omitting R here as discussed above crypto.add_keys2_into(L, ss[j], c_old, crypto.decodepoint_into(Hi, pk[i][j])) hasher.update(pk[i][j]) _hash_point(hasher, L, tmp_buff) for si in range(rows): crypto.encodeint_into(mg_buff[i + 1], ss[si], rows_b_size + 32 * si) crypto.decodeint_into(c, hasher.digest()) crypto.sc_copy(c_old, c) pk[i] = None i = (i + 1) % cols if i == 0: crypto.sc_copy(cc, c_old) gc.collect() del II # Finalizing rv.ss by processing rv.ss[index] mg_buff[index + 1] = bytearray(rows_b_size + 32 * rows) int_serialize.dump_uvarint_b_into(rows, mg_buff[index + 1]) for j in range(rows): crypto.sc_mulsub_into(ss[j], c, xx[j], alpha[j]) crypto.encodeint_into(mg_buff[index + 1], ss[j], rows_b_size + 32 * j) # rv.cc mg_buff[-1] = crypto.encodeint(cc) return mg_buff