Follow portable CultNet provider signature bytes
This commit is contained in:
parent
d74b61f4b7
commit
a7647a1660
2 changed files with 7 additions and 8 deletions
|
|
@ -13,13 +13,13 @@ const idDomain=Buffer.from("gamecult.provider-health.identity.v1\0"),signatureDo
|
|||
|
||||
test("Persona-feedback emits the exact canonical signed daemon-health tuple",async()=>{
|
||||
const identity=await identityFixture(),incarnation="019f523f-f650-7001-be75-b4428985652b",signed=createSignedPersonaFeedbackHealth({daemonId:"yggdrasil-bifrost-persona-feedback",healthContract:"bifrost.cultnet-rudp-persona-feedback-health",state:"active",detail:"ready",identity,publisherIncarnationId:incarnation,publisherSequence:7,observedAtUnixMillis:1773950400123}),record=decode(signed.payload,{useBigInt64:true});
|
||||
assert.equal(record.length,17);assert.deepEqual(record.slice(0,10),["idunn.signed_daemon_health.v1","yggdrasil-bifrost-persona-feedback","bifrost.cultnet-rudp-persona-feedback-health","bifrost-persona-feedback","active","ready",signed.providerIdentityId,incarnation,7,1773950400123n]);assert.deepEqual(record.slice(10,14),[null,null,null,null]);assert.equal(record[14],"ed25519");assert.ok(Array.isArray(record[15]));assert.equal(record[15].length,64);assert.equal(record[16],false);
|
||||
const canonical=[...record];canonical[15]=[];assert.equal(verifyProvider(identity,encode(canonical,{useBigInt64:true}),record[15]),true);
|
||||
assert.equal(record.length,17);assert.deepEqual(record.slice(0,10),["idunn.signed_daemon_health.v1","yggdrasil-bifrost-persona-feedback","bifrost.cultnet-rudp-persona-feedback-health","bifrost-persona-feedback","active","ready",signed.providerIdentityId,incarnation,7,1773950400123n]);assert.deepEqual(record.slice(10,14),[null,null,null,null]);assert.ok(record[15] instanceof Uint8Array);assert.equal(record[14],"ed25519");assert.equal(record[15].length,64);assert.equal(record[16],false);
|
||||
const canonical=[...record];canonical[15]=new Uint8Array();assert.equal(verifyProvider(identity,encode(canonical,{useBigInt64:true}),record[15]),true);
|
||||
assert.equal(signed.providerIdentityId,createHash("sha256").update(idDomain).update(identity.publicKey).digest("hex"));assert.notEqual(signed.providerIdentityId,identity.identityId);
|
||||
});
|
||||
|
||||
test("provider-health signature rejects purpose, key, and payload substitution",async()=>{
|
||||
const identity=await identityFixture(),other=await identityFixture(),signed=createSignedPersonaFeedbackHealth({daemonId:"daemon",healthContract:"contract",state:"degraded",detail:"readiness-degraded",identity,publisherIncarnationId:"019f523f-f650-7001-be75-b4428985652b",publisherSequence:1,observedAtUnixMillis:1773950400123}),record=decode(signed.payload,{useBigInt64:true}),canonical=[...record];canonical[15]=[];
|
||||
const identity=await identityFixture(),other=await identityFixture(),signed=createSignedPersonaFeedbackHealth({daemonId:"daemon",healthContract:"contract",state:"degraded",detail:"readiness-degraded",identity,publisherIncarnationId:"019f523f-f650-7001-be75-b4428985652b",publisherSequence:1,observedAtUnixMillis:1773950400123}),record=decode(signed.payload,{useBigInt64:true}),canonical=[...record];canonical[15]=new Uint8Array();
|
||||
const canonicalPayload=encode(canonical,{useBigInt64:true});assert.equal(verifyProvider(identity,canonicalPayload,record[15]),true);assert.equal(verifyProvider(other,canonicalPayload,record[15]),false);
|
||||
const mutated=[...canonical];mutated[4]="active";assert.equal(verifyProvider(identity,encode(mutated,{useBigInt64:true}),record[15]),false);
|
||||
const oldDomainSignature=signFeedbackAdmission(identity,canonicalPayload);assert.equal(verifyProvider(identity,canonicalPayload,oldDomainSignature),false);
|
||||
|
|
|
|||
|
|
@ -25,13 +25,12 @@ export function createSignedPersonaFeedbackHealth(input){
|
|||
if(!isUuid(input.publisherIncarnationId))throw new Error("Bifrost Persona-feedback publisher incarnation must be a UUID.");
|
||||
if(!Number.isSafeInteger(input.publisherSequence)||input.publisherSequence<=0)throw new Error("Bifrost Persona-feedback publisher sequence must be a positive safe integer.");
|
||||
const observed=Number(input.observedAtUnixMillis??Date.now());if(!Number.isSafeInteger(observed)||observed<=0)throw new Error("Bifrost Persona-feedback observation time must be positive Unix milliseconds.");
|
||||
// Rust's canonical positional contract represents Vec<u8> as a MessagePack
|
||||
// integer array. Uint8Array lowers to bin8 and is therefore a different
|
||||
// signed payload even though both decode to bytes in JavaScript.
|
||||
// The shared CultNet contract marks signatures as portable bytes, so both
|
||||
// Rust and JavaScript lower this field as MessagePack binary.
|
||||
// Safe JavaScript numbers above u32 lower as float64. Rust's u64 lowers as
|
||||
// uint64, so retain the timestamp as BigInt on this signed wire surface.
|
||||
const provider=providerHealthIdentity(input.identity),record=[schema,input.daemonId,input.healthContract,sourceRuntimeId,input.state,input.detail,provider.identityId,input.publisherIncarnationId,input.publisherSequence,BigInt(observed),null,null,null,null,"ed25519",[],false];
|
||||
const proof=signProviderHealth(input.identity,canonicalHealthEncode(record));if(proof.identityId!==provider.identityId)throw new Error("Provider-health signer identity derivation disagrees with the packet.");record[15]=Array.from(proof.signature);
|
||||
const provider=providerHealthIdentity(input.identity),record=[schema,input.daemonId,input.healthContract,sourceRuntimeId,input.state,input.detail,provider.identityId,input.publisherIncarnationId,input.publisherSequence,BigInt(observed),null,null,null,null,"ed25519",new Uint8Array(),false];
|
||||
const proof=signProviderHealth(input.identity,canonicalHealthEncode(record));if(proof.identityId!==provider.identityId)throw new Error("Provider-health signer identity derivation disagrees with the packet.");record[15]=new Uint8Array(proof.signature);
|
||||
return {record,payload:canonicalHealthEncode(record),providerIdentityId:provider.identityId,observedAtUnixMillis:observed};
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue