You just need to implement those functions alongside your LLVMFuzzerTestOneInput.
The google/fuzzing repository has a tutorial on how to implement structure-aware fuzzing.
Also, you could take inspiration from CustomMutatorTest.cpp, and CustomCrossOverTest.cpp, from the LLVM repository.
The fuzzer is required to be deterministic.
Right, but here you will be writing the mutation functions, which are different; Mutations will happen before your LLVMFuzzerTestOneInput is called.
However, they have an analogous requirement.
As outlined in the source code, alongside LLVMFuzzerCustomMutator, and LLVMFuzzerCustomCrossOver respectively:
Optional user-provided custom mutator.
Mutates raw data in [Data, Data+Size) inplace.
Returns the new size, which is not greater than MaxSize.
Given the same Seed produces the same mutation.
Optional user-provided custom cross-over function.
Combines pieces of Data1 & Data2 together into Out.
Returns the new size, which is not greater than MaxOutSize.
Should produce the same mutation given the same Seed.
i.e. Two calls to a mutation function with the same Data and seed should produce the same result.
One last thing: you don't need to implement both functions;  LLVMFuzzerCustomMutator should be enough in most cases.