use cid::multihash::Multihash;
use cid::Cid;
pub const FIL_COMMITMENT_SEALED: u64 = 0xf102;
pub const FIL_COMMITMENT_UNSEALED: u64 = 0xf101;
pub const POSEIDON_BLS12_381_A1_FC1: u64 = 0xb401;
pub const SHA2_256_TRUNC254_PADDED: u64 = 0x1012;
pub type Commitment = [u8; 32];
pub fn commitment_to_cid(mc: u64, mh: u64, commitment: &Commitment) -> Result<Cid, &'static str> {
validate_filecoin_cid_segments(mc, mh, commitment)?;
let mh = Multihash::wrap(mh, commitment).map_err(|_| "failed to wrap commitment cid")?;
Ok(Cid::new_v1(mc, mh))
}
pub fn cid_to_commitment(c: &Cid) -> Result<(u64, u64, Commitment), &'static str> {
validate_filecoin_cid_segments(c.codec(), c.hash().code(), c.hash().digest())?;
let mut comm = Commitment::default();
comm.copy_from_slice(c.hash().digest());
Ok((c.codec(), c.hash().code(), comm))
}
pub fn data_commitment_v1_to_cid(comm_d: &Commitment) -> Result<Cid, &'static str> {
commitment_to_cid(FIL_COMMITMENT_UNSEALED, SHA2_256_TRUNC254_PADDED, comm_d)
}
pub fn cid_to_data_commitment_v1(c: &Cid) -> Result<Commitment, &'static str> {
let (codec, _, comm_d) = cid_to_commitment(c)?;
if codec != FIL_COMMITMENT_UNSEALED {
return Err("data commitment codec must be Unsealed");
}
Ok(comm_d)
}
pub fn replica_commitment_v1_to_cid(comm_r: &Commitment) -> Result<Cid, &'static str> {
commitment_to_cid(FIL_COMMITMENT_SEALED, POSEIDON_BLS12_381_A1_FC1, comm_r)
}
pub fn cid_to_replica_commitment_v1(c: &Cid) -> Result<Commitment, &'static str> {
let (codec, _, comm_r) = cid_to_commitment(c)?;
if codec != FIL_COMMITMENT_SEALED {
return Err("data commitment codec must be Sealed");
}
Ok(comm_r)
}
fn validate_filecoin_cid_segments(mc: u64, mh: u64, comm_x: &[u8]) -> Result<(), &'static str> {
match mc {
FIL_COMMITMENT_UNSEALED => {
if mh != SHA2_256_TRUNC254_PADDED {
return Err("Incorrect hash function for unsealed commitment");
}
}
FIL_COMMITMENT_SEALED => {
if mh != POSEIDON_BLS12_381_A1_FC1 {
return Err("Incorrect hash function for sealed commitment");
}
}
_ => return Err("Invalid Codec, expected sealed or unsealed commitment codec"),
}
if comm_x.len() != 32 {
Err("commitments must be 32 bytes long")
} else {
Ok(())
}
}
pub fn piece_commitment_v1_to_cid(comm_p: &Commitment) -> Result<Cid, &'static str> {
data_commitment_v1_to_cid(comm_p)
}
pub fn cid_to_piece_commitment_v1(c: &Cid) -> Result<Commitment, &'static str> {
cid_to_data_commitment_v1(c)
}