Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PE-1136 Refactor ArConnect Signing #20

Open
wants to merge 18 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 36 additions & 4 deletions lib/src/models/data_item.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,23 @@ import 'dart:convert';
import 'dart:typed_data';

import 'package:arweave/src/utils/bundle_tag_parser.dart';
import 'package:json_annotation/json_annotation.dart';

import '../crypto/crypto.dart';
import '../utils.dart';
import 'models.dart';

part 'data_item.g.dart';

final MIN_BINARY_SIZE = 1044;

/// ANS-104 [DataItem]
/// Spec: https://github.com/joshbenaron/arweave-standards/blob/ans104/ans/ANS-104.md
@JsonSerializable(explicitToJson: true)
class DataItem implements TransactionBase {
@JsonKey(defaultValue: 1)
final int format = 1;

@override
String get id => _id;
late String _id;
Expand All @@ -34,9 +41,15 @@ class DataItem implements TransactionBase {
@override
late Uint8List data;

@JsonKey(name: 'data_size')
String get dataSize => _dataSize;
String _dataSize = '0';

@override
String get signature => _signature;
late String _signature;

@JsonKey(ignore: true)
late ByteBuffer binary;

/// This constructor is reserved for JSON serialisation.
Expand All @@ -49,13 +62,18 @@ class DataItem implements TransactionBase {
List<Tag>? tags,
String? data,
Uint8List? dataBytes,
String? dataSize,
}) : target = target ?? '',
nonce = nonce ?? '',
_owner = owner ?? '',
data = data != null
? decodeBase64ToBytes(data)
: (dataBytes ?? Uint8List(0)),
_tags = tags ?? [];
_tags = tags ?? [] {
if (dataSize != null) {
_dataSize = dataSize;
karlprieb marked this conversation as resolved.
Show resolved Hide resolved
}
}

/// Constructs a [DataItem] with the specified JSON data and appropriate Content-Type tag.
factory DataItem.withJsonData({
Expand Down Expand Up @@ -87,6 +105,7 @@ class DataItem implements TransactionBase {
nonce: nonce,
tags: tags,
dataBytes: data,
dataSize: data.lengthInBytes.toString(),
);

@override
Expand All @@ -106,7 +125,7 @@ class DataItem implements TransactionBase {
Future<Uint8List> getSignatureData() => deepHash(
[
utf8.encode('dataitem'),
utf8.encode('1'), //Transaction format
utf8.encode(format.toString()), //Transaction format
utf8.encode('1'), //Signature type
decodeBase64ToBytes(owner),
decodeBase64ToBytes(target),
Expand All @@ -119,8 +138,7 @@ class DataItem implements TransactionBase {
/// Signs the [DataItem] using the specified wallet and sets the `id` and `signature` appropriately.
@override
Future<Uint8List> sign(Wallet wallet) async {
final signatureData = await getSignatureData();
final rawSignature = await wallet.sign(signatureData);
final rawSignature = await wallet.sign(this);

_signature = encodeBytesToBase64(rawSignature);

Expand Down Expand Up @@ -287,4 +305,18 @@ class DataItem implements TransactionBase {
bytesBuilder.add(data);
return bytesBuilder;
}

/// Encodes the [DataItem] as JSON with the `data` as the original unencoded [Uint8List].
@override
Map<String, dynamic> toJson() => _$DataItemToJson(this);

@override
Map<String, dynamic> toUnsignedJson() => <String, dynamic>{
'format': format,
'owner': owner,
'tags': tags.map((e) => e.toJson()).toList(),
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should avoid one-character identifiers such as e in this case

'target': target,
'data': data,
'data_size': dataSize,
};
}
25 changes: 25 additions & 0 deletions lib/src/models/data_item.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 6 additions & 8 deletions lib/src/models/id.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion lib/src/models/tag.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import 'package:json_annotation/json_annotation.dart';

part 'tag.g.dart';

@JsonSerializable()
@JsonSerializable(explicitToJson: true)
class Tag {
/// The tag's name encoded as Base64.
final String name;
Expand Down
10 changes: 4 additions & 6 deletions lib/src/models/tag.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions lib/src/models/transaction-base.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,7 @@ abstract class TransactionBase {
Future<void> sign(Wallet wallet);

Future<bool> verify();

Map<String, dynamic> toJson();
Map<String, dynamic> toUnsignedJson();
}
20 changes: 17 additions & 3 deletions lib/src/models/transaction.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ part 'transaction.g.dart';
String _bigIntToString(BigInt v) => v.toString();
BigInt _stringToBigInt(String v) => BigInt.parse(v);

@JsonSerializable()
@JsonSerializable(explicitToJson: true)
class Transaction implements TransactionBase {
@JsonKey(defaultValue: 1)
final int format;
Expand Down Expand Up @@ -277,8 +277,7 @@ class Transaction implements TransactionBase {

@override
Future<void> sign(Wallet wallet) async {
final signatureData = await getSignatureData();
final rawSignature = await wallet.sign(signatureData);
final rawSignature = await wallet.sign(this);

_signature = encodeBytesToBase64(rawSignature);

Expand Down Expand Up @@ -312,5 +311,20 @@ class Transaction implements TransactionBase {
_$TransactionFromJson(json);

/// Encodes the [Transaction] as JSON with the `data` as the original unencoded [Uint8List].
@override
Map<String, dynamic> toJson() => _$TransactionToJson(this);

@override
Map<String, dynamic> toUnsignedJson() => <String, dynamic>{
'format': format,
'last_tx': lastTx,
'owner': owner,
'tags': tags.map((e) => e.toJson()).toList(),
'target': target,
'quantity': _bigIntToString(quantity),
'data': data,
'data_size': dataSize,
'data_root': dataRoot,
'reward': _bigIntToString(reward),
};
}
36 changes: 17 additions & 19 deletions lib/src/models/transaction.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion lib/src/models/wallet.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'dart:core';
import 'dart:math';
import 'dart:typed_data';

import 'package:arweave/arweave.dart';
import 'package:cryptography/cryptography.dart';
import 'package:jwk/jwk.dart';
import 'package:pointycastle/export.dart';
Expand Down Expand Up @@ -54,7 +55,10 @@ class Wallet {
await _keyPair!.extractPublicKey().then((res) => res.n));
Future<String> getAddress() async => ownerToAddress(await getOwner());

Future<Uint8List> sign(Uint8List message) async =>
Future<Uint8List> sign(TransactionBase transaction) async => rsaPssSign(
message: await transaction.getSignatureData(), keyPair: _keyPair!);

Future<Uint8List> signMessage(Uint8List message) async =>
rsaPssSign(message: message, keyPair: _keyPair!);

factory Wallet.fromJwk(Map<String, dynamic> jwk) {
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ environment:
dependencies:
cryptography: ^2.0.1
http: ^0.13.3
json_annotation: ^4.0.1
json_annotation: 4.4.0
jwk: ^0.1.0
meta: ^1.7.0
pointycastle: ^3.1.1
Expand Down
6 changes: 3 additions & 3 deletions test/wallets_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import 'dart:io';
import 'dart:typed_data';

import 'package:arweave/arweave.dart';
import 'package:arweave/utils.dart' as utils;
import 'package:arweave/utils.dart';
import 'package:test/test.dart';

import 'utils.dart';
Expand Down Expand Up @@ -62,9 +62,9 @@ void main() {
final wallet = await getTestWallet();
final message = utf8.encode('<test message>');

final signature = await wallet.sign(message as Uint8List);
final signature = await wallet.signMessage(message as Uint8List);
expect(
utils.encodeBytesToBase64(signature),
encodeBytesToBase64(signature),
startsWith('II5LxGnPt4WTSz9P__wMAdjzXWlZE-wGbKU7wm4DbGuPXB5Vifs'),
);
}, onPlatform: {
Expand Down