Skip to content

Drop adaptive_number, it breaks the package on dart2wasm and is unmaintained #8

Description

@MichealReed

ed25519_edwards is unusable on the dart2wasm compile target (flutter build web --wasm). Any call into the library throws before doing any work:

Unsupported operation: Cannot create a Number without package
dart.library.io or dart.library.html being available
    at createNumber (package:adaptive_number/src/stub.dart:3)
    at new Number (package:adaptive_number/src/number.dart:12)
    at Number.zero (package:adaptive_number/src/number.dart:8)
    at FieldElement (package:ed25519_edwards/src/edwards25519.dart:12)

Cause

package:adaptive_number selects its implementation like this (lib/src/number.dart):

import 'package:adaptive_number/src/stub.dart'
if (dart.library.io) 'package:adaptive_number/src/int.dart'
if (dart.library.html) 'package:adaptive_number/src/int64.dart';

dart2wasm provides neither dart:io nor dart:html, it exposes dart:js_interop, so both conditions are false and the import resolves to the throwing stub. edwards25519.dart:12 hits it immediately via Number.zero in the FieldElement initializer, so the failure is unconditional rather than edge-case.

adaptive_number has had no release since 1.0.0 and looks unmaintained, so a fix upstream there seems unlikely.

Suggested fix

Depend on package:fixnum directly and select on integer semantics rather than on platform libraries, for example a single conditional import keyed on dart.library.js_interop (true on dart2js and dart2wasm, false on VM/AOT), with the dart2js-vs-wasm split made explicit via const bool.fromEnvironment('dart.library.js_interop') plus an identical(0, 0.0) check, which is the standard way to detect "ints are doubles here". Alternatively, vendor the ~2 KB NumberInt/NumberInt64 pair directly into this package so the selection is under your control.

Related, worth fixing in the same pass

There is a correctness issue that also comes from adaptive_number: ScMinimal (the canonical-scalar / S < L check) compares 64-bit limbs through Number, and on dart2js those comparisons are not exact. The observed result is that a malleated signature with S + L substituted verifies as valid on dart2js while correctly failing on the Dart VM and it is rejected by ed25519-dalek's verify_strict, so it is also a cross-language split. Removing adaptive_number in favour of exact integer handling would close that as well.

Repro

Any flutter build web --wasm app calling ed.newKeyFromSeed(...), ed.sign(...) or ed.verify(...). Versions: ed25519_edwards 0.3.1, adaptive_number 1.0.0, Dart 3.12.0-dev, Flutter master.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions