Skip to content

Commit 73d8438

Browse files
committed
Update Payload Distribution Algorithm
1 parent 0790b3d commit 73d8438

3 files changed

Lines changed: 147 additions & 29 deletions

File tree

src/javascript/main.test.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,31 +55,31 @@ test("加/解密测试", { timeout: 15000 }, () => {
5555
let TestTemp3 = TestString;
5656

5757
//将随机字符串用仿真加密循环加/解密6次,判断一致性和中途是否出错。
58-
for (let i = 0; i <= 5; i++) {
58+
for (let i = 0; i <= 6; i++) {
5959
Abra.Input_Next(
6060
TestTemp,
6161
"ENCRYPT",
6262
"ABRACADABRA",
6363
i % 2 == 0,
64-
100,
64+
50,
6565
i % 2 == 0,
6666
i % 2 != 0
6767
);
6868
TestTemp = Abra.Output();
6969
}
7070

71-
for (let i = 0; i <= 5; i++) {
71+
for (let i = 0; i <= 6; i++) {
7272
Abra.Input_Next(TestTemp, "DECRYPT", "ABRACADABRA");
7373
TestTemp = Abra.Output();
7474
}
7575

7676
//将随机字符串用传统加密循环加/解密6次,判断一致性和中途是否出错。
77-
for (let i = 0; i <= 5; i++) {
77+
for (let i = 0; i <= 6; i++) {
7878
Abra.Input(TestTemp2, "ENCRYPT", "ABRACADABRA", true);
7979
TestTemp2 = Abra.Output();
8080
}
8181

82-
for (let i = 0; i <= 5; i++) {
82+
for (let i = 0; i <= 6; i++) {
8383
Abra.Input(TestTemp2, "DECRYPT", "ABRACADABRA");
8484
TestTemp2 = Abra.Output();
8585
}

src/javascript/utils_next.js

Lines changed: 141 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -802,6 +802,134 @@ function RoundControlInit(key) {
802802
RoundControl = HashArray;
803803
}
804804

805+
function shuffle(array) {
806+
for (let i = array.length - 1; i > 0; i--) {
807+
const j = Math.floor(Math.random() * (i + 1));
808+
[array[i], array[j]] = [array[j], array[i]];
809+
}
810+
return array;
811+
}
812+
813+
function avoidAdjacentDuplicates(arr) {
814+
if (arr.length <= 1) return arr;
815+
const newArr = [...arr];
816+
let hasAdjacent = true;
817+
let maxTries = newArr.length;
818+
819+
while (hasAdjacent && maxTries > 0) {
820+
hasAdjacent = false;
821+
for (let i = 0; i < newArr.length - 1; i++) {
822+
if (newArr[i] === newArr[i + 1]) {
823+
hasAdjacent = true;
824+
// 尝试在i+2位置之后找一个可以交换的元素
825+
for (let j = i + 2; j < newArr.length; j++) {
826+
if (
827+
newArr[j] !== newArr[i] &&
828+
(j === 0 || newArr[j - 1] !== newArr[i]) &&
829+
(j === newArr.length - 1 || newArr[j + 1] !== newArr[i])
830+
) {
831+
[newArr[i + 1], newArr[j]] = [newArr[j], newArr[i + 1]];
832+
break;
833+
}
834+
}
835+
break;
836+
}
837+
}
838+
maxTries--;
839+
}
840+
return newArr;
841+
}
842+
843+
function mergeNumbers(arr, factor) {
844+
// 分离小于3的数字和其他数字
845+
const lessThan3 = arr.filter((num) => num < 3);
846+
const rest = arr.filter((num) => num >= 3);
847+
848+
// 根据因子计算需要保留的小于3的数字数量
849+
const preserveCount = Math.max(
850+
0,
851+
Math.floor((1 - factor) * lessThan3.length)
852+
);
853+
854+
// 保留部分数字
855+
const preserved = [];
856+
const toMerge = [];
857+
858+
// 随机选择要保留的数字
859+
const temp = [...lessThan3];
860+
for (let i = 0; i < preserveCount; i++) {
861+
const randomIndex = Math.floor(Math.random() * temp.length);
862+
preserved.push(temp.splice(randomIndex, 1)[0]);
863+
}
864+
toMerge.push(...temp);
865+
866+
// 如果没有需要合并的数字,直接返回
867+
if (toMerge.length === 0) {
868+
return [...shuffle(rest), ...shuffle(preserved)];
869+
}
870+
871+
// 计算需要合并的总和
872+
const sum = toMerge.reduce((acc, val) => acc + val, 0);
873+
874+
// 计算合并后的数字数量范围
875+
const minSegments = Math.ceil(sum / 9); // 最少段数
876+
const maxSegments = Math.min(toMerge.length, Math.floor(sum / 3)); // 最多段数
877+
let bestSegmentCount = minSegments;
878+
879+
// 寻找最优合并段数
880+
let minVariance = Infinity;
881+
for (let k = minSegments; k <= maxSegments; k++) {
882+
const base = Math.floor(sum / k);
883+
const remainder = sum % k;
884+
const values = [];
885+
886+
// 生成k个数值
887+
for (let i = 0; i < k; i++) {
888+
values.push(i < remainder ? base + 1 : base);
889+
}
890+
891+
// 计算方差(均匀度)
892+
const mean = sum / k;
893+
const variance =
894+
values.reduce((acc, val) => acc + Math.pow(val - mean, 2), 0) / k;
895+
896+
// 更新最优解
897+
if (variance < minVariance) {
898+
minVariance = variance;
899+
bestSegmentCount = k;
900+
}
901+
}
902+
903+
// 生成合并后的数字
904+
const base = Math.floor(sum / bestSegmentCount);
905+
const remainder = sum % bestSegmentCount;
906+
const merged = [];
907+
908+
for (let i = 0; i < bestSegmentCount; i++) {
909+
merged.push(i < remainder ? base + 1 : base);
910+
}
911+
912+
// 组合结果并返回
913+
return [...shuffle(rest), ...shuffle(preserved), ...merged];
914+
}
915+
916+
function processArray(twoDArray, factor) {
917+
return twoDArray.map((subArray) => {
918+
// 检查是否需要合并
919+
if (subArray.length > 6) {
920+
const countLessThan3 = subArray.filter((num) => num < 3).length;
921+
if (countLessThan3 / subArray.length > 0.35) {
922+
subArray = mergeNumbers(subArray, factor);
923+
}
924+
}
925+
926+
// 打乱顺序
927+
subArray = shuffle(subArray);
928+
// 避免相邻重复
929+
return avoidAdjacentDuplicates(subArray);
930+
});
931+
}
932+
805933
function distributeInteger(num) {
806934
//把文言文密文的载荷根据一定比例分成三份(一段)
807935
if (num <= 3) {
@@ -812,16 +940,6 @@ function distributeInteger(num) {
812940
let maxPart = Math.floor(num * 0.2); // 计算每个部分的最大值
813941
let remaining = num - 2 * maxPart; // 计算剩余部分
814942

815-
if (remaining <= 0) {
816-
// 如果剩余部分小于等于 0,则调整最大值,确保每个元素都大于 0
817-
maxPart = Math.floor((num - 2) / 3); // 调整 maxPart 的计算方式
818-
remaining = num - 2 * maxPart;
819-
820-
if (remaining <= 0) {
821-
return []; // 如果调整后仍然无法满足要求,则返回空数组
822-
}
823-
}
824-
825943
const result = [maxPart, remaining, maxPart]; // 创建包含三个整数的数组
826944

827945
return result;
@@ -849,6 +967,7 @@ export function selectSentence(PayloadLength, RandomIndex = 0, p, l) {
849967
//L 强制多用逻辑句式
850968
//句式选择算法
851969
//RandomIndex 随机指数,越大,给出的句式越随机,最大100。
970+
/* v8 ignore next 7 */
852971
if (RandomIndex > 100 || RandomIndex < 0) {
853972
//错误的输入。
854973
throw "Incorrect Random Index";
@@ -923,16 +1042,17 @@ export function selectSentence(PayloadLength, RandomIndex = 0, p, l) {
9231042
}
9241043
}
9251044

926-
for (let z = 0; z < 3; z++) {
1045+
/*for (let z = 0; z < 3; z++) {
9271046
//标准洗牌算法,打乱负载的分布
9281047
for (let i = SegmentedPayload[z].length - 1; i >= 1; i--) {
929-
const j = Math.floor(Math.random() * (i + 1));
1048+
const j = Math.floor(MT.random() * (i + 1));
9301049
[SegmentedPayload[z][i], SegmentedPayload[z][j]] = [
9311050
SegmentedPayload[z][j],
9321051
SegmentedPayload[z][i],
9331052
];
9341053
}
935-
}
1054+
}*/
1055+
SegmentedPayload = processArray(SegmentedPayload, 1 - RandomIndex / 100);
9361056

9371057
//开始根据分配好的载荷执行组句
9381058
for (let i = 0; i < 3; i++) {
@@ -1305,6 +1425,7 @@ export function deMap(input, key) {
13051425

13061426
findtemp = findOriginText(temp); //查找第一个字符的原文
13071427
if (findtemp == NULL_STR) {
1428+
/* v8 ignore next 2 */
13081429
throw "Bad Input. Try force encrypt if intended.";
13091430
}
13101431
TempStr1 = TempStr1 + findtemp; //把找到的原文增加到字符串上
@@ -1316,6 +1437,7 @@ export function deMap(input, key) {
13161437
let TempStr2Int = new Uint8Array();
13171438
let RandomBytes = new Array(2);
13181439
if (!Base64.isValid(TempStr1)) {
1440+
/* v8 ignore next 3 */
13191441
//检查Base64是否合法,如果不合法,那么就没有必要继续处理下去
13201442
throw "Error Decoding. Bad Input or Incorrect Key.";
13211443
}
@@ -1335,23 +1457,16 @@ export function deMap(input, key) {
13351457
TempStr2Int = GZIP_DECOMPRESS(TempStr2Int);
13361458
TempStr2Int = UNISHOX_DECOMPRESS(TempStr2Int);
13371459
} catch (err) {
1460+
/* v8 ignore next 3 */
13381461
//解压缩/解密失败,丢出错误。
13391462
throw "Error Decoding. Bad Input or Incorrect Key.";
13401463
}
13411464

13421465
if (!CheckLuhnBit(TempStr2Int)) {
1466+
/* v8 ignore next 3 */
13431467
//检查密文的校验位是否匹配
1344-
if (
1345-
TempStr2Int.at(TempStr2Int.byteLength - 1) == 2 &&
1346-
TempStr2Int.at(TempStr2Int.byteLength - 2) == 2 &&
1347-
TempStr2Int.at(TempStr2Int.byteLength - 3) == 2
1348-
) {
1349-
//这个兼容性判断将会在未来被移除。
1350-
TempStr2Int = TempStr2Int.subarray(0, TempStr2Int.byteLength - 3);
1351-
} else {
1352-
//校验不通过,则丢出错误。
1353-
throw "Error Decrypting. Checksum Mismatch.";
1354-
}
1468+
//校验不通过,则丢出错误。
1469+
throw "Error Decrypting. Checksum Mismatch.";
13551470
} else {
13561471
//校验通过,则移除校验位。
13571472
TempStr2Int = TempStr2Int.subarray(0, TempStr2Int.byteLength - 1);
@@ -1486,6 +1601,7 @@ export function getCryptText(text, type) {
14861601
}
14871602
}
14881603
}
1604+
/* v8 ignore next 2 */
14891605
return NULL_STR;
14901606
}
14911607

@@ -1503,6 +1619,7 @@ export function findOriginText(text) {
15031619
if (res) {
15041620
return res;
15051621
} else {
1622+
/* v8 ignore next 2 */
15061623
return NULL_STR;
15071624
}
15081625
}

vite.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export default defineConfig({
1515
"dist",
1616
"JavyInputAppendix.js",
1717
"src/javascript/unishox2.js",
18+
"docs",
1819
],
1920
},
2021
},

0 commit comments

Comments
 (0)