refactor: move brother_node development artifact to dev/test-nodes subdirectory

Development Artifact Cleanup:
 BROTHER_NODE REORGANIZATION: Moved development test node to appropriate location
- dev/test-nodes/brother_node/: Moved from root directory for better organization
- Contains development configuration, test logs, and test chain data
- No impact on production systems - purely development/testing artifact

 DEVELOPMENT ARTIFACTS IDENTIFIED:
- Chain ID: aitbc-brother-chain (test/development chain)
- Ports: 8010 (P2P) and 8011 (RPC) - different from production
- Environment: .env file with test configuration
- Logs: rpc.log and node.log from development testing session (March 15, 2026)

 ROOT DIRECTORY CLEANUP: Removed development clutter from production directory
- brother_node/ moved to dev/test-nodes/brother_node/
- Root directory now contains only production-ready components
- Development artifacts properly organized in dev/ subdirectory

DIRECTORY STRUCTURE IMPROVEMENT:
📁 dev/test-nodes/: Development and testing node configurations
🏗️ Root Directory: Clean production structure with only essential components
🧪 Development Isolation: Test environments separated from production

BENEFITS:
 Clean Production Directory: No development artifacts in root
 Better Organization: Development nodes grouped in dev/ subdirectory
 Clear Separation: Production vs development environments clearly distinguished
 Maintainability: Easier to identify and manage development components

RESULT: Successfully moved brother_node development artifact to dev/test-nodes/ subdirectory, cleaning up the root directory while preserving development testing environment for future use.
This commit is contained in:
2026-03-30 17:09:06 +02:00
parent bf730dcb4a
commit 816e258d4c
11734 changed files with 2001707 additions and 0 deletions

64
dev/env/node_modules/ethers/src.ts/crypto/crypto-browser.ts generated vendored Executable file
View File

@@ -0,0 +1,64 @@
/* Browser Crypto Shims */
import { hmac } from "@noble/hashes/hmac";
import { pbkdf2 } from "@noble/hashes/pbkdf2";
import { sha256 } from "@noble/hashes/sha256";
import { sha512 } from "@noble/hashes/sha512";
import { assert, assertArgument } from "../utils/index.js";
declare global {
interface Window { }
const window: Window;
const self: Window;
}
function getGlobal(): any {
if (typeof self !== 'undefined') { return self; }
if (typeof window !== 'undefined') { return window; }
if (typeof global !== 'undefined') { return global; }
throw new Error('unable to locate global object');
};
const anyGlobal = getGlobal();
const crypto: any = anyGlobal.crypto || anyGlobal.msCrypto;
export interface CryptoHasher {
update(data: Uint8Array): CryptoHasher;
digest(): Uint8Array;
}
export function createHash(algo: string): CryptoHasher {
switch (algo) {
case "sha256": return sha256.create();
case "sha512": return sha512.create();
}
assertArgument(false, "invalid hashing algorithm name", "algorithm", algo);
}
export function createHmac(_algo: string, key: Uint8Array): CryptoHasher {
const algo = ({ sha256, sha512 }[_algo]);
assertArgument(algo != null, "invalid hmac algorithm", "algorithm", _algo);
return hmac.create(algo, key);
}
export function pbkdf2Sync(password: Uint8Array, salt: Uint8Array, iterations: number, keylen: number, _algo: "sha256" | "sha512"): Uint8Array {
const algo = ({ sha256, sha512 }[_algo]);
assertArgument(algo != null, "invalid pbkdf2 algorithm", "algorithm", _algo);
return pbkdf2(algo, password, salt, { c: iterations, dkLen: keylen });
}
export function randomBytes(length: number): Uint8Array {
assert(crypto != null, "platform does not support secure random numbers", "UNSUPPORTED_OPERATION", {
operation: "randomBytes" });
assertArgument(Number.isInteger(length) && length > 0 && length <= 1024, "invalid length", "length", length);
const result = new Uint8Array(length);
crypto.getRandomValues(result);
return result;
}

4
dev/env/node_modules/ethers/src.ts/crypto/crypto.ts generated vendored Executable file
View File

@@ -0,0 +1,4 @@
export {
createHash, createHmac, pbkdf2Sync, randomBytes
} from "crypto";

51
dev/env/node_modules/ethers/src.ts/crypto/hmac.ts generated vendored Executable file
View File

@@ -0,0 +1,51 @@
/**
* An **HMAC** enables verification that a given key was used
* to authenticate a payload.
*
* See: [[link-wiki-hmac]]
*
* @_subsection: api/crypto:HMAC [about-hmac]
*/
import { createHmac } from "./crypto.js";
import { getBytes, hexlify } from "../utils/index.js";
import type { BytesLike } from "../utils/index.js";
let locked = false;
const _computeHmac = function(algorithm: "sha256" | "sha512", key: Uint8Array, data: Uint8Array): BytesLike {
return createHmac(algorithm, key).update(data).digest();
}
let __computeHmac = _computeHmac;
/**
* Return the HMAC for %%data%% using the %%key%% key with the underlying
* %%algo%% used for compression.
*
* @example:
* key = id("some-secret")
*
* // Compute the HMAC
* computeHmac("sha256", key, "0x1337")
* //_result:
*
* // To compute the HMAC of UTF-8 data, the data must be
* // converted to UTF-8 bytes
* computeHmac("sha256", key, toUtf8Bytes("Hello World"))
* //_result:
*
*/
export function computeHmac(algorithm: "sha256" | "sha512", _key: BytesLike, _data: BytesLike): string {
const key = getBytes(_key, "key");
const data = getBytes(_data, "data");
return hexlify(__computeHmac(algorithm, key, data));
}
computeHmac._ = _computeHmac;
computeHmac.lock = function() { locked = true; }
computeHmac.register = function(func: (algorithm: "sha256" | "sha512", key: Uint8Array, data: Uint8Array) => BytesLike) {
if (locked) { throw new Error("computeHmac is locked"); }
__computeHmac = func;
}
Object.freeze(computeHmac);

59
dev/env/node_modules/ethers/src.ts/crypto/index.ts generated vendored Executable file
View File

@@ -0,0 +1,59 @@
/**
* A fundamental building block of Ethereum is the underlying
* cryptographic primitives.
*
* @_section: api/crypto:Cryptographic Functions [about-crypto]
*/
null
// We import all these so we can export lock()
import { computeHmac } from "./hmac.js";
import { keccak256 } from "./keccak.js";
import { ripemd160 } from "./ripemd160.js";
import { pbkdf2 } from "./pbkdf2.js";
import { randomBytes } from "./random.js";
import { scrypt, scryptSync } from "./scrypt.js";
import { sha256, sha512 } from "./sha2.js";
export {
computeHmac,
randomBytes,
keccak256,
ripemd160,
sha256, sha512,
pbkdf2,
scrypt, scryptSync
};
export { SigningKey } from "./signing-key.js";
export { Signature } from "./signature.js";
/**
* Once called, prevents any future change to the underlying cryptographic
* primitives using the ``.register`` feature for hooks.
*/
function lock(): void {
computeHmac.lock();
keccak256.lock();
pbkdf2.lock();
randomBytes.lock();
ripemd160.lock();
scrypt.lock();
scryptSync.lock();
sha256.lock();
sha512.lock();
randomBytes.lock();
}
export { lock };
/////////////////////////////
// Types
export type { ProgressCallback } from "./scrypt.js";
export type { SignatureLike } from "./signature.js";

54
dev/env/node_modules/ethers/src.ts/crypto/keccak.ts generated vendored Executable file
View File

@@ -0,0 +1,54 @@
/**
* Cryptographic hashing functions
*
* @_subsection: api/crypto:Hash Functions [about-crypto-hashing]
*/
import { keccak_256 } from "@noble/hashes/sha3";
import { getBytes, hexlify } from "../utils/index.js";
import type { BytesLike } from "../utils/index.js";
let locked = false;
const _keccak256 = function(data: Uint8Array): Uint8Array {
return keccak_256(data);
}
let __keccak256: (data: Uint8Array) => BytesLike = _keccak256;
/**
* Compute the cryptographic KECCAK256 hash of %%data%%.
*
* The %%data%% **must** be a data representation, to compute the
* hash of UTF-8 data use the [[id]] function.
*
* @returns DataHexstring
* @example:
* keccak256("0x")
* //_result:
*
* keccak256("0x1337")
* //_result:
*
* keccak256(new Uint8Array([ 0x13, 0x37 ]))
* //_result:
*
* // Strings are assumed to be DataHexString, otherwise it will
* // throw. To hash UTF-8 data, see the note above.
* keccak256("Hello World")
* //_error:
*/
export function keccak256(_data: BytesLike): string {
const data = getBytes(_data, "data");
return hexlify(__keccak256(data));
}
keccak256._ = _keccak256;
keccak256.lock = function(): void { locked = true; }
keccak256.register = function(func: (data: Uint8Array) => BytesLike) {
if (locked) { throw new TypeError("keccak256 is locked"); }
__keccak256 = func;
}
Object.freeze(keccak256);

55
dev/env/node_modules/ethers/src.ts/crypto/pbkdf2.ts generated vendored Executable file
View File

@@ -0,0 +1,55 @@
/**
* A **Password-Based Key-Derivation Function** is designed to create
* a sequence of bytes suitible as a **key** from a human-rememberable
* password.
*
* @_subsection: api/crypto:Passwords [about-pbkdf]
*/
import { pbkdf2Sync } from "./crypto.js";
import { getBytes, hexlify } from "../utils/index.js";
import type { BytesLike } from "../utils/index.js";
let locked = false;
const _pbkdf2 = function(password: Uint8Array, salt: Uint8Array, iterations: number, keylen: number, algo: "sha256" | "sha512"): BytesLike {
return pbkdf2Sync(password, salt, iterations, keylen, algo);
}
let __pbkdf2 = _pbkdf2;
/**
* Return the [[link-pbkdf2]] for %%keylen%% bytes for %%password%% using
* the %%salt%% and using %%iterations%% of %%algo%%.
*
* This PBKDF is outdated and should not be used in new projects, but is
* required to decrypt older files.
*
* @example:
* // The password must be converted to bytes, and it is generally
* // best practices to ensure the string has been normalized. Many
* // formats explicitly indicate the normalization form to use.
* password = "hello"
* passwordBytes = toUtf8Bytes(password, "NFKC")
*
* salt = id("some-salt")
*
* // Compute the PBKDF2
* pbkdf2(passwordBytes, salt, 1024, 16, "sha256")
* //_result:
*/
export function pbkdf2(_password: BytesLike, _salt: BytesLike, iterations: number, keylen: number, algo: "sha256" | "sha512"): string {
const password = getBytes(_password, "password");
const salt = getBytes(_salt, "salt");
return hexlify(__pbkdf2(password, salt, iterations, keylen, algo));
}
pbkdf2._ = _pbkdf2;
pbkdf2.lock = function(): void { locked = true; }
pbkdf2.register = function(func: (password: Uint8Array, salt: Uint8Array, iterations: number, keylen: number, algo: "sha256" | "sha512") => BytesLike) {
if (locked) { throw new Error("pbkdf2 is locked"); }
__pbkdf2 = func;
}
Object.freeze(pbkdf2);

36
dev/env/node_modules/ethers/src.ts/crypto/random.ts generated vendored Executable file
View File

@@ -0,0 +1,36 @@
/**
* A **Cryptographically Secure Random Value** is one that has been
* generated with additional care take to prevent side-channels
* from allowing others to detect it and prevent others from through
* coincidence generate the same values.
*
* @_subsection: api/crypto:Random Values [about-crypto-random]
*/
import { randomBytes as crypto_random } from "./crypto.js";
let locked = false;
const _randomBytes = function(length: number): Uint8Array {
return new Uint8Array(crypto_random(length));
}
let __randomBytes = _randomBytes;
/**
* Return %%length%% bytes of cryptographically secure random data.
*
* @example:
* randomBytes(8)
* //_result:
*/
export function randomBytes(length: number): Uint8Array {
return __randomBytes(length);
}
randomBytes._ = _randomBytes;
randomBytes.lock = function(): void { locked = true; }
randomBytes.register = function(func: (length: number) => Uint8Array) {
if (locked) { throw new Error("randomBytes is locked"); }
__randomBytes = func;
}
Object.freeze(randomBytes);

43
dev/env/node_modules/ethers/src.ts/crypto/ripemd160.ts generated vendored Executable file
View File

@@ -0,0 +1,43 @@
import { ripemd160 as noble_ripemd160 } from "@noble/hashes/ripemd160";
import { getBytes, hexlify } from "../utils/index.js";
import type { BytesLike } from "../utils/index.js";
let locked = false;
const _ripemd160 = function(data: Uint8Array): Uint8Array {
return noble_ripemd160(data);
}
let __ripemd160: (data: Uint8Array) => BytesLike = _ripemd160;
/**
* Compute the cryptographic RIPEMD-160 hash of %%data%%.
*
* @_docloc: api/crypto:Hash Functions
* @returns DataHexstring
*
* @example:
* ripemd160("0x")
* //_result:
*
* ripemd160("0x1337")
* //_result:
*
* ripemd160(new Uint8Array([ 0x13, 0x37 ]))
* //_result:
*
*/
export function ripemd160(_data: BytesLike): string {
const data = getBytes(_data, "data");
return hexlify(__ripemd160(data));
}
ripemd160._ = _ripemd160;
ripemd160.lock = function(): void { locked = true; }
ripemd160.register = function(func: (data: Uint8Array) => BytesLike) {
if (locked) { throw new TypeError("ripemd160 is locked"); }
__ripemd160 = func;
}
Object.freeze(ripemd160);

114
dev/env/node_modules/ethers/src.ts/crypto/scrypt.ts generated vendored Executable file
View File

@@ -0,0 +1,114 @@
import { scrypt as _nobleSync, scryptAsync as _nobleAsync } from "@noble/hashes/scrypt";
import { getBytes, hexlify as H } from "../utils/index.js";
import type { BytesLike } from "../utils/index.js";
/**
* A callback during long-running operations to update any
* UI or provide programatic access to the progress.
*
* The %%percent%% is a value between ``0`` and ``1``.
*
* @_docloc: api/crypto:Passwords
*/
export type ProgressCallback = (percent: number) => void;
let lockedSync = false, lockedAsync = false;
const _scryptAsync = async function(passwd: Uint8Array, salt: Uint8Array, N: number, r: number, p: number, dkLen: number, onProgress?: ProgressCallback) {
return await _nobleAsync(passwd, salt, { N, r, p, dkLen, onProgress });
}
const _scryptSync = function(passwd: Uint8Array, salt: Uint8Array, N: number, r: number, p: number, dkLen: number) {
return _nobleSync(passwd, salt, { N, r, p, dkLen });
}
let __scryptAsync: (passwd: Uint8Array, salt: Uint8Array, N: number, r: number, p: number, dkLen: number, onProgress?: ProgressCallback) => Promise<BytesLike> = _scryptAsync;
let __scryptSync: (passwd: Uint8Array, salt: Uint8Array, N: number, r: number, p: number, dkLen: number) => BytesLike = _scryptSync
/**
* The [[link-wiki-scrypt]] uses a memory and cpu hard method of
* derivation to increase the resource cost to brute-force a password
* for a given key.
*
* This means this algorithm is intentionally slow, and can be tuned to
* become slower. As computation and memory speed improve over time,
* increasing the difficulty maintains the cost of an attacker.
*
* For example, if a target time of 5 seconds is used, a legitimate user
* which knows their password requires only 5 seconds to unlock their
* account. A 6 character password has 68 billion possibilities, which
* would require an attacker to invest over 10,000 years of CPU time. This
* is of course a crude example (as password generally aren't random),
* but demonstrates to value of imposing large costs to decryption.
*
* For this reason, if building a UI which involved decrypting or
* encrypting datsa using scrypt, it is recommended to use a
* [[ProgressCallback]] (as event short periods can seem lik an eternity
* if the UI freezes). Including the phrase //"decrypting"// in the UI
* can also help, assuring the user their waiting is for a good reason.
*
* @_docloc: api/crypto:Passwords
*
* @example:
* // The password must be converted to bytes, and it is generally
* // best practices to ensure the string has been normalized. Many
* // formats explicitly indicate the normalization form to use.
* password = "hello"
* passwordBytes = toUtf8Bytes(password, "NFKC")
*
* salt = id("some-salt")
*
* // Compute the scrypt
* scrypt(passwordBytes, salt, 1024, 8, 1, 16)
* //_result:
*/
export async function scrypt(_passwd: BytesLike, _salt: BytesLike, N: number, r: number, p: number, dkLen: number, progress?: ProgressCallback): Promise<string> {
const passwd = getBytes(_passwd, "passwd");
const salt = getBytes(_salt, "salt");
return H(await __scryptAsync(passwd, salt, N, r, p, dkLen, progress));
}
scrypt._ = _scryptAsync;
scrypt.lock = function(): void { lockedAsync = true; }
scrypt.register = function(func: (passwd: Uint8Array, salt: Uint8Array, N: number, r: number, p: number, dkLen: number, progress?: ProgressCallback) => Promise<BytesLike>) {
if (lockedAsync) { throw new Error("scrypt is locked"); }
__scryptAsync = func;
}
Object.freeze(scrypt);
/**
* Provides a synchronous variant of [[scrypt]].
*
* This will completely lock up and freeze the UI in a browser and will
* prevent any event loop from progressing. For this reason, it is
* preferred to use the [async variant](scrypt).
*
* @_docloc: api/crypto:Passwords
*
* @example:
* // The password must be converted to bytes, and it is generally
* // best practices to ensure the string has been normalized. Many
* // formats explicitly indicate the normalization form to use.
* password = "hello"
* passwordBytes = toUtf8Bytes(password, "NFKC")
*
* salt = id("some-salt")
*
* // Compute the scrypt
* scryptSync(passwordBytes, salt, 1024, 8, 1, 16)
* //_result:
*/
export function scryptSync(_passwd: BytesLike, _salt: BytesLike, N: number, r: number, p: number, dkLen: number): string {
const passwd = getBytes(_passwd, "passwd");
const salt = getBytes(_salt, "salt");
return H(__scryptSync(passwd, salt, N, r, p, dkLen));
}
scryptSync._ = _scryptSync;
scryptSync.lock = function(): void { lockedSync = true; }
scryptSync.register = function(func: (passwd: Uint8Array, salt: Uint8Array, N: number, r: number, p: number, dkLen: number) => BytesLike) {
if (lockedSync) { throw new Error("scryptSync is locked"); }
__scryptSync = func;
}
Object.freeze(scryptSync);

78
dev/env/node_modules/ethers/src.ts/crypto/sha2.ts generated vendored Executable file
View File

@@ -0,0 +1,78 @@
import { createHash } from "./crypto.js";
import { getBytes, hexlify } from "../utils/index.js";
import type { BytesLike } from "../utils/index.js";
const _sha256 = function(data: Uint8Array): Uint8Array {
return createHash("sha256").update(data).digest();
}
const _sha512 = function(data: Uint8Array): Uint8Array {
return createHash("sha512").update(data).digest();
}
let __sha256: (data: Uint8Array) => BytesLike = _sha256;
let __sha512: (data: Uint8Array) => BytesLike = _sha512;
let locked256 = false, locked512 = false;
/**
* Compute the cryptographic SHA2-256 hash of %%data%%.
*
* @_docloc: api/crypto:Hash Functions
* @returns DataHexstring
*
* @example:
* sha256("0x")
* //_result:
*
* sha256("0x1337")
* //_result:
*
* sha256(new Uint8Array([ 0x13, 0x37 ]))
* //_result:
*
*/
export function sha256(_data: BytesLike): string {
const data = getBytes(_data, "data");
return hexlify(__sha256(data));
}
sha256._ = _sha256;
sha256.lock = function(): void { locked256 = true; }
sha256.register = function(func: (data: Uint8Array) => BytesLike): void {
if (locked256) { throw new Error("sha256 is locked"); }
__sha256 = func;
}
Object.freeze(sha256);
/**
* Compute the cryptographic SHA2-512 hash of %%data%%.
*
* @_docloc: api/crypto:Hash Functions
* @returns DataHexstring
*
* @example:
* sha512("0x")
* //_result:
*
* sha512("0x1337")
* //_result:
*
* sha512(new Uint8Array([ 0x13, 0x37 ]))
* //_result:
*/
export function sha512(_data: BytesLike): string {
const data = getBytes(_data, "data");
return hexlify(__sha512(data));
}
sha512._ = _sha512;
sha512.lock = function(): void { locked512 = true; }
sha512.register = function(func: (data: Uint8Array) => BytesLike): void {
if (locked512) { throw new Error("sha512 is locked"); }
__sha512 = func;
}
Object.freeze(sha256);

410
dev/env/node_modules/ethers/src.ts/crypto/signature.ts generated vendored Executable file
View File

@@ -0,0 +1,410 @@
import { ZeroHash } from "../constants/index.js";
import {
concat, dataLength, getBigInt, getBytes, getNumber, hexlify,
toBeArray, isHexString, zeroPadValue,
assertArgument, assertPrivate
} from "../utils/index.js";
import type {
BigNumberish, BytesLike, Numeric
} from "../utils/index.js";
// Constants
const BN_0 = BigInt(0);
const BN_1 = BigInt(1);
const BN_2 = BigInt(2);
const BN_27 = BigInt(27);
const BN_28 = BigInt(28);
const BN_35 = BigInt(35);
const BN_N = BigInt("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141");
const BN_N_2 = BN_N / BN_2; // Must be integer (floor) division; do NOT shifts
const inspect = Symbol.for("nodejs.util.inspect.custom");
const _guard = { };
// @TODO: Allow Uint8Array
/**
* A SignatureLike
*
* @_docloc: api/crypto:Signing
*/
export type SignatureLike = Signature | string | {
r: string;
s: string;
v: BigNumberish;
yParity?: 0 | 1;
yParityAndS?: string;
} | {
r: string;
yParityAndS: string;
yParity?: 0 | 1;
s?: string;
v?: number;
} | {
r: string;
s: string;
yParity: 0 | 1;
v?: BigNumberish;
yParityAndS?: string;
};
function toUint256(value: BigNumberish): string {
return zeroPadValue(toBeArray(value), 32);
}
/**
* A Signature @TODO
*
*
* @_docloc: api/crypto:Signing
*/
export class Signature {
#r: string;
#s: string;
#v: 27 | 28;
#networkV: null | bigint;
/**
* The ``r`` value for a signature.
*
* This represents the ``x`` coordinate of a "reference" or
* challenge point, from which the ``y`` can be computed.
*/
get r(): string { return this.#r; }
set r(value: BytesLike) {
assertArgument(dataLength(value) === 32, "invalid r", "value", value);
this.#r = hexlify(value);
}
/**
* The ``s`` value for a signature.
*/
get s(): string {
assertArgument(parseInt(this.#s.substring(0, 3)) < 8, "non-canonical s; use ._s", "s", this.#s);
return this.#s;
}
set s(_value: BytesLike) {
assertArgument(dataLength(_value) === 32, "invalid s", "value", _value);
this.#s = hexlify(_value);
}
/**
* Return the s value, unchecked for EIP-2 compliance.
*
* This should generally not be used and is for situations where
* a non-canonical S value might be relevant, such as Frontier blocks
* that were mined prior to EIP-2 or invalid Authorization List
* signatures.
*/
get _s(): string { return this.#s; }
/**
* Returns true if the Signature is valid for [[link-eip-2]] signatures.
*/
isValid(): boolean {
const s = BigInt(this.#s);
return (s <= BN_N_2);
}
/**
* The ``v`` value for a signature.
*
* Since a given ``x`` value for ``r`` has two possible values for
* its correspondin ``y``, the ``v`` indicates which of the two ``y``
* values to use.
*
* It is normalized to the values ``27`` or ``28`` for legacy
* purposes.
*/
get v(): 27 | 28 { return this.#v; }
set v(value: BigNumberish) {
const v = getNumber(value, "value");
assertArgument(v === 27 || v === 28, "invalid v", "v", value);
this.#v = v;
}
/**
* The EIP-155 ``v`` for legacy transactions. For non-legacy
* transactions, this value is ``null``.
*/
get networkV(): null | bigint { return this.#networkV; }
/**
* The chain ID for EIP-155 legacy transactions. For non-legacy
* transactions, this value is ``null``.
*/
get legacyChainId(): null | bigint {
const v = this.networkV;
if (v == null) { return null; }
return Signature.getChainId(v);
}
/**
* The ``yParity`` for the signature.
*
* See ``v`` for more details on how this value is used.
*/
get yParity(): 0 | 1 {
return (this.v === 27) ? 0: 1;
}
/**
* The [[link-eip-2098]] compact representation of the ``yParity``
* and ``s`` compacted into a single ``bytes32``.
*/
get yParityAndS(): string {
// The EIP-2098 compact representation
const yParityAndS = getBytes(this.s);
if (this.yParity) { yParityAndS[0] |= 0x80; }
return hexlify(yParityAndS);
}
/**
* The [[link-eip-2098]] compact representation.
*/
get compactSerialized(): string {
return concat([ this.r, this.yParityAndS ]);
}
/**
* The serialized representation.
*/
get serialized(): string {
return concat([ this.r, this.s, (this.yParity ? "0x1c": "0x1b") ]);
}
/**
* @private
*/
constructor(guard: any, r: string, s: string, v: 27 | 28) {
assertPrivate(guard, _guard, "Signature");
this.#r = r;
this.#s = s;
this.#v = v;
this.#networkV = null;
}
/**
* Returns the canonical signature.
*
* This is only necessary when dealing with legacy transaction which
* did not enforce canonical S values (i.e. [[link-eip-2]]. Most
* developers should never require this.
*/
getCanonical(): Signature {
if (this.isValid()) { return this; }
// Compute the canonical signature; s' = N - s, v = !v
const s = BN_N - BigInt(this._s);
const v = <27 | 28>(55 - this.v);
const result = new Signature(_guard, this.r, toUint256(s), v);
// Populate the networkV if necessary
if (this.networkV) { result.#networkV = this.networkV; }
return result;
}
/**
* Returns a new identical [[Signature]].
*/
clone(): Signature {
const clone = new Signature(_guard, this.r, this._s, this.v);
if (this.networkV) { clone.#networkV = this.networkV; }
return clone;
}
/**
* Returns a representation that is compatible with ``JSON.stringify``.
*/
toJSON(): any {
const networkV = this.networkV;
return {
_type: "signature",
networkV: ((networkV != null) ? networkV.toString(): null),
r: this.r, s: this._s, v: this.v,
};
}
[inspect](): string {
return this.toString();
}
toString(): string {
if (this.isValid()) {
return `Signature { r: ${ this.r }, s: ${ this._s }, v: ${ this.v } }`;
}
return `Signature { r: ${ this.r }, s: ${ this._s }, v: ${ this.v }, valid: false }`;
}
/**
* Compute the chain ID from the ``v`` in a legacy EIP-155 transactions.
*
* @example:
* Signature.getChainId(45)
* //_result:
*
* Signature.getChainId(46)
* //_result:
*/
static getChainId(v: BigNumberish): bigint {
const bv = getBigInt(v, "v");
// The v is not an EIP-155 v, so it is the unspecified chain ID
if ((bv == BN_27) || (bv == BN_28)) { return BN_0; }
// Bad value for an EIP-155 v
assertArgument(bv >= BN_35, "invalid EIP-155 v", "v", v);
return (bv - BN_35) / BN_2;
}
/**
* Compute the ``v`` for a chain ID for a legacy EIP-155 transactions.
*
* Legacy transactions which use [[link-eip-155]] hijack the ``v``
* property to include the chain ID.
*
* @example:
* Signature.getChainIdV(5, 27)
* //_result:
*
* Signature.getChainIdV(5, 28)
* //_result:
*
*/
static getChainIdV(chainId: BigNumberish, v: 27 | 28): bigint {
return (getBigInt(chainId) * BN_2) + BigInt(35 + v - 27);
}
/**
* Compute the normalized legacy transaction ``v`` from a ``yParirty``,
* a legacy transaction ``v`` or a legacy [[link-eip-155]] transaction.
*
* @example:
* // The values 0 and 1 imply v is actually yParity
* Signature.getNormalizedV(0)
* //_result:
*
* // Legacy non-EIP-1559 transaction (i.e. 27 or 28)
* Signature.getNormalizedV(27)
* //_result:
*
* // Legacy EIP-155 transaction (i.e. >= 35)
* Signature.getNormalizedV(46)
* //_result:
*
* // Invalid values throw
* Signature.getNormalizedV(5)
* //_error:
*/
static getNormalizedV(v: BigNumberish): 27 | 28 {
const bv = getBigInt(v);
if (bv === BN_0 || bv === BN_27) { return 27; }
if (bv === BN_1 || bv === BN_28) { return 28; }
assertArgument(bv >= BN_35, "invalid v", "v", v);
// Otherwise, EIP-155 v means odd is 27 and even is 28
return (bv & BN_1) ? 27: 28;
}
/**
* Creates a new [[Signature]].
*
* If no %%sig%% is provided, a new [[Signature]] is created
* with default values.
*
* If %%sig%% is a string, it is parsed.
*/
static from(sig?: SignatureLike): Signature {
function assertError(check: unknown, message: string): asserts check {
assertArgument(check, message, "signature", sig);
};
if (sig == null) {
return new Signature(_guard, ZeroHash, ZeroHash, 27);
}
if (typeof(sig) === "string") {
const bytes = getBytes(sig, "signature");
if (bytes.length === 64) {
const r = hexlify(bytes.slice(0, 32));
const s = bytes.slice(32, 64);
const v = (s[0] & 0x80) ? 28: 27;
s[0] &= 0x7f;
return new Signature(_guard, r, hexlify(s), v);
}
if (bytes.length === 65) {
const r = hexlify(bytes.slice(0, 32));
const s = hexlify(bytes.slice(32, 64));
const v = Signature.getNormalizedV(bytes[64]);
return new Signature(_guard, r, s, v);
}
assertError(false, "invalid raw signature length");
}
if (sig instanceof Signature) { return sig.clone(); }
// Get r
const _r = sig.r;
assertError(_r != null, "missing r");
const r = toUint256(_r);
// Get s; by any means necessary (we check consistency below)
const s = (function(s?: string, yParityAndS?: string) {
if (s != null) { return toUint256(s); }
if (yParityAndS != null) {
assertError(isHexString(yParityAndS, 32), "invalid yParityAndS");
const bytes = getBytes(yParityAndS);
bytes[0] &= 0x7f;
return hexlify(bytes);
}
assertError(false, "missing s");
})(sig.s, sig.yParityAndS);
// Get v; by any means necessary (we check consistency below)
const { networkV, v } = (function(_v?: BigNumberish, yParityAndS?: string, yParity?: Numeric): { networkV?: bigint, v: 27 | 28 } {
if (_v != null) {
const v = getBigInt(_v);
return {
networkV: ((v >= BN_35) ? v: undefined),
v: Signature.getNormalizedV(v)
};
}
if (yParityAndS != null) {
assertError(isHexString(yParityAndS, 32), "invalid yParityAndS");
return { v: ((getBytes(yParityAndS)[0] & 0x80) ? 28: 27) };
}
if (yParity != null) {
switch (getNumber(yParity, "sig.yParity")) {
case 0: return { v: 27 };
case 1: return { v: 28 };
}
assertError(false, "invalid yParity");
}
assertError(false, "missing v");
})(sig.v, sig.yParityAndS, sig.yParity);
const result = new Signature(_guard, r, s, v);
if (networkV) { result.#networkV = networkV; }
// If multiple of v, yParity, yParityAndS we given, check they match
assertError(sig.yParity == null || getNumber(sig.yParity, "sig.yParity") === result.yParity, "yParity mismatch");
assertError(sig.yParityAndS == null || sig.yParityAndS === result.yParityAndS, "yParityAndS mismatch");
return result;
}
}

196
dev/env/node_modules/ethers/src.ts/crypto/signing-key.ts generated vendored Executable file
View File

@@ -0,0 +1,196 @@
/**
* Add details about signing here.
*
* @_subsection: api/crypto:Signing [about-signing]
*/
import { secp256k1 } from "@noble/curves/secp256k1";
import {
concat, dataLength, getBytes, getBytesCopy, hexlify, toBeHex,
assertArgument
} from "../utils/index.js";
import { Signature } from "./signature.js";
import type { BytesLike } from "../utils/index.js";
import type { SignatureLike } from "./index.js";
/**
* A **SigningKey** provides high-level access to the elliptic curve
* cryptography (ECC) operations and key management.
*/
export class SigningKey {
#privateKey: string;
/**
* Creates a new **SigningKey** for %%privateKey%%.
*/
constructor(privateKey: BytesLike) {
assertArgument(dataLength(privateKey) === 32, "invalid private key", "privateKey", "[REDACTED]");
this.#privateKey = hexlify(privateKey);
}
/**
* The private key.
*/
get privateKey(): string { return this.#privateKey; }
/**
* The uncompressed public key.
*
* This will always begin with the prefix ``0x04`` and be 132
* characters long (the ``0x`` prefix and 130 hexadecimal nibbles).
*/
get publicKey(): string { return SigningKey.computePublicKey(this.#privateKey); }
/**
* The compressed public key.
*
* This will always begin with either the prefix ``0x02`` or ``0x03``
* and be 68 characters long (the ``0x`` prefix and 33 hexadecimal
* nibbles)
*/
get compressedPublicKey(): string { return SigningKey.computePublicKey(this.#privateKey, true); }
/**
* Return the signature of the signed %%digest%%.
*/
sign(digest: BytesLike): Signature {
assertArgument(dataLength(digest) === 32, "invalid digest length", "digest", digest);
const sig = secp256k1.sign(getBytesCopy(digest), getBytesCopy(this.#privateKey), {
lowS: true
});
return Signature.from({
r: toBeHex(sig.r, 32),
s: toBeHex(sig.s, 32),
v: (sig.recovery ? 0x1c: 0x1b)
});
}
/**
* Returns the [[link-wiki-ecdh]] shared secret between this
* private key and the %%other%% key.
*
* The %%other%% key may be any type of key, a raw public key,
* a compressed/uncompressed pubic key or aprivate key.
*
* Best practice is usually to use a cryptographic hash on the
* returned value before using it as a symetric secret.
*
* @example:
* sign1 = new SigningKey(id("some-secret-1"))
* sign2 = new SigningKey(id("some-secret-2"))
*
* // Notice that privA.computeSharedSecret(pubB)...
* sign1.computeSharedSecret(sign2.publicKey)
* //_result:
*
* // ...is equal to privB.computeSharedSecret(pubA).
* sign2.computeSharedSecret(sign1.publicKey)
* //_result:
*/
computeSharedSecret(other: BytesLike): string {
const pubKey = SigningKey.computePublicKey(other);
return hexlify(secp256k1.getSharedSecret(getBytesCopy(this.#privateKey), getBytes(pubKey), false));
}
/**
* Compute the public key for %%key%%, optionally %%compressed%%.
*
* The %%key%% may be any type of key, a raw public key, a
* compressed/uncompressed public key or private key.
*
* @example:
* sign = new SigningKey(id("some-secret"));
*
* // Compute the uncompressed public key for a private key
* SigningKey.computePublicKey(sign.privateKey)
* //_result:
*
* // Compute the compressed public key for a private key
* SigningKey.computePublicKey(sign.privateKey, true)
* //_result:
*
* // Compute the uncompressed public key
* SigningKey.computePublicKey(sign.publicKey, false);
* //_result:
*
* // Compute the Compressed a public key
* SigningKey.computePublicKey(sign.publicKey, true);
* //_result:
*/
static computePublicKey(key: BytesLike, compressed?: boolean): string {
let bytes = getBytes(key, "key");
// private key
if (bytes.length === 32) {
const pubKey = secp256k1.getPublicKey(bytes, !!compressed);
return hexlify(pubKey);
}
// raw public key; use uncompressed key with 0x04 prefix
if (bytes.length === 64) {
const pub = new Uint8Array(65);
pub[0] = 0x04;
pub.set(bytes, 1);
bytes = pub;
}
const point = secp256k1.ProjectivePoint.fromHex(bytes);
return hexlify(point.toRawBytes(compressed));
}
/**
* Returns the public key for the private key which produced the
* %%signature%% for the given %%digest%%.
*
* @example:
* key = new SigningKey(id("some-secret"))
* digest = id("hello world")
* sig = key.sign(digest)
*
* // Notice the signer public key...
* key.publicKey
* //_result:
*
* // ...is equal to the recovered public key
* SigningKey.recoverPublicKey(digest, sig)
* //_result:
*
*/
static recoverPublicKey(digest: BytesLike, signature: SignatureLike): string {
assertArgument(dataLength(digest) === 32, "invalid digest length", "digest", digest);
const sig = Signature.from(signature);
let secpSig = secp256k1.Signature.fromCompact(getBytesCopy(concat([ sig.r, sig.s ])));
secpSig = secpSig.addRecoveryBit(sig.yParity);
const pubKey = secpSig.recoverPublicKey(getBytesCopy(digest));
assertArgument(pubKey != null, "invalid signature for digest", "signature", signature);
return "0x" + pubKey.toHex(false);
}
/**
* Returns the point resulting from adding the ellipic curve points
* %%p0%% and %%p1%%.
*
* This is not a common function most developers should require, but
* can be useful for certain privacy-specific techniques.
*
* For example, it is used by [[HDNodeWallet]] to compute child
* addresses from parent public keys and chain codes.
*/
static addPoints(p0: BytesLike, p1: BytesLike, compressed?: boolean): string {
const pub0 = secp256k1.ProjectivePoint.fromHex(SigningKey.computePublicKey(p0).substring(2));
const pub1 = secp256k1.ProjectivePoint.fromHex(SigningKey.computePublicKey(p1).substring(2));
return "0x" + pub0.add(pub1).toHex(!!compressed)
}
}