The source code of whatever software you're using.
Here's some C code I used when I played around with it 5 years ago. No guarantees that it is bug-free or does anything useful (you still need a double sha256 and base58 encoding to get a string representation), but it gives you an idea of the complexity/simplicity.
void sha256_ripe160(uint8_t *bytes, size_t len, uint8_t result[RIPEMD160_DIGEST_LENGTH])
{
uint8_t buf[32];
CC_SHA256(bytes, len, buf);
RIPEMD160(buf, 32, result);
}
void privkey_to_pubsig_hash(uint8_t privkey[32], uint8_t pubsig[20])
{
static EC_GROUP *curve = 0;
if (!curve) {
curve = EC_GROUP_new_by_curve_name(NID_secp256k1);
}
assert(curve);
BIGNUM *priv_bn = BN_new();
priv_bn = BN_bin2bn(privkey, 32, priv_bn);
assert(priv_bn);
EC_POINT *pub_pt = EC_POINT_new(curve);
BN_CTX *ctx = BN_CTX_new();
int result = EC_POINT_mul(curve, pub_pt, priv_bn, NULL, NULL, ctx);
assert(result);
BN_free(priv_bn);
BIGNUM *pub_bn = BN_new();
EC_POINT_point2bn(curve, pub_pt, POINT_CONVERSION_UNCOMPRESSED, pub_bn, ctx);
EC_POINT_free(pub_pt);
BN_CTX_free(ctx);
assert(BN_num_bytes(pub_bn) == 65);
uint8_t pub_bytes[65];
BN_bn2bin(pub_bn, pub_bytes);
BN_free(pub_bn);
sha256_ripe160(pub_bytes, 65, pubsig);
}
One of the myriad Python libraries to deal with bitcoin is probably a better starting point if you want to explore more.