VirtualBox 7.0.4安装macOS High Sierra

硬件要求

Intel E3-1230 v3 可以成功安装, AMD Ryzen 5900 CPULinux 系统上,需要配置 CPU 模仿 Intel CPU 的特性。并且 CPU 部分,不要启用 嵌套VT-x/AMD-V

生成系统安装镜像

macOS (实验使用的系统是 macOS Big Sur (11.7.1))系统上,执行如下命令,生成系统安装镜像

继续阅读VirtualBox 7.0.4安装macOS High Sierra

Failed to download https://chrome-infra-packages.appspot.com/dl/flutter/web/canvaskit_bundle 超时 解决办法

flutter项目下执行 flutter run 提示信号灯超时时间已到

1、问题截图如下:

2、解决办法

终端输入

后回车

再次执行flutter run 启动项目即可成功。

注:

为设置使用国内镜像

参考链接


Failed to download https://chrome-infra-packages.appspot.com/dl/flutter/web/canvaskit_bundle 超时 解决办法

Flutter The Linux toolchain CMake build dependency (CMake 3.14 or higher is required. You are running version 3.10.2)

ubuntu 22.04 通过 snap 安装了 Flutter SDK(当前是Flutter 3.3.4),如果第三方的依赖了 CMake 3.10.2 更高的版本,会在编译的时候报错:

这个报错的原因是由于 snap 安装的 Flutter SDK 构建了一个沙箱环境,在这个环境中的 CMake3.10.2 版本,不管系统安装的是哪个版本的 CMake ,都是无效的。

要解决这个问题,或者等待 snapFlutter SDK 更新版本,或者参照 Linux install Flutter 的说明,手工安装并配置 Flutter SDK

可以参考如下代码:

参考链接


Android各大市场更改APP名称

公司上架了一款App,因为产品运营需要去修改App名称,在iOS应用市场提交新版本的时候可以改App名称。那么Android 各大市场如何更改APP名称呢?

目前上架的Android 应用市场有:360手机助手、腾讯应用宝、百度手机助手、阿里应用分发市场(豌豆荚)、安智市场、小米应用商店、华为应用市场、OPPO商店、魅族应用商店、vivo应用市场、搜狗手机助手等平台。

每家Android应用市场的规则都不同,小编整理了Android 各大市场更改APP名称的规则。

1、 百度 : 百度平台的最简单。直接更新app的版本即可(应用名称是系统从您提交的应用中解析的,如需修改请联系贵司技术修改apk包内信息。)

百度如何修改app名称
百度如何修改app名称

2、应用宝: 用上线后,开发者可通过工单系统提交应用名称修改需求 (入口1:如图点击“名称更改指引”即可直接跳转到修改应用名称的工单系统;入口2:管理中心-->点击需要修改名称的应用-->基础服务-->工单系统-->应用宝商务类-->移动应用名称修改-->填单提交)。修改应用名称需要提供软件著作权; 若暂无软著,可提供此款应用在其他外市场,改过名字后的前后台上线管理截图(其他证明文件均不接受);

腾讯开放平台应用改名
腾讯开放平台应用改名

重要提示:根据平台规则,应用上线后,应用名称最多可支持修改2次,超过修改次数将不再受理,请谨慎确定好需要修改的应用名称后,再提交工单申请。

腾讯移动应用名称修改
腾讯移动应用名称修改

3、华为: 在开发者后台在该应用下点击上架或者升级,上传更名后的APK包,并在应用信息处更改应用名称,如应用分类涉及软著要求,请在“版本信息”的“应用版权证书或代理证书”处更新应用软著及免责函,提交应用审核。

华为应用商店应用改名
华为应用商店应用改名

4、360移动开放平台和百度移动开放平台是一样的,直接更新app的版本即可。

5、 vivo开放平台:

1)应用类APP需要修改名称: 直接在后台编辑更新,保证apk包内和在后台填写的名称一致即可;若名称相差较大,请在版权证明栏补充软著;游戏类APP(网游/单机)需要修改名称:需联系对接商务处理。

2)若需要更改应用包名,请联系贵司技术人员;更改之后再在平台创建应用提交新包名应用,旧包名应用需申请下架(登录平台--管理中心--点击您的应用--“下架申请”即可)。

6、 OPPO开放平台:也是上传后将自动解析包名。

7、魅族开放平台:也是上传后将自动解析包名。

8、小米市场: 应用名称修改需于应用包内及应用信息一同更改。应用包内名称更改还请贵司技术开发人员自行更改。(可以试一下直接上传后将自动解析包名。)

9、豌豆荚(阿里云应用分发平台):也是上传后将自动解析包名。

参考链接


Android 各大市场更改APP名称

Flutter-从数据库中获取记录并使用ListView Builder显示出来

数据保存在数据库中,根据表名称获取所有记录的列表,并在"ListView.builder"中显示的代码如下:

参考链接


Flutter 3.0实现Windows本地化/国际化

参照 Flutter 2.8.1本地化/国际化应用程序名称 可以实现 Android/macOS/iOS/Web 的应用名称相关的国际化。Linux 参考 Flutter 3.0实现Linux本地化/国际化

那么在 Windows 应用上如何相同的功能呢?

下面我们探讨一下一个比较简单的解决方案,就是直接修改RC文件,这个方案 适用于涉及到的语言类型不太多的情况

Windows 代码编译,需要安装 Microsoft Visual Studio 2022 Community,但是不能直接使用 Microsoft Visual Studio 2022 Community 编辑 RC 文件,打开就会报错:

具体的操作方法如下:

我们假定工程的名字为 LanauageTest

首先在项目根目录下,执行

生成 build 目录,然后使用 Microsoft Visual Studio 2022 Community 打开 build\windows\LanauageTest.sln 文件。

接着在资源视图中找到字符串资源(如果不存在则新建),选择默认的 StringTable ,然后右键选择 “插入副本

虽然可以使用上面的操作来添加语言,但是只能作为参考,原因在于 Microsoft Visual Studio 2022 CommunityRC 文件编辑器在修改 LanauageTest.RC 文件的时候,把预定义的宏进行了展开,直接使用宏的实际值替代了宏本身,导致这些数据失去动态变化的能力。我们只能手工再编辑一次,恢复原来的宏才可以。

至于使用的话,可以通过 LoadString 加载定义的字符串资源,更详细参考 Using Resources

参考链接


Flutter 3.0实现Linux本地化/国际化

参照 Flutter 2.8.1本地化/国际化应用程序名称 可以实现 Android/macOS/iOS/Web 的应用名称相关的国际化。但是在 Linux 应用上如何相同的功能,目前暂时没有一个统一的标准。

研究了许久,终于基本上算是搞定,解决方案如下:

使用 gettext 来实现国际化相关的功能。

首先配置,调整工程的目录如下:

project/
project/linux
project/linux/flutter
project/linux/flutter/CMakeLists.txt
project/linux/locale/en_US/app.po
project/linux/locale/zh_CN/app.mo
project/linux/locale/CMakeLists.txt
project/linux/CMakeLists.txt
project/linux/main.cc
project/linux/my_application.cc
project/linux/my_application.h

对应语言 i18n 相关配置文件的内容如下:

接下来,修改 Linux 工程的配置文件,增加对 本地化(i18n) 文件的引用,在合适的位置增加如下代码:

完整的代码参考如下:

使用多语言的代码如下:

参考链接


编译NanoPi R5S Android 12 (RK3568)

最近,入手了一部 NanoPi R5S ,官方是提供了 Anroid 12 的系统镜像,但是却没有给出相应的源代码2023年10月12日,NanoPi 官方已经给出了Android 12的源代码,整个共享目录大约130GB左右,建议直接使用官方源代码进行编译)。尝试用官方提供的 Anroid 11 编译,结果编译出的系统镜像无法正常运行。

凑巧看到 研华科技 放出了 RSB-4810 开发板的 Anroid 12 编译指南,两者的配置差不多,试了一下,竟然可以正常运行!!

系统要求,内存不低于 32GB,否则编译过程中可能会由于内存不足,造成编译失败。

研华科技 官方文档是通过 docker 利用 ubuntu 18.04 进行编译的,如下:

1. 配置 docker 运行环境

2. 下载源代码并进行编译

3. 下载并解压缩编译工具( prebuilts.tar.gz 密码: 1234)

4. 编译代码

5. 核对编译后的文件

编译完成后的产物在 rockdev/Image-rsb4810_s/ 目录下,具体的文件列表如下:

5. 刷机

按照正常的流程刷机,整个流程走起来会比较繁琐,此处给相对简单的做法。

    1. NanoPi R5S官方WIKI 去下载已经编译好的镜像
    2. 如果是需要SD卡刷机,则直接把下载到的镜像文件写入准备好的数据卡
    3. 用刚刚编译出的文件替换SD卡上的android12目录下的同名文件,注意,只替换同名文件,里面的配置文件不要删除
    4. 插上SD卡,重启即可完成刷机
    5. 如果使用USB刷机,则也可以通过替换文件的方式达到相同的目的

参考链接


RSA算法原理

如果你问我,哪一种算法最重要?

我可能会回答"公钥加密算法"

因为它是计算机通信安全的基石,保证了加密数据不会被破解。你可以想象一下,信用卡交易被破解的后果。

进入正题之前,我先简单介绍一下,什么是"公钥加密算法"。

一、一点历史

1976年以前,所有的加密方法都是同一种模式:

  (1)甲方选择某一种加密规则,对信息进行加密;

  (2)乙方使用同一种规则,对信息进行解密。

由于加密和解密使用同样规则(简称"密钥"),这被称为"对称加密算法"(Symmetric-Key  Algorithm)。

这种加密模式有一个最大弱点:甲方必须把加密规则告诉乙方,否则无法解密。保存和传递密钥,就成了最头疼的问题。

1976年,两位美国计算机学家Whitfield Diffie 和 Martin Hellman,提出了一种崭新构思,可以在不直接传递密钥的情况下,完成解密。这被称为"Diffie-Hellman密钥交换算法"。这个算法启发了其他科学家。人们认识到,加密和解密可以使用不同的规则,只要这两种规则之间存在某种对应关系即可,这样就避免了直接传递密钥。

这种新的加密模式被称为"非对称加密算法"。

  (1)乙方生成两把密钥(公钥和私钥)。公钥是公开的,任何人都可以获得,私钥则是保密的。

  (2)甲方获取乙方的公钥,然后用它对信息加密。

  (3)乙方得到加密后的信息,用私钥解密。

如果公钥加密的信息只有私钥解得开,那么只要私钥不泄漏,通信就是安全的。

1977年,三位数学家Rivest、Shamir 和 Adleman 设计了一种算法,可以实现非对称加密。这种算法用他们三个人的名字命名,叫做RSA算法。从那时直到现在,RSA算法一直是最广为使用的"非对称加密算法"。毫不夸张地说,只要有计算机网络的地方,就有RSA算法。

这种算法非常可靠,密钥越长,它就越难破解。根据已经披露的文献,目前被破解的最长RSA密钥是768个二进制位。也就是说,长度超过768位的密钥,还无法破解(至少没人公开宣布)。因此可以认为,1024位的RSA密钥基本安全,2048位的密钥极其安全。

下面,我就进入正题,解释RSA算法的原理。文章共分成两部分,今天是第一部分,介绍要用到的四个数学概念。你可以看到,RSA算法并不难,只需要一点数论知识就可以理解。

二、互质关系

如果两个正整数,除了1以外,没有其他公因子,我们就称这两个数是互质关系(coprime)。比如,15和32没有公因子,所以它们是互质关系。这说明,不是质数也可以构成互质关系。

关于互质关系,不难得到以下结论:

  1. 任意两个质数构成互质关系,比如13和61。

  2. 一个数是质数,另一个数只要不是前者的倍数,两者就构成互质关系,比如3和10。

  3. 如果两个数之中,较大的那个数是质数,则两者构成互质关系,比如97和57。

  4. 1和任意一个自然数是都是互质关系,比如1和99。

  5. p是大于1的整数,则p和p-1构成互质关系,比如57和56。

  6. p是大于1的奇数,则p和p-2构成互质关系,比如17和15。

三、欧拉函数

请思考以下问题:

  任意给定正整数n,请问在小于等于n的正整数之中,有多少个与n构成互质关系?(比如,在1到8之中,有多少个数与8构成互质关系?)

计算这个值的方法就叫做欧拉函数,以$φ(n)$表示。在1到8之中,与8形成互质关系的是1、3、5、7,所以 $φ(n) = 4$。

$φ(n)$ 的计算方法并不复杂,但是为了得到最后那个公式,需要一步步讨论。

第一种情况

如果$n=1$,则 $\phi(1) = 1$ 。因为$1$与任何数(包括自身)都构成互质关系。

第二种情况

如果$n$是质数,则 $\Phi(n)=n-1$ 。因为质数与小于它的每一个数,都构成互质关系。比如5与1、2、3、4都构成互质关系。

第三种情况

如果$n$是质数的某一个次方,即 $n = p^k$ ($p$为质数,$k$为大于等于$1$的整数),则

$\varPhi(p^k) {=} p^k - p^{k-1}$

比如 $φ(8) = φ(2^3) =2^3 - 2^2 = 8 -4 = 4$。

这是因为只有当一个数不包含质数p,才可能与n互质。而包含质数p的数一共有p^(k-1)个,即1×p、2×p、3×p、...、p^(k-1)×p,把它们去除,剩下的就是与n互质的数。

上面的式子还可以写成下面的形式:

$\varPhi(p^k) {=} p^k - p^{k-1} = p^k(1- \frac{1}{p})$

可以看出,上面的第二种情况是 k=1 时的特例。

第四种情况

如果n可以分解成两个互质的整数之积,

  $n = p_1 * p_2$

  $φ(n) = φ(p_1p_2) = φ(p_1)φ(p_2)$

即积的欧拉函数等于各个因子的欧拉函数之积。比如,φ(56)=φ(8×7)=φ(8)×φ(7)=4×6=24。

这一条的证明要用到"中国剩余定理",这里就不展开了,只简单说一下思路:如果a与$p_1$互质(a<$p_1$),b与$p_2$互质(b<$p_2$),c与$p_1p_2$互质(c<$p_1p_2$),则c与数对 (a,b) 是一一对应关系。由于a的值有$φ(p_1)$种可能,b的值有$φ(p_2)$种可能,则数对 (a,b) 有$φ(p_1)φ(p_2)$种可能,而c的值有$φ(p_1p_2)$种可能,所以$φ(p_1p_2)$就等于$φ(p_1)φ(p_2)$。

第五种情况

因为任意一个大于1的正整数,都可以写成一系列质数的积。

$n {=} p_1^{k_1} p_2^{k_2} \cdots p_r^{k_r}$

根据第4条的结论,得到

$\varPhi(n) {=} \varPhi(p_1^{k_1}) \varPhi(p_2^{k_2}) \cdots \varPhi(p_r^{k_r})$

再根据第3条的结论,得到

$\varPhi(n) {=}  p_1^{k_1} p_2^{k_2} \cdots p_r^{k_r} (1- \frac{1}{p_1}) (1- \frac{1}{p_2}) \cdots (1- \frac{1}{p_r})$

也就等于

$\varPhi(n) {=} n(1- \frac{1}{p_1}) (1- \frac{1}{p_2}) \cdots (1- \frac{1}{p_r})$

这就是欧拉函数的通用计算公式。比如,1323的欧拉函数,计算过程如下:

$\varPhi(1323) {=} \varPhi(3^3 * 7^2) {=} 1323 (1- \frac{1}{3}) (1- \frac{1}{7}) = 756$

四、欧拉定理

欧拉函数的用处,在于欧拉定理。"欧拉定理"指的是:

如果两个正整数a和n互质,则n的欧拉函数 $φ(n)$ 可以让下面的等式成立:

$a^{\varPhi(n)} \equiv 1 \pmod{n}$

也就是说,a的φ(n)次方被n除的余数为1。或者说,a的φ(n)次方减去1,可以被n整除。比如,3和7互质,而7的欧拉函数φ(7)等于6,所以3的6次方(729)减去1,可以被7整除(728/7=104)。

欧拉定理的证明比较复杂,这里就省略了。我们只要记住它的结论就行了。

欧拉定理可以大大简化某些运算。比如,7和10互质,根据欧拉定理,

$7^{\varPhi(10)} \equiv 1 \pmod{10}$

已知 φ(10) 等于4,所以马上得到7的4倍数次方的个位数肯定是1。

$7^{4k} \equiv 1 \pmod{10}$

因此,7的任意次方的个位数(例如7的222次方),心算就可以算出来。

欧拉定理有一个特殊情况。

假设正整数a与质数p互质,因为质数p的φ(p)等于p-1,则欧拉定理可以写成

$a^{p-1} \equiv 1 \pmod{p}$

这就是著名的费马小定理。它是欧拉定理的特例。

欧拉定理是RSA算法的核心。理解了这个定理,就可以理解RSA。

五、模反元素

还剩下最后一个概念:

如果两个正整数a和n互质,那么一定可以找到整数b,使得 ab-1 被n整除,或者说ab被n除的余数是1。

$ab \equiv 1 \pmod{n}$

这时,b就叫做a的"模反元素"

比如,3和11互质,那么3的模反元素就是4,因为 (3 × 4)-1 可以被11整除。显然,模反元素不止一个, 4加减11的整数倍都是3的模反元素 {...,-18,-7,4,15,26,...},即如果b是a的模反元素,则 b+kn 都是a的模反元素。

欧拉定理可以用来证明模反元素必然存在。

$a^{\varPhi(n)} {=} a* a^{\varPhi(n)-1} \equiv 1 \pmod{n}$

可以看到,a的 $φ(n)-1$ 次方,就是a的模反元素。

==========================================

好了,需要用到的数学工具,全部介绍完了。RSA算法涉及的数学知识,就是上面这些,下一次我就来介绍公钥和私钥到底是怎么生成的。

有了这些知识,我们就可以看懂RSA算法。这是目前地球上最重要的加密算法。

六、密钥生成的步骤

我们通过一个例子,来理解RSA算法。假设爱丽丝要与鲍勃进行加密通信,她该怎么生成公钥和私钥呢?

第一步,随机选择两个不相等的质数p和q。

爱丽丝选择了61和53。(实际应用中,这两个质数越大,就越难破解。)

第二步,计算p和q的乘积n。

爱丽丝就把61和53相乘。

  $n = 61*53 = 3233$

n的长度就是密钥长度。3233写成二进制是110010100001,一共有12位,所以这个密钥就是12位。实际应用中,RSA密钥一般是1024位,重要场合则为2048位。

第三步,计算n的欧拉函数φ(n)。

根据公式:

  $\varPhi(n) = (p-1)(q-1)$

爱丽丝算出φ(3233)等于60×52,即3120。

第四步,随机选择一个整数e,条件是1< e < φ(n),且e与φ(n) 互质。

爱丽丝就在1到3120之间,随机选择了17。(实际应用中,常常选择65537)

第五步,计算e对于φ(n)的模反元素d。

所谓"模反元素"就是指有一个整数d,可以使得ed被φ(n)除的余数为1。

  $ed \equiv 1 \pmod{\varPhi(n)}$

这个式子等价于

  $ed - 1 = k\varPhi(n)$

于是,找到模反元素d,实质上就是对下面这个二元一次方程求解。

  $ex + \varPhi(n)y = 1$

已知 e=17, φ(n)=3120,

  $17x + 3120y = 1$

这个方程可以用"扩展欧几里得算法"求解,此处省略具体过程。总之,爱丽丝算出一组整数解为 (x,y)=(2753,-15),即 d=2753。

至此所有计算完成。

第六步,将n和e封装成公钥,n和d封装成私钥。

在爱丽丝的例子中,n=3233,e=17,d=2753,所以公钥就是 (3233,17),私钥就是(3233, 2753)。

实际应用中,公钥和私钥的数据都采用ASN.1格式表达(实例)。

七、RSA算法的可靠性

回顾上面的密钥生成步骤,一共出现六个数字:

  p
  q
  n
  φ(n)
  e
  d

这六个数字之中,公钥用到了两个(n和e),其余四个数字都是不公开的。其中最关键的是d,因为n和d组成了私钥,一旦d泄漏,就等于私钥泄漏。

那么,有无可能在已知n和e的情况下,推导出d?

  (1)ed≡1 (mod φ(n))。只有知道e和φ(n),才能算出d。

  (2)φ(n)=(p-1)(q-1)。只有知道p和q,才能算出φ(n)。

  (3)n=pq。只有将n因数分解,才能算出p和q。

结论:如果n可以被因数分解,d就可以算出,也就意味着私钥被破解。

可是,大整数的因数分解,是一件非常困难的事情。目前,除了暴力破解,还没有发现别的有效方法。维基百科这样写道:

  "对极大整数做因数分解的难度决定了RSA算法的可靠性。换言之,对一极大整数做因数分解愈困难,RSA算法愈可靠。

  假如有人找到一种快速因数分解的算法,那么RSA的可靠性就会极度下降。但找到这样的算法的可能性是非常小的。今天只有短的RSA密钥才可能被暴力破解。到2008年为止,世界上还没有任何可靠的攻击RSA算法的方式。

  只要密钥长度足够长,用RSA加密的信息实际上是不能被解破的。"

举例来说,你可以对3233进行因数分解(61×53),但是你没法对下面这个整数进行因数分解。

  12301866845301177551304949
  58384962720772853569595334
  79219732245215172640050726
  36575187452021997864693899
  56474942774063845925192557
  32630345373154826850791702
  61221429134616704292143116
  02221240479274737794080665
  351419597459856902143413

它等于这样两个质数的乘积:

  33478071698956898786044169
  84821269081770479498371376
  85689124313889828837938780
  02287614711652531743087737
  814467999489
    ×
  36746043666799590428244633
  79962795263227915816434308
  76426760322838157396665112
  79233373417143396810270092
  798736308917

事实上,这大概是人类已经分解的最大整数(232个十进制位,768个二进制位)。比它更大的因数分解,还没有被报道过,因此目前被破解的最长RSA密钥就是768位。

八、加密和解密

有了公钥和密钥,就能进行加密和解密了。

(1)加密要用公钥 (n,e)

假设鲍勃要向爱丽丝发送加密信息m,他就要用爱丽丝的公钥 (n,e) 对m进行加密。这里需要注意,m必须是整数(字符串可以取ascii值或unicode值),且m必须小于n。

所谓"加密",就是算出下式的c:

  $m^e \equiv c \pmod{n}$

爱丽丝的公钥是 (3233, 17),鲍勃的m假设是65,那么可以算出下面的等式:

  $65^{17} \equiv 2790 \pmod{3233}$

于是,c等于2790,鲍勃就把2790发给了爱丽丝。

(2)解密要用私钥(n,d)

爱丽丝拿到鲍勃发来的2790以后,就用自己的私钥(3233, 2753) 进行解密。可以证明,下面的等式一定成立:

  $c^d \equiv m \pmod{n}$

也就是说,c的d次方除以n的余数为m。现在,c等于2790,私钥是(3233, 2753),那么,爱丽丝算出

  $2790^{2753} \equiv 65 \pmod{3233}$

因此,爱丽丝知道了鲍勃加密前的原文就是65。

至此,"加密--解密"的整个过程全部完成。

我们可以看到,如果不知道d,就没有办法从c求出m。而前面已经说过,要知道d就必须分解n,这是极难做到的,所以RSA算法保证了通信安全。

你可能会问,公钥(n,e) 只能加密小于n的整数m,那么如果要加密大于n的整数,该怎么办?有两种解决方法:一种是把长信息分割成若干段短消息,每段分别加密;另一种是先选择一种"对称性加密算法"(比如DES),用这种算法的密钥加密信息,再用RSA公钥加密DES密钥。

九、私钥解密的证明

最后,我们来证明,为什么用私钥解密,一定可以正确地得到m。也就是证明下面这个式子:

  $c^d \equiv m \pmod{n}$

因为,根据加密规则

  $m^e \equiv c \pmod{n}$

于是,c可以写成下面的形式:

  $c = m^e - kn$

将c代入要我们要证明的那个解密规则:

  $(m^e - kn)^d \equiv m \pmod{n}$

它等同于求证

  $m^{ed} \equiv m \pmod{n}$

由于

  $ed \equiv 1 \pmod{\varPhi(n)}$

所以

  $ed = h\varPhi(n)+1$

将ed代入:

  $m^{h\varPhi(n)+1} \equiv m \pmod{n}$

接下来,分成两种情况证明上面这个式子。

(1)m与n互质。

根据欧拉定理,此时

  $m^{\varPhi(n)} \equiv 1 \pmod{n}$

得到

  $(m^{\varPhi(n)})^h × m \equiv m \pmod{n}$

原式得到证明。

(2)m与n不是互质关系。

此时,由于n等于质数p和q的乘积,所以m必然等于kp或kq。

以 m = kp为例,考虑到这时k与q必然互质,则根据欧拉定理,下面的式子成立:

  $(kp)^{q-1} \equiv 1 \pmod{q}$

进一步得到

  $[(kp)^{q-1}]^{h(p-1)} * kp \equiv kp \pmod{q}$

  $(kp)^{ed} \equiv kp \pmod{q}$

将它改写成下面的等式

  $(kp)^{ed} = tq + kp$

这时t必然能被p整除,即 t=t'p

  $(kp)^{ed} = t'pq + kp$

因为 m=kp,n=pq,所以

  $m^{ed} \equiv m \pmod{n}$

原式得到证明。

参考链接


Robolectric 4.8.2修改进程名/私有静态变量

Roboletric 4.8.2 修改进程名:

Roboletric 4.8.2 修改私有静态变量:

如果报错:

则修改方式如下:

完整的例子如下:

参考链接


Using PowerMock - robolectric/robolectric Wiki