code wiki / (root) / nx_accept_binding_candidate_t230.nx

nx_accept_binding_candidate_t230.nx source

↩ module page · 88 lines · 4120 B

1// Candidate additive acceptance binding for nx_accept owner; legacy subject records unchanged. 2// This predicate verifies evidence identity, not evaluator authority. The workflow must authorize 3// the evidence producer and retain stage-specific policy/test receipts. No implicit promotion. 4// Wire schema (exactly seven TSV fields, one terminal LF): 5// acceptance-release/v1 SUBJECT CANDIDATE_SHA256 STAGE VERDICT POLICY_SHA256 EVIDENCE_REF 6// EVIDENCE_REF identifies the detailed test bundle; its contents are validated by the workflow. 7// Expected receipt SHA256 binds every byte, including the evidence reference. 8import "nx_sha256.nx" 9 10const ARB_ACCEPTED: i64 = 0 11const ARB_INCOMPLETE: i64 = 1 12const ARB_REJECTED: i64 = 2 13const ARB_INVALID: i64 = 3 14const ARB_IDENTITY: i64 = 4 15const ARB_IO: i64 = 5 16const ARB_FIELDS: i64 = 7 17const ARB_SPAN_WORDS: i64 = 2 18const ARB_WORD_BYTES: i64 = 8 19const ARB_HASH_HEX: i64 = SHA256_DIGEST_BYTES*2 20 21func arb_len(s: *u8) -> i64 { 22 if (s as i64)<=0{return 0};var n:i64=0;while s[n]!=0{n=n+1};return n 23} 24func arb_eq(a:*u8,an:i64,b:*u8,bn:i64)->i64 { 25 if an!=bn{return 0};var i:i64=0;while i<an{if a[i]!=b[i]{return 0};i=i+1};return 1 26} 27func arb_hex_ok(s:*u8,n:i64)->i64 { 28 if n!=ARB_HASH_HEX{return 0};var i:i64=0 29 while i<n {let c:i64=s[i] as i64;if (c<48||c>57)&&(c<97||c>102){return 0};i=i+1};return 1 30} 31func arb_stage(s:*u8,n:i64)->i64 { 32 if arb_eq(s,n,"alpha",5)==1{return 1} 33 if arb_eq(s,n,"beta",4)==1{return 1} 34 return arb_eq(s,n,"production",10) 35} 36func arb_field_eq(b:*u8,fields:*i64,field:i64,s:*u8)->i64 { 37 return arb_eq(((b as i64)+fields[field*ARB_SPAN_WORDS]) as *u8,fields[field*ARB_SPAN_WORDS+1],s,arb_len(s)) 38} 39func arb_parse(b:*u8,n:i64,fields:*i64)->i64 { 40 if n<=0||(b as i64)<=0{return ARB_INCOMPLETE} 41 var i:i64=0;var start:i64=0;var f:i64=0 42 while i<n { 43 let c:i64=b[i] as i64 44 if c==9||c==10 { 45 if f>=ARB_FIELDS||i==start{return ARB_INVALID} 46 fields[f*ARB_SPAN_WORDS]=start;fields[f*ARB_SPAN_WORDS+1]=i-start;f=f+1;start=i+1 47 if c==10 {if i!=n-1||f!=ARB_FIELDS{return ARB_INVALID};return ARB_ACCEPTED} 48 } else {if c<32||c==127{return ARB_INVALID}} 49 i=i+1 50 } 51 return ARB_INVALID 52} 53func arb_check_fields(subject:*u8,candidate:*u8,stage:*u8,policy:*u8,b:*u8,n:i64,fields:*i64)->i64 { 54 let parsed:i64=arb_parse(b,n,fields);if parsed!=ARB_ACCEPTED{return parsed} 55 if arb_field_eq(b,fields,0,"acceptance-release/v1")!=1{return ARB_INVALID} 56 if arb_field_eq(b,fields,1,subject)!=1{return ARB_IDENTITY} 57 if arb_field_eq(b,fields,2,candidate)!=1{return ARB_IDENTITY} 58 if arb_field_eq(b,fields,3,stage)!=1{return ARB_IDENTITY} 59 if arb_field_eq(b,fields,5,policy)!=1{return ARB_IDENTITY} 60 if arb_field_eq(b,fields,4,"incomplete")==1{return ARB_INCOMPLETE} 61 if arb_field_eq(b,fields,4,"fail")==1{return ARB_REJECTED} 62 if arb_field_eq(b,fields,4,"pass")!=1{return ARB_INVALID} 63 return ARB_ACCEPTED 64} 65func arb_receipt(subject:*u8,candidate:*u8,stage:*u8,policy:*u8,receipt_sha:*u8,b:*u8,n:i64)->i64 { 66 if arb_len(subject)==0||arb_stage(stage,arb_len(stage))!=1{return ARB_INVALID} 67 if arb_hex_ok(candidate,arb_len(candidate))!=1||arb_hex_ok(policy,arb_len(policy))!=1{return ARB_INVALID} 68 if arb_hex_ok(receipt_sha,arb_len(receipt_sha))!=1{return ARB_INVALID} 69 if n<=0||(b as i64)<=0{return ARB_INCOMPLETE} 70 let digest:*u8=sys_mmap(SHA256_DIGEST_BYTES) 71 if (digest as i64)<=0{return ARB_IO} 72 let hashed:i64=sha256_digest_checked_native(b,n,digest) 73 if hashed!=0{sys_munmap(digest,SHA256_DIGEST_BYTES);return ARB_IO} 74 let alphabet:*u8="0123456789abcdef" 75 var i:i64=0;var matches:i64=1 76 while i<SHA256_DIGEST_BYTES { 77 let c:i64=digest[i] as i64 78 if alphabet[(c>>4)&15]!=receipt_sha[i*2]||alphabet[c&15]!=receipt_sha[i*2+1]{matches=0} 79 i=i+1 80 } 81 let released:i64=sys_munmap(digest,SHA256_DIGEST_BYTES) 82 if released!=0{return ARB_IO};if matches!=1{return ARB_IDENTITY} 83 let fields:*i64=sys_mmap(ARB_FIELDS*ARB_SPAN_WORDS*ARB_WORD_BYTES) as *i64 84 if (fields as i64)<=0{return ARB_IO} 85 let result:i64=arb_check_fields(subject,candidate,stage,policy,b,n,fields) 86 if sys_munmap(fields as *u8,ARB_FIELDS*ARB_SPAN_WORDS*ARB_WORD_BYTES)!=0{return ARB_IO} 87 return result 88}