Skip to content

Commit

Permalink
Add stricter analysis options and fix problems
Browse files Browse the repository at this point in the history
  • Loading branch information
MatthewLM committed Feb 9, 2024
1 parent 73b6c57 commit 9986dc3
Show file tree
Hide file tree
Showing 40 changed files with 92 additions and 76 deletions.
7 changes: 7 additions & 0 deletions coinlib/analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
include: package:lints/recommended.yaml

analyzer:
language:
strict-casts: true
strict-inference: true
strict-raw-types: true

# Lint rules and documentation, see http://dart-lang.github.io/linter/lints
linter:
rules:
Expand All @@ -10,3 +16,4 @@ linter:
- unrelated_type_equality_checks
- valid_regexps
- require_trailing_commas
- comment_references
5 changes: 2 additions & 3 deletions coinlib/lib/src/common/bytes.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,8 @@ Uint8List copyCheckBytes(
Uint8List bytes, int length, { String name = "Bytes", }
) => Uint8List.fromList(checkBytes(bytes, length, name: name));

/// Determines if two objects are equal Uint8List data
bool bytesEqual(Object? a, Object? b)
=> (a is Uint8List) && (b is Uint8List) && ListEquality().equals(a, b);
/// Determines if two [Uint8List] lists are equal
bool bytesEqual(Uint8List a, Uint8List b) => ListEquality<int>().equals(a, b);

/// Compares two Uint8List bytes from the left-most to right-most byte. If all
/// bytes are the same apart from one list being longer, the shortest list comes
Expand Down
12 changes: 6 additions & 6 deletions coinlib/lib/src/common/checks.dart
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@

_checkInt(int i, int min, int max, String type, String name) {
void _checkInt(int i, int min, int max, String type, String name) {
if (i < min || i > max) {
throw ArgumentError.value(i, name, "must be a $type");
}
}

checkUint8(int i, [String name = "i"])
void checkUint8(int i, [String name = "i"])
=> _checkInt(i, 0, 0xff, "uint8", name);

checkUint16(int i, [String name = "i"])
void checkUint16(int i, [String name = "i"])
=> _checkInt(i, 0, 0xffff, "uint16", name);

checkUint32(int i, [String name = "i"])
void checkUint32(int i, [String name = "i"])
=> _checkInt(i, 0, 0xffffffff, "uint32", name);

checkInt32(int i, [String name = "i"])
void checkInt32(int i, [String name = "i"])
=> _checkInt(i, -0x80000000, 0x7fffffff, "int32", name);

final BigInt maxUint64 = (BigInt.from(1) << 64) - BigInt.one;

checkUint64(BigInt i, [String name = "i"]) {
void checkUint64(BigInt i, [String name = "i"]) {
if (i.isNegative || i > maxUint64) {
throw ArgumentError.value(i, name, "must be a uint64");
}
Expand Down
3 changes: 1 addition & 2 deletions coinlib/lib/src/crypto/ec_public_key.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import 'dart:typed_data';
import 'package:coinlib/src/secp256k1/secp256k1.dart';
import 'package:coinlib/src/common/bytes.dart';
import 'package:coinlib/src/common/hex.dart';
import 'package:collection/collection.dart';

class InvalidPublicKey implements Exception {}

Expand Down Expand Up @@ -70,7 +69,7 @@ class ECPublicKey {

@override
bool operator ==(Object other)
=> (other is ECPublicKey) && ListEquality().equals(_data, other._data);
=> (other is ECPublicKey) && bytesEqual(_data, other._data);

@override
int get hashCode => _data[1] | _data[2] << 8 | _data[3] << 16 | _data[4] << 24;
Expand Down
2 changes: 1 addition & 1 deletion coinlib/lib/src/crypto/ecdsa_signature.dart
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ class ECDSASignature {
}
}

/// Takes a BIP66 DER formatted [signature] as a HEX string.
/// Takes a BIP66 DER formatted signature as a HEX string.
/// See [ECDSASignature.fromDer].
factory ECDSASignature.fromDerHex(String hex)
=> ECDSASignature.fromDer(hexToBytes(hex));
Expand Down
4 changes: 2 additions & 2 deletions coinlib/lib/src/crypto/message_signature.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class MagicHash with Writable {
final String prefix;
MagicHash(this.message, this.prefix);

static _writeUtf8(Writer writer, String msg)
static void _writeUtf8(Writer writer, String msg)
=> writer.writeVarSlice(utf8.encode(msg));

@override
Expand All @@ -33,7 +33,7 @@ class MessageSignature {

final ECDSARecoverableSignature signature;

static magicHash(String message, String prefix)
static Uint8List magicHash(String message, String prefix)
=> MagicHash(message, prefix).hash;

MessageSignature.fromBase64(String str)
Expand Down
8 changes: 4 additions & 4 deletions coinlib/lib/src/crypto/nums_public_key.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import 'package:coinlib/src/crypto/random.dart';

/// A "nothing up my sleeve" [ECPublicKey] that is created from a point with no
/// known private key and tweaked with a scalar value named [rTweak]. The key is
/// reproduceable from this scalar using [fromRTweak]. Any of these keys have no
/// known associted private key. Sharing the [rTweak] allows others to verify
/// this. These keys can be used as Taproot internal keys where no key-path
/// spending is desired.
/// reproduceable from this scalar using [fromRTweak()]. Any of
/// these keys have no known associted private key. Sharing the [rTweak] allows
/// others to verify this. These keys can be used as Taproot internal keys where
/// no key-path spending is desired.
class NUMSPublicKey extends ECPublicKey {

/// To prove that this point does not have an associated private key, the
Expand Down
4 changes: 2 additions & 2 deletions coinlib/lib/src/scripts/operations.dart
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import 'dart:typed_data';
import 'package:coinlib/src/common/bytes.dart';
import 'package:coinlib/src/common/hex.dart';
import 'package:coinlib/src/common/serial.dart';
import 'package:coinlib/src/crypto/ec_public_key.dart';
import 'package:coinlib/src/tx/inputs/input_signature.dart';
import 'package:collection/collection.dart';
import 'codes.dart';

class InvalidScriptAsm implements Exception {}
Expand Down Expand Up @@ -312,7 +312,7 @@ class ScriptPushData implements ScriptOp {

@override
bool match(ScriptOp other)
=> (other is ScriptPushData && ListEquality().equals(_data, other._data))
=> (other is ScriptPushData && bytesEqual(_data, other._data))
|| (other is ScriptPushDataMatcher && _data.length == other.size);

}
Expand Down
4 changes: 2 additions & 2 deletions coinlib/lib/src/scripts/program.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ abstract class Program {

/// Takes a [script] and constructs a matching Program subclass if one exists,
/// or a basic [RawProgram] if there is no match. The script should use
/// minimal pushes. [decompile] can be used directly on compiled scripts or
/// [fromAsm] can be used to match directly against ASM.
/// minimal pushes. [Program.decompile] can be used directly on compiled
/// scripts or [Program.fromAsm] can be used to match directly against ASM.
factory Program.match(Script script) {

try {
Expand Down
2 changes: 1 addition & 1 deletion coinlib/lib/src/scripts/programs/p2sh.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class P2SH implements Program {
late final Uint8List _scriptHash;

/// Construct using an output script, not to be confused with the redeem
/// script. For that use [fromRedeemScript].
/// script. For that use [fromRedeemScript()].
P2SH.fromScript(this.script) {
if (!template.match(script)) throw NoProgramMatch();
_scriptHash = (script[1] as ScriptPushData).data;
Expand Down
2 changes: 1 addition & 1 deletion coinlib/lib/src/scripts/programs/p2wsh.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import 'package:coinlib/src/scripts/script.dart';
class P2WSH extends P2Witness {

/// Construct using an output script, not to be confused with the witness
/// script. For that use [fromWitnessScript].
/// script. For that use [P2WSH.fromWitnessScript].
P2WSH.fromScript(super.script) : super.fromScript() {
if (data.length != 32 || version != 0) throw NoProgramMatch();
}
Expand Down
2 changes: 1 addition & 1 deletion coinlib/lib/src/secp256k1/heap_array_base.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ import 'dart:typed_data';
abstract class HeapArrayBase<Ptr> {
Ptr get ptr;
Uint8List get list;
load(Uint8List data);
void load(Uint8List data);
}
2 changes: 1 addition & 1 deletion coinlib/lib/src/secp256k1/heap_array_wasm.dart
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,6 @@ class HeapArrayWasmFactory {

HeapArrayWasmFactory(this.memory, this.malloc, this.free);

create(int size) => HeapArrayWasm(size, memory, malloc, free);
HeapArrayWasm create(int size) => HeapArrayWasm(size, memory, malloc, free);

}
25 changes: 15 additions & 10 deletions coinlib/lib/src/secp256k1/secp256k1_base.dart
Original file line number Diff line number Diff line change
Expand Up @@ -90,13 +90,16 @@ abstract class Secp256k1Base<
) extSchnorrVerify;

// Heap arrays
late HeapArrayBase key32Array; // Used for private keys and x-only public keys
late HeapArrayBase scalarArray;
late HeapArrayBase serializedPubKeyArray;
late HeapArrayBase hashArray;
late HeapArrayBase entropyArray;
late HeapArrayBase serializedSigArray;
late HeapArrayBase derSigArray;

// Used for private keys and x-only public keys
late HeapArrayBase<HeapArrayPtr> key32Array;

late HeapArrayBase<HeapArrayPtr> scalarArray;
late HeapArrayBase<HeapArrayPtr> serializedPubKeyArray;
late HeapArrayBase<HeapArrayPtr> hashArray;
late HeapArrayBase<HeapArrayPtr> entropyArray;
late HeapArrayBase<HeapArrayPtr> serializedSigArray;
late HeapArrayBase<HeapArrayPtr> derSigArray;

// Other pointers
late CtxPtr ctxPtr;
Expand Down Expand Up @@ -194,7 +197,7 @@ abstract class Secp256k1Base<
Future<void> internalLoad() async {}

bool _loaded = false;
_requireLoad() {
void _requireLoad() {
if (!_loaded) throw Secp256k1Exception("load() not called");
}

Expand Down Expand Up @@ -311,7 +314,9 @@ abstract class Secp256k1Base<
// Using null as it doesn't require passing an additional constant from
// the web and io implementations.
nullPtr,
extraEntropy == null ? nullPtr : entropyArray.ptr,
// The pointer is not actually null when entropy is provided but NullPtr
// works for void pointers too
extraEntropy == null ? nullPtr : entropyArray.ptr as NullPtr,
) != 1
) {
throw Secp256k1Exception("Cannot sign message with private key");
Expand Down Expand Up @@ -441,7 +446,7 @@ abstract class Secp256k1Base<
if (
extSchnorrSign32(
ctxPtr, serializedSigArray.ptr, hashArray.ptr, keyPairPtr,
extraEntropy == null ? nullPtr : entropyArray.ptr,
extraEntropy == null ? nullPtr as HeapArrayPtr : entropyArray.ptr,
) != 1
) {
throw Secp256k1Exception("Cannot sign Schnorr signature");
Expand Down
6 changes: 3 additions & 3 deletions coinlib/lib/src/secp256k1/secp256k1_web.dart
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ class Secp256k1 extends Secp256k1Base<
// Dummy WASI imports. No file descriptor support provided.
importMap: {
"wasi_snapshot_preview1" : {
"fd_close": () => {},
"fd_seek": () => {},
"fd_write": () => {},
"fd_close": () => Object(),
"fd_seek": () => Object(),
"fd_write": () => Object(),
},
},
);
Expand Down
3 changes: 2 additions & 1 deletion coinlib/lib/src/taproot.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'dart:typed_data';
import 'package:coinlib/src/common/bytes.dart';
import 'package:coinlib/src/common/serial.dart';
import 'package:coinlib/src/crypto/ec_private_key.dart';
import 'package:coinlib/src/crypto/ec_public_key.dart';
Expand Down Expand Up @@ -186,7 +187,7 @@ class TapLeaf with Writable implements TapNode {
bool operator ==(Object other)
=> (other is TapLeaf)
&& version == other.version
&& ListEquality().equals(script.compiled, other.script.compiled);
&& bytesEqual(script.compiled, other.script.compiled);

@override
int get hashCode => hash[0] | hash[1] << 8 | hash[2] << 16 | hash[3] << 24;
Expand Down
4 changes: 2 additions & 2 deletions coinlib/lib/src/tx/inputs/input.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import 'p2sh_multisig_input.dart';
import 'raw_input.dart';
import 'witness_input.dart';

/// The base class for all inputs, providing the [match] factory constructor to
/// determine the appropriate subclass from a [RawInput]
/// The base class for all inputs, providing the [Input.match] factory
/// constructor to determine the appropriate subclass from a [RawInput]
abstract class Input with Writable {

static const sequenceFinal = 0xffffffff;
Expand Down
1 change: 1 addition & 0 deletions coinlib/lib/src/tx/inputs/input_signature.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'dart:typed_data';
import 'package:coinlib/src/crypto/ecdsa_signature.dart';
import 'package:coinlib/src/crypto/schnorr_signature.dart';
import 'package:coinlib/src/tx/sighash/sighash_type.dart';
import 'input.dart';

class InvalidInputSignature implements Exception {}

Expand Down
6 changes: 4 additions & 2 deletions coinlib/lib/src/tx/inputs/legacy_input.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import 'package:coinlib/src/tx/sighash/sighash_type.dart';
import 'package:coinlib/src/tx/transaction.dart';
import 'input.dart';
import 'input_signature.dart';
import 'p2pkh_input.dart';
import 'p2sh_multisig_input.dart';
import 'raw_input.dart';

/// Inputs that are not witness inputs: [P2PKHInput] and [P2SHMultisigInput].
Expand All @@ -24,7 +26,7 @@ abstract class LegacyInput extends RawInput {
required Transaction tx,
required int inputN,
required ECPrivateKey key,
hashType = const SigHashType.all(),
SigHashType hashType = const SigHashType.all(),
});

/// Creates a signature for the input. Used by subclasses to implement
Expand All @@ -34,7 +36,7 @@ abstract class LegacyInput extends RawInput {
required int inputN,
required ECPrivateKey key,
required Script scriptCode,
hashType = const SigHashType.all(),
SigHashType hashType = const SigHashType.all(),
}) => ECDSAInputSignature(
ECDSASignature.sign(
key,
Expand Down
4 changes: 2 additions & 2 deletions coinlib/lib/src/tx/inputs/legacy_witness_input.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ abstract class LegacyWitnessInput extends WitnessInput {
required int inputN,
required ECPrivateKey key,
required BigInt value,
hashType = const SigHashType.all(),
SigHashType hashType = const SigHashType.all(),
});

/// Creates a signature for the input. Used by subclasses to implement
Expand All @@ -38,7 +38,7 @@ abstract class LegacyWitnessInput extends WitnessInput {
required ECPrivateKey key,
required Script scriptCode,
required BigInt value,
hashType = const SigHashType.all(),
SigHashType hashType = const SigHashType.all(),
}) => ECDSAInputSignature(
ECDSASignature.sign(
key,
Expand Down
1 change: 1 addition & 0 deletions coinlib/lib/src/tx/inputs/p2sh_multisig_input.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import 'package:coinlib/src/crypto/ec_public_key.dart';
import 'package:coinlib/src/scripts/operations.dart';
import 'package:coinlib/src/scripts/program.dart';
import 'package:coinlib/src/scripts/programs/multisig.dart';
import 'package:coinlib/src/scripts/programs/p2sh.dart';
import 'package:coinlib/src/scripts/script.dart';
import 'package:coinlib/src/tx/sighash/legacy_signature_hasher.dart';
import 'package:coinlib/src/tx/sighash/sighash_type.dart';
Expand Down
1 change: 1 addition & 0 deletions coinlib/lib/src/tx/inputs/p2wpkh_input.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'dart:typed_data';
import 'package:coinlib/src/crypto/ec_private_key.dart';
import 'package:coinlib/src/crypto/ec_public_key.dart';
import 'package:coinlib/src/scripts/programs/p2wpkh.dart';
import 'package:coinlib/src/tx/sighash/sighash_type.dart';
import 'package:coinlib/src/tx/transaction.dart';
import 'input.dart';
Expand Down
4 changes: 2 additions & 2 deletions coinlib/lib/src/tx/inputs/taproot_input.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ abstract class TaprootInput extends WitnessInput {
required int inputN,
required ECPrivateKey key,
required List<Output> prevOuts,
hashType = const SigHashType.all(),
SigHashType hashType = const SigHashType.all(),
}) => throw CannotSignInput("Unimplemented sign() for {this.runtimeType}");

/// Creates a signature for the input. Used by subclasses to implement
Expand All @@ -37,7 +37,7 @@ abstract class TaprootInput extends WitnessInput {
required int inputN,
required ECPrivateKey key,
required List<Output> prevOuts,
hashType = const SigHashType.all(),
SigHashType hashType = const SigHashType.all(),
Uint8List? leafHash,
int codeSeperatorPos = 0xFFFFFFFF,
}) => SchnorrInputSignature(
Expand Down
2 changes: 1 addition & 1 deletion coinlib/lib/src/tx/inputs/taproot_key_input.dart
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ class TaprootKeyInput extends TaprootInput {
required int inputN,
required ECPrivateKey key,
required List<Output> prevOuts,
hashType = const SigHashType.all(),
SigHashType hashType = const SigHashType.all(),
}) {

if (inputN >= prevOuts.length) {
Expand Down
2 changes: 1 addition & 1 deletion coinlib/lib/src/tx/inputs/taproot_script_input.dart
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ class TaprootScriptInput extends TaprootInput {
required int inputN,
required ECPrivateKey key,
required List<Output> prevOuts,
hashType = const SigHashType.all(),
SigHashType hashType = const SigHashType.all(),
int codeSeperatorPos = 0xFFFFFFFF,
}) => createInputSignature(
tx: tx,
Expand Down
4 changes: 2 additions & 2 deletions coinlib/lib/src/tx/outpoint.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import 'package:coinlib/src/common/bytes.dart';
import 'package:coinlib/src/common/checks.dart';
import 'package:coinlib/src/common/hex.dart';
import 'package:coinlib/src/common/serial.dart';
import 'package:collection/collection.dart';
import 'output.dart';

/// Reference to an [Output] by transaction hash and index
class OutPoint with Writable {
Expand Down Expand Up @@ -36,7 +36,7 @@ class OutPoint with Writable {
@override
bool operator ==(Object other)
=> (other is OutPoint)
&& ListEquality().equals(_hash, other._hash)
&& bytesEqual(_hash, other._hash)
&& n == other.n;

@override
Expand Down

0 comments on commit 9986dc3

Please sign in to comment.