diff --git a/Classes/FCryptoQWORD.uc b/Classes/FCryptoQWORD.uc new file mode 100644 index 0000000..de0a652 --- /dev/null +++ b/Classes/FCryptoQWORD.uc @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2024 Tuomo Kriikkula + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +class FCryptoQWORD extends Object + abstract + notplaceable; + +// 64-bit integer simulated as two 32-bit integers. +struct FCQWORD +{ + var int A; // High. + var int B; // Low. +}; + +// Return A > B. +final static function bool IsGt(FCQWORD A, FCQWORD B) +{ + if (IsGt_AsUInt32(A.A, B.A)) + { + return True; + } + + return IsGt_AsUInt32(A.B, B.B); +} + +// Interpret A and B as unsigned 32-bit integers and return A > B. +final static function bool IsGt_AsUInt32(int A, int B) +{ + local int Ltb; + local int Gtb; + + // All bits in A that are less than their corresponding bits in B. + Ltb = ~A & B; + + // All bits in A that are greater than their corresponding bits in B. + Gtb = A & ~B; + + Ltb = Ltb | (Ltb >>> 1); + Ltb = Ltb | (Ltb >>> 2); + Ltb = Ltb | (Ltb >>> 4); + Ltb = Ltb | (Ltb >>> 8); + Ltb = Ltb | (Ltb >>> 16); + + // A > B --> non-zero. + // A <= B --> zero. + return bool(Gtb & ~Ltb); +} diff --git a/Classes/FCryptoSHA2.uc b/Classes/FCryptoSHA2.uc index 58a7cc0..3dc28c7 100644 --- a/Classes/FCryptoSHA2.uc +++ b/Classes/FCryptoSHA2.uc @@ -40,7 +40,7 @@ class FCryptoSHA2 extends Object; var const array SHA224_IV; var const array SHA256_IV; var const array K_SMALL; -// var const array K_BIG; // TODO +var const array K_BIG; static final function Sha2SmallRound( const out array Buf, @@ -343,47 +343,46 @@ DefaultProperties 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2 )} - // TODO: QWORDs needed? - // K_BIG={( - // 0x428A2F98D728AE22, 0x7137449123EF65CD, - // 0xB5C0FBCFEC4D3B2F, 0xE9B5DBA58189DBBC, - // 0x3956C25BF348B538, 0x59F111F1B605D019, - // 0x923F82A4AF194F9B, 0xAB1C5ED5DA6D8118, - // 0xD807AA98A3030242, 0x12835B0145706FBE, - // 0x243185BE4EE4B28C, 0x550C7DC3D5FFB4E2, - // 0x72BE5D74F27B896F, 0x80DEB1FE3B1696B1, - // 0x9BDC06A725C71235, 0xC19BF174CF692694, - // 0xE49B69C19EF14AD2, 0xEFBE4786384F25E3, - // 0x0FC19DC68B8CD5B5, 0x240CA1CC77AC9C65, - // 0x2DE92C6F592B0275, 0x4A7484AA6EA6E483, - // 0x5CB0A9DCBD41FBD4, 0x76F988DA831153B5, - // 0x983E5152EE66DFAB, 0xA831C66D2DB43210, - // 0xB00327C898FB213F, 0xBF597FC7BEEF0EE4, - // 0xC6E00BF33DA88FC2, 0xD5A79147930AA725, - // 0x06CA6351E003826F, 0x142929670A0E6E70, - // 0x27B70A8546D22FFC, 0x2E1B21385C26C926, - // 0x4D2C6DFC5AC42AED, 0x53380D139D95B3DF, - // 0x650A73548BAF63DE, 0x766A0ABB3C77B2A8, - // 0x81C2C92E47EDAEE6, 0x92722C851482353B, - // 0xA2BFE8A14CF10364, 0xA81A664BBC423001, - // 0xC24B8B70D0F89791, 0xC76C51A30654BE30, - // 0xD192E819D6EF5218, 0xD69906245565A910, - // 0xF40E35855771202A, 0x106AA07032BBD1B8, - // 0x19A4C116B8D2D0C8, 0x1E376C085141AB53, - // 0x2748774CDF8EEB99, 0x34B0BCB5E19B48A8, - // 0x391C0CB3C5C95A63, 0x4ED8AA4AE3418ACB, - // 0x5B9CCA4F7763E373, 0x682E6FF3D6B2B8A3, - // 0x748F82EE5DEFB2FC, 0x78A5636F43172F60, - // 0x84C87814A1F0AB72, 0x8CC702081A6439EC, - // 0x90BEFFFA23631E28, 0xA4506CEBDE82BDE9, - // 0xBEF9A3F7B2C67915, 0xC67178F2E372532B, - // 0xCA273ECEEA26619C, 0xD186B8C721C0C207, - // 0xEADA7DD6CDE0EB1E, 0xF57D4F7FEE6ED178, - // 0x06F067AA72176FBA, 0x0A637DC5A2C898A6, - // 0x113F9804BEF90DAE, 0x1B710B35131C471B, - // 0x28DB77F523047D84, 0x32CAAB7B40C72493, - // 0x3C9EBE0A15C9BEBC, 0x431D67C49C100D4C, - // 0x4CC5D4BECB3E42B6, 0x597F299CFC657E2A, - // 0x5FCB6FAB3AD6FAEC, 0x6C44198C4A475817 - // )} + K_BIG={( + (A=0x428A2F98, B=0xD728AE22), (A=0x71374491, B=0x23EF65CD), + (A=0xB5C0FBCF, B=0xEC4D3B2F), (A=0xE9B5DBA5, B=0x8189DBBC), + (A=0x3956C25B, B=0xF348B538), (A=0x59F111F1, B=0xB605D019), + (A=0x923F82A4, B=0xAF194F9B), (A=0xAB1C5ED5, B=0xDA6D8118), + (A=0xD807AA98, B=0xA3030242), (A=0x12835B01, B=0x45706FBE), + (A=0x243185BE, B=0x4EE4B28C), (A=0x550C7DC3, B=0xD5FFB4E2), + (A=0x72BE5D74, B=0xF27B896F), (A=0x80DEB1FE, B=0x3B1696B1), + (A=0x9BDC06A7, B=0x25C71235), (A=0xC19BF174, B=0xCF692694), + (A=0xE49B69C1, B=0x9EF14AD2), (A=0xEFBE4786, B=0x384F25E3), + (A=0x0FC19DC6, B=0x8B8CD5B5), (A=0x240CA1CC, B=0x77AC9C65), + (A=0x2DE92C6F, B=0x592B0275), (A=0x4A7484AA, B=0x6EA6E483), + (A=0x5CB0A9DC, B=0xBD41FBD4), (A=0x76F988DA, B=0x831153B5), + (A=0x983E5152, B=0xEE66DFAB), (A=0xA831C66D, B=0x2DB43210), + (A=0xB00327C8, B=0x98FB213F), (A=0xBF597FC7, B=0xBEEF0EE4), + (A=0xC6E00BF3, B=0x3DA88FC2), (A=0xD5A79147, B=0x930AA725), + (A=0x06CA6351, B=0xE003826F), (A=0x14292967, B=0x0A0E6E70), + (A=0x27B70A85, B=0x46D22FFC), (A=0x2E1B2138, B=0x5C26C926), + (A=0x4D2C6DFC, B=0x5AC42AED), (A=0x53380D13, B=0x9D95B3DF), + (A=0x650A7354, B=0x8BAF63DE), (A=0x766A0ABB, B=0x3C77B2A8), + (A=0x81C2C92E, B=0x47EDAEE6), (A=0x92722C85, B=0x1482353B), + (A=0xA2BFE8A1, B=0x4CF10364), (A=0xA81A664B, B=0xBC423001), + (A=0xC24B8B70, B=0xD0F89791), (A=0xC76C51A3, B=0x0654BE30), + (A=0xD192E819, B=0xD6EF5218), (A=0xD6990624, B=0x5565A910), + (A=0xF40E3585, B=0x5771202A), (A=0x106AA070, B=0x32BBD1B8), + (A=0x19A4C116, B=0xB8D2D0C8), (A=0x1E376C08, B=0x5141AB53), + (A=0x2748774C, B=0xDF8EEB99), (A=0x34B0BCB5, B=0xE19B48A8), + (A=0x391C0CB3, B=0xC5C95A63), (A=0x4ED8AA4A, B=0xE3418ACB), + (A=0x5B9CCA4F, B=0x7763E373), (A=0x682E6FF3, B=0xD6B2B8A3), + (A=0x748F82EE, B=0x5DEFB2FC), (A=0x78A5636F, B=0x43172F60), + (A=0x84C87814, B=0xA1F0AB72), (A=0x8CC70208, B=0x1A6439EC), + (A=0x90BEFFFA, B=0x23631E28), (A=0xA4506CEB, B=0xDE82BDE9), + (A=0xBEF9A3F7, B=0xB2C67915), (A=0xC67178F2, B=0xE372532B), + (A=0xCA273ECE, B=0xEA26619C), (A=0xD186B8C7, B=0x21C0C207), + (A=0xEADA7DD6, B=0xCDE0EB1E), (A=0xF57D4F7F, B=0xEE6ED178), + (A=0x06F067AA, B=0x72176FBA), (A=0x0A637DC5, B=0xA2C898A6), + (A=0x113F9804, B=0xBEF90DAE), (A=0x1B710B35, B=0x131C471B), + (A=0x28DB77F5, B=0x23047D84), (A=0x32CAAB7B, B=0x40C72493), + (A=0x3C9EBE0A, B=0x15C9BEBC), (A=0x431D67C4, B=0x9C100D4C), + (A=0x4CC5D4BE, B=0xCB3E42B6), (A=0x597F299C, B=0xFC657E2A), + (A=0x5FCB6FAB, B=0x3AD6FAEC), (A=0x6C44198C, B=0x4A475817) + )} } diff --git a/Classes/FCryptoTestMutator.uc b/Classes/FCryptoTestMutator.uc index d5665c0..fe31fb8 100644 --- a/Classes/FCryptoTestMutator.uc +++ b/Classes/FCryptoTestMutator.uc @@ -990,6 +990,43 @@ private final simulated function int TestOperations() `endif } +// TODO: prototyping. +final static function bool IsEq(int A, int B) +{ + local int C; + + C = A ^ B; + C = C | (C >>> 16); + C = C | (C >>> 8); + C = C | (C >>> 4); + C = C | (C >>> 2); + C = C | (C >>> 1); + return bool(-(C & 1)); +} + +// TODO: prototyping. +final static function bool IsGt(int A, int B) +{ + local int Ltb; + local int Gtb; + + // These are all the bits in a that are less than their corresponding bits in b. + Ltb = ~A & B; + + // These are all the bits in a that are greater than their corresponding bits in b. + Gtb = A & ~B; + + Ltb = Ltb | (Ltb >>> 1); + Ltb = Ltb | (Ltb >>> 2); + Ltb = Ltb | (Ltb >>> 4); + Ltb = Ltb | (Ltb >>> 8); + Ltb = Ltb | (Ltb >>> 16); + + // Nonzero if a > b + // Zero if a <= b + return bool(Gtb & ~Ltb); +} + // Mirrors most of the tests from BearSSL's test_match.c, // with some UnrealScript-specific additions. private final simulated function int TestMath() @@ -1026,8 +1063,10 @@ private final simulated function int TestMath() local string BigIntString; local int Dummy; + local FCQWORD QW; + local bool bQWCarry; - // TODO: Design for QWORD arithmetic. + // TODO: Design for FCQWORD arithmetic. Dummy = 0xFFFFFFFF; `fclog("Dummy=" $ Dummy); `fclog("Dummy=" $ ToHex(Dummy)); @@ -1035,6 +1074,41 @@ private final simulated function int TestMath() `fclog("Dummy=" $ Dummy); `fclog("Dummy=" $ ToHex(Dummy)); + QW.A = 0x00000000; + QW.B = 0xFFFFFFFF; + QW.B += 0xF; + `fclog("QW.B=" $ QW.B); + `fclog("QW.B=" $ ToHex(QW.B)); + bQWCarry = QW.B < 0xFFFFFFFF; // TODO: might need a bitwise check for this? + `fclog("bQWCarry=" $ bQWCarry); + + QW.B = MaxInt; + QW.B += 0xF; + `fclog("QW.B=" $ QW.B); + `fclog("QW.B=" $ ToHex(QW.B)); + bQWCarry = QW.B < 0xFFFFFFFF; // TODO: might need a bitwise check for this? + `fclog("bQWCarry=" $ bQWCarry); + + `fclog("0x00000000 == 0xFFFFFFFF :" @ IsEq(0x00000000, 0xFFFFFFFF)); + `fclog("0xFFFFFFFF == 0xFFFFFFFF :" @ IsEq(0xFFFFFFFF, 0xFFFFFFFF)); + `fclog("0x00000000 == 0x00000000 :" @ IsEq(0x00000000, 0x00000000)); + `fclog("0x7FFFFFFF == 0x00000000 :" @ IsEq(0x7FFFFFFF, 0x00000000)); + `fclog("0x00000000 == 0x7FFFFFFF :" @ IsEq(0x00000000, 0x7FFFFFFF)); + `fclog("0x00000001 == 0x00000002 :" @ IsEq(0x00000001, 0x00000002)); + `fclog("0x00000002 == 0x00000001 :" @ IsEq(0x00000002, 0x00000001)); + `fclog("0x7FFFFFFF == 0xFFFFFFFF :" @ IsEq(0x7FFFFFFF, 0xFFFFFFFF)); + `fclog("0xFFFFFFFF == 0x7FFFFFFF :" @ IsEq(0xFFFFFFFF, 0x7FFFFFFF)); + + `fclog("0x00000000 > 0xFFFFFFFF :" @ IsGt(0x00000000, 0xFFFFFFFF)); + `fclog("0xFFFFFFFF > 0xFFFFFFFF :" @ IsGt(0xFFFFFFFF, 0xFFFFFFFF)); + `fclog("0x00000000 > 0x00000000 :" @ IsGt(0x00000000, 0x00000000)); + `fclog("0x7FFFFFFF > 0x00000000 :" @ IsGt(0x7FFFFFFF, 0x00000000)); + `fclog("0x00000000 > 0x7FFFFFFF :" @ IsGt(0x00000000, 0x7FFFFFFF)); + `fclog("0x00000001 > 0x00000002 :" @ IsGt(0x00000001, 0x00000002)); + `fclog("0x00000002 > 0x00000001 :" @ IsGt(0x00000002, 0x00000001)); + `fclog("0x7FFFFFFF > 0xFFFFFFFF :" @ IsGt(0x7FFFFFFF, 0xFFFFFFFF)); + `fclog("0xFFFFFFFF > 0x7FFFFFFF :" @ IsGt(0xFFFFFFFF, 0x7FFFFFFF)); + // BearSSL assumes all operands caller-allocated. // We'll do some bare minimum allocations here to avoid issues. // TODO: does UScript dynamic array allocation break CT guarantees? diff --git a/Classes/FCryptoUtils.uc b/Classes/FCryptoUtils.uc index 1027b02..9c363f7 100644 --- a/Classes/FCryptoUtils.uc +++ b/Classes/FCryptoUtils.uc @@ -88,3 +88,26 @@ static final function bool FromHex(string HexString, out int Result) Result = Res; return True; } + +// TODO: just use BytesFromHex from FCryptoBigInt? And move it here? +/* + * Decode a hexadecimal string. Returned value is the number of decoded + * bytes. + */ +// static final function int HexToBin(out string Dst, string Src) +// { +// local int Num; +// local int Acc; +// local int Z; + +// Num = 0; +// Z = 0; +// Acc = 0; + +// while (False) +// { + +// } + +// return Num; +// }