OwnershipCircuit
Proves knowledge of a secret key without revealing it: "I know sk such that Poseidon(sk) == owner_hash."
- 1 public input:
owner_hash - 1 private witness:
secret_key - Single constraint:
poseidon(sk) == owner_hash
Structurally identical to PreimageCircuit but semantically distinct -- this circuit is used for key ownership proofs in the Root14 identity layer.
Struct
#[derive(Clone)]
pub struct OwnershipCircuit {
pub secret_key: Option<Fr>,
}
Constraint Generation
impl ConstraintSynthesizer<Fr> for OwnershipCircuit {
fn generate_constraints(self, cs: ConstraintSystemRef<Fr>) -> Result<(), SynthesisError> {
let owner_hash_pub = FpVar::new_input(cs.clone(), || {
let sk = self.secret_key.ok_or(SynthesisError::AssignmentMissing)?;
Ok(r14_poseidon::poseidon_hash(&[sk]))
})?;
let sk_var = FpVar::new_witness(cs.clone(), || {
self.secret_key.ok_or(SynthesisError::AssignmentMissing)
})?;
let computed = poseidon_hash_var(cs, &[sk_var])?;
computed.enforce_equal(&owner_hash_pub)?;
Ok(())
}
}
Public Inputs
pub struct PublicInputs {
pub owner_hash: Fr,
}
impl PublicInputs {
pub fn to_vec(&self) -> Vec<Fr> {
vec![self.owner_hash]
}
}
API
setup(rng) -> (ProvingKey, VerifyingKey)
Groth16 trusted setup with an empty circuit (witness = None).
pub fn setup<R: RngCore + CryptoRng>(
rng: &mut R,
) -> (ProvingKey<Bls12_381>, VerifyingKey<Bls12_381>)
prove(pk, secret_key, rng) -> (Proof, PublicInputs)
Hashes the secret key natively to produce owner_hash, then generates the Groth16 proof.
pub fn prove<R: RngCore + CryptoRng>(
pk: &ProvingKey<Bls12_381>,
secret_key: Fr,
rng: &mut R,
) -> (ark_groth16::Proof<Bls12_381>, PublicInputs)
verify_offchain(vk, proof, pi) -> bool
Off-chain verification using PreparedVerifyingKey.
pub fn verify_offchain(
vk: &VerifyingKey<Bls12_381>,
proof: &ark_groth16::Proof<Bls12_381>,
pi: &PublicInputs,
) -> bool
constraint_count() -> usize
Returns the R1CS constraint count. Expected range: 100-1000.
pub fn constraint_count() -> usize