UNPKG

@ethersphere/bee-js

Version:
167 lines 5.18 kB
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);