一、MLSCA原理介绍

基于机器学习的侧信道分析(MLSCA)是一种结合传统侧信道分析技术与现代机器学习算法的密码分析方法。该方法通过分析密码设备运行时的物理泄漏信息(如功耗、电磁辐射等),利用机器学习模型建立泄漏数据与密钥信息之间的关联模型,从而实现对密钥的恢复攻击。与传统分析方法相比,MLSCA能够自动提取特征并处理复杂的非线性关系,显著提高了攻击效率。

MLSCA的核心思想是将侧信道攻击转化为分类或回归问题。在本文中,攻击者针对AES算法的S盒输出汉明重量构建分类模型。汉明重量反映了数据在硬件处理时的功耗特征,是侧信道分析中最常用的泄漏模型之一。通过采集大量已知明文的功耗曲线,机器学习模型学习不同汉明重量对应的功耗模式特征,进而预测未知曲线对应的中间值,最终通过统计分析恢复出密钥信息。

该方法通常包含两个阶段:模板构建阶段和匹配攻击阶段。模板构建阶段使用已知密钥的功耗数据训练机器学习模型,建立中间值与功耗特征的映射关系。匹配攻击阶段则利用训练好的模型分析目标设备的未知功耗曲线,通过比较预测结果与假设中间值的匹配程度,逐步缩小密钥候选范围,最终确定最可能的密钥值。支持向量机(SVC)等分类算法在此过程中表现出色,能够有效处理高维非线性特征。

二、Python代码实现

1. 数据加载与预处理函数

load_trs_to_dict函数负责读取trs格式的侧信道数据文件,这种格式专门用于存储能量迹数据。该函数将文件头信息、能量迹曲线和附加参数分别存储在字典结构中,便于后续处理。函数支持指定读取的能量迹范围,有效管理内存使用。

get_intermediate_values函数根据AES算法的S盒操作生成中间值矩阵。它采用汉明重量作为泄漏模型,计算真实密钥和256种假设密钥对应的中间值。该函数返回两个关键矩阵:实际中间值向量和假设中间值矩阵,为后续的机器学习分析提供基础数据。

2. 机器学习核心组件

ProbCalculator类实现了密钥猜测的似然概率计算,采用对数似然累加方式评估各个密钥假设的可能性。该类维护一个256元素的数组,记录每个可能密钥的累积得分,支持增量更新和结果查询。

train_model函数使用支持向量机(SVC)作为分类器,训练模型建立能量迹特征与汉明重量标签之间的映射关系。SVC模型启用概率估计功能,可以输出每个类别的预测概率,这对后续的密钥排名计算至关重要。

3. 攻击评估与分析函数

single_attack函数执行单次攻击实验,通过分批处理能量迹数据并更新密钥似然值,跟踪真实密钥的排名变化。该函数体现了MLSCA的核心攻击流程,展示了如何利用训练好的模型逐步缩小密钥候选范围。

guess_entropy函数是综合评估模块,通过多次重复实验计算猜测熵和成功率两个关键指标。它自动记录攻击过程中密钥排名的演变情况,并统计达到特定成功率所需的最小能量迹数量,为评估攻击效果提供量化依据。

具体代码如下:

"""
对AES算法的软件实现进行基于机器学习的侧信道分析(MLSCA)的Python代码
泄漏模型:S盒输出的汉明重量
运行前先激活Python环境,执行pip install numpy tqdm trsfile matplotlib scikit-learn命令安装所需的库
'AES_POWER_STM32F_NO-PROTECT_60000.trs'是功耗曲线文件,请点击https://download.csdn.net/download/weixin_43261410/91057055免费下载
查看.trs格式文件介绍请浏览https://blog.csdn.net/weixin_43261410/article/details/148737286?fromshare=blogdetail&sharetype=blogdetail&sharerId=148737286&sharerefer=PC&sharesource=weixin_43261410&sharefrom=from_link
"""import os
import numpy as np
from sklearn.svm import SVC # 导入支持向量机
from tqdm import tqdm  # 用于显示进度条
from trsfile import trs_open  # 用于读取.trs格式的侧信道数据文件
import matplotlib.pyplot as plt  # 用于画图AES_SBOX = np.array([0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16
], dtype=np.uint8)# 汉明重量查找表,用于快速计算一个字节的汉明重量(二进制中1的个数)
HW_ARRAY = np.array([0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
])def load_trs_to_dict(trs_file_path: str, start_trace: int = None, end_trace: int = None):"""加载.trs文件到字典结构中参数:trs_file_path: .trs文件路径start_trace: 起始能量曲线索引(可选)end_trace: 结束能量曲线索引(可选)返回:包含头信息、能量曲线数据和额外参数的字典"""header, traces, param = {}, [], {}with trs_open(trs_file_path, 'r') as trs_file:# 读取文件头信息for key, value in trs_file.get_headers().items():header[key.name] = value# 处理能量曲线范围number_traces = header['NUMBER_TRACES']start_trace = 0 if start_trace is None else min(start_trace, number_traces - 1)end_trace = number_traces if end_trace is None else min(end_trace, number_traces)header['NUMBER_TRACES'] = end_trace - start_trace# 初始化能量曲线数据数组traces = np.zeros((header['NUMBER_TRACES'], header['NUMBER_SAMPLES']), dtype=np.float32)# 初始化参数数组param = {}for key in trs_file[0].parameters:param_len = len(trs_file[0].parameters[key].value)param[key] = np.zeros((header['NUMBER_TRACES'], param_len), dtype=np.uint8)# 读取能量曲线数据和参数for i, trace in enumerate(trs_file[start_trace:end_trace]):for key in trace.parameters:param[key][i] = trace.parameters[key].valuetraces[i] = np.array(trace.samples)# 返回结构化数据trs_dict = {"HEADER": header,"TRACES": traces,"PARAM": param}return trs_dictdef get_intermediate_values(plaintext, target_byte, real_key):"""生成中间值矩阵(基于汉明重量模型)参数:plaintext: 明文数组 (N x 16)target_byte: 目标字节位置(0-15)real_key: 真实密钥字节返回:actual: 真实中间值向量(长度等于能量曲线数量)hypo: 假设中间值矩阵(能量曲线数量 × 256种密钥假设)"""# 计算真实的S盒输入actual_sbox_in = plaintext[:, target_byte] ^ real_key# 计算S盒输出actual_sbox_out = AES_SBOX[actual_sbox_in]# 计算汉明重量作为功耗模型actual = HW_ARRAY[actual_sbox_out]# 生成256种可能的密钥假设hypo_key = np.array(range(256), np.uint8)# 计算S盒输入hypo_sbox_in = np.array([pt ^ hypo_key for pt in plaintext[:, target_byte]], np.uint8)# 计算S盒输出hypo_sbox_out = AES_SBOX[hypo_sbox_in]# 将汉明重量作为功耗模型hypo = HW_ARRAY[hypo_sbox_out]return actual, hypoclass ProbCalculator():"""计算密钥假设的似然概率"""def __init__(self):# 初始化密钥假设的似然累加器,256个可能的密钥假设self.guess_key_likelihood = np.zeros((256))def update(self, predict, hypo):"""更新似然值参数:predict: 当当前批次的概率值hypo: 当前批次的假设中间值"""# 获取每个假设对应的概率值likelihood_matrix = np.array([predict[i, hypo[i]] for i in range(predict.shape[0])])# 处理概率为0的情况,避免对数运算出错min_nzero = min(min(likelihood_matrix[likelihood_matrix != 0]), 0.01)likelihood_matrix = np.where(likelihood_matrix == 0, min_nzero ** 2, likelihood_matrix)# 计算对数似然并累加guess_key_likelihood = np.sum(np.log(likelihood_matrix), axis=0)self.guess_key_likelihood = self.guess_key_likelihood + guess_key_likelihooddef __call__(self):"""返回当前似然值向量"""return self.guess_key_likelihooddef train_model(traces, actual):"""训练SVC模型参数:traces: 用于训练SVC模型的能量曲线actual: 每条曲线对应的真实汉明重量返回:model: SVC模型"""# 使用支持向量机分类器,启用概率估计model = SVC(probability=True, verbose=True)model.fit(traces, actual)return modeldef single_attack(predict_matrix, hypo, real_key, index):"""执行单次攻击参数:predict_matrix: 模型预测的概率值数据hypo: 假设中间值数据real_key: 真实密钥字节(用于评估攻击效果)index: 分批处理的索引列表返回:key_rank_list: 每次更新后真实密钥的排名列表"""# 初始化概率计算器probability = ProbCalculator()key_rank_list = []# 分批处理能量曲线数据for i in range(len(index) - 1):# 获取当前批次的曲线和中间值start_idx = index[i]end_idx = index[i + 1]current_predict = predict_matrix[start_idx:end_idx]current_hypo = hypo[start_idx:end_idx]# 更新密钥似然值probability.update(current_predict, current_hypo)# 获取当前所有密钥假设的似然值prob = probability()# 计算密钥排名(似然值越小排名越高)prob_sort = np.argsort(np.argsort(-prob))# 记录真实密钥的当前排名key_rank = prob_sort[real_key]key_rank_list.append(key_rank)return key_rank_listdef guess_entropy(traces, hypo, model, real_key, result_path='result.txt', repeat_n=100, sample=500, header='', step=1):"""计算猜测熵和成功率参数:traces: 能量曲线数据hypo: 假设中间值数据model: SVC模型real_key: 真实密钥字节result_path: 结果保存路径repeat_n: 重复实验次数sample: 每次实验使用的能量曲线数量header: 结果文件头部信息step: 能量曲线数量增加的步长"""def get_value_n(arr, value, traces_number, less):"""辅助函数: 获取达到特定值所需的最少能量曲线数量"""if less:mask = arr <= valueelse:mask = arr >= valuevalid_index = np.cumprod(mask[::-1])[::-1]valid_index = np.where(valid_index)[0]return traces_number[valid_index[0]] if len(valid_index) > 0 else None# 设置分批索引列表index = [i for i in range(0, sample, step)]index.append(sample)# 准备随机排列key_rank_arr = []permutations = np.zeros((repeat_n, sample), dtype=int)for i in range(repeat_n):permutations[i] = np.random.permutation(traces.shape[0])[:sample]# 获取模型对所有能量曲线的预测结果predict_matrix = model.predict_proba(traces)# 多次重复实验for i in tqdm(range(repeat_n)):predict_random = predict_matrix[permutations[i]]hypo_random = hypo[permutations[i]]key_rank_list = single_attack(predict_random, hypo_random, real_key, index)key_rank_arr.append(key_rank_list)key_rank_arr = np.array(key_rank_arr)traces_number = np.array(index[1:])# 计算猜测熵guess_entropy = np.mean(key_rank_arr, axis=0)guess_entropy_10 = get_value_n(guess_entropy, 10, traces_number, True)guess_entropy_1 = get_value_n(guess_entropy, 1, traces_number, True)guess_entropy_0 = get_value_n(guess_entropy, 0, traces_number, True)# 计算成功率success_rate = np.mean(key_rank_arr < 10, axis=0)  # 排名小于10被认为攻击成功success_rate_p9 = get_value_n(success_rate, 0.9, traces_number, False)success_rate_p99 = get_value_n(success_rate, 0.99, traces_number, False)success_rate_1 = get_value_n(success_rate, 1, traces_number, False)# 保存结果到文件mode = 'a' if os.path.exists(result_path) else 'w'with open(result_path, mode, encoding='utf-8') as f:f.write(header)trs_n = ' '.join(f"{int(x)}" for x in traces_number)f.write('traces number: ' + trs_n + '\n')success_rate = ' '.join(f"{x:.2f}" for x in success_rate)f.write('success rate: ' + success_rate + '\n')guess_entropy = ' '.join(f"{x:.2f}" for x in guess_entropy)f.write('guess entropy: ' + guess_entropy + '\n')f.write(f'tips: When guess entropy equals 10, 1, or 0, the corresponding traces number are {guess_entropy_10}, {guess_entropy_1}, and {guess_entropy_0}.\n')f.write(f'tips: When success rate equals 0.9, 0.99, or 1, the corresponding traces number are {success_rate_p9}, {success_rate_p99}, and {success_rate_1}.\n\n')def stratified_sampling(X, y, sample_n):"""分层抽样函数,确保每个类别的样本比例均衡参数:X: 特征数据y: 标签数据sample_n: 总样本数返回:X_resampled: 重采样后的特征数据y_resampled: 重采样后的标签数据"""unique_classes, class_counts = np.unique(y, return_counts=True)n_classes = len(unique_classes)base_samples_per_class = sample_n // n_classesremainder = sample_n % n_classesbalanced_samples = []for i, cls in enumerate(unique_classes):target_sample_index = np.where(y == cls)[0]n_samples = class_counts[i]if i < remainder:required = base_samples_per_class + 1else:required = base_samples_per_classif required > n_samples:repeats = required // n_samplesremainder_samples = required % n_samplessamples = np.concatenate([np.tile(target_sample_index, repeats),np.random.choice(target_sample_index, remainder_samples, replace=False)])else:samples = np.random.choice(target_sample_index, required, replace=(required > n_samples))balanced_samples.append(samples)balanced_samples = np.concatenate(balanced_samples)np.random.shuffle(balanced_samples)X_resampled = X[balanced_samples]y_resampled = y[balanced_samples]return X_resampled, y_resampleddef show_result():"""可视化攻击结果从result.txt文件中读取数据并绘制成功率与猜测熵曲线"""result_path = 'result.txt'# 读取结果文件with open(result_path, 'r', encoding='utf-8') as f:lines = f.readlines()# 初始化数据列表traces = []success_rate = []guess_entropy = []# 解析结果文件for line in lines:if line.startswith('traces number:'):traces = list(map(int, line.split(':')[1].strip().split()))elif line.startswith('success rate:'):success_rate = list(map(float, line.split(':')[1].strip().split()))elif line.startswith('guess entropy:'):guess_entropy = list(map(float, line.split(':')[1].strip().split()))# 检查是否成功读取数据if not traces or not success_rate or not guess_entropy:print("Error: Could not find valid data in result file.")return# 创建图形和双轴fig, ax1 = plt.subplots(figsize=(12, 6))# 绘制成功率曲线(左轴,蓝色)color = 'tab:blue'ax1.set_xlabel('Number of Traces', fontsize=12)ax1.set_ylabel('Success Rate', color=color, fontsize=12)ax1.plot(traces, success_rate, color=color, label='Success Rate', linewidth=2)ax1.tick_params(axis='y', labelcolor=color)ax1.grid(True, linestyle='--', alpha=0.7)ax1.set_ylim(0, 1.05)  # 设置成功率y轴范围# 创建第二个y轴用于猜测熵ax2 = ax1.twinx()color = 'tab:red'ax2.set_ylabel('Guess Entropy', color=color, fontsize=12)ax2.plot(traces, guess_entropy, color=color, label='Guess Entropy', linewidth=2)ax2.tick_params(axis='y', labelcolor=color)ax2.set_ylim(0, 256)  # 固定猜测熵y轴范围为0-256# 添加图例lines1, labels1 = ax1.get_legend_handles_labels()lines2, labels2 = ax2.get_legend_handles_labels()ax1.legend(lines1 + lines2, labels1 + labels2, loc='upper right', fontsize=10)# 添加标题plt.title('MLSCA (SVC) Attack Performance: Success Rate and Guess Entropy', fontsize=14, pad=20)# 调整布局并保存图像(同时保存svg格式和png格式)fig.tight_layout()plt.savefig('result.svg', format='svg', bbox_inches='tight')plt.savefig('result.png', dpi=600, bbox_inches='tight')plt.show()def test():"""测试函数:执行完整的MLSCA流程"""target_byte = 0  # 攻击的字节位置(0表示第一个字节)traces_train_n = 50000  # 用于训练模型的曲线数量sample_n = 10000  # 实际用于训练的样本数量(经过分层抽样后)# 主密钥(16字节)mkey = [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10]# 加载能量曲线数据trs_path = 'AES_POWER_STM32F_NO-PROTECT_60000.trs'trs_dict = load_trs_to_dict(trs_path)traces, plaintext = trs_dict['TRACES'], trs_dict['PARAM']['plaintext']# 生成真实中间值向量和假设中间值矩阵actual, hypo = get_intermediate_values(plaintext, target_byte, mkey[target_byte])# 分割数据集traces_build, traces_match = traces[:traces_train_n], traces[traces_train_n:]actual_build, hypo_match = actual[:traces_train_n], hypo[traces_train_n:]# 对训练数据进行分层抽样,平衡各类样本数量traces_build, actual_build = stratified_sampling(traces_build, actual_build, sample_n)# 训练SVC模型model = train_model(traces_build, actual_build)# 设置实验参数repeat_n = 100  # 重复次数sample = 100  # 每次实验使用的能量曲线数量step = 1  # 能量曲线数量增加的步长# 执行猜测熵分析guess_entropy(traces_match, hypo_match, model, mkey[target_byte], repeat_n=repeat_n, sample=sample, step=step)# 可视化结果show_result()if __name__ == '__main__':test()

 三、实验结果

实验使用STM32F系列芯片采集的60,000条AES加密功耗曲线,其中50,000条用于模型训练,剩余10,000条用于攻击。结果显示,经过分层抽样的SVC模型表现出色,仅需约10条能量曲线即可将猜测熵降至10以下,约25条曲线能使成功率超过90%。当使用51条曲线时,猜测熵接近0,成功率稳定在100%,表明密钥被完全恢复。

结果可视化展示了猜测熵和成功率随能量曲线数量增加的变化趋势。两条曲线呈现明显的负相关关系,符合理论预期。值得注意的是,在曲线数量较少时,指标改善速度较快,随后趋于平缓,这种非线性特性反映了机器学习模型的特征学习过程。实验结果验证了MLSCA方法对未加防护AES实现的有效性,也为评估防护措施的安全性提供了基准参考。

四、总结 

本文研究了基于机器学习(SVC)的侧信道分析方法(MLSCA)在AES算法实现上的应用。通过采集STM32F芯片的功耗曲线,以S盒输出的汉明重量作为泄漏模型,构建支持向量机分类器建立功耗特征与密钥信息的映射关系。实验采用分层抽样优化数据分布,使用50,000条曲线训练模型,10,000条曲线测试攻击效果。结果表明,该方法仅需约25条功耗曲线即可实现90%以上的密钥恢复成功率,51条曲线时猜测熵趋近于0,完全破解密钥。研究验证了MLSCA对未防护AES实现的高效攻击能力,揭示了硬件密码实现中侧信道防护的重要性。 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/88587.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/88587.shtml
英文地址,请注明出处:http://en.pswp.cn/diannao/88587.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【LLM】位置编码

【LLM】位置编码 1 绝对位置嵌入为什么用 1000 0 2 t d 10000^{\frac{2t}{d}} 10000d2t​? 2 相对位置嵌入2.1 Shaw等人的方法&#xff08;2018&#xff09;2.2 Dai等人的方法&#xff08;2019&#xff09;2.3 Raffel 等人的方法&#xff08;2020&#xff09;2.4 He 等人的方法…

Java 根据分组key构建合并数据集

文章目录 前言背景总结 前言 请各大网友尊重本人原创知识分享&#xff0c;谨记本人博客&#xff1a;南国以南i、 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 背景 Java 需要返回一组数据供前端展示&#xff0c;获取到的数据格式如下&#xff1a; …

Linux平台Oracle开机自启动设置

网上和官方文档已经有不少介绍如何设置开机启动Oracle实例的文章(Linux平台)&#xff0c;不过以sysvinit和service这种方式居多。最近遇到了UAT环境的服务器打补丁后需要重启服务器的情况&#xff0c; 需要DBA去手工启动Oracle实例的情形&#xff0c;和同事讨论&#xff0c;决定…

商品中心—商品B端搜索系统的实现文档(二)

8.步骤四&#xff1a;基于索引实现搜索功能 (1)基于suggest索引的自动补全实现 实现自动补全的代码比较简单&#xff0c;其原理是&#xff1a;把搜索词汇和倒排索引里的所有前缀匹配的词条进行score比较&#xff0c;然后把分数最高的那些返回&#xff0c;其中会涉及到suggest索…

Codeforces Round 1027 (Div. 3)

A. Square Year 题目大意 给你一个四个字符的字符串&#xff0c;代表一个数字s 问是否存在a,b两个数字&#xff0c;使得 ( a b ) 2 s (ab)^2s (ab)2s 思路 如果s是奇数或不能被开根号一定不行 设sq为s开根号后的结果 将sq一分为2&#xff0c;考虑sq/2有没有余数的情况 //…

时序数据库IoTDB的架构、安装启动方法与数据模式总结

一、IoTDB的架构 IoTDB的架构主要分为三个部分&#xff1a; ‌时序文件&#xff08;Tsfile&#xff09;‌&#xff1a; 专为时序数据设计的文件存储格式。支持高效的压缩和查询性能。可独立使用&#xff0c;并可通过TsFileSync工具同步至HDFS进行大数据处理。 ‌数据库引擎‌…

ArrayList和LinkedList详解

在Java后端开发中&#xff0c;集合框架是我们日常编程不可或缺的工具&#xff0c;它为数据存储和操作提供了丰富的实现方式。作为Java集合框架中最常用的两种List实现&#xff0c;ArrayList和LinkedList各自具有独特的特性和适用场景。 1. 基本概念 1.1 ArrayList的定义与特性…

警惕微软Entra ID风险:访客账户存在隐蔽的权限提升策略

访客用户订阅权限漏洞解析 微软Entra ID的订阅管理存在访问控制缺陷&#xff0c;允许访客用户在受邀租户中创建和转移订阅&#xff0c;同时保留对这些订阅的完全所有权。访客用户只需具备在源租户创建订阅的权限&#xff0c;以及受邀成为外部租户访客的身份即可实施此操作。这…

EEG分类攻略2-Welch 周期图

在EEG信号处理的上下文中&#xff0c;使用Welch方法来估算信号的功率谱密度&#xff08;Power Spectral Density, PSD&#xff09;是一种常见的做法。你的代码片段是利用**scipy.signal.welch**函数来进行功率谱密度估算&#xff0c;并且涉及到一些关键的参数和步骤。让我们逐步…

开疆智能CCLinkIE转ModbusTCP网关连接脉冲计数器配置案例

本案例是三菱PLC通过CCLinkIE转ModbusTCP网关连接脉冲计数器的配置案例&#xff0c;具体配置如下。 配置过程&#xff1a; 首先设置从站通讯参数 主要设置IP地址&#xff0c;工作模式以及端口号&#xff08;Modbus默认502&#xff09; 找到通讯点表&#xff0c;找到需要读写的…

gRPC 使用(python 版本)

.proto 文件 .proto 文件 是 gRPC 和 Protocol Buffers 的接口定义文件&#xff0c;它描述了&#xff1a; 要传递什么数据&#xff08;也就是消息体 message&#xff09;。要暴露什么接口&#xff08;也就是服务 service 和它们的 方法&#xff09;。 也就是一份规范文件&am…

VMware安装

勾选【增强型键盘驱动程序】 #后期虚拟机用鼠标键盘比较好用 VMware创建主机Windows2 选择类型配置【自定义】 安装客户机操作系统【稍后安装操作系统】 客户机操作系统【Microsoft Windows】,版本选Windows最高版本 【固件类型】默认UEFI 【处理器配置】选1个处理…

【沉浸式解决问题】微服务子模块引入公共模块的依赖后无法bean未注入

目录 一、问题描述二、场景还原三、原因分析四、解决方案五、拓展知识参考文献 一、问题描述 在微服务项目中的公共模块进行了Mybatis Plus配置&#xff0c;创建了配置类并添加了Configuration注解&#xff0c;其他模块引入该模块后不生效 我这里是在Mybatis Plus公共模块中注…

SQL进阶:CASE表达式

目录 1、用一条SQL语句进行不同条件的统计 建表语句&#xff08;MySQL8&#xff09;&#xff1a; 录入数据&#xff1a; *按性别统计SQL 输出结果&#xff08;行列转换&#xff09; 2、在UPDATE语句里进行条件分支 建表语句&#xff08;MySQL8&#xff09;&#xff1a;…

哪四款AI工具让3D人物手办制作如此简单?

在当今数字化时代&#xff0c;AI技术的飞速发展为我们的生活带来了诸多便利和惊喜。其中&#xff0c;AI生成3D人物手办工具的出现&#xff0c;让我们能够轻松地将自己的创意和想象转化为实体手办&#xff0c;满足了众多手办爱好者的个性化需求。今天&#xff0c;我将为大家推荐…

Docker高级管理--Dockerfile镜像制作

目录 一:Docker 镜像管理 1:Docker 镜像结构 2:Dockerfile介绍 二:Dockerfile 语法基础 1:基础指令 2:环境设置指令 3:文件操作指令 4:执行命令指令 5:网络和暴露端口指令 6.容器挂载指令 三&#xff1a;dockerfile案例 1.构建nginx容器 一:Docker 镜像管理 Docker…

数字时代的“灵魂”之争:虚拟人形象的著作权困局与破局之道

首席数据官高鹏律师数字经济团队创作&#xff0c;AI辅助。 一、虚拟人的“数字生命”&#xff1a;一场关于“灵魂”的商业博弈 当一个虚拟偶像的“眼神”被复刻成千万个相似的数字面孔&#xff0c;当一段虚拟主播的“声音”被拆解为可交易的数据碎片——我们正在见证一个“数…

小型CI/CD搭建(TODO)

1 方案 因为是在国内&#xff0c;所以gitbub Actions&#xff0c;​​Azure DevOps​这些就直接拜拜了。 目前主流的大概是三种&#xff1a; 1 阿里云效/腾讯云CODING 2 GitLab CE GitLab Runner 3 Gitee Jenkins deepeseek比较了一下如下&#xff1a; 阿里云效 vs Git…

Android Studio flutter项目运行、打包时间太长

Android Studio&#xff1a;Android Studio Meerkat Feature Drop | 2024.3.2 Patch 1 flutter Sdk&#xff1a;3.29.3 系统&#xff1a;windows flutter sdk从2.10.5升级到3.29.3&#xff0c;但是Flutter 3.16开始新增了使用 Gradle声明式 plugins {} 块&#xff0c;gradle文…

【OpenGL学习】(六)图形添加纹理

文章目录 【OpenGL学习】&#xff08;六&#xff09;图形添加纹理纹理环绕纹理过滤纹理颜色与顶点颜色混合 OpenGL纹理介绍&#xff1a;https://learnopengl-cn.github.io/01%20Getting%20started/06%20Textures/ 【OpenGL学习】&#xff08;六&#xff09;图形添加纹理 项目…