Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,11 @@
"sha256": "8bf5d5a1c0f00ce245a1ecb18b923aa1631483345962d72b633e466c242a8a1d"
},
{
"bytes": 17408,
"bytes": 18517,
"license": "MIT",
"path": "crates/labcolors-core/src/lib.rs",
"role": "module_registration_source",
"sha256": "0a43c29b5dcff9c344443c62e8dddfcc82e516ac7ca6e6708f11354202e9fcd9"
"sha256": "37b3cae3969a85d27863ab8177a056c1736cbc45e75e5bbcfc5aa603a7200cd7"
},
{
"bytes": 39439,
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
a27604c3306a3a40818594c173b09e7feda925653eb9658d64c9b9784526c48e receipt-v1.json
959f1b235e4a08004c0632c87678622b4b688ded4fd507cd28f9d41072fd3ac0 receipt-v1.json

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions crates/labcolors-core/src/contextual_region_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,14 @@ use crate::lcs_occurrence::{
const FORMULA_SPEC_BYTES: &[u8] = include_bytes!("../contracts/contextual-region-formula-v1.lcir");
const FORMULA_SPEC_DOMAIN: &[u8] = b"labcolors.nominal-exact-real-lift.ascii-ssa.v1\0";

const POSITIVE_ZERO: u64 = 0x0000_0000_0000_0000;
pub(crate) const POSITIVE_ZERO: u64 = 0x0000_0000_0000_0000;
const NEGATIVE_ZERO: u64 = 0x8000_0000_0000_0000;
const MIN_SUBNORMAL: u64 = 0x0000_0000_0000_0001;
const MIN_NORMAL: u64 = 0x0010_0000_0000_0000;
const NEGATIVE_MIN_SUBNORMAL: u64 = 0x8000_0000_0000_0001;
const ONE: u64 = 0x3ff0_0000_0000_0000;
pub(crate) const ONE: u64 = 0x3ff0_0000_0000_0000;
const ONE_AND_HALF: u64 = 0x3ff8_0000_0000_0000;
const TWO: u64 = 0x4000_0000_0000_0000;
pub(crate) const TWO: u64 = 0x4000_0000_0000_0000;
const TWO_AND_HALF: u64 = 0x4004_0000_0000_0000;
const THREE: u64 = 0x4008_0000_0000_0000;
const FOUR: u64 = 0x4010_0000_0000_0000;
Expand All @@ -37,7 +37,7 @@ const NEGATIVE_ONE: u64 = 0xbff0_0000_0000_0000;
const MAX_FINITE: u64 = 0x7fef_ffff_ffff_ffff;
const NEGATIVE_MAX_FINITE: u64 = 0xffef_ffff_ffff_ffff;

fn context(frame: crate::lcs_occurrence::ColorimetricFrameId) -> AppearanceContextId {
pub(crate) fn context(frame: crate::lcs_occurrence::ColorimetricFrameId) -> AppearanceContextId {
context_with(frame, 64.0, 0.2, SurroundProfileId::AverageV1)
}

Expand All @@ -60,7 +60,7 @@ fn knot(tone: u64, center_a: u64, center_b: u64, radius_squared: u64) -> TubeKno
TubeKnotBitsV1::new(tone, center_a, center_b, radius_squared)
}

fn region_with_centers(centers: [[u64; 2]; 2]) -> PiecewiseLinearCartesianTubeV1 {
pub(crate) fn region_with_centers(centers: [[u64; 2]; 2]) -> PiecewiseLinearCartesianTubeV1 {
PiecewiseLinearCartesianTubeV1::try_from_bits(
Shape2BitsV1::new(ONE, POSITIVE_ZERO, ONE),
&[
Expand All @@ -71,7 +71,7 @@ fn region_with_centers(centers: [[u64; 2]; 2]) -> PiecewiseLinearCartesianTubeV1
.unwrap()
}

fn pipeline(context: AppearanceContextId) -> ContextualRegionPipelineV1 {
pub(crate) fn pipeline(context: AppearanceContextId) -> ContextualRegionPipelineV1 {
pipeline_with_release(context, MODELED_LCS_OCCURRENCE_RELEASE_V1)
}

Expand Down
25 changes: 24 additions & 1 deletion crates/labcolors-core/src/family_artifact.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,9 @@ impl FamilyImageCertificateV2 {
///
/// Потребитель сверяет его с `ContextualRegionFamilyProviderV1`, иначе
/// доверенная запись говорит лишь «этот артефакт цел», но не «этот
/// артефакт — образ того региона, который я спрашивал».
/// артефакт — образ того региона, который я спрашивал». Сам loader этот
/// адрес не интерпретирует: сверка принадлежит `family_definition_binding`
/// и является единственным её местом.
pub(crate) const fn definition_digest(self) -> FamilyDefinitionDigestV2 {
self.definition_digest
}
Expand Down Expand Up @@ -280,6 +282,27 @@ impl FamilyImageCertificateV2 {
self
}

/// Переадресует certificate на другое определение, пересчитывая semantic
/// release и receipt.
///
/// Когерентность здесь обязательна, а не удобна: guard определения обязан
/// отказывать входу, который `parse_trusted` принимает. Некогерентный
/// certificate доказывал бы отказ на недостижимом значении.
#[cfg(test)]
pub(crate) fn definition_with_coherent_certificate_for_test(
mut self,
definition_digest: FamilyDefinitionDigestV2,
) -> Self {
self.definition_digest = definition_digest;
self.semantic_release = semantic_family_release_id_v2(
self.definition_digest,
self.image_digest,
self.member_count,
);
self.artifact_receipt = artifact_receipt(self);
self
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

#[cfg(test)]
pub(crate) fn semantic_mismatch_with_valid_receipt_for_test(mut self) -> Self {
let mut bytes = *self.semantic_release.as_bytes();
Expand Down
99 changes: 99 additions & 0 deletions crates/labcolors-core/src/family_definition_binding.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
//! Связывание доверенного certificate с адресом спрошенного определения.
//!
//! `contextual_region` отвечает, какой content address имеет спрошенный регион.
//! `family_artifact` отвечает, что байты точно соответствуют доверенному
//! certificate. Ни одна из границ не отвечает на вопрос «а этот certificate
//! вообще про спрошенный регион?»: целый artifact ДРУГОГО региона проходит обе
//! проверки. Модуль замыкает цепь одним сравнением двух адресов.

#![cfg_attr(
not(test),
expect(
dead_code,
reason = "V5b2b keeps the definition-bound admission private until the public family provider cutover"
)
)]

use core::fmt;

use crate::contextual_region::{
ContextualRegionFamilyProviderV1, ContextualRegionPipelineV1, PiecewiseLinearCartesianTubeV1,
};
use crate::family::FamilyDefinitionDigestV2;
use crate::family_artifact::{
AdmittedFamilyArtifactV2, EncodedFamilyArtifactV2, FamilyArtifactLoadErrorV1,
FamilyArtifactLoaderV1, FamilyImageCertificateV2,
};

/// Причина, по которой artifact не допущен как образ спрошенного региона.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum DefinitionBoundFamilyLoadErrorV1 {
/// Certificate доверен и цел, но адресует другое определение.
ForeignDefinition {
asked: FamilyDefinitionDigestV2,
certified: FamilyDefinitionDigestV2,
},
/// Certificate про спрошенное определение, но transport его не подтвердил.
Artifact(FamilyArtifactLoadErrorV1),
}

/// Неуспех возвращает те же owned bytes: диагностика, исправление или повтор
/// не требуют refetch и clone.
pub(crate) struct DefinitionBoundFamilyLoadFailureV1 {
cause: DefinitionBoundFamilyLoadErrorV1,
encoded: EncodedFamilyArtifactV2,
}

impl fmt::Debug for DefinitionBoundFamilyLoadFailureV1 {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter
.debug_struct("DefinitionBoundFamilyLoadFailureV1")
.field("cause", &self.cause)
.finish_non_exhaustive()
}
}

impl DefinitionBoundFamilyLoadFailureV1 {
pub(crate) const fn cause(&self) -> DefinitionBoundFamilyLoadErrorV1 {
self.cause
}

pub(crate) fn into_parts(self) -> (DefinitionBoundFamilyLoadErrorV1, EncodedFamilyArtifactV2) {
(self.cause, self.encoded)
}
}

/// Единственный вход, допускающий artifact к тому определению, которое
/// потребитель действительно спросил.
pub(crate) struct DefinitionBoundFamilyLoaderV1;

impl DefinitionBoundFamilyLoaderV1 {
/// Спрошенный регион задаётся `pipeline` и `region`; семейство приходит
/// извне как доверенный `certificate` и его `encoded` bytes.
///
/// Сравнение адресов идёт по двум записям и завершается до parse envelope,
/// хеширования payload и decode образа: чужое определение стоит одного
/// content address, а не мегабайтов.
pub(crate) fn load(
pipeline: ContextualRegionPipelineV1,
region: &PiecewiseLinearCartesianTubeV1,
certificate: FamilyImageCertificateV2,
encoded: EncodedFamilyArtifactV2,
) -> Result<AdmittedFamilyArtifactV2, DefinitionBoundFamilyLoadFailureV1> {
let asked = ContextualRegionFamilyProviderV1::definition_digest(pipeline, region);
let certified = certificate.definition_digest();
if asked != certified {
return Err(DefinitionBoundFamilyLoadFailureV1 {
cause: DefinitionBoundFamilyLoadErrorV1::ForeignDefinition { asked, certified },
encoded,
});
}
FamilyArtifactLoaderV1::load(certificate, encoded).map_err(|failure| {
let (cause, encoded) = failure.into_parts();
DefinitionBoundFamilyLoadFailureV1 {
cause: DefinitionBoundFamilyLoadErrorV1::Artifact(cause),
encoded,
}
})
}
}
Loading
Loading