// atproto repo commit — sign + verify.
//
// A commit is { did, version: 3, data: <MST root CID>, rev, prev, sig }. The
// signature is ECDSA-secp256k1 (low-S) over sha256(dag-cbor(unsignedCommit)), stored
// as a raw 64-byte CBOR byte string (NOT base64url — that's the did:plc genesis).
// The relay validates this sig against the DID doc's verificationMethod.
import * as dagCbor from '@ipld/dag-cbor'
import { sha256 as nobleSha256 } from '@noble/hashes/sha2'
import { secp256k1 } from '@noble/curves/secp256k1'
import { cidForBytesSync } from './cid.js'
export const REPO_VERSION = 3
// The unsigned commit (everything the signature covers).
export function unsignedCommit ({ did, rev, data, prev = null }) {
return { did, version: REPO_VERSION, data, rev, prev }
}
// Sign an unsigned commit -> signed commit with `sig` (64 raw bytes).
export function signCommit (unsigned, privateKey) {
const hash = nobleSha256(dagCbor.encode(unsigned))
const sig = secp256k1.sign(hash, privateKey, { lowS: true }).toCompactRawBytes()
return { ...unsigned, sig }
}
export function commitCid (signedCommit) {
return cidForBytesSync(dagCbor.encode(signedCommit))
}
// Verify a signed commit against a compressed secp256k1 pubkey (33 bytes).
export function verifyCommit (signedCommit, publicKey) {
const { sig, ...unsigned } = signedCommit
const hash = nobleSha256(dagCbor.encode(unsigned))
return secp256k1.verify(sig, hash, publicKey, { lowS: true })
}