@ethersphere/bee-js
Version:
Javascript client for Bee
167 lines • 5.18 kB
JavaScript
import { Binary, Elliptic } from 'cafe-utility';
import { Bytes } from "./bytes.js";
import { convertCidToReference, convertReferenceToCid } from "./cid.js"; // TODO: add JSdocs for each class
const ENCODER = new TextEncoder();
export class PrivateKey extends Bytes {
constructor(bytes) {
super(bytes, 32);
}
publicKey() {
const [x, y] = Elliptic.privateKeyToPublicKey(Binary.uint256ToNumber(this.bytes, 'BE'));
return new PublicKey(Binary.concatBytes(Binary.numberToUint256(x, 'BE'), Binary.numberToUint256(y, 'BE')));
}
sign(data) {
const digest = Binary.concatBytes(ENCODER.encode(`\x19Ethereum Signed Message:\n32`), Binary.keccak256(data instanceof Uint8Array ? data : ENCODER.encode(data)));
const [r, s, v] = Elliptic.signMessage(digest, Binary.uint256ToNumber(this.bytes, 'BE'));
return new Signature(Binary.concatBytes(Binary.numberToUint256(r, 'BE'), Binary.numberToUint256(s, 'BE'), new Uint8Array([Number(v)])));
}
}
PrivateKey.LENGTH = 32;
export class PublicKey extends Bytes {
constructor(bytes) {
const b = new Bytes(bytes);
if (b.length === 33) {
const [x, y] = Elliptic.publicKeyFromCompressed(b.toUint8Array());
super(Binary.concatBytes(Binary.numberToUint256(x, 'BE'), Binary.numberToUint256(y, 'BE')), 64);
} else {
super(bytes, 64);
}
}
address() {
const x = Binary.uint256ToNumber(this.bytes.slice(0, 32), 'BE');
const y = Binary.uint256ToNumber(this.bytes.slice(32, 64), 'BE');
return new EthAddress(Elliptic.publicKeyToAddress([x, y]));
}
toCompressedUint8Array() {
const x = Binary.uint256ToNumber(this.bytes.slice(0, 32), 'BE');
const y = Binary.uint256ToNumber(this.bytes.slice(32, 64), 'BE');
return Elliptic.compressPublicKey([x, y]);
}
toCompressedHex() {
return Binary.uint8ArrayToHex(this.toCompressedUint8Array());
}
}
PublicKey.LENGTH = 64;
export class EthAddress extends Bytes {
constructor(bytes) {
super(bytes, 20);
}
toChecksum() {
return Elliptic.checksumEncode(this.bytes);
}
}
EthAddress.LENGTH = 20;
export class Identifier extends Bytes {
constructor(bytes) {
super(bytes, 32);
}
static fromString(value) {
return new Identifier(Binary.keccak256(ENCODER.encode(value)));
}
}
Identifier.LENGTH = 32;
export class Reference extends Bytes {
constructor(bytes) {
if (typeof bytes === 'string' && bytes.startsWith('bah5')) {
const decoded = convertCidToReference(bytes);
super(decoded.reference.bytes, 32);
} else {
super(bytes, [32, 64]);
}
}
toCid(type) {
return convertReferenceToCid(this.bytes, type);
}
static isValid(value) {
try {
new Reference(value);
return true;
} catch {
return false;
}
}
}
Reference.LENGTH = 32;
export class TransactionId extends Bytes {
constructor(bytes) {
super(bytes, 32);
}
}
TransactionId.LENGTH = 32;
export class Span extends Bytes {
constructor(bytes) {
super(bytes, 8);
}
static fromBigInt(number) {
return new Span(Binary.numberToUint64(number, 'LE'));
}
toBigInt() {
return Binary.uint64ToNumber(this.bytes, 'LE');
}
static fromSlice(bytes, start) {
return new Span(bytes.slice(start, start + Span.LENGTH));
}
}
Span.LENGTH = 8;
export class PeerAddress extends Bytes {
constructor(bytes) {
super(bytes, 32);
}
}
PeerAddress.LENGTH = 32;
export class BatchId extends Bytes {
constructor(bytes) {
super(bytes, 32);
}
}
BatchId.LENGTH = 32;
export class Signature extends Bytes {
constructor(bytes) {
super(bytes, 65);
}
static fromSlice(bytes, start) {
return new Signature(bytes.slice(start, start + Signature.LENGTH));
}
recoverPublicKey(digest) {
const r = Binary.uint256ToNumber(this.bytes.slice(0, 32), 'BE');
const s = Binary.uint256ToNumber(this.bytes.slice(32, 64), 'BE');
const v = BigInt(this.bytes[64]);
const [x, y] = Elliptic.recoverPublicKey(Binary.concatBytes(ENCODER.encode(`\x19Ethereum Signed Message:\n32`), Binary.keccak256(digest instanceof Uint8Array ? digest : ENCODER.encode(digest))), r, s, v);
return new PublicKey(Binary.concatBytes(Binary.numberToUint256(x, 'BE'), Binary.numberToUint256(y, 'BE')));
}
isValid(digest, expectedAddress) {
const publicKey = this.recoverPublicKey(digest);
const address = publicKey.address();
return address.equals(expectedAddress);
}
}
Signature.LENGTH = 65;
export class Topic extends Bytes {
constructor(bytes) {
super(bytes, 32);
}
static fromString(value) {
return new Topic(Binary.keccak256(ENCODER.encode(value)));
}
}
Topic.LENGTH = 32;
const MAX_UINT64 = new Uint8Array(8).fill(0xff, 0, 8);
export class FeedIndex extends Bytes {
constructor(bytes) {
super(bytes, 8);
}
static fromBigInt(number) {
return new FeedIndex(Binary.numberToUint64(number, 'BE'));
}
toBigInt() {
return Binary.uint64ToNumber(this.bytes, 'BE');
}
next() {
if (Binary.equals(this.bytes, MAX_UINT64)) {
return FeedIndex.fromBigInt(0n);
}
return FeedIndex.fromBigInt(this.toBigInt() + 1n);
}
}
FeedIndex.LENGTH = 8;
FeedIndex.MINUS_ONE = new FeedIndex(MAX_UINT64);