blob: 83bda2024ac9dba1343a02d0e137ece91a290ffe [file] [log] [blame]
// This file has been migrated.
library impl.digest.cshake;
import 'dart:typed_data';
import 'package:pointycastle/api.dart';
import 'package:pointycastle/digests/shake.dart';
import 'package:pointycastle/digests/xof_utils.dart';
import 'package:pointycastle/src/registry/registry.dart';
import 'package:pointycastle/src/utils.dart';
///
/// implementation of SHAKE based on following KeccakNISTInterface.c from http://keccak.noekeon.org/
///
/// Following the naming conventions used in the C source code to enable easy review of the implementation.
///
class CSHAKEDigest extends SHAKEDigest implements Xof {
static final RegExp _cshakeREGEX = RegExp(r'^CSHAKE-([0-9]+)$');
/// Intended for internal use.
static final FactoryConfig factoryConfig = DynamicFactoryConfig(
Digest,
_cshakeREGEX,
(_, final Match match) => () {
var bitLength = int.parse(match.group(1)!);
return CSHAKEDigest(bitLength);
});
Uint8List? _diff;
final _padding = Uint8List(100);
CSHAKEDigest([int bitLength = 256, Uint8List? N, Uint8List? S]) {
switch (bitLength) {
case 128:
case 256:
init(bitLength);
if ((N == null || N.isEmpty) && (S == null || S.isEmpty)) {
_diff = null;
} else {
_diff = concatUint8List([
XofUtils.leftEncode(rate ~/ 8),
_encodeString(N),
_encodeString(S)
]);
_diffPadAndAbsorb();
}
break;
default:
throw StateError(
'invalid bitLength ($bitLength) for CSHAKE must only be 128 or 256');
}
}
@override
String get algorithmName => 'CSHAKE-$fixedOutputLength';
@override
int doOutput(Uint8List out, int outOff, int outLen) {
if (_diff != null) {
if (!squeezing) {
absorbBits(0x00, 2);
}
squeeze(out, outOff, (outLen) * 8);
return outLen;
} else {
return super.doOutput(out, outOff, outLen);
}
}
@override
void update(Uint8List inp, int inpOff, int len) {
absorbRange(inp, inpOff, len);
}
@override
void reset() {
super.reset();
if (_diff != null) {
_diffPadAndAbsorb();
}
}
// bytepad in SP 800-185
void _diffPadAndAbsorb() {
var blockSize = rate ~/ 8;
absorbRange(_diff!, 0, _diff!.length);
var delta = _diff!.length % blockSize;
// only add padding if needed
if (delta != 0) {
var required = blockSize - delta;
while (required > _padding.length) {
absorbRange(_padding, 0, _padding.length);
required -= _padding.length;
}
absorbRange(_padding, 0, required);
}
}
Uint8List _encodeString(Uint8List? str) {
if (str == null || str.isEmpty) {
return XofUtils.leftEncode(0);
}
return concatUint8List([XofUtils.leftEncode(str.length * 8), str]);
}
}