Updates
This commit is contained in:
124
tools/gen_auth.sh
Executable file
124
tools/gen_auth.sh
Executable file
@@ -0,0 +1,124 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
usage() {
|
||||
cat <<'USAGE'
|
||||
Usage:
|
||||
gen_auth.sh --nonce "<nonce_string>" [--priv <private_key_hex>] [--json]
|
||||
|
||||
Options:
|
||||
--nonce The nonce string returned by fetch_nonce (paste as-is).
|
||||
--priv Optional private key hex (64 hex chars). If omitted, a new key is generated.
|
||||
--json Output JSON instead of plain KEY=VALUE lines.
|
||||
|
||||
Outputs:
|
||||
PRIVATE_HEX Private key hex (only when generated, or echoed back if provided)
|
||||
PUBLIC_HEX Compressed secp256k1 public key hex (33 bytes, 66 hex chars)
|
||||
NONCE The nonce string you passed in
|
||||
SIGNATURE_HEX Compact ECDSA signature hex (64 bytes, 128 hex chars)
|
||||
|
||||
Notes:
|
||||
- The signature is produced by signing sha256(nonce_ascii) and encoded as compact r||s (64 bytes),
|
||||
which matches the server/client behavior ([interfaces/openrpc/client/src/auth.rs](interfaces/openrpc/client/src/auth.rs:55), [interfaces/openrpc/server/src/auth.rs](interfaces/openrpc/server/src/auth.rs:85)).
|
||||
USAGE
|
||||
}
|
||||
|
||||
NONCE=""
|
||||
PRIV_HEX=""
|
||||
OUT_JSON=0
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--nonce)
|
||||
NONCE="${2:-}"; shift 2 ;;
|
||||
--priv)
|
||||
PRIV_HEX="${2:-}"; shift 2 ;;
|
||||
--json)
|
||||
OUT_JSON=1; shift ;;
|
||||
-h|--help)
|
||||
usage; exit 0 ;;
|
||||
*)
|
||||
echo "Unknown arg: $1" >&2; usage; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ -z "$NONCE" ]]; then
|
||||
echo "Error: --nonce is required" >&2
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v python3 >/dev/null 2>&1; then
|
||||
echo "Error: python3 not found. Install Python 3 (e.g., sudo pacman -S python) and retry." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Ensure 'ecdsa' module is available; install to user site if missing.
|
||||
if ! python3 - <<'PY' >/dev/null 2>&1
|
||||
import importlib; importlib.import_module("ecdsa")
|
||||
PY
|
||||
then
|
||||
echo "Installing Python 'ecdsa' package in user site..." >&2
|
||||
if ! python3 -m pip install --user --quiet ecdsa; then
|
||||
echo "Error: failed to install 'ecdsa'. Install manually: python3 -m pip install --user ecdsa" >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Now run Python to generate/derive keys and sign the nonce (ASCII) with compact ECDSA.
|
||||
python3 - "$NONCE" "$PRIV_HEX" "$OUT_JSON" <<'PY'
|
||||
import sys, json, hashlib
|
||||
from ecdsa import SigningKey, VerifyingKey, SECP256k1, util
|
||||
|
||||
NONCE = sys.argv[1]
|
||||
PRIV_HEX = sys.argv[2]
|
||||
OUT_JSON = int(sys.argv[3]) == 1
|
||||
|
||||
def to_compact_signature(sk: SigningKey, msg_ascii: str) -> bytes:
|
||||
digest = hashlib.sha256(msg_ascii.encode()).digest()
|
||||
return sk.sign_digest(digest, sigencode=util.sigencode_string) # 64 bytes r||s
|
||||
|
||||
def compressed_pubkey(vk: VerifyingKey) -> bytes:
|
||||
try:
|
||||
return vk.to_string("compressed")
|
||||
except TypeError:
|
||||
p = vk.pubkey.point
|
||||
x = p.x()
|
||||
y = vk.pubkey.point.y()
|
||||
prefix = b'\x02' if (y % 2 == 0) else b'\x03'
|
||||
return prefix + x.to_bytes(32, "big")
|
||||
|
||||
generated = False
|
||||
if PRIV_HEX:
|
||||
if len(PRIV_HEX) != 64:
|
||||
print("ERROR: Provided --priv must be 64 hex chars", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
sk = SigningKey.from_string(bytes.fromhex(PRIV_HEX), curve=SECP256k1)
|
||||
else:
|
||||
sk = SigningKey.generate(curve=SECP256k1)
|
||||
generated = True
|
||||
|
||||
vk = sk.get_verifying_key()
|
||||
pub_hex = compressed_pubkey(vk).hex()
|
||||
sig_hex = to_compact_signature(sk, NONCE).hex()
|
||||
priv_hex = sk.to_string().hex()
|
||||
|
||||
out = {
|
||||
"PUBLIC_HEX": pub_hex,
|
||||
"NONCE": NONCE,
|
||||
"SIGNATURE_HEX": sig_hex,
|
||||
}
|
||||
if generated or PRIV_HEX:
|
||||
out["PRIVATE_HEX"] = priv_hex
|
||||
|
||||
if OUT_JSON:
|
||||
print(json.dumps(out, separators=(",", ":")))
|
||||
else:
|
||||
if "PRIVATE_HEX" in out:
|
||||
print(f"PRIVATE_HEX={out['PRIVATE_HEX']}")
|
||||
print(f"PUBLIC_HEX={out['PUBLIC_HEX']}")
|
||||
print(f"NONCE={out['NONCE']}")
|
||||
print(f"SIGNATURE_HEX={out['SIGNATURE_HEX']}")
|
||||
PY
|
||||
|
||||
# End
|
Reference in New Issue
Block a user