blob: 0ba221d677e921ec8e2bc948674e7fabc5c90b04 [file] [log] [blame] [edit]
// 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));
}
}
}