# crypto > written against zig 0.15. zig 0.15 crypto paths and patterns. ## ecdsa the ecdsa types are under `std.crypto.sign.ecdsa`, not `std.crypto.ecdsa`: ```zig const crypto = std.crypto; // correct (0.15) const Secp256k1 = crypto.sign.ecdsa.EcdsaSecp256k1Sha256; const P256 = crypto.sign.ecdsa.EcdsaP256Sha256; // wrong - will error "has no member named 'ecdsa'" // const Secp256k1 = crypto.ecdsa.EcdsaSecp256k1Sha256; ``` ## verifying signatures ```zig const Scheme = std.crypto.sign.ecdsa.EcdsaSecp256k1Sha256; // signature is r || s (64 bytes for 256-bit curves) const sig = Scheme.Signature.fromBytes(sig_bytes[0..64].*); // public key from SEC1 compressed format (33 bytes) const public_key = try Scheme.PublicKey.fromSec1(key_bytes); // verify - returns error.SignatureVerificationFailed on mismatch try sig.verify(message, public_key); ``` ## key sizes | curve | compressed pubkey | uncompressed pubkey | signature (r\|\|s) | |-------|-------------------|---------------------|-------------------| | P-256 | 33 bytes | 65 bytes | 64 bytes | | secp256k1 | 33 bytes | 65 bytes | 64 bytes | compressed keys start with 0x02 or 0x03. uncompressed start with 0x04. see: [zat/jwt.zig](https://tangled.sh/@zzstoatzz.io/zat/tree/main/src/internal/jwt.zig) (zat is a library of atproto building blocks for zig) ## signing ```zig const Scheme = std.crypto.sign.ecdsa.EcdsaSecp256k1Sha256; // secret key from raw 32 bytes const secret_key = try Scheme.SecretKey.fromBytes(key_bytes[0..32].*); // sign with RFC 6979 deterministic nonce (null = no additional randomness) const sig = secret_key.sign(message, null); // low-S normalization (required by AT Protocol / Bitcoin) const Curve = std.crypto.ecc.Secp256k1; const s_order = Curve.scalar.neg(sig.s, .big); // if s > half_order, replace with order - s ``` the `null` second arg means RFC 6979 deterministic nonce — no randomness source needed, signature is reproducible from the same key+message. low-S normalization ensures `s <= half_order`. some protocols (AT Protocol, Bitcoin) reject high-S signatures. check by comparing the s component against the curve half-order. see: [zat/jwt.zig](https://tangled.sh/@zzstoatzz.io/zat/tree/main/src/internal/crypto/jwt.zig), [k256 tests](https://tangled.sh/@zzstoatzz.io/k256) ## sha-256 hashing for content addressing (CIDs, integrity checks). hash data into a fixed-size digest: ```zig const Sha256 = std.crypto.hash.sha2.Sha256; var hash: [Sha256.digest_length]u8 = undefined; // 32 bytes Sha256.hash(data, &hash, .{}); ``` no allocation needed — the digest is a fixed 32-byte array on the stack. the `.{}` is options (empty = defaults). use case: creating CIDs (content identifiers) for IPLD/AT Protocol — hash DAG-CBOR encoded data, then wrap the digest in a CID with version + codec + multihash framing. see: [zat/cbor.zig Cid.forDagCbor](https://tangled.sh/@zzstoatzz.io/zat/tree/main/src/internal/cbor.zig) ## sources - zat — src/internal/jwt.zig, src/internal/crypto/jwt.zig, src/internal/cbor.zig - k256 — signature tests