| // See file LICENSE for more information. |
| |
| import 'dart:typed_data'; |
| |
| import 'package:pointycastle/src/platform_check/platform_check.dart'; |
| |
| void arrayCopy(Uint8List? sourceArr, int sourcePos, Uint8List? outArr, |
| int outPos, int len) { |
| for (var i = 0; i < len; i++) { |
| outArr![outPos + i] = sourceArr![sourcePos + i]; |
| } |
| } |
| |
| /// |
| ///A constant time equals comparison - does not terminate early if |
| ///test will fail. For best results always pass the expected value |
| ///as the first parameter. |
| /// |
| /// @param expected first array |
| /// @param supplied second array |
| /// @return true if arrays equal, false otherwise. |
| /// |
| bool constantTimeAreEqual(Uint8List expected, Uint8List supplied) { |
| if (expected == supplied) { |
| return true; |
| } |
| |
| var len = |
| (expected.length < supplied.length) ? expected.length : supplied.length; |
| |
| var nonEqual = expected.length ^ supplied.length; |
| |
| for (var i = 0; i != len; i++) { |
| nonEqual |= expected[i] ^ supplied[i]; |
| } |
| for (var i = len; i < supplied.length; i++) { |
| nonEqual |= supplied[i] ^ ~supplied[i]; |
| } |
| |
| return nonEqual == 0; |
| } |
| |
| Uint8List concatUint8List(Iterable<Uint8List> list) => |
| Uint8List.fromList(list.expand((element) => element).toList()); |
| |
| /// Decode a BigInt from bytes in big-endian encoding. |
| /// Twos compliment. |
| BigInt decodeBigInt(List<int> bytes) { |
| var negative = bytes.isNotEmpty && bytes[0] & 0x80 == 0x80; |
| |
| BigInt result; |
| |
| if (bytes.length == 1) { |
| result = BigInt.from(bytes[0]); |
| } else { |
| result = BigInt.zero; |
| for (var i = 0; i < bytes.length; i++) { |
| var item = bytes[bytes.length - i - 1]; |
| result |= BigInt.from(item) << (8 * i); |
| } |
| } |
| return result != BigInt.zero |
| ? negative |
| ? result.toSigned(result.bitLength) |
| : result |
| : BigInt.zero; |
| } |
| |
| /// Decode a big integer with arbitrary sign. |
| /// When: |
| /// sign == 0: Zero regardless of magnitude |
| /// sign < 0: Negative |
| /// sign > 0: Positive |
| BigInt decodeBigIntWithSign(int sign, List<int> magnitude) { |
| if (sign == 0) { |
| return BigInt.zero; |
| } |
| |
| BigInt result; |
| |
| if (magnitude.length == 1) { |
| result = BigInt.from(magnitude[0]); |
| } else { |
| result = BigInt.from(0); |
| for (var i = 0; i < magnitude.length; i++) { |
| var item = magnitude[magnitude.length - i - 1]; |
| result |= BigInt.from(item) << (8 * i); |
| } |
| } |
| |
| if (result != BigInt.zero) { |
| if (sign < 0) { |
| result = result.toSigned(result.bitLength); |
| } else { |
| result = result.toUnsigned(result.bitLength); |
| } |
| } |
| return result; |
| } |
| |
| var _byteMask = BigInt.from(0xff); |
| final negativeFlag = BigInt.from(0x80); |
| |
| /// Encode a BigInt into bytes using big-endian encoding. |
| /// It encodes the integer to a minimal twos-compliment integer as defined by |
| /// ASN.1 |
| Uint8List encodeBigInt(BigInt? number) { |
| if (number == BigInt.zero) { |
| return Uint8List.fromList([0]); |
| } |
| |
| int needsPaddingByte; |
| int rawSize; |
| |
| if (number! > BigInt.zero) { |
| rawSize = (number.bitLength + 7) >> 3; |
| needsPaddingByte = |
| ((number >> (rawSize - 1) * 8) & negativeFlag) == negativeFlag ? 1 : 0; |
| } else { |
| needsPaddingByte = 0; |
| rawSize = (number.bitLength + 8) >> 3; |
| } |
| |
| final size = rawSize + needsPaddingByte; |
| var result = Uint8List(size); |
| for (var i = 0; i < rawSize; i++) { |
| result[size - i - 1] = (number! & _byteMask).toInt(); |
| number = number >> 8; |
| } |
| return result; |
| } |
| |
| /// Encode as Big Endian unsigned byte array. |
| Uint8List encodeBigIntAsUnsigned(BigInt number) { |
| if (number == BigInt.zero) { |
| return Uint8List.fromList([0]); |
| } |
| var size = number.bitLength + (number.isNegative ? 8 : 7) >> 3; |
| var result = Uint8List(size); |
| for (var i = 0; i < size; i++) { |
| result[size - i - 1] = (number & _byteMask).toInt(); |
| number = number >> 8; |
| } |
| return result; |
| } |
| |
| bool constantTimeAreEqualOffset( |
| int len, Uint8List a, int aOff, Uint8List b, int bOff) { |
| if (len < 0) { |
| throw ArgumentError('"len" cannot be negative'); |
| } |
| if (aOff > (a.length - len)) { |
| throw ArgumentError('"aOff" value invalid for specified length'); |
| } |
| if (bOff > (b.length - len)) { |
| throw ArgumentError('"bOff" value invalid for specified length'); |
| } |
| |
| var d = 0; |
| for (var i = 0; i < len; ++i) { |
| d |= a[aOff + i] ^ b[bOff + i]; |
| } |
| return 0 == d; |
| } |
| |
| abstract class Pack { |
| static int littleEndianToLong(Uint8List bs, int off) { |
| var data = ByteData.view(bs.buffer); |
| return data.getInt64(off, Endian.little); |
| } |
| |
| static void littleEndianToLongAtList(Uint8List bs, int off, Uint64List ns) { |
| for (var i = 0; i < ns.length; ++i) { |
| ns[i] = littleEndianToLong(bs, off); |
| off += 8; |
| } |
| } |
| |
| static void littleEndianToInt32AtList(Uint8List bs, int off, Uint32List ns) { |
| for (var i = 0; i < ns.length; ++i) { |
| ns[i] = littleEndianToInt(bs, off); |
| off += 4; |
| } |
| } |
| |
| static void intToLittleEndian(int n, Uint8List bs, int off) { |
| var data = ByteData.view(bs.buffer); |
| data.setInt32(off, n, Endian.little); |
| } |
| |
| static Uint8List longToLittleEndianList(int n) { |
| var bs = Uint8List(8); |
| longToLittleEndianAtList(n, bs, 0); |
| return bs; |
| } |
| |
| static void longToLittleEndianAtList(int n, Uint8List bs, int off) { |
| var data = ByteData.view(bs.buffer); |
| data.setInt64(off, n, Endian.little); |
| } |
| |
| static Uint8List longListToLittleEndianList(Uint64List ns) { |
| var bs = Uint8List(8 * ns.length); |
| longListToLittleEndianAtList(ns, bs, 0); |
| return bs; |
| } |
| |
| static void longListToLittleEndianAtList( |
| Uint64List ns, Uint8List bs, int off) { |
| for (var i = 0; i < ns.length; ++i) { |
| longToLittleEndianAtList(ns[i], bs, off); |
| off += 8; |
| } |
| } |
| |
| static int littleEndianToInt(Uint8List bs, int off) { |
| var data = ByteData.view(bs.buffer); |
| return data.getInt32(off, Endian.little); |
| } |
| |
| static Uint8List intToLittleEndianList(int n) { |
| var bs = Uint8List(4); |
| intToLittleEndianAtList(n, bs, 0); |
| return bs; |
| } |
| |
| static void intToLittleEndianAtList(int n, Uint8List bs, int off) { |
| var data = ByteData.view(bs.buffer); |
| data.setInt32(off, n, Endian.little); |
| } |
| |
| static Uint8List intListToLittleEndian(Uint32List ns) { |
| var bs = Uint8List(4 * ns.length); |
| intListToLittleEndianAtList(ns, bs, 0); |
| return bs; |
| } |
| |
| static void intListToLittleEndianAtList( |
| Uint32List ns, Uint8List bs, int off) { |
| for (var i = 0; i < ns.length; ++i) { |
| intToLittleEndianAtList(ns[i], bs, off); |
| off += 4; |
| } |
| } |
| } |
| |
| abstract class Longs { |
| static const _MASK_32 = 0xFFFFFFFF; |
| |
| static const _MASK32_HI_BITS = <int>[ |
| 0xFFFFFFFF, |
| 0x7FFFFFFF, |
| 0x3FFFFFFF, |
| 0x1FFFFFFF, |
| 0x0FFFFFFF, |
| 0x07FFFFFF, |
| 0x03FFFFFF, |
| 0x01FFFFFF, |
| 0x00FFFFFF, |
| 0x007FFFFF, |
| 0x003FFFFF, |
| 0x001FFFFF, |
| 0x000FFFFF, |
| 0x0007FFFF, |
| 0x0003FFFF, |
| 0x0001FFFF, |
| 0x0000FFFF, |
| 0x00007FFF, |
| 0x00003FFF, |
| 0x00001FFF, |
| 0x00000FFF, |
| 0x000007FF, |
| 0x000003FF, |
| 0x000001FF, |
| 0x000000FF, |
| 0x0000007F, |
| 0x0000003F, |
| 0x0000001F, |
| 0x0000000F, |
| 0x00000007, |
| 0x00000003, |
| 0x00000001, |
| 0x00000000 |
| ]; |
| |
| static int rotateRight(int n, int distance) { |
| if (distance == 0) { |
| // do nothing: |
| return n; |
| } |
| |
| var hi32 = (n >> 32) & 0xFFFFFFFF; |
| var lo32 = n & 0xFFFFFFFF; |
| |
| if (distance >= 32) { |
| var swap = hi32; |
| hi32 = lo32; |
| lo32 = swap; |
| distance -= 32; |
| |
| if (distance == 0) { |
| return (hi32 << 32) | lo32; |
| } |
| } |
| |
| final distance32 = 32 - distance; |
| final m = _MASK32_HI_BITS[distance32]; |
| |
| final hi32cp = hi32; |
| |
| hi32 = hi32 >> distance; |
| hi32 |= ((lo32 & m) << distance32) & _MASK_32; |
| |
| lo32 = lo32 >> distance; |
| lo32 |= ((hi32cp & m) << distance32) & _MASK_32; |
| |
| return (hi32 << 32) | lo32; |
| } |
| |
| static int toInt32(int n) => n & 0xFFFFFFFF; |
| } |
| |
| const mask64 = (0xFFFFFFFF << 32) + 0xFFFFFFFF; |
| |
| int unsignedShiftRight64(int n, int count) { |
| if (Platform.instance.isNative) { |
| return (n >> count) & ~(-1 << (64 - count)); |
| } else { |
| count &= 0x1f; |
| if (n >= 0) { |
| return n >> count; |
| } else { |
| return (n >> count) ^ (mask64 ^ ((1 << (64 - count)) - 1)); |
| } |
| } |
| } |