···11(* Fuzz SCITT decoding — arbitrary bytes must not crash. *)
2233-let () =
44- Crowbar.run "scitt"
33+let suite =
44+ ( "decode",
55 [
66- ( "decode",
77- [
88- Crowbar.test_case "Signed_statement.decode doesn't crash"
99- Crowbar.[ bytes ]
1010- (fun b ->
1111- match Scitt.Signed_statement.decode b with
1212- | Ok _ -> ()
1313- | Error _ -> ());
1414- Crowbar.test_case "Receipt.decode doesn't crash"
1515- Crowbar.[ bytes ]
1616- (fun b ->
1717- match Scitt.Receipt.decode b with Ok _ -> () | Error _ -> ());
1818- Crowbar.test_case "Transparent_statement.decode doesn't crash"
1919- Crowbar.[ bytes ]
2020- (fun b ->
2121- match Scitt.Transparent_statement.decode b with
2222- | Ok _ -> ()
2323- | Error _ -> ());
2424- ] );
2525- ]
66+ Alcobar.test_case "Signed_statement.decode doesn't crash"
77+ Alcobar.[ bytes ]
88+ (fun b ->
99+ match Scitt.Signed_statement.decode b with
1010+ | Ok _ -> ()
1111+ | Error _ -> ());
1212+ Alcobar.test_case "Receipt.decode doesn't crash"
1313+ Alcobar.[ bytes ]
1414+ (fun b ->
1515+ match Scitt.Receipt.decode b with Ok _ -> () | Error _ -> ());
1616+ Alcobar.test_case "Transparent_statement.decode doesn't crash"
1717+ Alcobar.[ bytes ]
1818+ (fun b ->
1919+ match Scitt.Transparent_statement.decode b with
2020+ | Ok _ -> ()
2121+ | Error _ -> ());
2222+ ] )
+7
ocaml-scitt/fuzz/fuzz_scitt.mli
···11+(** Fuzz tests for {!Scitt}.
22+33+ Exercises CBOR decoders with arbitrary byte strings to check that no input
44+ causes an unhandled exception. *)
55+66+val suite : string * Alcobar.test_case list
77+(** [suite] is the Crowbar test suite. *)
+19
ocaml-scitt/fuzz/gen_corpus.ml
···11+let write_seed dir name content =
22+ let oc = open_out (Filename.concat dir name) in
33+ output_string oc content;
44+ close_out oc
55+66+let () =
77+ let dir = "corpus" in
88+ (try Unix.mkdir dir 0o755 with Unix.Unix_error (Unix.EEXIST, _, _) -> ());
99+ (* Minimal valid COSE Sign1 envelope (tag 18, array of 4 elements) *)
1010+ write_seed dir "cose_sign1_minimal" "\xd2\x84\x40\xa0\xf6\x40";
1111+ (* Empty CBOR array *)
1212+ write_seed dir "cbor_empty_array" "\x80";
1313+ (* CBOR array of two byte strings (transparent statement shape) *)
1414+ write_seed dir "cbor_pair" "\x82\x41\x00\x81\x41\x00";
1515+ (* Random garbage *)
1616+ write_seed dir "garbage" "\xff\xfe\xfd\xfc";
1717+ (* Empty input *)
1818+ write_seed dir "empty" "";
1919+ Fmt.pr "Generated 5 seed files in %s/@." dir
+44
ocaml-scitt/lib/hash.ml
···11+(* Hash agility for SCITT VDS backends.
22+33+ Each hash algorithm has a unique [id] stored in receipts for dispatch
44+ during verification. Per RFC 9162 §9, a single tree uses exactly one
55+ hash algorithm. *)
66+77+type t = { id : int; digest_size : int; digest : string -> string }
88+99+let make ~id ~digest_size f = { id; digest_size; digest = f }
1010+let id h = h.id
1111+1212+type proof_format = Rfc9162 | Prefixed
1313+1414+(* VDS registry: maps algorithm_id to (hash, proof_format). *)
1515+type vds_info = { hash : t; proof_format : proof_format }
1616+1717+let vds_registry : (int, vds_info) Hashtbl.t = Hashtbl.create 8
1818+1919+let register ?(proof_format = Rfc9162) h =
2020+ if Hashtbl.mem vds_registry h.id then
2121+ invalid_arg
2222+ (Fmt.str "Scitt.register_hash: algorithm_id %d already registered" h.id);
2323+ Hashtbl.add vds_registry h.id { hash = h; proof_format }
2424+2525+let find id =
2626+ Option.map (fun info -> info.hash) (Hashtbl.find_opt vds_registry id)
2727+2828+let vds_info id = Hashtbl.find_opt vds_registry id
2929+3030+module SHA256 = struct
3131+ let v =
3232+ make ~id:1 ~digest_size:32 (fun s ->
3333+ Digestif.SHA256.(digest_string s |> to_raw_string))
3434+3535+ let () = register v
3636+end
3737+3838+let sha256 = SHA256.v
3939+4040+(* Hash-parameterized leaf and node hashing per RFC 9162 §2.1. *)
4141+let leaf_hash_with h entry = h.digest ("\x00" ^ entry)
4242+let node_hash_with h left right = h.digest ("\x01" ^ left ^ right)
4343+let leaf_hash entry = leaf_hash_with sha256 entry
4444+let node_hash left right = node_hash_with sha256 left right
+29
ocaml-scitt/lib/hash.mli
···11+(** Hash agility for SCITT VDS backends. *)
22+33+type t = { id : int; digest_size : int; digest : string -> string }
44+(** A hash algorithm with a unique identifier. *)
55+66+val make : id:int -> digest_size:int -> (string -> string) -> t
77+val id : t -> int
88+99+type proof_format = Rfc9162 | Prefixed
1010+type vds_info = { hash : t; proof_format : proof_format }
1111+1212+val register : ?proof_format:proof_format -> t -> unit
1313+(** [register ?proof_format h] adds [h] to the global VDS registry. *)
1414+1515+val find : int -> t option
1616+(** [find id] looks up a registered hash by [id]. *)
1717+1818+val vds_info : int -> vds_info option
1919+(** [vds_info id] looks up the full VDS info (hash + proof format). *)
2020+2121+module SHA256 : sig
2222+ val v : t
2323+end
2424+2525+val sha256 : t
2626+val leaf_hash_with : t -> string -> string
2727+val node_hash_with : t -> string -> string -> string
2828+val leaf_hash : string -> string
2929+val node_hash : string -> string -> string
+88
ocaml-scitt/lib/proof.ml
···11+(* Merkle proof verification for SCITT.
22+33+ Implements RFC 9162 §2.1.3.2 (binary merkle tree) and MST (AT Proto)
44+ proof verification via Irmin. *)
55+66+type level = Merkle_proof | Ts_signature_only
77+88+let pp_level ppf = function
99+ | Merkle_proof -> Fmt.string ppf "merkle-proof"
1010+ | Ts_signature_only -> Fmt.string ppf "ts-signature-only"
1111+1212+let weaker a b =
1313+ match (a, b) with
1414+ | Ts_signature_only, _ | _, Ts_signature_only -> Ts_signature_only
1515+ | Merkle_proof, Merkle_proof -> Merkle_proof
1616+1717+(** RFC 9162 §2.1.3.2: Verifying an Inclusion Proof.
1818+1919+ [path] contains raw sibling hashes (no direction prefix). The direction
2020+ (left/right) is determined algorithmically from [fn] (leaf_index) and [sn]
2121+ (tree_size - 1) at each step. *)
2222+let verify_inclusion ?(hash = Hash.sha256) (proof : Vds.inclusion_proof) =
2323+ let node_hash = Hash.node_hash_with hash in
2424+ if List.length proof.path > Vds.max_proof_path_length then false
2525+ else if proof.leaf_index >= proof.tree_size then false
2626+ else
2727+ let rec shift_until_lsb fn sn =
2828+ if fn = 0 || fn land 1 = 1 then (fn, sn)
2929+ else shift_until_lsb (fn asr 1) (sn asr 1)
3030+ in
3131+ let rec step fn sn r = function
3232+ | [] -> sn = 0 && Eqaf.equal r proof.root
3333+ | _ :: _ when sn = 0 -> false
3434+ | p :: rest ->
3535+ let fn, sn, r =
3636+ if fn land 1 = 1 || fn = sn then
3737+ let fn, sn = shift_until_lsb fn sn in
3838+ (fn, sn, node_hash p r)
3939+ else (fn, sn, node_hash r p)
4040+ in
4141+ step (fn asr 1) (sn asr 1) r rest
4242+ in
4343+ step proof.leaf_index (proof.tree_size - 1) proof.leaf_hash proof.path
4444+4545+(** Verify an MST (AT Proto) Irmin proof. *)
4646+let verify_mst ~hash:_ ~root path =
4747+ match path with
4848+ | [ vdp_data ] -> (
4949+ match Cbort.decode_string Cbort.any vdp_data with
5050+ | Error _ -> Error "MST vdp: invalid CBOR"
5151+ | Ok vdp_cbor -> (
5252+ match Cbort.Cbor.to_array vdp_cbor with
5353+ | Some [ key_cbor; proof_cbor ] -> (
5454+ let repo_key =
5555+ Option.value ~default:"" (Cbort.Cbor.to_text key_cbor)
5656+ in
5757+ let irmin_proof_bytes =
5858+ Option.value ~default:"" (Cbort.Cbor.to_bytes proof_cbor)
5959+ in
6060+ match
6161+ Irmin.Proof.decode_cbor ~decode_hash:Atp.Cid.of_raw_bytes
6262+ ~decode_contents:Fun.id irmin_proof_bytes
6363+ with
6464+ | exception Eio.Io _ -> Error "MST proof decode: malformed CID"
6565+ | Error (`Msg msg) -> Error ("MST proof decode: " ^ msg)
6666+ | Ok irmin_proof -> (
6767+ let irmin_root_cid =
6868+ match Irmin.Proof.before irmin_proof with
6969+ | `Node h -> h
7070+ | `Contents h -> h
7171+ in
7272+ let irmin_root = Atp.Cid.to_raw_bytes irmin_root_cid in
7373+ if not (Eqaf.equal irmin_root root) then
7474+ Error "MST proof root does not match authenticated root"
7575+ else
7676+ match
7777+ Irmin.Proof.Mst.verify irmin_proof (fun tree ->
7878+ let v = Irmin.Proof.Mst.Tree.find tree [ repo_key ] in
7979+ (tree, v))
8080+ with
8181+ | exception Eio.Io _ ->
8282+ Error "MST proof verify: malformed CID"
8383+ | Ok (_, Some _) -> Ok Merkle_proof
8484+ | Ok (_, None) -> Error "MST proof: key not in tree"
8585+ | Error (`Proof_mismatch msg) ->
8686+ Error ("MST proof mismatch: " ^ msg)))
8787+ | _ -> Error "MST vdp must be [repo_key, proof_cbor]"))
8888+ | _ -> Error "MST receipt must have exactly one proof entry"
···561561 "Efficient Data Structures for Tamper-Evident Logging" (2009), Theorem 1:
562562 finding a valid alternative inclusion proof requires a hash collision. *)
563563564564- (** Decode and verify an MST (AT Proto) Irmin proof from the receipt's
565565- unprotected [vdp] path. The path must contain exactly one entry: a CBOR
566566- array [[repo_key, irmin_proof_cbor]].
564564+ (* Decode and verify an MST (AT Proto) Irmin proof from the receipt's
565565+ unprotected vdp path. The path must contain exactly one entry: a CBOR
566566+ array [repo_key, irmin_proof_cbor].
567567568568- Checks: 1. The Irmin proof's root CID matches [~root] (the
569569- TS-authenticated root). 2. [Irmin.Proof.Mst.verify] succeeds (proof tree
570570- hashes are consistent). 3. The key exists in the proven tree.
568568+ Checks: 1. The Irmin proof's root CID matches ~root (the
569569+ TS-authenticated root). 2. Irmin.Proof.Mst.verify succeeds (proof tree
570570+ hashes are consistent). 3. The key exists in the proven tree.
571571+572572+ The found value is NOT compared to the signed statement — the MST stores
573573+ DAG-CBOR wrapped AT Proto records, not raw COSE bytes. The binding between
574574+ the statement and the tree is via the TS signature over (root, leaf_hash),
575575+ verified by the caller. *)
571576572572- The found value is NOT compared to the signed statement — the MST stores
573573- DAG-CBOR wrapped AT Proto records, not raw COSE bytes. The binding between
574574- the statement and the tree is via the TS signature over (root, leaf_hash),
575575- verified by the caller. *)
576576- let verify_mst_proof ~hash:_ ~root path =
577577+ (** Extract the [cose] field from a DAG-CBOR AT Proto statement record. *)
578578+ let extract_cose_from_dagcbor dagcbor_bytes =
579579+ match Atp.Dagcbor.decode_string dagcbor_bytes with
580580+ | exception _ -> None
581581+ | dagcbor -> (
582582+ match Atp.Dagcbor.to_json dagcbor with
583583+ | Error _ -> None
584584+ | Ok json -> (
585585+ match json with
586586+ | Jsont.Object (mems, _) -> (
587587+ match Jsont.Json.find_mem "cose" mems with
588588+ | Some (_, Jsont.String (s, _)) -> Some s
589589+ | _ -> None)
590590+ | _ -> None))
591591+592592+ let verify_mst_proof ~hash ~expected_leaf ~root path =
577593 match path with
578594 | [ vdp_data ] -> (
579595 match Cbort.decode_string Cbort.any vdp_data with
···616632 with
617633 | exception Eio.Io _ ->
618634 Error (Proof_error "MST proof verify: malformed CID")
619619- | Ok (_, Some _) -> Ok Merkle_proof
635635+ | Ok (_, Some found_dagcbor) -> (
636636+ (* Extract the cose field from the DAG-CBOR record
637637+ and verify its leaf hash matches expected_leaf.
638638+ This binds the Irmin proof to the signed statement. *)
639639+ match extract_cose_from_dagcbor found_dagcbor with
640640+ | None ->
641641+ Error
642642+ (Proof_error
643643+ "MST proof: cannot extract cose from record")
644644+ | Some cose_bytes ->
645645+ let found_leaf =
646646+ hash.digest ("\x00" ^ cose_bytes)
647647+ in
648648+ if Eqaf.equal found_leaf expected_leaf then
649649+ Ok Merkle_proof
650650+ else
651651+ Error
652652+ (Proof_error
653653+ "MST proof: record cose does not match \
654654+ signed statement"))
620655 | Ok (_, None) ->
621656 Error (Proof_error "MST proof: key not in tree")
622657 | Error (`Proof_mismatch msg) ->
···664699 | Some vds_info ->
665700 let hash = vds_info.hash in
666701 if vds_info.proof_format = Prefixed then
667667- verify_mst_proof ~hash ~root:proof.root proof.path
702702+ verify_mst_proof ~hash ~expected_leaf:proof.leaf_hash
703703+ ~root:proof.root proof.path
668704 else if verify_inclusion ~hash proof then Ok Merkle_proof
669705 else Error (Proof_error "merkle inclusion proof failed")))
670706
+74-3
ocaml-scitt/lib/scitt.mli
···5858 | Registration_error of string
59596060val pp_error : error Fmt.t
6161+(** [pp_error] is a pretty-printer for {!error}. *)
61626263(** {1 Hash Agility}
6364···155156 Merkle paths are not yet available. *)
156157157158val pp_proof_level : proof_level Fmt.t
159159+(** [pp_proof_level] is a pretty-printer for {!proof_level}. *)
158160159161val verify_inclusion : ?hash:hash -> inclusion_proof -> bool
160162(** [verify_inclusion ~hash proof] verifies a Merkle inclusion proof per
···186188187189 val append :
188190 t -> key:string -> value:string -> (inclusion_proof, string) result
191191+ (** [append t ~key ~value] registers [value] under [key] and returns an
192192+ inclusion proof, or an error if [key] is already present. *)
189193190194 val lookup : t -> key:string -> string option
195195+ (** [lookup t ~key] is the value stored under [key], if any. *)
196196+191197 val root : t -> string
198198+ (** [root t] is the current Merkle tree root hash. *)
199199+192200 val size : t -> int
201201+ (** [size t] is the number of entries in the tree. *)
202202+193203 val algorithm_id : t -> int
204204+ (** [algorithm_id t] is the VDS hash algorithm identifier stored in receipts.
205205+ *)
206206+194207 val proof_format : proof_format
208208+ (** [proof_format] is the encoding used for inclusion proof paths. *)
209209+195210 val export : t -> string
211211+ (** [export t] serialises the VDS state to a CBOR byte string. *)
196212end
197213198214val vds_of_backend : (module VDS_backend with type t = 'a) -> 'a -> vds
199199-(** [vds_of_backend (module B) state] wraps a backend into a {!vds} value. This
200200- is for backend implementors — users should call [Vds_rfc9162.v ()] or
201201- [Scitt_atp.Make(C).v ()] instead. *)
215215+(** [vds_of_backend (module B) s] wraps the backend module [B] and its state [s]
216216+ into an opaque {!vds} value. This is for backend implementors -- users
217217+ should call [Vds_rfc9162.v ()] or [Scitt_atp.Make(C).v ()] instead. *)
202218203219val vds_append :
204220 vds -> key:string -> value:string -> (inclusion_proof, error) result
221221+(** [vds_append vds ~key ~value] appends an entry and returns an inclusion
222222+ proof. *)
205223206224val vds_lookup : vds -> key:string -> string option
225225+(** [vds_lookup vds ~key] retrieves the value stored under [key]. *)
226226+207227val vds_root : vds -> string
228228+(** [vds_root vds] is the current root hash. *)
229229+208230val vds_size : vds -> int
231231+(** [vds_size vds] is the number of entries. *)
232232+209233val vds_export : vds -> string
234234+(** [vds_export vds] serialises the VDS state. *)
210235211236(** {1 RFC 9162 VDS}
212237···236261 content_type:string ->
237262 payload:string ->
238263 t
264264+ (** [v ~issuer ~subject ~content_type ~payload] is a new statement. *)
239265240266 val issuer : t -> string
267267+ (** [issuer t] is the issuer DID. *)
268268+241269 val subject : t -> string
270270+ (** [subject t] is the artifact reference. *)
271271+242272 val content_type : t -> string
273273+ (** [content_type t] is the media type of the payload. *)
274274+243275 val payload : t -> string
276276+ (** [payload t] is the statement payload. *)
244277end
245278246279(** {1 Signed Statements} *)
···249282 type t
250283251284 val sign : key:X509.Private_key.t -> Statement.t -> (t, error) result
285285+ (** [sign ~key stmt] signs [stmt] with [key] and returns a COSE Sign1
286286+ envelope. *)
287287+252288 val statement : t -> Statement.t
289289+ (** [statement t] is the underlying statement. *)
290290+253291 val cose : t -> Cose.Sign1.t
292292+ (** [cose t] is the COSE Sign1 envelope. *)
293293+254294 val issuer : t -> string
295295+ (** [issuer t] is the issuer DID from the statement. *)
296296+255297 val subject : t -> string
298298+ (** [subject t] is the artifact reference from the statement. *)
299299+256300 val encode : t -> string
301301+ (** [encode t] serialises [t] to CBOR bytes. *)
302302+257303 val decode : string -> (t, error) result
304304+ (** [decode s] deserialises a signed statement from CBOR bytes. *)
258305end
259306260307(** {1 Receipts} *)
···269316 }
270317271318 val inclusion_proof : t -> inclusion_proof
319319+ (** [inclusion_proof t] is the Merkle inclusion proof. *)
320320+272321 val algorithm_id : t -> int
322322+ (** [algorithm_id t] is the VDS hash algorithm identifier. *)
273323274324 val service_id : t -> string option
275325 (** [service_id r] is the COSE [kid] from the receipt's protected header — the
···277327 look up the TS public key from a local trust store. *)
278328279329 val encode : t -> string
330330+ (** [encode t] serialises [t] to CBOR bytes. *)
331331+280332 val decode : string -> (t, error) result
333333+ (** [decode s] deserialises a receipt from CBOR bytes. *)
281334end
282335283336(** {1 Transparent Statements}
···309362 type t
310363311364 val v : Signed_statement.t -> Receipt.t list -> t
365365+ (** [v signed receipts] is a transparent statement bundling [signed] with
366366+ [receipts]. *)
367367+312368 val signed_statement : t -> Signed_statement.t
369369+ (** [signed_statement t] is the signed statement. *)
370370+313371 val receipts : t -> Receipt.t list
372372+ (** [receipts t] is the list of receipts. *)
314373315374 val verify :
316375 ts_key:X509.Public_key.t ->
···330389 across all receipts. *)
331390332391 val encode : t -> string
392392+ (** [encode t] serialises [t] to CBOR bytes. *)
393393+333394 val decode : string -> (t, error) result
395395+ (** [decode s] deserialises a transparent statement from CBOR bytes. *)
334396end
335397336398(** {1 Transparency Service} *)
···345407 corresponding public key from their trust store. *)
346408347409 val register : t -> Signed_statement.t -> (Receipt.t, error) result
410410+ (** [register t signed] appends [signed] to the log and returns a receipt. *)
411411+348412 val lookup : t -> key:string -> Signed_statement.t option
413413+ (** [lookup t ~key] retrieves the signed statement stored under [key]. *)
414414+349415 val root : t -> string
416416+ (** [root t] is the current Merkle tree root hash. *)
417417+350418 val size : t -> int
419419+ (** [size t] is the number of entries in the log. *)
420420+351421 val export : t -> string
422422+ (** [export t] serialises the underlying VDS state. *)
352423end
+167
ocaml-scitt/lib/vds.ml
···11+(* Verifiable Data Structures for SCITT. *)
22+33+let max_statement_size = 16 * 1024 * 1024 (* 16 MiB *)
44+let max_proof_path_length = 64 (* 2^64 leaves *)
55+66+type inclusion_proof = {
77+ leaf_index : int;
88+ tree_size : int;
99+ root : string;
1010+ path : string list;
1111+ leaf_hash : string;
1212+}
1313+1414+module type Backend = sig
1515+ type t
1616+1717+ val append :
1818+ t -> key:string -> value:string -> (inclusion_proof, string) result
1919+2020+ val lookup : t -> key:string -> string option
2121+ val root : t -> string
2222+ val size : t -> int
2323+ val algorithm_id : t -> int
2424+ val proof_format : Hash.proof_format
2525+ val export : t -> string
2626+end
2727+2828+(* Existential wrapper *)
2929+type t = V : (module Backend with type t = 'a) * 'a -> t
3030+3131+let of_backend (type a) (m : (module Backend with type t = a)) (s : a) = V (m, s)
3232+let append (V ((module B), s)) ~key ~value = B.append s ~key ~value
3333+let lookup (V ((module B), s)) ~key = B.lookup s ~key
3434+let root (V ((module B), s)) = B.root s
3535+let size (V ((module B), s)) = B.size s
3636+let export (V ((module B), s)) = B.export s
3737+let algorithm_id (V ((module B), s)) = B.algorithm_id s
3838+let proof_format (V ((module B), _)) = B.proof_format
3939+4040+(* -- RFC 9162 VDS -- *)
4141+4242+module Rfc9162_impl = struct
4343+ (** Growing array with O(1) amortized append (doubling strategy). *)
4444+ module Growable = struct
4545+ type t = { mutable data : string array; mutable len : int }
4646+4747+ let create cap = { data = Array.make (max cap 16) ""; len = 0 }
4848+ let length t = t.len
4949+5050+ let get t i =
5151+ if i < 0 || i >= t.len then invalid_arg "Growable.get: out of bounds";
5252+ t.data.(i)
5353+5454+ let push t v =
5555+ if t.len = Array.length t.data then begin
5656+ let new_cap = Array.length t.data * 2 in
5757+ let new_data = Array.make new_cap "" in
5858+ Array.blit t.data 0 new_data 0 t.len;
5959+ t.data <- new_data
6060+ end;
6161+ t.data.(t.len) <- v;
6262+ t.len <- t.len + 1
6363+ end
6464+6565+ type t = {
6666+ hash : Hash.t;
6767+ leaves : (string, string) Hashtbl.t;
6868+ mutable leaves_order : string list;
6969+ hashes : Growable.t;
7070+ }
7171+7272+ let algorithm_id t = Hash.id t.hash
7373+ let proof_format = Hash.Rfc9162
7474+7575+ let create ?(hash = Hash.sha256) () =
7676+ {
7777+ hash;
7878+ leaves = Hashtbl.create 256;
7979+ leaves_order = [];
8080+ hashes = Growable.create 256;
8181+ }
8282+8383+ let size t = Growable.length t.hashes
8484+8585+ let compute_root ~hash hashes off len =
8686+ let node_hash = Hash.node_hash_with hash in
8787+ let rec go off len =
8888+ if len = 0 then hash.Hash.digest ""
8989+ else if len = 1 then Growable.get hashes off
9090+ else
9191+ let split =
9292+ let rec p2 k = if k >= len then k / 2 else p2 (k * 2) in
9393+ p2 1
9494+ in
9595+ let left = go off split in
9696+ let right = go (off + split) (len - split) in
9797+ node_hash left right
9898+ in
9999+ go off len
100100+101101+ let root t =
102102+ let n = Growable.length t.hashes in
103103+ if n = 0 then t.hash.Hash.digest ""
104104+ else compute_root ~hash:t.hash t.hashes 0 n
105105+106106+ (** RFC 9162 §2.1.3.1: PATH(m, D_n). *)
107107+ let inclusion_path ~hash hashes off len idx =
108108+ let rec go off len idx acc =
109109+ if len <= 1 then acc
110110+ else
111111+ let split =
112112+ let rec p2 k = if k >= len then k / 2 else p2 (k * 2) in
113113+ p2 1
114114+ in
115115+ if idx < split then
116116+ let right_hash =
117117+ compute_root ~hash hashes (off + split) (len - split)
118118+ in
119119+ go off split idx (right_hash :: acc)
120120+ else
121121+ let left_hash = compute_root ~hash hashes off split in
122122+ go (off + split) (len - split) (idx - split) (left_hash :: acc)
123123+ in
124124+ go off len idx []
125125+126126+ let append t ~key ~value =
127127+ if Hashtbl.mem t.leaves key then Error ("duplicate key: " ^ key)
128128+ else
129129+ let leaf_h = Hash.leaf_hash_with t.hash value in
130130+ let idx = Growable.length t.hashes in
131131+ Hashtbl.replace t.leaves key value;
132132+ t.leaves_order <- key :: t.leaves_order;
133133+ Growable.push t.hashes leaf_h;
134134+ let n = Growable.length t.hashes in
135135+ let path = inclusion_path ~hash:t.hash t.hashes 0 n idx in
136136+ let root = compute_root ~hash:t.hash t.hashes 0 n in
137137+ Ok { leaf_index = idx; tree_size = n; root; path; leaf_hash = leaf_h }
138138+139139+ let lookup t ~key = Hashtbl.find_opt t.leaves key
140140+141141+ let export t =
142142+ let keys = List.rev t.leaves_order in
143143+ let entries =
144144+ Cbort.Cbor.array
145145+ (List.filter_map
146146+ (fun k ->
147147+ match Hashtbl.find_opt t.leaves k with
148148+ | Some v ->
149149+ Some
150150+ (Cbort.Cbor.array
151151+ [ Cbort.Cbor.string k; Cbort.Cbor.bytes v ])
152152+ | None -> None)
153153+ keys)
154154+ in
155155+ Cbort.encode_string Cbort.any
156156+ (Cbort.Cbor.map
157157+ [
158158+ (Cbort.Cbor.string "algorithm", Cbort.Cbor.int (algorithm_id t));
159159+ (Cbort.Cbor.string "entries", entries);
160160+ ])
161161+end
162162+163163+module Rfc9162 = struct
164164+ let v ?hash () =
165165+ let state = Rfc9162_impl.create ?hash () in
166166+ of_backend (module Rfc9162_impl) state
167167+end
+44
ocaml-scitt/lib/vds.mli
···11+(** Verifiable Data Structures for SCITT. *)
22+33+val max_statement_size : int
44+(** Maximum encoded statement size in bytes (16 MiB). *)
55+66+val max_proof_path_length : int
77+(** Maximum inclusion proof path entries (64). *)
88+99+type inclusion_proof = {
1010+ leaf_index : int;
1111+ tree_size : int;
1212+ root : string;
1313+ path : string list;
1414+ leaf_hash : string;
1515+}
1616+1717+module type Backend = sig
1818+ type t
1919+2020+ val append :
2121+ t -> key:string -> value:string -> (inclusion_proof, string) result
2222+2323+ val lookup : t -> key:string -> string option
2424+ val root : t -> string
2525+ val size : t -> int
2626+ val algorithm_id : t -> int
2727+ val proof_format : Hash.proof_format
2828+ val export : t -> string
2929+end
3030+3131+type t
3232+3333+val of_backend : (module Backend with type t = 'a) -> 'a -> t
3434+val append : t -> key:string -> value:string -> (inclusion_proof, string) result
3535+val lookup : t -> key:string -> string option
3636+val root : t -> string
3737+val size : t -> int
3838+val export : t -> string
3939+val algorithm_id : t -> int
4040+val proof_format : t -> Hash.proof_format
4141+4242+module Rfc9162 : sig
4343+ val v : ?hash:Hash.t -> unit -> t
4444+end
+2408
ocaml-scitt/spec/rfc9942.txt
···11+22+33+44+55+SCITT H. Birkholz
66+Internet-Draft Fraunhofer SIT
77+Intended status: Standards Track A. Delignat-Lavaud
88+Expires: 17 May 2025 C. Fournet
99+ Microsoft Research
1010+ Y. Deshpande
1111+ ARM
1212+ S. Lasker
1313+ DataTrails
1414+ 13 November 2024
1515+1616+1717+ An Architecture for Trustworthy and Transparent Digital Supply Chains
1818+ draft-ietf-scitt-architecture-10
1919+2020+Abstract
2121+2222+ Traceability of physical and digital Artifacts in supply chains is a
2323+ long-standing, but increasingly serious security concern. The rise
2424+ in popularity of verifiable data structures as a mechanism to make
2525+ actors more accountable for breaching their compliance promises has
2626+ found some successful applications to specific use cases (such as the
2727+ supply chain for digital certificates), but lacks a generic and
2828+ scalable architecture that can address a wider range of use cases.
2929+3030+ This document defines a generic, interoperable and scalable
3131+ architecture to enable transparency across any supply chain with
3232+ minimum adoption barriers. It provides flexibility, enabling
3333+ interoperability across different implementations of Transparency
3434+ Services with various auditing and compliance requirements. Issuers
3535+ can register their Signed Statements on any Transparency Service,
3636+ with the guarantee that any Relying Parties will be able to verify
3737+ them.
3838+3939+About This Document
4040+4141+ This note is to be removed before publishing as an RFC.
4242+4343+ Status information for this document may be found at
4444+ https://datatracker.ietf.org/doc/draft-ietf-scitt-architecture/.
4545+4646+ Discussion of this document takes place on the SCITT Working Group
4747+ mailing list (mailto:scitt@ietf.org), which is archived at
4848+ https://mailarchive.ietf.org/arch/browse/scitt/. Subscribe at
4949+ https://www.ietf.org/mailman/listinfo/scitt/.
5050+5151+ Source for this draft and an issue tracker can be found at
5252+ https://github.com/ietf-wg-scitt/draft-ietf-scitt-architecture.
5353+5454+5555+5656+Birkholz, et al. Expires 17 May 2025 [Page 1]
5757+5858+Internet-Draft SCITT Architecture November 2024
5959+6060+6161+Status of This Memo
6262+6363+ This Internet-Draft is submitted in full conformance with the
6464+ provisions of BCP 78 and BCP 79.
6565+6666+ Internet-Drafts are working documents of the Internet Engineering
6767+ Task Force (IETF). Note that other groups may also distribute
6868+ working documents as Internet-Drafts. The list of current Internet-
6969+ Drafts is at https://datatracker.ietf.org/drafts/current/.
7070+7171+ Internet-Drafts are draft documents valid for a maximum of six months
7272+ and may be updated, replaced, or obsoleted by other documents at any
7373+ time. It is inappropriate to use Internet-Drafts as reference
7474+ material or to cite them other than as "work in progress."
7575+7676+ This Internet-Draft will expire on 17 May 2025.
7777+7878+Copyright Notice
7979+8080+ Copyright (c) 2024 IETF Trust and the persons identified as the
8181+ document authors. All rights reserved.
8282+8383+ This document is subject to BCP 78 and the IETF Trust's Legal
8484+ Provisions Relating to IETF Documents (https://trustee.ietf.org/
8585+ license-info) in effect on the date of publication of this document.
8686+ Please review these documents carefully, as they describe your rights
8787+ and restrictions with respect to this document. Code Components
8888+ extracted from this document must include Revised BSD License text as
8989+ described in Section 4.e of the Trust Legal Provisions and are
9090+ provided without warranty as described in the Revised BSD License.
9191+9292+Table of Contents
9393+9494+ 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 3
9595+ 1.1. Requirements Notation . . . . . . . . . . . . . . . . . . 4
9696+ 2. Terminology . . . . . . . . . . . . . . . . . . . . . . . . . 4
9797+ 3. Definition of Transparency . . . . . . . . . . . . . . . . . 7
9898+ 4. Architecture Overview . . . . . . . . . . . . . . . . . . . . 9
9999+ 4.1. Transparency Service . . . . . . . . . . . . . . . . . . 12
100100+ 4.1.1. Registration Policies . . . . . . . . . . . . . . . . 12
101101+ 4.1.2. Initialization and Bootstrapping . . . . . . . . . . 13
102102+ 4.1.3. Append-only Log . . . . . . . . . . . . . . . . . . . 14
103103+ 4.1.4. Adjacent Services . . . . . . . . . . . . . . . . . . 14
104104+ 4.2. Signed Statements . . . . . . . . . . . . . . . . . . . . 15
105105+ 4.2.1. Signed Statement Examples . . . . . . . . . . . . . . 16
106106+ 4.3. Registration . . . . . . . . . . . . . . . . . . . . . . 18
107107+ 4.4. Transparent Statements . . . . . . . . . . . . . . . . . 19
108108+ 4.4.1. Validation . . . . . . . . . . . . . . . . . . . . . 22
109109+110110+111111+112112+Birkholz, et al. Expires 17 May 2025 [Page 2]
113113+114114+Internet-Draft SCITT Architecture November 2024
115115+116116+117117+ 5. Privacy Considerations . . . . . . . . . . . . . . . . . . . 23
118118+ 6. Security Considerations . . . . . . . . . . . . . . . . . . . 23
119119+ 6.1. Security Guarantees . . . . . . . . . . . . . . . . . . . 25
120120+ 6.2. Threat Model . . . . . . . . . . . . . . . . . . . . . . 25
121121+ 6.2.1. Append-only Log . . . . . . . . . . . . . . . . . . . 26
122122+ 6.2.2. Availability of Receipts . . . . . . . . . . . . . . 27
123123+ 6.2.3. Confidentiality and Privacy . . . . . . . . . . . . . 27
124124+ 6.2.4. Cryptographic Agility . . . . . . . . . . . . . . . . 28
125125+ 6.2.5. Transparency Service Client Applications . . . . . . 28
126126+ 6.2.6. Impersonation . . . . . . . . . . . . . . . . . . . . 28
127127+ 7. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 29
128128+ 7.1. Media Type Registration . . . . . . . . . . . . . . . . . 29
129129+ 8. References . . . . . . . . . . . . . . . . . . . . . . . . . 29
130130+ 8.1. Normative References . . . . . . . . . . . . . . . . . . 29
131131+ 8.2. Informative References . . . . . . . . . . . . . . . . . 30
132132+ Appendix A. Common Terminology Disambiguation . . . . . . . . . 33
133133+ Appendix B. Identifiers . . . . . . . . . . . . . . . . . . . . 35
134134+ B.1. Identifiers For Binary Content . . . . . . . . . . . . . 36
135135+ B.2. Identifiers For SCITT Messages . . . . . . . . . . . . . 37
136136+ B.3. Identifiers For Transparent Statements . . . . . . . . . 37
137137+ B.4. Statements . . . . . . . . . . . . . . . . . . . . . . . 38
138138+ B.4.1. Statement URN . . . . . . . . . . . . . . . . . . . . 38
139139+ B.4.2. Statement URL . . . . . . . . . . . . . . . . . . . . 38
140140+ B.4.3. Statement Data URL . . . . . . . . . . . . . . . . . 38
141141+ B.5. Signed Statements . . . . . . . . . . . . . . . . . . . . 38
142142+ B.5.1. Signed Statement URN . . . . . . . . . . . . . . . . 38
143143+ B.5.2. Signed Statement URL . . . . . . . . . . . . . . . . 38
144144+ B.5.3. Signed Statement Data URL . . . . . . . . . . . . . . 38
145145+ B.6. Receipts . . . . . . . . . . . . . . . . . . . . . . . . 39
146146+ B.6.1. Receipt URN . . . . . . . . . . . . . . . . . . . . . 39
147147+ B.6.2. Receipt URL . . . . . . . . . . . . . . . . . . . . . 39
148148+ B.6.3. Receipt Data URL . . . . . . . . . . . . . . . . . . 39
149149+ B.7. Transparent Statements . . . . . . . . . . . . . . . . . 39
150150+ B.7.1. Transparent Statement URN . . . . . . . . . . . . . . 39
151151+ B.7.2. Transparent Statement URL . . . . . . . . . . . . . . 39
152152+ B.7.3. Transparent Statement Data URL . . . . . . . . . . . 39
153153+ Appendix C. Signing Statements Remotely . . . . . . . . . . . . 40
154154+ Contributors . . . . . . . . . . . . . . . . . . . . . . . . . . 41
155155+ Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . 42
156156+157157+1. Introduction
158158+159159+ This document describes the generic, interoperable, and scalable
160160+ SCITT architecture. Its goal is to enhance auditability and
161161+ accountability across supply chains.
162162+163163+164164+165165+166166+167167+168168+Birkholz, et al. Expires 17 May 2025 [Page 3]
169169+170170+Internet-Draft SCITT Architecture November 2024
171171+172172+173173+ In supply chains, downstream Artifacts are built upon upstream
174174+ Artifacts. The complexity of traceability and quality control for
175175+ these supply chains increases with the number of Artifacts and
176176+ parties contributing to them. There are many parties who publish
177177+ information about Artifacts: For example, the original manufacturer
178178+ may provide information about the state of the Artifact when it left
179179+ the factory. The shipping company may add information about the
180180+ transport environment of the Artifact. Compliance Auditors may
181181+ provide information about their compliance assessment of the
182182+ Artifact. Security companies may publish vulnerability information
183183+ about an Artifact. Some of these parties may publish information
184184+ about their analysis or use of an Artifact.
185185+186186+ SCITT provides a way for Relying Parties to obtain this information
187187+ in a way that is "transparent", that is, parties cannot lie about the
188188+ information that they publish without it being detected. SCITT
189189+ achieves this by having producers publish information in a
190190+ Transparency Service, where Relying Parties can check the
191191+ information.
192192+193193+1.1. Requirements Notation
194194+195195+ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
196196+ "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and
197197+ "OPTIONAL" in this document are to be interpreted as described in
198198+ BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all
199199+ capitals, as shown here.
200200+201201+2. Terminology
202202+203203+ The terms defined in this section have special meaning in the context
204204+ of Supply Chain Integrity, Transparency, and Trust, which are used
205205+ throughout this document. When used in text, the corresponding terms
206206+ are capitalized. To ensure readability, only a core set of terms is
207207+ included in this section.
208208+209209+ The terms "header", "payload", and "to-be-signed bytes" are defined
210210+ in [RFC9052].
211211+212212+ The term "claim" is defined in [RFC8392].
213213+214214+ Append-only Log (Ledger): the verifiable append-only data structure
215215+ that stores Signed Statements in a Transparency Service, often
216216+ referred to by the synonym Ledger. SCITT supports multiple Ledger
217217+ and Receipt formats to accommodate different Transparency Service
218218+ implementations, and the proof types associated with different
219219+ types of Append-only Logs.
220220+221221+222222+223223+224224+Birkholz, et al. Expires 17 May 2025 [Page 4]
225225+226226+Internet-Draft SCITT Architecture November 2024
227227+228228+229229+ Artifact: a physical or non-physical item that is moving along a
230230+ supply chain.
231231+232232+ Auditor: an entity that checks the correctness and consistency of
233233+ all Transparent Statements issued by a Transparency Service. An
234234+ Auditor is an example of a specialized Relying Party.
235235+236236+ Client: an application making protected Transparency Service
237237+ resource requests on behalf of the resource owner and with its
238238+ authorization.
239239+240240+ Envelope: metadata, created by the Issuer to produce a Signed
241241+ Statement. The Envelope contains the identity of the Issuer and
242242+ information about the Artifact, enabling Transparency Service
243243+ Registration Policies to validate the Signed Statement. A Signed
244244+ Statement is a COSE Envelope wrapped around a Statement, binding
245245+ the metadata in the Envelope to the Statement. In COSE, an
246246+ Envelope consists of a protected header (included in the Issuer's
247247+ signature) and an unprotected header (not included in the Issuer's
248248+ signature).
249249+250250+ Equivocation: a state where it is possible for a Transparency
251251+ Service to provide different views of its Append-only log to
252252+ Relying Parties about the same Artifact [EQUIVOCATION].
253253+254254+ Issuer: an identifier representing an organization, device, user, or
255255+ entity securing Statements about supply chain Artifacts. An
256256+ Issuer may be the owner or author of Artifacts, or an independent
257257+ third party such as an Auditor, reviewer or an endorser. In SCITT
258258+ Statements and Receipts, the iss CWT Claim is a member of the COSE
259259+ header parameter 15: CWT_Claims within the protected header of a
260260+ COSE Envelope.
261261+262262+ Non-equivocation: a state where it is impossible for a Transparency
263263+ Service to provide different views of its Append-only Log to
264264+ Relying Parties about the same Artifact. Over time, an Issuer may
265265+ register new Signed Statements about an Artifact in a Transparency
266266+ Service with new information. However, the consistency of a
267267+ collection of Signed Statements about the Artifact can be checked
268268+ by all Relying Parties.
269269+270270+ Receipt: a cryptographic proof that a Signed Statement is included
271271+ in the Append-only Log. Receipts are signed proofs of verifiable
272272+ data-structure properties. The types of Receipts MUST support
273273+ inclusion proofs and MAY support other proof types, such as
274274+ consistency proofs.
275275+276276+ Registration: the process of submitting a Signed Statement to a
277277+278278+279279+280280+Birkholz, et al. Expires 17 May 2025 [Page 5]
281281+282282+Internet-Draft SCITT Architecture November 2024
283283+284284+285285+ Transparency Service, applying the Transparency Service's
286286+ Registration Policy, adding to the Append-only Log, and producing
287287+ a Receipt.
288288+289289+ Registration Policy: the pre-condition enforced by the Transparency
290290+ Service before registering a Signed Statement, based on
291291+ information in the non-opaque header and metadata contained in its
292292+ COSE Envelope.
293293+294294+ Relying Party: a Relying Parties consumes Transparent Statements,
295295+ verifying their proofs and inspecting the Statement payload,
296296+ either before using corresponding Artifacts, or later to audit an
297297+ Artifact's provenance on the supply chain.
298298+299299+ Signed Statement: an identifiable and non-repudiable Statement about
300300+ an Artifact signed by an Issuer. In SCITT, Signed Statements are
301301+ encoded as COSE signed objects; the payload of the COSE structure
302302+ contains the issued Statement.
303303+304304+ Statement: any serializable information about an Artifact. To help
305305+ interpretation of Statements, they must be tagged with a media
306306+ type (as specified in [RFC6838]). A Statement may represent a
307307+ Software Bill Of Materials (SBOM) that lists the ingredients of a
308308+ software Artifact, an endorsement or attestation about an
309309+ Artifact, indicate the End of Life (EOL), redirection to a newer
310310+ version, or any content an Issuer wishes to publish about an
311311+ Artifact. The additional Statements about an Artifact are
312312+ correlated by the Subject defined in the [CWT_CLAIMS] protected
313313+ header. The Statement is considered opaque to Transparency
314314+ Service, and MAY be encrypted.
315315+316316+ Subject: an identifier, defined by the Issuer, that represents the
317317+ organization, device, user, entity, or Artifact about which
318318+ Statements (and Receipts) are made and by which a logical
319319+ collection of Statements can be grouped. It is possible that
320320+ there are multiple Statements about the same Artifact. In these
321321+ cases, distinct Issuers (iss) might agree to use the sub CWT Claim
322322+ to create a coherent sequence of Signed Statements about the same
323323+ Artifact and Relying Parties can leverage sub to ensure
324324+ completeness and Non-equivocation across Statements by identifying
325325+ all Transparent Statements associated to a specific Subject.
326326+327327+ Transparency Service: an entity that maintains and extends the
328328+329329+330330+331331+332332+333333+334334+335335+336336+Birkholz, et al. Expires 17 May 2025 [Page 6]
337337+338338+Internet-Draft SCITT Architecture November 2024
339339+340340+341341+ Append-only Log, and endorses its state. A Transparency Service
342342+ can be a complex system, requiring the Transparency Service to
343343+ provide many security guarantees about its Append-only Log. The
344344+ identity of a Transparency Service is captured by a public key
345345+ that must be known by Relying Parties in order to validate
346346+ Receipts.
347347+348348+ Transparent Statement: a Signed Statement that is augmented with a
349349+ Receipt created via Registration in a Transparency Service. The
350350+ Receipt is stored in the unprotected header of COSE Envelope of
351351+ the Signed Statement. A Transparent Statement remains a valid
352352+ Signed Statement, and may be registered again in a different
353353+ Transparency Service.
354354+355355+ Verifiable Data Structure: a data structure which supports one or
356356+ more proof types, such as "inclusion proofs" or "consistency
357357+ proofs" (as defined in [I-D.draft-ietf-cose-merkle-tree-proofs]).
358358+359359+3. Definition of Transparency
360360+361361+ In this document, the definition of transparency is intended to build
362362+ over abstract notions of Append-only Logs and Receipts. Existing
363363+ transparency systems such as Certificate Transparency are instances
364364+ of this definition.
365365+366366+ A Signed Statement is an identifiable and non-repudiable Statement
367367+ made by an Issuer. The Issuer selects additional metadata and
368368+ attaches a proof of endorsement (in most cases, a signature) using
369369+ the identity key of the Issuer that binds the Statement and its
370370+ metadata. Signed Statements can be made transparent by attaching a
371371+ proof of Registration by a Transparency Service, in the form of a
372372+ Receipt. Receipts demonstrate inclusion of Signed Statements in the
373373+ Append-only Log of a Transparency Service. By extension, the Signed
374374+ Statement may say an Artifact (for example, a firmware binary) is
375375+ transparent if it comes with one or more Transparent Statements from
376376+ its author or owner, though the context should make it clear what
377377+ type of Signed Statements is expected for a given Artifact.
378378+379379+ Transparency does not prevent dishonest or compromised Issuers, but
380380+ it holds them accountable. Any Artifact that may be verified, is
381381+ subject to scrutiny and auditing by other parties. The Transparency
382382+ Service provides a history of Statements, which may be made by
383383+ multiple Issuers, enabling Relying Parties to make informed
384384+ decisions.
385385+386386+ Transparency is implemented by providing a consistent, append-only,
387387+ cryptographically verifiable, publicly available record of entries.
388388+ A SCITT instance is referred to as a Transparency Service.
389389+390390+391391+392392+Birkholz, et al. Expires 17 May 2025 [Page 7]
393393+394394+Internet-Draft SCITT Architecture November 2024
395395+396396+397397+ Implementations of Transparency Services may protect their Append-
398398+ only Log using a combination of trusted hardware, replication and
399399+ consensus protocols, and cryptographic evidence. A Receipt is an
400400+ offline, universally-verifiable proof that an entry is registered in
401401+ the Append-only Log. Requesting a receipt can result in the
402402+ production of a new receipt for the same signed statement. A
403403+ Receipt's verification key, signing algorithm, validity period,
404404+ header parameters or other claims MAY change each time a Receipt is
405405+ produced.
406406+407407+ Anyone with access to the Transparency Service can independently
408408+ verify its consistency and review the complete list of Transparent
409409+ Statements registered by each Issuer. However, the Registrations on
410410+ a separate Transparency Service is generally disjoint, though it is
411411+ possible to take a Transparent Statement (i.e. a Signed Statement
412412+ with a Receipt in its unprotected header, from a from the first
413413+ Transparency Service) and register it on another Transparency
414414+ Service, where the second Receipt will be over the first Receipt in
415415+ the unprotected header.
416416+417417+ Reputable Issuers are thus incentivized to carefully review their
418418+ Statements before signing them to produce Signed Statements.
419419+ Similarly, reputable Transparency Services are incentivized to secure
420420+ their Append-only Log, as any inconsistency can easily be pinpointed
421421+ by any Auditor with read access to the Transparency Service.
422422+423423+ The building blocks defined in SCITT are intended to support
424424+ applications in any supply chain that produces or relies upon digital
425425+ Artifacts, from the build and supply of software and IoT devices to
426426+ advanced manufacturing and food supply.
427427+428428+ SCITT is a generalization of Certificate Transparency (CT) [RFC9162],
429429+ which can be interpreted as a transparency architecture for the
430430+ supply chain of X.509 certificates. Considering CT in terms of
431431+ SCITT:
432432+433433+ * CAs (Issuers) sign the ASN.1 DER encoded tbsCertificate structure
434434+ to produce an X.509 certificate (Signed Statements)
435435+436436+ * CAs submit the certificates to one or more CT logs (Transparency
437437+ Services)
438438+439439+ * CT logs produce Signed Certificate Timestamps (Transparent
440440+ Statements)
441441+442442+ * Signed Certificate Timestamps, Signed Tree Heads, and their
443443+ respective consistency proofs are checked by Relying Parties
444444+445445+446446+447447+448448+Birkholz, et al. Expires 17 May 2025 [Page 8]
449449+450450+Internet-Draft SCITT Architecture November 2024
451451+452452+453453+ * The Append-only Log can be checked by Auditors
454454+455455+4. Architecture Overview
456456+457457+ The SCITT architecture consists of a very loose federation of
458458+ Transparency Services, and a set of common formats and protocols for
459459+ issuing and registering Signed Statements, and auditing Transparent
460460+ Statements.
461461+462462+ In order to accommodate as many Transparency Service implementations
463463+ as possible, this document only specifies the format of Signed
464464+ Statements (which must be used by all Issuers) and a very thin
465465+ wrapper format for Receipts, which specifies the Transparency Service
466466+ identity and the agility parameters for the Signed Inclusion Proofs.
467467+ Most of the details of the Receipt's contents are specified in the
468468+ COSE Signed Merkle Tree Proof document
469469+ [I-D.draft-ietf-cose-merkle-tree-proofs].
470470+471471+ Figure 1 illustrates the roles and processes that comprise a
472472+ Transparency Service independent of any one use case.
473473+474474+ This section describes the three main roles and associated processes
475475+ in SCITT:
476476+477477+ * Issuers that use their credentials to create Signed Statements
478478+ about Artifacts
479479+480480+ * Transparency Services that evaluate Signed Statements against
481481+ Registration Policies, producing Receipts upon successful
482482+ Registration. The returned Receipt may be combined with the
483483+ Signed Statement to create a Transparent Statement.
484484+485485+ * Relying Parties that:
486486+487487+ - collect Receipts of Signed Statements for subsequent
488488+ registration of Transparent Statements;
489489+490490+ - retrieve Transparent Statements for analysis of Statements
491491+ about Artifacts themselves (e.g. verification);
492492+493493+ - or replay all the Transparent Statements to check for the
494494+ consistency of the Transparency Service's Append-only Log (e.g.
495495+ auditing)
496496+497497+498498+499499+500500+501501+502502+503503+504504+Birkholz, et al. Expires 17 May 2025 [Page 9]
505505+506506+Internet-Draft SCITT Architecture November 2024
507507+508508+509509+ In addition, Figure 1 illustrates multiple Transparency Services and
510510+ multiple Receipts as a single Signed Statement MAY be registered with
511511+ one or more Transparency Service. Each Transparency Service produces
512512+ a Receipt, which may be aggregated in a single Transparent Statement,
513513+ demonstrating the Signed Statement was registered by multiple
514514+ Transparency Services.
515515+516516+ The arrows indicate the flow of information.
517517+518518+519519+520520+521521+522522+523523+524524+525525+526526+527527+528528+529529+530530+531531+532532+533533+534534+535535+536536+537537+538538+539539+540540+541541+542542+543543+544544+545545+546546+547547+548548+549549+550550+551551+552552+553553+554554+555555+556556+557557+558558+559559+560560+Birkholz, et al. Expires 17 May 2025 [Page 10]
561561+562562+Internet-Draft SCITT Architecture November 2024
563563+564564+565565+ +------------+
566566+ .----------. | Issuer |
567567+ | Artifact | +-+--------+-+
568568+ '----+-----' v v
569569+ v .--------+-. .-+--------.
570570+ .----+----. / sign / / verify /
571571+ | Statement | '-----+----+ '------+---+
572572+ '----+----' | |
573573+ | .--------' '--. |
574574+ | | | |
575575+ v v | .-' '-.
576576+ .----+---+---. | | |
577577+ | Signed | | | |
578578+ | Statement | | | |
579579+ '------+-----' v v |
580580+ | +---+-------+---+ |
581581+ .--' '----------->+ Transparency | |
582582+ | .--------. | | |
583583+ | | Receipt +<---+ Service +-+ |
584584+ | | +. +--+------------+ | |
585585+ | '-+------' | | Transparency | |
586586+ | | Receipt +<----+ | |
587587+ | '------+' | Service | |
588588+ '-------. .-' +------------+-+ |
589589+ | | |
590590+ v | |
591591+ .-----+-----. | |
592592+ | Transparent | | |
593593+ | Statement | | |
594594+ '--+--------' | |
595595+ | | |
596596+ |'-----------. .----------)--'
597597+ | | | |
598598+ | v v |
599599+ | .--------+-+---------. |
600600+ | / Verify Transparent / |
601601+ | / Statement / |
602602+ | '----+---------------+ |
603603+ | | Relying Party | |
604604+ | +---------------+ |
605605+ v v
606606+ .-------+-------------. .----------+------.
607607+ / Collecting Receipts / / Replay Log /
608608+ '-----+---------------+ '-+---------------+
609609+ | Relying Party | | Relying Party |
610610+ +---------------+ +---------------+
611611+612612+ Figure 1: Relationship of Concepts in SCITT
613613+614614+615615+616616+Birkholz, et al. Expires 17 May 2025 [Page 11]
617617+618618+Internet-Draft SCITT Architecture November 2024
619619+620620+621621+ The subsequent sections describe the main concepts, namely
622622+ Transparency Service, Signed Statements, Registration, and
623623+ Transparent Statements in more detail.
624624+625625+4.1. Transparency Service
626626+627627+ Transparency Services MUST feature an Append-only Log. The Append-
628628+ only Log is the verifiable data structure that records registered
629629+ Signed Statements and supports the production of Receipts.
630630+631631+ All Transparency Services MUST expose APIs for the Registration of
632632+ Signed Statements and issuance of Receipts.
633633+634634+ Transparency Services MAY support additional APIs for auditing, for
635635+ instance, to query the history of Signed Statements.
636636+637637+ Typically a Transparency Service has a single Issuer identity which
638638+ is present in the iss Claim of Receipts for that service.
639639+640640+ Multi-tenant support can be enabled through the use of identifiers in
641641+ the iss Claim, for example, ts.example may have a distinct Issuer
642642+ identity for each sub domain, such as customer1.ts.example and
643643+ customer2.ts.example.
644644+645645+4.1.1. Registration Policies
646646+647647+ Registration Policies refer to additional checks over and above the
648648+ Mandatory Registration Checks that are performed before a Signed
649649+ Statement is accepted to be registered to the Append-only Log.
650650+651651+ Transparency Services MUST maintain Registration Policies.
652652+ Transparency Services MUST maintain a list of trust anchors (see
653653+ definition of trust anchor in [RFC4949]). Transparency Services MUST
654654+ authenticate signed statements as part of a Registration Policy. For
655655+ instance, a trust anchor could be an X.509 root certificate, a
656656+ pointer to an OpenID Connect identity provider, or any other COSE-
657657+ compatible trust anchor.
658658+659659+ Registration Policies and trust anchors MUST be made transparent and
660660+ available to all Relying Parties of the Transparency Service by
661661+ registering them as Signed Statements on the Append-only Log, and
662662+ distributing the associated Receipts.
663663+664664+ This specification leaves implementation, encoding and documentation
665665+ of Registration Policies and trust anchors to the operator of the
666666+ Transparency Service.
667667+668668+669669+670670+671671+672672+Birkholz, et al. Expires 17 May 2025 [Page 12]
673673+674674+Internet-Draft SCITT Architecture November 2024
675675+676676+677677+4.1.1.1. Mandatory Registration Checks
678678+679679+ During Registration, a Transparency Service MUST, at a minimum,
680680+ syntactically check the Issuer of the Signed Statement by
681681+ cryptographically verifying the COSE signature according to
682682+ [RFC9052]. The Issuer identity MUST be bound to the Signed Statement
683683+ by including an identifier in the protected header. If the protected
684684+ header includes multiple identifiers, all those that are registered
685685+ by the Transparency Service MUST be checked.
686686+687687+ In essence, when using X.509 Signed Statements, the Transparency
688688+ Service MUST build and validate a complete certification path from an
689689+ Issuer's certificate to one of the root certificates most recently
690690+ registered as a trust anchor by the Transparency Service.
691691+692692+ The protected header of the COSE_Sign1 Envelope MUST include either
693693+ the Issuer's certificate as x5t or the chain including the Issuer's
694694+ certificate as x5chain. If x5t is included in the protected header,
695695+ an x5chain with a leaf certificate corresponding to the x5t value MAY
696696+ be included in the unprotected header.
697697+698698+ The Transparency Service MUST apply the Registration Policy that was
699699+ most recently added to the Append-only Log at the time of
700700+ Registration.
701701+702702+4.1.1.2. Auditability of Registration
703703+704704+ The operator of a Transparency Service MAY update the Registration
705705+ Policy or the trust anchors of a Transparency Service at any time.
706706+707707+ Transparency Services MUST ensure that for any Signed Statement they
708708+ register, enough information is made available to Auditors (either in
709709+ the Append-only Log and retrievable through audit APIs, or included
710710+ in the Receipt) to reproduce the Registration checks that were
711711+ defined by the Registration Policies at the time of Registration.
712712+713713+4.1.2. Initialization and Bootstrapping
714714+715715+ Since the mandatory Registration checks rely on having registered
716716+ Signed Statements for the Registration Policy and trust anchors,
717717+ Transparency Services MUST support at least one of the three
718718+ following bootstrapping mechanisms:
719719+720720+ * Pre-configured Registration Policy and trust anchors;
721721+722722+ * Acceptance of a first Signed Statement whose payload is a valid
723723+ Registration Policy, without performing Registration checks
724724+725725+726726+727727+728728+Birkholz, et al. Expires 17 May 2025 [Page 13]
729729+730730+Internet-Draft SCITT Architecture November 2024
731731+732732+733733+ * An out-of-band authenticated management interface
734734+735735+4.1.3. Append-only Log
736736+737737+ The security properties of the Append-only Log are determined by the
738738+ choice of the verifiable data structure used by the Transparency
739739+ Service to implement the Log. This verifiable data structure MUST
740740+ support the following security requirements:
741741+742742+ Append-Only: once included in the verifiable data structure, a
743743+ Signed Statement cannot be modified, deleted, or reordered; hence
744744+ its Receipt provides an offline verifiable proof of Registration.
745745+746746+ Non-equivocation: there is no fork in the Append-only Log. Everyone
747747+ with access to its content sees the same collection of Signed
748748+ Statements and can check that it is consistent with any Receipts
749749+ they have verified.
750750+751751+ Replayability: the Append-only Log includes sufficient information
752752+ to enable authorized actors with access to its content to check
753753+ that each included Signed Statement has been correctly registered.
754754+755755+ In addition to Receipts, some verifiable data structures might
756756+ support additional proof types, such as proofs of consistency, or
757757+ proofs of non inclusion.
758758+759759+ Specific verifiable data structures, such those describes in
760760+ [RFC9162] and [I-D.draft-ietf-cose-merkle-tree-proofs], and the
761761+ review of their security requirements for SCITT are out of scope for
762762+ this document.
763763+764764+4.1.4. Adjacent Services
765765+766766+ Transparency Services can be deployed along side other database or
767767+ object storage technologies. For example, a Transparency Service
768768+ that is supporting a software package management system, might be
769769+ referenced from the APIs exposed for package management. Providing
770770+ an ability to request a fresh Receipt for a given software package,
771771+ or to request a list of Signed Statements associated with the
772772+ software package.
773773+774774+775775+776776+777777+778778+779779+780780+781781+782782+783783+784784+Birkholz, et al. Expires 17 May 2025 [Page 14]
785785+786786+Internet-Draft SCITT Architecture November 2024
787787+788788+789789+4.2. Signed Statements
790790+791791+ This specification prioritizes conformance to [RFC9052] and its
792792+ required and optional properties. Profiles and implementation
793793+ specific choices should be used to determine admissability of
794794+ conforming messages. This specification is left intentionally open
795795+ to allow implementations to make the restrictions that make the most
796796+ sense for their operational use cases.
797797+798798+ There are many types of Statements (such as SBOMs, malware scans,
799799+ audit reports, policy definitions) that Issuers may want to turn into
800800+ Signed Statements. An Issuer must first decide on a suitable format
801801+ (3: payload type) to serialize the Statement payload. For a software
802802+ supply chain, payloads describing the software Artifacts may include:
803803+804804+ * [COSWID]
805805+806806+ * [CycloneDX]
807807+808808+ * [in-toto]
809809+810810+ * [SPDX-CBOR]
811811+812812+ * [SPDX-JSON]
813813+814814+ * [SLSA]
815815+816816+ * [SWID]
817817+818818+ Once all the Envelope headers are set, an Issuer MUST use a standard
819819+ COSE implementation to produce an appropriately serialized Signed
820820+ Statement. The SCITT tag COSE_Sign1_Tagged is outside the scope of
821821+ COSE, and used to indicate that a signed object is a Signed
822822+ Statement.
823823+824824+ Issuers can produce Signed Statements about different Artifacts under
825825+ the same Identity. Issuers and Relying Parties must be able to
826826+ recognize the Artifact to which the Statements pertain by looking at
827827+ the Signed Statement. The iss and sub Claims, within the CWT_Claims
828828+ protected header, are used to identify the Artifact the Statement
829829+ pertains to. (See Subject under Section 2 Terminology.)
830830+831831+ Issuers MAY use different signing keys (identified by kid in the
832832+ protected header) for different Artifacts, or sign all Signed
833833+ Statements under the same key.
834834+835835+836836+837837+838838+839839+840840+Birkholz, et al. Expires 17 May 2025 [Page 15]
841841+842842+Internet-Draft SCITT Architecture November 2024
843843+844844+845845+ An Issuer can make multiple Statements about the same Artifact. For
846846+ example, an Issuer can make amended Statements about the same
847847+ Artifact as their view changes over time.
848848+849849+ Multiple Issuers can make different, even conflicting Statements,
850850+ about the same Artifact. Relying Parties can choose which Issuers
851851+ they trust.
852852+853853+ Multiple Issuers can make the same Statement about a single Artifact,
854854+ affirming multiple Issuers agree.
855855+856856+ At least one identifier representing one credential MUST be included
857857+ in the protected header of the COSE Envelope, as one of x5t, x5chain
858858+ or kid. Additionally, x5chain that corresponds to either x5t or kid
859859+ identifying the leaf certificate in the included certification path
860860+ MAY be included in the unprotected header of the COSE Envelope.
861861+862862+ * When using x.509 certificates, support for either x5t or x5chain
863863+ in the protected header is REQUIRED to implement.
864864+865865+ * Support for kid in the protected header and x5chain in the
866866+ unprotected header is OPTIONAL to implement.
867867+868868+ When x5t or x5chain is present in the protected header, iss MUST be a
869869+ string that meets URI requirements defined in [RFC8392]. The iss
870870+ value's length MUST be between 1 and 8192 characters in length.
871871+872872+ The kid header parameter MUST be present when neither x5t nor x5chain
873873+ is present in the protected header. Key discovery protocols are out-
874874+ of-scope of this document.
875875+876876+ The protected header of a Signed Statement and a Receipt MUST include
877877+ the CWT Claims header parameter as specified in Section 2 of
878878+ [CWT_CLAIMS_COSE]. The CWT Claims value MUST include the Issuer
879879+ Claim (Claim label 1) and the Subject Claim (Claim label 2)
880880+ [IANA.cwt].
881881+882882+ A Receipt is a Signed Statement, (cose-sign1), with addition Claims
883883+ in its protected header related to verifying the inclusion proof in
884884+ its unprotected header. See
885885+ [I-D.draft-ietf-cose-merkle-tree-proofs].
886886+887887+4.2.1. Signed Statement Examples
888888+889889+ Figure 2 illustrates a normative CDDL definition (see [RFC8610]) for
890890+ of the protected header and unprotected header of Signed Statements
891891+ and Receipts.
892892+893893+894894+895895+896896+Birkholz, et al. Expires 17 May 2025 [Page 16]
897897+898898+Internet-Draft SCITT Architecture November 2024
899899+900900+901901+ This definition specifies the minimal mandatory labels.
902902+ Implementation-specific Registration Policies may define additional
903903+ mandatory labels. A Transparency Service implementation MUST reject
904904+ registering Signed Statements that do not meet their current
905905+ Registration Policy requirements. Each implementation SHOULD provide
906906+ details for their registration policies through documentation or
907907+ discovery APIs.
908908+909909+ Signed_Statement = #6.18(COSE_Sign1)
910910+ Receipt = #6.18(COSE_Sign1)
911911+912912+ COSE_Sign1 = [
913913+ protected : bstr .cbor Protected_Header,
914914+ unprotected : Unprotected_Header,
915915+ payload : bstr / nil,
916916+ signature : bstr
917917+ ]
918918+919919+ Protected_Header = {
920920+ &(CWT_Claims: 15) => CWT_Claims
921921+ ? &(alg: 1) => int
922922+ ? &(content_type: 3) => tstr / uint
923923+ ? &(kid: 4) => bstr
924924+ ? &(x5t: 34) => COSE_CertHash
925925+ * int => any
926926+ }
927927+928928+ CWT_Claims = {
929929+ &(iss: 1) => tstr
930930+ &(sub: 2) => tstr
931931+ * int => any
932932+ }
933933+934934+ Unprotected_Header = {
935935+ ? &(x5chain: 33) => COSE_X509
936936+ ? &(receipts: 394) => [+ Receipt]
937937+ * int => any
938938+ }
939939+940940+ Figure 2: CDDL definition for Signed Statements and Receipts
941941+942942+ Figure 3 illustrates an instance of a Signed Statement in Extended
943943+ Diagnostic Notation (EDN), with a payload that is detached. Detached
944944+ payloads support large Statements, and ensure Signed Statements can
945945+ integrate with existing storage systems.
946946+947947+948948+949949+950950+951951+952952+Birkholz, et al. Expires 17 May 2025 [Page 17]
953953+954954+Internet-Draft SCITT Architecture November 2024
955955+956956+957957+ 18( / COSE Sign 1 /
958958+ [
959959+ h'a4012603...6d706c65', / Protected /
960960+ {}, / Unprotected /
961961+ nil, / Detached payload /
962962+ h'79ada558...3a28bae4' / Signature /
963963+ ]
964964+ )
965965+966966+ Figure 3: CBOR Extended Diagnostic Notation example of a Signed
967967+ Statement
968968+969969+ Figure 4 illustrates the decoded protected header of the Signed
970970+ Statement in Figure 3. It indicates the Signed Statement is securing
971971+ a JSON content type, and identifying the content with the sub Claim
972972+ "vendor.product.example".
973973+974974+ { / Protected /
975975+ 1: -7, / Algorithm /
976976+ 3: application/example+json, / Content type /
977977+ 4: h'50685f55...50523255', / Key identifier /
978978+ 15: { / CWT Claims /
979979+ 1: software.vendor.example, / Issuer /
980980+ 2: vendor.product.example, / Subject /
981981+ }
982982+ }
983983+984984+ Figure 4: CBOR Extended Diagnostic Notation example of a Signed
985985+ Statement's Protected Header
986986+987987+4.3. Registration
988988+989989+ To register a Signed Statement, the Transparency Service performs the
990990+ following steps:
991991+992992+ 1. *Client authentication:* A Client authenticates with the
993993+ Transparency Service before registering Signed Statements on
994994+ behalf of one or more Issuers. Authentication and authorization
995995+ are implementation-specific and out of scope of the SCITT
996996+ architecture.
997997+998998+999999+10001000+10011001+10021002+10031003+10041004+10051005+10061006+10071007+10081008+Birkholz, et al. Expires 17 May 2025 [Page 18]
10091009+10101010+Internet-Draft SCITT Architecture November 2024
10111011+10121012+10131013+ 2. *TS Signed Statement Verification and Validation:* The
10141014+ Transparency Service MUST perform signature verification per
10151015+ Section 4.4 of [RFC9052] and MUST verify the signature of the
10161016+ Signed Statement with the signature algorithm and verification
10171017+ key of the Issuer per [RFC9360]. The Transparency Service MUST
10181018+ also check the Signed Statement includes the required protected
10191019+ headers. The Transparency Service MAY validate the Signed
10201020+ Statement payload in order to enforce domain specific
10211021+ registration policies that apply to specific content types.
10221022+10231023+ 3. *Apply Registration Policy:* The Transparency Service MUST check
10241024+ the attributes required by a Registration Policy are present in
10251025+ the protected headers. Custom Signed Statements are evaluated
10261026+ given the current Transparency Service state and the entire
10271027+ Envelope, and may use information contained in the attributes of
10281028+ named policies.
10291029+10301030+ 4. *Register the Signed Statement* to the Append-only Log.
10311031+10321032+ 5. *Return the Receipt*, which MAY be asynchronous from
10331033+ Registration. The Transparency Service MUST be able to provide a
10341034+ Receipt for all registered Signed Statements. Details about
10351035+ generating Receipts are described in Section 4.4.
10361036+10371037+ The last two steps may be shared between a batch of Signed Statements
10381038+ registered in the Append-only Log.
10391039+10401040+ A Transparency Service MUST ensure that a Signed Statement is
10411041+ registered before releasing its Receipt.
10421042+10431043+ The same Signed Statement may be independently registered in multiple
10441044+ Transparency Services, producing multiple, independent Receipts. The
10451045+ multiple Receipts may be attached to the unprotected header of the
10461046+ Signed Statement, creating a Transparent Statement.
10471047+10481048+4.4. Transparent Statements
10491049+10501050+ The Client (which is not necessarily the Issuer) that registers a
10511051+ Signed Statement and receives a Receipt can produce a Transparent
10521052+ Statement by adding the Receipt to the unprotected header of the
10531053+ Signed Statement. Client applications MAY register Signed Statements
10541054+ on behalf of one or more Issuers. Client applications MAY request
10551055+ Receipts regardless of the identity of the Issuer of the associated
10561056+ Signed Statement.
10571057+10581058+ When a Signed Statement is registered by a Transparency Service a
10591059+ Receipt becomes available. When a Receipt is included in a Signed
10601060+ Statement a Transparent Statement is produced.
10611061+10621062+10631063+10641064+Birkholz, et al. Expires 17 May 2025 [Page 19]
10651065+10661066+Internet-Draft SCITT Architecture November 2024
10671067+10681068+10691069+ Receipts are based on Signed Inclusion Proofs as described in COSE
10701070+ Signed Merkle Tree Proofs ([I-D.draft-ietf-cose-merkle-tree-proofs])
10711071+ that also provides the COSE header parameter semantics for label 394.
10721072+10731073+ The Registration time is recorded as the timestamp when the
10741074+ Transparency Service added this Signed Statement to its Append-only
10751075+ Log.
10761076+10771077+ Figure 5 illustrates a normative CDDL definition of Transparent
10781078+ Statements.
10791079+10801080+ Transparent_Statement = #6.18(COSE_Sign1)
10811081+10821082+ Unprotected_Header = {
10831083+ &(receipts: 394) => [+ Receipt]
10841084+ }
10851085+10861086+ Figure 5: CDDL definition for a Transparent Statement
10871087+10881088+ Figure 6 illustrates a Transparent Statement with a detached payload,
10891089+ and two Receipts in its unprotected header. The type of label 394
10901090+ receipts in the unprotected header is a CBOR array that can contain
10911091+ one or more Receipts (each entry encoded as a .cbor encoded
10921092+ Receipts).
10931093+10941094+ 18( / COSE Sign 1 /
10951095+ [
10961096+ h'a4012603...6d706c65', / Protected /
10971097+ { / Unprotected /
10981098+ 394: [ / Receipts (2) /
10991099+ h'd284586c...4191f9d2' / Receipt 1 /
11001100+ h'c624586c...8f4af97e' / Receipt 2 /
11011101+ ]
11021102+ },
11031103+ nil, / Detached payload /
11041104+ h'79ada558...3a28bae4' / Signature /
11051105+ ]
11061106+ )
11071107+11081108+ Figure 6: CBOR Extended Diagnostic Notation example of a
11091109+ Transparent Statement
11101110+11111111+11121112+11131113+11141114+11151115+11161116+11171117+11181118+11191119+11201120+Birkholz, et al. Expires 17 May 2025 [Page 20]
11211121+11221122+Internet-Draft SCITT Architecture November 2024
11231123+11241124+11251125+ Figure 7 one of the decoded Receipt from Figure 6. The Receipt
11261126+ contains inclusion proofs for verifiable data structures. The
11271127+ unprotected header contains verifiable data structure proofs. See
11281128+ the protected header for details regarding the specific verifiable
11291129+ data structure used. Per the COSE Verifiable Data Structure Registry
11301130+ documented in [I-D.draft-ietf-cose-merkle-tree-proofs], the COSE key
11311131+ type RFC9162_SHA256 is value 1. Labels identify inclusion proofs
11321132+ (-1) and consistency proofs (-2).
11331133+11341134+ 18( / COSE Sign 1 /
11351135+ [
11361136+ h'a4012604...6d706c65', / Protected /
11371137+ { / Unprotected /
11381138+ -222: { / Proofs /
11391139+ -1: [ / Inclusion proofs (1) /
11401140+ h'83080783...32568964', / Inclusion proof 1 /
11411141+ ]
11421142+ },
11431143+ },
11441144+ nil, / Detached payload /
11451145+ h'10f6b12a...4191f9d2' / Signature /
11461146+ ]
11471147+ )
11481148+11491149+ Figure 7: CBOR Extended Diagnostic Notation example of a Receipt
11501150+11511151+ Figure 8 illustrates the decoded protected header of the Transparent
11521152+ Statement in Figure 6. The verifiable data structure (-111) uses 1
11531153+ from (RFC9162_SHA256).
11541154+11551155+ { / Protected /
11561156+ 1: -7, / Algorithm /
11571157+ 4: h'50685f55...50523255', / Key identifier /
11581158+ -111: 1, / Verifiable Data Structure /
11591159+ 15: { / CWT Claims /
11601160+ 1: transparency.vendor.example, / Issuer /
11611161+ 2: vendor.product.example, / Subject /
11621162+ }
11631163+ }
11641164+11651165+ Figure 8: CBOR Extended Diagnostic Notation example of a
11661166+ Receipt's Protected Header
11671167+11681168+ Figure 9 illustrates the decoded inclusion proof from Figure 7. This
11691169+ inclusion proof indicates that the size of the Append-only Log was 8
11701170+ at the time the Receipt was issued. The structure of this inclusion
11711171+ proof is specific to the verifiable data structure used
11721172+ (RFC9162_SHA256).
11731173+11741174+11751175+11761176+Birkholz, et al. Expires 17 May 2025 [Page 21]
11771177+11781178+Internet-Draft SCITT Architecture November 2024
11791179+11801180+11811181+ [ / Inclusion proof 1 /
11821182+ 8, / Tree size /
11831183+ 7, / Leaf index /
11841184+ [ / Inclusion hashes (3) /
11851185+ h'c561d333...f9850597' / Intermediate hash 1 /
11861186+ h'75f177fd...2e73a8ab' / Intermediate hash 2 /
11871187+ h'0bdaaed3...32568964' / Intermediate hash 3 /
11881188+ ]
11891189+ ]
11901190+11911191+ Figure 9: CBOR Extended Diagnostic Notation example of a
11921192+ Receipt's Inclusion Proof
11931193+11941194+4.4.1. Validation
11951195+11961196+ Relying Parties MUST apply the verification process as described in
11971197+ Section 4.4 of RFC9052, when checking the signature of Signed
11981198+ Statements and Receipts.
11991199+12001200+ A Relying Party MUST trust the verification key or certificate and
12011201+ the associated identity of at least one Issuer of a Receipt.
12021202+12031203+ A Relying Party MAY decide to verify only a single Receipt that is
12041204+ acceptable to them, and not check the signature on the Signed
12051205+ Statement or Receipts which rely on verifiable data structures which
12061206+ they do not understand.
12071207+12081208+ APIs exposing verification logic for Transparent Statements may
12091209+ provide more details than a single boolean result. For example, an
12101210+ API may indicate if the signature on the Receipt or Signed Statement
12111211+ is valid, if Claims related to the validity period are valid, or if
12121212+ the inclusion proof in the Receipt is valid.
12131213+12141214+ Relying Parties MAY be configured to re-verify the Issuer's Signed
12151215+ Statement locally.
12161216+12171217+ In addition, Relying Parties MAY apply arbitrary validation policies
12181218+ after the Transparent Statement has been verified and validated.
12191219+ Such policies may use as input all information in the Envelope, the
12201220+ Receipt, and the Statement payload, as well as any local state.
12211221+12221222+12231223+12241224+12251225+12261226+12271227+12281228+12291229+12301230+12311231+12321232+Birkholz, et al. Expires 17 May 2025 [Page 22]
12331233+12341234+Internet-Draft SCITT Architecture November 2024
12351235+12361236+12371237+5. Privacy Considerations
12381238+12391239+ Transparency Services MAY support anonymous access. Issuers SHOULD
12401240+ ensure Signed Statements submitted to public access services are
12411241+ acceptable for public disclosure. Publicly accessible Signed
12421242+ Statements MUST NOT carry confidential information. Once a Signed
12431243+ Statement is inserted into the Append-only Log maintained by a
12441244+ Transparency Service, it cannot be removed from the Log. In some
12451245+ deployments, a special role, such as an Auditor, might require access
12461246+ to Signed Statements.
12471247+12481248+6. Security Considerations
12491249+12501250+ On its own, verifying a Transparent Statement does not guarantee that
12511251+ its Envelope or contents are trustworthy. Just that they have been
12521252+ signed by the apparent Issuer and counter-signed by the Transparency
12531253+ Service. If the Relying Party trusts the Issuer, after validation of
12541254+ the Issuer identity, it can infer that an Issuer's Signed Statement
12551255+ was issued with this Envelope and contents, which may be interpreted
12561256+ as the Issuer saying the Artifact is fit for its intended purpose.
12571257+ If the Relying Party trusts the Transparency Service, it can
12581258+ independently infer that the Signed Statement passed the Transparency
12591259+ Service Registration Policy and that has been persisted in the
12601260+ Append-only Log. Unless advertised in the Transparency Service
12611261+ Registration Policy, the Relying Party cannot assume that the
12621262+ ordering of Signed Statements in the Append-only Log matches the
12631263+ ordering of their issuance.
12641264+12651265+ Similarly, the fact that an Issuer can be held accountable for its
12661266+ Transparent Statements does not on its own provide any mitigation or
12671267+ remediation mechanism in case one of these Transparent Statements
12681268+ turned out to be misleading or malicious. Just that signed evidence
12691269+ will be available to support them.
12701270+12711271+ An Issuer that knows of a changed state of quality for an Artifact,
12721272+ SHOULD Register a new Signed Statement, using the same 15 CWT iss and
12731273+ sub Claims.
12741274+12751275+ Issuers MUST ensure that the Statement payloads in their Signed
12761276+ Statements are correct and unambiguous, for example by avoiding ill-
12771277+ defined or ambiguous formats that may cause Relying Parties to
12781278+ interpret the Signed Statement as valid for some other purpose.
12791279+12801280+ Issuers and Transparency Services MUST carefully protect their
12811281+ private signing keys and avoid these keys being used for any purpose
12821282+ not described in this architecture document. In cases where key re-
12831283+ use is unavoidable, keys MUST NOT sign any other message that may be
12841284+ verified as an Envelope as part of a Signed Statement.
12851285+12861286+12871287+12881288+Birkholz, et al. Expires 17 May 2025 [Page 23]
12891289+12901290+Internet-Draft SCITT Architecture November 2024
12911291+12921292+12931293+ For instance, the code for the Registration Policy evaluation and
12941294+ endorsement may be protected by running in a Trusted Execution
12951295+ Environment (TEE).
12961296+12971297+ The Transparency Service may be replicated with a consensus
12981298+ algorithm, such as Practical Byzantine Fault Tolerance [PBFT] and may
12991299+ be used to protect against malicious or vulnerable replicas.
13001300+ Threshold signatures may be use to protect the service key, etc.
13011301+13021302+ Issuers and Transparency Services MUST rotate their keys in well-
13031303+ defined cryptoperiods, see [KEY-MANAGEMENT].
13041304+13051305+ A Transparency Service MAY provide additional authenticity assurances
13061306+ about its secure implementation and operation, enabling remote
13071307+ attestation of the hardware platforms and/or software Trusted
13081308+ Computing Bases (TCB) that run the Transparency Service. If present,
13091309+ these additional authenticity assurances MUST be registered in the
13101310+ Append-only Log and MUST always be exposed by the Transparency
13111311+ Services' APIs. An example of Signed Statement's payloads that can
13121312+ improve authenticity assurances are trustworthiness assessments that
13131313+ are RATS Conceptual Messages, such as Evidence, Endorsements, or
13141314+ corresponding Attestation Results (see [RFC9334]).
13151315+13161316+ For example, if a Transparency Service is implemented using a set of
13171317+ redundant replicas, each running within its own hardware-protected
13181318+ trusted execution environments (TEEs), then each replica can provide
13191319+ fresh Evidence or fresh Attestation Results about its TEEs. The
13201320+ respective Evidence can show, for example, the binding of the
13211321+ hardware platform to the software that runs the Transparency Service,
13221322+ the long-term public key of the service, or the key used by the
13231323+ replica for signing Receipts. The respective Attestation Result, for
13241324+ example, can show that the remote attestation Evidence was appraised
13251325+ by a Relying Party and complies with well-known Reference Values and
13261326+ Endorsements.
13271327+13281328+ Auditors should be aware that the certification path information
13291329+ included in an unprotected x5chain header of a to-be-registered
13301330+ Signed Statement can be tampered with by a malicious Transparency
13311331+ Service (e.g., one that does not incorporate remote attestation),
13321332+ which may replace the intermediate certificates and ultimately
13331333+ connect to an unexpected root. This modification helps protect
13341334+ against person-in-the-middle attacks, but not denial-of-service.
13351335+ Auditors MUST perform certification path validation in accordance
13361336+ with PKIX rules specified in [RFC5280]. In particular, Auditors MUST
13371337+ verify that certification paths chain to one or more trust anchors
13381338+ (often represented as root certificates).
13391339+13401340+13411341+13421342+13431343+13441344+Birkholz, et al. Expires 17 May 2025 [Page 24]
13451345+13461346+Internet-Draft SCITT Architecture November 2024
13471347+13481348+13491349+6.1. Security Guarantees
13501350+13511351+ SCITT provides the following security guarantees:
13521352+13531353+ 1. Statements made by Issuers about supply chain Artifacts are
13541354+ identifiable, can be authenticated, and once authenticated, are
13551355+ non-repudiable
13561356+13571357+ 2. Statement provenance and history can be independently and
13581358+ consistently audited
13591359+13601360+ 3. Issuers can efficiently prove that their Statement is logged by a
13611361+ Transparency Service
13621362+13631363+ The first guarantee is achieved by requiring Issuers to sign their
13641364+ Statements and associated metadata using a distributed public key
13651365+ infrastructure. The second guarantee is achieved by storing the
13661366+ Signed Statement on an Append-only Log. The third guarantee is
13671367+ achieved by implementing the Append-only Log using a verifiable data
13681368+ structure (such as a Merkle Tree [MERKLE]).
13691369+13701370+6.2. Threat Model
13711371+13721372+ This section provides a generic threat model for SCITT, describing
13731373+ its residual security properties when some of its actors (Issuers,
13741374+ Transparency Services, and Auditors) are corrupt or compromised.
13751375+13761376+ This threat model may need to be refined to account for specific
13771377+ supply chain use cases.
13781378+13791379+ SCITT primarily supports checking of Signed Statement authenticity,
13801380+ both from the Issuer (authentication) and from the Transparency
13811381+ Service (transparency). These guarantees are meant to hold for
13821382+ extensive periods of time, possibly decades.
13831383+13841384+ It can never be assumed that some Issuers and some Transparency
13851385+ Services will not be corrupt.
13861386+13871387+ SCITT entities explicitly trust one another on the basis of their
13881388+ long-term identity, which maps to shorter-lived cryptographic
13891389+ credentials. A Relying Party SHOULD validate a Transparent Statement
13901390+ originating from a given Issuer, registered at a given Transparency
13911391+ Service (both identified in the Relying Party's local authorization
13921392+ policy) and would not depend on any other Issuer or Transparency
13931393+ Services.
13941394+13951395+13961396+13971397+13981398+13991399+14001400+Birkholz, et al. Expires 17 May 2025 [Page 25]
14011401+14021402+Internet-Draft SCITT Architecture November 2024
14031403+14041404+14051405+ Issuers cannot be stopped from producing Signed Statements including
14061406+ false assertions in their Statement payload (either by mistake or by
14071407+ corruption), but these Issuers can made accountable by ensuring their
14081408+ Signed Statements are systematically registered at a Transparency
14091409+ Service.
14101410+14111411+ Similarly, providing strong residual guarantees against faulty/
14121412+ corrupt Transparency Services is a SCITT design goal. Preventing a
14131413+ Transparency Service from registering Signed Statements that do not
14141414+ meet its stated Registration Policy, or to issue Receipts that are
14151415+ not consistent with their Append-only Log is not possible. In
14161416+ contrast Transparency Services can be held accountable and they can
14171417+ be called out by any Auditor that replays their Append-only Log
14181418+ against any contested Receipt. Note that the SCITT Architecture does
14191419+ not require trust in a single centralized Transparency Service.
14201420+ Different actors may rely on different Transparency Services, each
14211421+ registering a subset of Signed Statements subject to their own
14221422+ policy.
14231423+14241424+ In both cases, the SCITT architecture provides generic, universally-
14251425+ verifiable cryptographic proofs to individually blame Issuers or the
14261426+ Transparency Service. On one hand, this enables valid actors to
14271427+ detect and disambiguate malicious actors who employ Equivocation with
14281428+ Signed Statements to different entities. On the other hand, their
14291429+ liability and the resulting damage to their reputation are
14301430+ application specific, and out of scope of the SCITT architecture.
14311431+14321432+ Relying Parties and Auditors need not be trusted by other actors. In
14331433+ particular, so long as actors maintain proper control of their
14341434+ signing keys and identity infrastructure they cannot "frame" an
14351435+ Issuer or a Transparency Service for Signed Statements they did not
14361436+ issue or register.
14371437+14381438+6.2.1. Append-only Log
14391439+14401440+ If a Transparency Service is honest, then a Transparent Statement
14411441+ including a correct Receipt ensures that the associated Signed
14421442+ Statement passed its Registration Policy and was registered
14431443+ appropriately.
14441444+14451445+ Conversely, a corrupt Transparency Service may:
14461446+14471447+ 1. refuse or delay the Registration of Signed Statements
14481448+14491449+ 2. register Signed Statements that do not pass its Registration
14501450+ Policy (e.g., Signed Statement with Issuer identities and
14511451+ signatures that do not verify)
14521452+14531453+14541454+14551455+14561456+Birkholz, et al. Expires 17 May 2025 [Page 26]
14571457+14581458+Internet-Draft SCITT Architecture November 2024
14591459+14601460+14611461+ 3. issue verifiable Receipts for Signed Statements that do not match
14621462+ its Append-only Log
14631463+14641464+ 4. refuse access to its Transparency Service (e.g., to Auditors,
14651465+ possibly after storage loss)
14661466+14671467+ An Auditor granted (partial) access to a Transparency Service and to
14681468+ a collection of disputed Receipts will be able to replay it, detect
14691469+ any invalid Registration (2) or incorrect Receipt in this collection
14701470+ (3), and blame the Transparency Service for them. This ensures any
14711471+ Relying Party that trusts at least one such Auditor that (2, 3) will
14721472+ be blamed to the Transparency Service.
14731473+14741474+ Due to the operational challenge of maintaining a globally consistent
14751475+ Append-only Log, some Transparency Services may provide limited
14761476+ support for historical queries on the Signed Statements they have
14771477+ registered, and accept the risk of being blamed for inconsistent
14781478+ Registration or Issuer Equivocation.
14791479+14801480+ Relying Parties and Auditors may also witness (1, 4) but may not be
14811481+ able to collect verifiable evidence for it.
14821482+14831483+6.2.2. Availability of Receipts
14841484+14851485+ Networking and Storage are trusted only for availability.
14861486+14871487+ Auditing may involve access to data beyond what is persisted in the
14881488+ Transparency Services. For example, the registered Transparency
14891489+ Service may include only the hash of a detailed SBOM, which may limit
14901490+ the scope of auditing.
14911491+14921492+ Resistance to denial-of-service is implementation specific.
14931493+14941494+ Actors may want to independently keep their own record of the Signed
14951495+ Statements they issue, endorse, verify, or audit.
14961496+14971497+6.2.3. Confidentiality and Privacy
14981498+14991499+ All contents exchanged between actors is protected using secure
15001500+ authenticated channels (e.g., TLS) but may not exclude network
15011501+ traffic analysis.
15021502+15031503+ The Transparency Service is trusted with the confidentiality of the
15041504+ Signed Statements presented for Registration. Some Transparency
15051505+ Services may publish every Signed Statement in their logs, to
15061506+ facilitate their dissemination and auditing. Transparency Services
15071507+ MAY return Receipts to Client applications synchronously or
15081508+ asynchronously.
15091509+15101510+15111511+15121512+Birkholz, et al. Expires 17 May 2025 [Page 27]
15131513+15141514+Internet-Draft SCITT Architecture November 2024
15151515+15161516+15171517+ A collection of Signed Statements must not leak information about the
15181518+ contents of other Signed Statements registered on the Transparency
15191519+ Service.
15201520+15211521+ Issuers must carefully review the inclusion of private/confidential
15221522+ materials in their Statements. For example, Issuers must remove
15231523+ Personally Identifiable Information (PII) as clear text in the
15241524+ Statement. Alternatively, Issuers may include opaque cryptographic
15251525+ Statements, such as hashes.
15261526+15271527+ The confidentiality of queries is implementation-specific, and
15281528+ generally not guaranteed. For example, while offline Envelope
15291529+ validation of Signed Statements is private, a Transparency Service
15301530+ may monitor which of its Transparent Statements are being verified
15311531+ from lookups to ensure their freshness.
15321532+15331533+6.2.4. Cryptographic Agility
15341534+15351535+ The SCITT Architecture supports cryptographic agility. The actors
15361536+ depend only on the subset of signing and Receipt schemes they trust.
15371537+ This enables the gradual transition to stronger algorithms, including
15381538+ e.g. post-quantum signature algorithms.
15391539+15401540+6.2.5. Transparency Service Client Applications
15411541+15421542+ Authentication of Client applications is out of scope for this
15431543+ document. Transparency Services MUST authenticate both Client
15441544+ applications and the Issuer of Signed Statements in order to ensure
15451545+ that implementation specific authentication and authorization
15461546+ policies are enforced. The specification of authentication and
15471547+ authorization policies is out of scope for this document.
15481548+15491549+6.2.6. Impersonation
15501550+15511551+ The identity resolution mechanism is trusted to associate long-term
15521552+ identifiers with their public signature-verification keys.
15531553+ Transparency Services and other parties may record identity-
15541554+ resolution evidence to facilitate its auditing.
15551555+15561556+ If one of the credentials of an Issuer gets compromised, the SCITT
15571557+ Architecture still guarantees the authenticity of all Signed
15581558+ Statements signed with this credential that have been registered on a
15591559+ Transparency Service before the compromise. It is up to the Issuer
15601560+ to notify Transparency Services of credential revocation to stop
15611561+ Relying Parties from accepting Signed Statements signed with
15621562+ compromised credentials.
15631563+15641564+15651565+15661566+15671567+15681568+Birkholz, et al. Expires 17 May 2025 [Page 28]
15691569+15701570+Internet-Draft SCITT Architecture November 2024
15711571+15721572+15731573+7. IANA Considerations
15741574+15751575+7.1. Media Type Registration
15761576+15771577+ Pending WG discussion.
15781578+15791579+8. References
15801580+15811581+8.1. Normative References
15821582+15831583+ [COSWID] Birkholz, H., Fitzgerald-McKay, J., Schmidt, C., and D.
15841584+ Waltermire, "Concise Software Identification Tags",
15851585+ RFC 9393, DOI 10.17487/RFC9393, June 2023,
15861586+ <https://www.rfc-editor.org/rfc/rfc9393>.
15871587+15881588+ [CWT_CLAIMS_COSE]
15891589+ Looker, T. and M. B. Jones, "CBOR Web Token (CWT) Claims
15901590+ in COSE Headers", Work in Progress, Internet-Draft, draft-
15911591+ ietf-cose-cwt-claims-in-headers-10, 29 November 2023,
15921592+ <https://datatracker.ietf.org/doc/html/draft-ietf-cose-
15931593+ cwt-claims-in-headers-10>.
15941594+15951595+ [I-D.draft-ietf-cose-merkle-tree-proofs]
15961596+ Steele, O., Birkholz, H., Delignat-Lavaud, A., and C.
15971597+ Fournet, "COSE Receipts", Work in Progress, Internet-
15981598+ Draft, draft-ietf-cose-merkle-tree-proofs-07, 17 October
15991599+ 2024, <https://datatracker.ietf.org/doc/html/draft-ietf-
16001600+ cose-merkle-tree-proofs-07>.
16011601+16021602+ [IANA.cwt] IANA, "CBOR Web Token (CWT) Claims",
16031603+ <https://www.iana.org/assignments/cwt>.
16041604+16051605+ [IANA.named-information]
16061606+ IANA, "Named Information",
16071607+ <https://www.iana.org/assignments/named-information>.
16081608+16091609+ [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
16101610+ Requirement Levels", BCP 14, RFC 2119,
16111611+ DOI 10.17487/RFC2119, March 1997,
16121612+ <https://www.rfc-editor.org/rfc/rfc2119>.
16131613+16141614+ [RFC4648] Josefsson, S., "The Base16, Base32, and Base64 Data
16151615+ Encodings", RFC 4648, DOI 10.17487/RFC4648, October 2006,
16161616+ <https://www.rfc-editor.org/rfc/rfc4648>.
16171617+16181618+16191619+16201620+16211621+16221622+16231623+16241624+Birkholz, et al. Expires 17 May 2025 [Page 29]
16251625+16261626+Internet-Draft SCITT Architecture November 2024
16271627+16281628+16291629+ [RFC5280] Cooper, D., Santesson, S., Farrell, S., Boeyen, S.,
16301630+ Housley, R., and W. Polk, "Internet X.509 Public Key
16311631+ Infrastructure Certificate and Certificate Revocation List
16321632+ (CRL) Profile", RFC 5280, DOI 10.17487/RFC5280, May 2008,
16331633+ <https://www.rfc-editor.org/rfc/rfc5280>.
16341634+16351635+ [RFC6570] Gregorio, J., Fielding, R., Hadley, M., Nottingham, M.,
16361636+ and D. Orchard, "URI Template", RFC 6570,
16371637+ DOI 10.17487/RFC6570, March 2012,
16381638+ <https://www.rfc-editor.org/rfc/rfc6570>.
16391639+16401640+ [RFC6838] Freed, N., Klensin, J., and T. Hansen, "Media Type
16411641+ Specifications and Registration Procedures", BCP 13,
16421642+ RFC 6838, DOI 10.17487/RFC6838, January 2013,
16431643+ <https://www.rfc-editor.org/rfc/rfc6838>.
16441644+16451645+ [RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC
16461646+ 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174,
16471647+ May 2017, <https://www.rfc-editor.org/rfc/rfc8174>.
16481648+16491649+ [RFC8392] Jones, M., Wahlstroem, E., Erdtman, S., and H. Tschofenig,
16501650+ "CBOR Web Token (CWT)", RFC 8392, DOI 10.17487/RFC8392,
16511651+ May 2018, <https://www.rfc-editor.org/rfc/rfc8392>.
16521652+16531653+ [RFC8610] Birkholz, H., Vigano, C., and C. Bormann, "Concise Data
16541654+ Definition Language (CDDL): A Notational Convention to
16551655+ Express Concise Binary Object Representation (CBOR) and
16561656+ JSON Data Structures", RFC 8610, DOI 10.17487/RFC8610,
16571657+ June 2019, <https://www.rfc-editor.org/rfc/rfc8610>.
16581658+16591659+ [RFC9052] Schaad, J., "CBOR Object Signing and Encryption (COSE):
16601660+ Structures and Process", STD 96, RFC 9052,
16611661+ DOI 10.17487/RFC9052, August 2022,
16621662+ <https://www.rfc-editor.org/rfc/rfc9052>.
16631663+16641664+ [RFC9360] Schaad, J., "CBOR Object Signing and Encryption (COSE):
16651665+ Header Parameters for Carrying and Referencing X.509
16661666+ Certificates", RFC 9360, DOI 10.17487/RFC9360, February
16671667+ 2023, <https://www.rfc-editor.org/rfc/rfc9360>.
16681668+16691669+8.2. Informative References
16701670+16711671+ [CWT_CLAIMS]
16721672+ "CBOR Web Token (CWT) Claims", n.d.,
16731673+ <https://www.iana.org/assignments/cwt/cwt.xhtml>.
16741674+16751675+16761676+16771677+16781678+16791679+16801680+Birkholz, et al. Expires 17 May 2025 [Page 30]
16811681+16821682+Internet-Draft SCITT Architecture November 2024
16831683+16841684+16851685+ [CycloneDX]
16861686+ "CycloneDX", n.d.,
16871687+ <https://cyclonedx.org/specification/overview/>.
16881688+16891689+ [EQUIVOCATION]
16901690+ Chun, B., Maniatis, P., Shenker, S., and J. Kubiatowicz,
16911691+ "Attested append-only memory: making adversaries stick to
16921692+ their word", Association for Computing Machinery (ACM),
16931693+ ACM SIGOPS Operating Systems Review vol. 41, no. 6, pp.
16941694+ 189-204, DOI 10.1145/1323293.1294280, October 2007,
16951695+ <https://doi.org/10.1145/1323293.1294280>.
16961696+16971697+ [FIPS.201] "Personal identity verification (PIV) of federal employees
16981698+ and contractors", National Institute of Standards and
16991699+ Technology (U.S.), DOI 10.6028/nist.fips.201-3, January
17001700+ 2022, <https://doi.org/10.6028/nist.fips.201-3>.
17011701+17021702+ [I-D.draft-ietf-core-href]
17031703+ Bormann, C. and H. Birkholz, "Constrained Resource
17041704+ Identifiers", Work in Progress, Internet-Draft, draft-
17051705+ ietf-core-href-16, 24 July 2024,
17061706+ <https://datatracker.ietf.org/doc/html/draft-ietf-core-
17071707+ href-16>.
17081708+17091709+ [I-D.draft-ietf-rats-eat]
17101710+ Lundblade, L., Mandyam, G., O'Donoghue, J., and C.
17111711+ Wallace, "The Entity Attestation Token (EAT)", Work in
17121712+ Progress, Internet-Draft, draft-ietf-rats-eat-31, 6
17131713+ September 2024, <https://datatracker.ietf.org/doc/html/
17141714+ draft-ietf-rats-eat-31>.
17151715+17161716+ [in-toto] "in-toto", n.d., <https://in-toto.io/>.
17171717+17181718+ [ISO.17000.2020]
17191719+ "ISO/IEC 17000:2020", n.d.,
17201720+ <https://www.iso.org/standard/73029.html>.
17211721+17221722+ [KEY-MANAGEMENT]
17231723+ Barker, E. and W. Barker, "Recommendation for key
17241724+ management:: part 2 -- best practices for key management
17251725+ organizations", National Institute of Standards and
17261726+ Technology, DOI 10.6028/nist.sp.800-57pt2r1, May 2019,
17271727+ <https://doi.org/10.6028/nist.sp.800-57pt2r1>.
17281728+17291729+17301730+17311731+17321732+17331733+17341734+17351735+17361736+Birkholz, et al. Expires 17 May 2025 [Page 31]
17371737+17381738+Internet-Draft SCITT Architecture November 2024
17391739+17401740+17411741+ [MERKLE] Merkle, R., "A Digital Signature Based on a Conventional
17421742+ Encryption Function", Springer Berlin Heidelberg, Lecture
17431743+ Notes in Computer Science pp. 369-378,
17441744+ DOI 10.1007/3-540-48184-2_32, ISBN ["9783540187967",
17451745+ "9783540481843"], 1988,
17461746+ <https://doi.org/10.1007/3-540-48184-2_32>.
17471747+17481748+ [NIST.SP.1800-19]
17491749+ Bartock, M., Dodson, D., Souppaya, M., Carroll, D.,
17501750+ Masten, R., Scinta, G., Massis, P., Prafullchandra, H.,
17511751+ Malnar, J., Singh, H., Ghandi, R., Storey, L. E., Yeluri,
17521752+ R., Shea, T., Dalton, M., Weber, R., Scarfone, K., Dukes,
17531753+ A., Haskins, J., Phoenix, C., Swarts, B., and National
17541754+ Institute of Standards and Technology (U.S.), "Trusted
17551755+ cloud :security practice guide for VMware hybrid cloud
17561756+ infrastructure as a service (IaaS) environments", NIST
17571757+ Special Publications (General) 1800-19,
17581758+ DOI 10.6028/NIST.SP.1800-19, 20 April 2022,
17591759+ <https://nvlpubs.nist.gov/nistpubs/SpecialPublications/
17601760+ NIST.SP.1800-19.pdf>.
17611761+17621762+ [NIST.SP.800-63-3]
17631763+ Grassi, P. A., Garcia, M. E., Fenton, J. L., and NIST,
17641764+ "Digital identity guidelines: revision 3", NIST Special
17651765+ Publications (General) 800-63-3,
17661766+ DOI 10.6028/NIST.SP.800-63-3, 22 June 2017,
17671767+ <https://nvlpubs.nist.gov/nistpubs/SpecialPublications/
17681768+ NIST.SP.800-63-3.pdf>.
17691769+17701770+ [PBFT] Castro, M. and B. Liskov, "Practical byzantine fault
17711771+ tolerance and proactive recovery", Association for
17721772+ Computing Machinery (ACM), ACM Transactions on Computer
17731773+ Systems vol. 20, no. 4, pp. 398-461,
17741774+ DOI 10.1145/571637.571640, November 2002,
17751775+ <https://doi.org/10.1145/571637.571640>.
17761776+17771777+ [RFC2397] Masinter, L., "The "data" URL scheme", RFC 2397,
17781778+ DOI 10.17487/RFC2397, August 1998,
17791779+ <https://www.rfc-editor.org/rfc/rfc2397>.
17801780+17811781+ [RFC4949] Shirey, R., "Internet Security Glossary, Version 2",
17821782+ FYI 36, RFC 4949, DOI 10.17487/RFC4949, August 2007,
17831783+ <https://www.rfc-editor.org/rfc/rfc4949>.
17841784+17851785+ [RFC7523] Jones, M., Campbell, B., and C. Mortimore, "JSON Web Token
17861786+ (JWT) Profile for OAuth 2.0 Client Authentication and
17871787+ Authorization Grants", RFC 7523, DOI 10.17487/RFC7523, May
17881788+ 2015, <https://www.rfc-editor.org/rfc/rfc7523>.
17891789+17901790+17911791+17921792+Birkholz, et al. Expires 17 May 2025 [Page 32]
17931793+17941794+Internet-Draft SCITT Architecture November 2024
17951795+17961796+17971797+ [RFC8141] Saint-Andre, P. and J. Klensin, "Uniform Resource Names
17981798+ (URNs)", RFC 8141, DOI 10.17487/RFC8141, April 2017,
17991799+ <https://www.rfc-editor.org/rfc/rfc8141>.
18001800+18011801+ [RFC8725] Sheffer, Y., Hardt, D., and M. Jones, "JSON Web Token Best
18021802+ Current Practices", BCP 225, RFC 8725,
18031803+ DOI 10.17487/RFC8725, February 2020,
18041804+ <https://www.rfc-editor.org/rfc/rfc8725>.
18051805+18061806+ [RFC9162] Laurie, B., Messeri, E., and R. Stradling, "Certificate
18071807+ Transparency Version 2.0", RFC 9162, DOI 10.17487/RFC9162,
18081808+ December 2021, <https://www.rfc-editor.org/rfc/rfc9162>.
18091809+18101810+ [RFC9334] Birkholz, H., Thaler, D., Richardson, M., Smith, N., and
18111811+ W. Pan, "Remote ATtestation procedureS (RATS)
18121812+ Architecture", RFC 9334, DOI 10.17487/RFC9334, January
18131813+ 2023, <https://www.rfc-editor.org/rfc/rfc9334>.
18141814+18151815+ [SLSA] "SLSA", n.d., <https://slsa.dev/>.
18161816+18171817+ [SPDX-CBOR]
18181818+ "SPDX Specification", n.d.,
18191819+ <https://spdx.dev/use/specifications/>.
18201820+18211821+ [SPDX-JSON]
18221822+ "SPDX Specification", n.d.,
18231823+ <https://spdx.dev/use/specifications/>.
18241824+18251825+ [SWID] "SWID Specification", n.d.,
18261826+ <https://csrc.nist.gov/Projects/Software-Identification-
18271827+ SWID/guidelines>.
18281828+18291829+ [URLs] "URL Living Standard", n.d.,
18301830+ <https://url.spec.whatwg.org/>.
18311831+18321832+Appendix A. Common Terminology Disambiguation
18331833+18341834+ This document has been developed in coordination with the COSE, OAUTH
18351835+ and RATS WG and uses terminology common to these working groups.
18361836+18371837+ This document uses the terms "Issuer", and "Subject" as described in
18381838+ [RFC8392], however the usage is consistent with the broader
18391839+ interpretation of these terms in both JOSE and COSE, and in
18401840+ particular, the guidance in [RFC8725] generally applies the COSE
18411841+ equivalent terms with consistent semantics.
18421842+18431843+18441844+18451845+18461846+18471847+18481848+Birkholz, et al. Expires 17 May 2025 [Page 33]
18491849+18501850+Internet-Draft SCITT Architecture November 2024
18511851+18521852+18531853+ The terms "verifier" and "Relying Party" are used interchangeably
18541854+ through the document. While these terms are related to "Verifier"
18551855+ and "Relying Party" as used in [RFC9334], they do not imply the
18561856+ processing of RATS conceptual messages, such as Evidence or
18571857+ Attestation Results that are specific to remote attestation. A SCITT
18581858+ "verifier" and "Relying Party" and "Issuer" of Receipts or Statements
18591859+ might take on the role of a RATS "Attester". Correspondingly, all
18601860+ RATS conceptual messages, such as Evidence and Attestation Results,
18611861+ can be the content of SCITT Statements and a SCITT "verifier" can
18621862+ also take on the role of a RATS "Verifier" to, for example, conduct
18631863+ the procedure of Appraisal of Evidence as a part of a SCITT
18641864+ "verifier"'s verification capabilities.
18651865+18661866+ The terms "Claim" and "Statement" are used throughout this document,
18671867+ where Claim is consistent with the usage in [I-D.draft-ietf-rats-eat]
18681868+ and [RFC7523], and Statement is reserved for any arbitrary bytes,
18691869+ possibly identified with a media type, about which the Claims are
18701870+ made.
18711871+18721872+ The term "Subject" provides an identifier of the Issuer's choosing to
18731873+ refer to a given Artifact, and ensures that all associated Statements
18741874+ can be attributed to the identifier chosen by the Issuer.
18751875+18761876+ In simpler language, a SCITT Statement could be some vendor-specific
18771877+ software bill of materials (SBOM), results from a model checker,
18781878+ static analyzer, or RATS Evidence about the authenticity of an SBOM
18791879+ creation process, where the Issuer identifies themselves using the
18801880+ iss Claim, and the specific software that was analyzed as the Subject
18811881+ using the sub Claim.
18821882+18831883+ In [RFC7523], the Authorization Server (AS) verifies Private Key JWT
18841884+ client authentication requests, and issues access tokens to clients
18851885+ configured to use "urn:ietf:params:oauth:client-assertion-type:jwt-
18861886+ bearer". This means the AS initially acts as a "verifier" of the
18871887+ authentication credentials in form of a JWT, and then later as an
18881888+ "Issuer" of access and refresh tokens. This mirrors how Signed
18891889+ Statements are verified before Receipts are issued by a Transparency
18901890+ Service. Note that the use of [RFC7523] is only one possible
18911891+ approach for client authentication in OAuth.
18921892+18931893+ [FIPS.201] defines "assertion" as "A verifiable statement from an IdP
18941894+ to an RP that contains information about an end user".
18951895+18961896+ [NIST.SP.800-63-3] defines "assertion" as "A statement from a
18971897+ verifier to an RP that contains information about a subscriber.
18981898+ Assertions may also contain verified attributes."
18991899+19001900+19011901+19021902+19031903+19041904+Birkholz, et al. Expires 17 May 2025 [Page 34]
19051905+19061906+Internet-Draft SCITT Architecture November 2024
19071907+19081908+19091909+ This document uses the term Statement to refer to potentially
19101910+ unsecured data and associated Claims, and Signed Statement and
19111911+ Receipt to refer to assertions from an Issuer, or the Transparency
19121912+ Service.
19131913+19141914+ [NIST.SP.1800-19] defines "attestation" as "The process of providing
19151915+ a digital signature for a set of measurements securely stored in
19161916+ hardware, and then having the requester validate the signature and
19171917+ the set of measurements."
19181918+19191919+ NIST guidance "Software Supply Chain Security Guidance EO 14028" uses
19201920+ the definition from [ISO.17000.2020], which states that an
19211921+ "attestation" is "The issue of a statement, based on a decision, that
19221922+ fulfillment of specified requirements has been demonstrated.". In
19231923+ the RATS context, a "NIST attestation" is similar to a RATS
19241924+ "Endorsement". Occasionally, RATS Evidence and RATS Attestation
19251925+ Results or the procedures of creating these conceptual messages are
19261926+ referred to as "attestation" or (in cases of the use as a verb) "to
19271927+ attest". The stand-alone use of "attestation" and "to attest" is
19281928+ discouraged outside a well-defined context, such as specification
19291929+ text that highlights the application of terminology, explicitly.
19301930+ Correspondingly, it is often useful for the intended audience to
19311931+ qualify the term "attestation" to avoid confusion and ambiguity.
19321932+19331933+Appendix B. Identifiers
19341934+19351935+ This section provides informative examples of identifiers for
19361936+ Statements, Signed Statements, and Receipts.
19371937+19381938+ SCITT Identifiers are primarily meant to be understood by humans and
19391939+ secondarily meant to be understood by machines, as such we define
19401940+ text encodings for message identifiers first, and then provide binary
19411941+ translations according to standard transformations for URLs and URNs
19421942+ to binary formats.
19431943+19441944+ SCITT Identifiers for URLs and URNs that are not Data URLs MUST be
19451945+ represented in binary using [I-D.draft-ietf-core-href].
19461946+19471947+ For each SCITT conceptual message, we define a Data URL format
19481948+ according to [RFC2397], a URN format according to [RFC8141] and a URL
19491949+ format according to [URLs].
19501950+19511951+ Note that Data URLs require base64 encoding, but the URN definitions
19521952+ require base64url encoding.
19531953+19541954+ Resolution and dereferencing of these identifiers is out of scope for
19551955+ this document, and can be implemented by any concrete api
19561956+ implementing the abstract interface defined as follows:
19571957+19581958+19591959+19601960+Birkholz, et al. Expires 17 May 2025 [Page 35]
19611961+19621962+Internet-Draft SCITT Architecture November 2024
19631963+19641964+19651965+ resource: content-type = dereference(identifier: identifier-type)
19661966+19671967+ These identifiers MAY be present in a tstr field that does not
19681968+ otherwise restrict the string in ways that prevent a URN or URL from
19691969+ being present.
19701970+19711971+ This includes iss, and sub which are used to express the Issuer and
19721972+ Subject of a Signed Statement or Receipt.
19731973+19741974+ This also includes kid which is used to express a hint for which
19751975+ public key should be used to verify a signature.
19761976+19771977+ All SCITT identifiers share common parameters to promote
19781978+ interoperability:
19791979+19801980+ Let hash-name be an algorithm name registered in
19811981+ [IANA.named-information].
19821982+19831983+ To promote interoperability, the hash-name MUST be "sha-256".
19841984+19851985+ Let base-encoding, be a base encoding defined in [RFC4648].
19861986+19871987+ To promote interoperability, the base encoding MUST be "base64url".
19881988+19891989+ In the blocks and examples that follow, note '' line wrapping per RFC
19901990+ 8792.
19911991+19921992+B.1. Identifiers For Binary Content
19931993+19941994+ Identifiers for binary content, such as Statements, or even Artifacts
19951995+ themselves are computed as follows:
19961996+19971997+ Let the base64url-encoded-bytes-digest for the message be the
19981998+ base64url encoded digest with the chosen hash algorithm of bytes /
19991999+ octets.
20002000+20012001+ Let the SCITT name for the message be the URN constructed from the
20022002+ following URI template, according to [RFC6570]:
20032003+20042004+ Let the message-type, be "statement" for Statements about Artifacts.
20052005+20062006+ urn:ietf:params:scitt:\
20072007+ {message-type}:\
20082008+ {hash-name}:{base-encoding}:\
20092009+ {base64url-encoded-bytes-digest}
20102010+20112011+20122012+20132013+20142014+20152015+20162016+Birkholz, et al. Expires 17 May 2025 [Page 36]
20172017+20182018+Internet-Draft SCITT Architecture November 2024
20192019+20202020+20212021+B.2. Identifiers For SCITT Messages
20222022+20232023+ Identifiers for COSE Sign 1 based messages, such as identifiers for
20242024+ Signed Statements and Receipts are computed as follows:
20252025+20262026+ Let the base64url-encoded-to-be-signed-bytes-digest for the message
20272027+ be the base64url encoded digest with the chosen hash algorithm of the
20282028+ "to-be-signed bytes", according to Section 8.1 of [RFC9052].
20292029+20302030+ Let the SCITT name for the message be the URN constructed from the
20312031+ following URI template, according to [RFC6570]:
20322032+20332033+ Let the message-type, be "signed-statement" for Signed Statements,
20342034+ and "receipt" for Receipts.
20352035+20362036+ urn:ietf:params:scitt:\
20372037+ {message-type}:\
20382038+ {hash-name}:{base-encoding}:\
20392039+ {base64url-encoded-to-be-signed-bytes-digest}
20402040+20412041+ Note that this means the content of the signature is not included in
20422042+ the identifier, even though signature related Claims, such as
20432043+ activation or expiration information in protected headers are
20442044+ included.
20452045+20462046+ As a result, an attacker may construct a new Signed Statement that
20472047+ has the same identifier as a previous Signed Statement, but has a
20482048+ different signature.
20492049+20502050+B.3. Identifiers For Transparent Statements
20512051+20522052+ Identifiers for Transparent Statements are defined as identifiers for
20532053+ binary content, but with "transparent-statement" as the message-type.
20542054+20552055+ urn:ietf:params:scitt:\
20562056+ {message-type}:\
20572057+ {hash-name}:{base-encoding}:\
20582058+ {base64url-encoded-bytes-digest}
20592059+20602060+ Note that because this identifier is computed over the unprotected
20612061+ header of the Signed Statement, any changes to the unprotected
20622062+ header, such as changing the order of the unprotected header map key
20632063+ value pairs, adding additional Receipts, or adding additional proofs
20642064+ to a Receipt, will change the identifier of a Transparent Statement.
20652065+20662066+20672067+20682068+20692069+20702070+20712071+20722072+Birkholz, et al. Expires 17 May 2025 [Page 37]
20732073+20742074+Internet-Draft SCITT Architecture November 2024
20752075+20762076+20772077+ Note that because this identifier is computed over the signatures of
20782078+ the Signed Statement and signatures in each Receipt, any
20792079+ canonicalization of the signatures after the fact will produce a
20802080+ distinct identifier.
20812081+20822082+B.4. Statements
20832083+20842084+B.4.1. Statement URN
20852085+20862086+ urn:ietf:params:scitt:statement:sha-256:base64url:5i6UeR...qnGmr1o
20872087+20882088+ Figure 10: Example Statement URN
20892089+20902090+B.4.2. Statement URL
20912091+20922092+ https://transparency.example/api/identifiers\
20932093+ /urn:ietf:params:scitt:statement:sha-256:base64url:5i6UeR...qnGmr1o
20942094+20952095+ Figure 11: Example Statement URL
20962096+20972097+B.4.3. Statement Data URL
20982098+20992099+ data:application/json;base64,SGVsb...xkIQ==
21002100+21012101+ Figure 12: Example Statement Data URL
21022102+21032103+B.5. Signed Statements
21042104+21052105+B.5.1. Signed Statement URN
21062106+21072107+ urn:ietf:params:scitt:\
21082108+ signed-statement:sha-256:base64url:5i6UeR...qnGmr1o
21092109+21102110+ Figure 13: Example Signed Statement URN
21112111+21122112+B.5.2. Signed Statement URL
21132113+21142114+ https://transparency.example/api/identifiers\
21152115+ /urn:ietf:params:scitt:\
21162116+ signed-statement:sha-256:base64url:5i6...r1o
21172117+21182118+ Figure 14: Example Signed Statement URL
21192119+21202120+B.5.3. Signed Statement Data URL
21212121+21222122+ data:application/cose;base64,SGVsb...xkIQ==
21232123+21242124+ Figure 15: Example Signed Statement Data URL
21252125+21262126+21272127+21282128+Birkholz, et al. Expires 17 May 2025 [Page 38]
21292129+21302130+Internet-Draft SCITT Architecture November 2024
21312131+21322132+21332133+B.6. Receipts
21342134+21352135+B.6.1. Receipt URN
21362136+21372137+ urn:ietf:params:scitt:receipt:sha-256:base64url:5i6UeR...qnGmr1o
21382138+21392139+ Figure 16: Example Receipt URN
21402140+21412141+B.6.2. Receipt URL
21422142+21432143+ https://transparency.example/api/identifiers\
21442144+ /urn:ietf:params:scitt:receipt:sha-256:base64url:5i6UeR...qnGmr1o
21452145+21462146+ Figure 17: Example Receipt URL
21472147+21482148+B.6.3. Receipt Data URL
21492149+21502150+ data:application/cose;base64,SGVsb...xkIQ==
21512151+21522152+ Figure 18: Example Receipt Data URL
21532153+21542154+B.7. Transparent Statements
21552155+21562156+B.7.1. Transparent Statement URN
21572157+21582158+ urn:ietf:params:scitt:\
21592159+ transparent-statement:sha-256:base64url:5i6UeR...qnGmr1o
21602160+21612161+ Figure 19: Example Transparent Statement URN
21622162+21632163+B.7.2. Transparent Statement URL
21642164+21652165+ https://transparency.example/api/identifiers\
21662166+ /urn:ietf:params:scitt:\
21672167+ transparent-statement:sha-256:base64url:5i6UeR...qnGmr1o
21682168+21692169+ Figure 20: Example Transparent Statement URL
21702170+21712171+B.7.3. Transparent Statement Data URL
21722172+21732173+ data:application/cose;base64,SGVsb...xkIQ==
21742174+21752175+ Figure 21: Example Transparent Statement Data URL
21762176+21772177+21782178+21792179+21802180+21812181+21822182+21832183+21842184+Birkholz, et al. Expires 17 May 2025 [Page 39]
21852185+21862186+Internet-Draft SCITT Architecture November 2024
21872187+21882188+21892189+Appendix C. Signing Statements Remotely
21902190+21912191+ Statements about digital Artifacts, containing digital Artifacts, or
21922192+ structured data regarding any type of Artifacts, can be too large or
21932193+ too sensitive to be send to a remote Transparency Services over the
21942194+ Internet. In these cases a Statement can also be hash, which becomes
21952195+ the payload included in COSE to-be-signed bytes. A Signed Statement
21962196+ (cose-sign1) MUST be produced from the to-be-signed bytes according
21972197+ to Section 4.4 of [RFC9052].
21982198+21992199+22002200+22012201+22022202+22032203+22042204+22052205+22062206+22072207+22082208+22092209+22102210+22112211+22122212+22132213+22142214+22152215+22162216+22172217+22182218+22192219+22202220+22212221+22222222+22232223+22242224+22252225+22262226+22272227+22282228+22292229+22302230+22312231+22322232+22332233+22342234+22352235+22362236+22372237+22382238+22392239+22402240+Birkholz, et al. Expires 17 May 2025 [Page 40]
22412241+22422242+Internet-Draft SCITT Architecture November 2024
22432243+22442244+22452245+ .----+-----.
22462246+ | Artifact |
22472247+ '+-+-------'
22482248+ | |
22492249+ .-' v
22502250+ | .--+-------.
22512251+ | | Hash +-+
22522252+ | '----------' | /\
22532253+ '-. | / \ .----------.
22542254+ | +-->+ OR +-->+ Payload |
22552255+ v | \ / '--------+-'
22562256+ .+--------. | \/ |
22572257+ | Statement +--+ |
22582258+ '---------' |
22592259+ |
22602260+ |
22612261+ ... Producer Network ... |
22622262+22632263+ ...
22642264+22652265+ ... Issuer Network ... |
22662266+ |
22672267+ |
22682268+ .---------. |
22692269+ | Identity | (iss, x5t) |
22702270+ | Document +--------------------+ |
22712271+ `----+----` | |
22722272+ ^ | |
22732273+ .----+-------. | |
22742274+ | Private Key | | |
22752275+ '----+-------' v |
22762276+ | .----+---. |
22772277+ | | Header | |
22782278+ | '----+---' |
22792279+ v v v
22802280+ .-+-----------. .------+------+--.
22812281+ / / / \
22822282+ / Sign +<------+ To Be Signed Bytes |
22832283+ / / \ /
22842284+ '-----+-------' '----------------'
22852285+ v
22862286+ .----+-------.
22872287+ | COSE Sign 1 |
22882288+ '------------'
22892289+22902290+Contributors
22912291+22922292+22932293+22942294+22952295+22962296+Birkholz, et al. Expires 17 May 2025 [Page 41]
22972297+22982298+Internet-Draft SCITT Architecture November 2024
22992299+23002300+23012301+ Orie Steele
23022302+ Transmute
23032303+ United States
23042304+ Email: orie@transmute.industries
23052305+23062306+23072307+ Orie contributed to improving the generalization of COSE building
23082308+ blocks and document consistency.
23092309+23102310+Authors' Addresses
23112311+23122312+ Henk Birkholz
23132313+ Fraunhofer SIT
23142314+ Rheinstrasse 75
23152315+ 64295 Darmstadt
23162316+ Germany
23172317+ Email: henk.birkholz@sit.fraunhofer.de
23182318+23192319+23202320+ Antoine Delignat-Lavaud
23212321+ Microsoft Research
23222322+ 21 Station Road
23232323+ Cambridge
23242324+ CB1 2FB
23252325+ United Kingdom
23262326+ Email: antdl@microsoft.com
23272327+23282328+23292329+ Cedric Fournet
23302330+ Microsoft Research
23312331+ 21 Station Road
23322332+ Cambridge
23332333+ CB1 2FB
23342334+ United Kingdom
23352335+ Email: fournet@microsoft.com
23362336+23372337+23382338+ Yogesh Deshpande
23392339+ ARM
23402340+ 110 Fulbourn Road
23412341+ Cambridge
23422342+ CB1 9NJ
23432343+ United Kingdom
23442344+ Email: yogesh.deshpande@arm.com
23452345+23462346+23472347+23482348+23492349+23502350+23512351+23522352+Birkholz, et al. Expires 17 May 2025 [Page 42]
23532353+23542354+Internet-Draft SCITT Architecture November 2024
23552355+23562356+23572357+ Steve Lasker
23582358+ DataTrails
23592359+ Seattle, WA 98199
23602360+ United States
23612361+ Email: steve.lasker@datatrails.ai
23622362+23632363+23642364+23652365+23662366+23672367+23682368+23692369+23702370+23712371+23722372+23732373+23742374+23752375+23762376+23772377+23782378+23792379+23802380+23812381+23822382+23832383+23842384+23852385+23862386+23872387+23882388+23892389+23902390+23912391+23922392+23932393+23942394+23952395+23962396+23972397+23982398+23992399+24002400+24012401+24022402+24032403+24042404+24052405+24062406+24072407+24082408+Birkholz, et al. Expires 17 May 2025 [Page 43]
+41-44
ocaml-scitt/test/atp/test_scitt_atp.ml
···14141515(* -- Test MST module: fresh in-memory blockstore per instance -- *)
16161717-let make_vds_mst () =
1717+let vds_mst () =
1818 let store = Atp.Blockstore.memory () in
1919 let module C = struct
2020 let store = store
···3030 let pub = X509.Private_key.public key in
3131 (key, pub)
32323333-let make_statement ?(issuer = "did:web:test.com") ?(subject = "sha256:abc")
3333+let statement ?(issuer = "did:web:test.com") ?(subject = "sha256:abc")
3434 ?(content_type = "application/json") ?(payload = "{}") () =
3535 Scitt.Statement.v ~issuer ~subject ~content_type ~payload
3636···3939 | Ok s -> s
4040 | Error e -> Alcotest.failf "sign failed: %a" Scitt.pp_error e
41414242-let make_ts_mst key =
4343- let vds = make_vds_mst () in
4242+let ts_mst key =
4343+ let vds = vds_mst () in
4444 Scitt.Transparency_service.create ~service_id:"test-mst" ~vds ~key
45454646let register ts signed =
···5353(* ================================================================ *)
54545555let test_mst_create () =
5656- let vds = make_vds_mst () in
5656+ let vds = vds_mst () in
5757 Alcotest.(check int) "empty size" 0 (Scitt.vds_size vds);
5858 let root = Scitt.vds_root vds in
5959 Alcotest.(check bool) "root not empty" true (String.length root > 0)
60606161let test_mst_single_entry () =
6262- let vds = make_vds_mst () in
6262+ let vds = vds_mst () in
6363 let proof = append_ok vds ~key:"sha256:aaa" ~value:"data-1" in
6464 Alcotest.(check int) "size" 1 (Scitt.vds_size vds);
6565 Alcotest.(check int) "proof leaf_index" 0 proof.leaf_index;
···6767 Alcotest.(check bool) "leaf not empty" true (String.length proof.leaf_hash > 0)
68686969let test_mst_multiple_entries () =
7070- let vds = make_vds_mst () in
7070+ let vds = vds_mst () in
7171 let _ = append_ok vds ~key:"sha256:aaa" ~value:"data-1" in
7272 let _ = append_ok vds ~key:"sha256:bbb" ~value:"data-2" in
7373 let p3 = append_ok vds ~key:"sha256:ccc" ~value:"data-3" in
···7676 Alcotest.(check int) "proof tree_size" 3 p3.tree_size
77777878let test_mst_lookup () =
7979- let vds = make_vds_mst () in
7979+ let vds = vds_mst () in
8080 let _ = append_ok vds ~key:"artifact-1" ~value:"data-1" in
8181 let _ = append_ok vds ~key:"artifact-2" ~value:"data-2" in
8282 Alcotest.(check (option string))
···9090 (Scitt.vds_lookup vds ~key:"artifact-3")
91919292let test_mst_root_changes () =
9393- let vds = make_vds_mst () in
9393+ let vds = vds_mst () in
9494 let root0 = Scitt.vds_root vds in
9595 let _ = append_ok vds ~key:"k1" ~value:"v1" in
9696 let root1 = Scitt.vds_root vds in
···100100 Alcotest.(check bool) "root changed again" true (root1 <> root2)
101101102102let test_mst_export () =
103103- let vds = make_vds_mst () in
103103+ let vds = vds_mst () in
104104 let _ = append_ok vds ~key:"k" ~value:"v" in
105105 let exported = Scitt.vds_export vds in
106106 Alcotest.(check bool) "export not empty" true (String.length exported > 0)
107107108108let test_mst_many_entries () =
109109- let vds = make_vds_mst () in
109109+ let vds = vds_mst () in
110110 for i = 0 to 49 do
111111- let k = Printf.sprintf "sha256:%064d" i in
112112- let v = Printf.sprintf "value-%d" i in
111111+ let k = Fmt.str "sha256:%064d" i in
112112+ let v = Fmt.str "value-%d" i in
113113 let _ = append_ok vds ~key:k ~value:v in
114114 ()
115115 done;
116116 Alcotest.(check int) "size" 50 (Scitt.vds_size vds);
117117- let mid = Printf.sprintf "sha256:%064d" 25 in
117117+ let mid = Fmt.str "sha256:%064d" 25 in
118118 Alcotest.(check (option string))
119119 "mid lookup" (Some "value-25")
120120 (Scitt.vds_lookup vds ~key:mid)
···128128 let issuer_key, issuer_pub = gen_key () in
129129 let ts_key, ts_pub = gen_key () in
130130 let stmt =
131131- make_statement ~issuer:"did:web:parsimoni.co" ~subject:"sha256:deadbeef"
131131+ statement ~issuer:"did:web:parsimoni.co" ~subject:"sha256:deadbeef"
132132 ~content_type:"application/spdx+json" ~payload:"{\"spdx\": \"mst-test\"}"
133133 ()
134134 in
135135 let signed = sign_statement issuer_key stmt in
136136- let ts = make_ts_mst ts_key in
136136+ let ts = ts_mst ts_key in
137137 let receipt = register ts signed in
138138 let proof = Scitt.Receipt.inclusion_proof receipt in
139139 Alcotest.(check int) "proof leaf_index" 0 proof.leaf_index;
···153153 Crypto_rng_unix.use_default ();
154154 let issuer_key, issuer_pub = gen_key () in
155155 let ts_key, ts_pub = gen_key () in
156156- let ts = make_ts_mst ts_key in
157157- let subjects = List.init 10 (fun i -> Printf.sprintf "sha256:%064d" i) in
156156+ let ts = ts_mst ts_key in
157157+ let subjects = List.init 10 (fun i -> Fmt.str "sha256:%064d" i) in
158158 List.iter
159159 (fun subject ->
160160- let stmt = make_statement ~subject ~payload:("data-" ^ subject) () in
160160+ let stmt = statement ~subject ~payload:("data-" ^ subject) () in
161161 let signed = sign_statement issuer_key stmt in
162162 let receipt = register ts signed in
163163 let transparent = Scitt.Transparent_statement.v signed [ receipt ] in
···174174 Crypto_rng_unix.use_default ();
175175 let issuer_key, _ = gen_key () in
176176 let ts_key, _ = gen_key () in
177177- let ts = make_ts_mst ts_key in
178178- let stmt1 = make_statement ~subject:"sha256:first" ~payload:"first-data" () in
179179- let stmt2 =
180180- make_statement ~subject:"sha256:second" ~payload:"second-data" ()
181181- in
177177+ let ts = ts_mst ts_key in
178178+ let stmt1 = statement ~subject:"sha256:first" ~payload:"first-data" () in
179179+ let stmt2 = statement ~subject:"sha256:second" ~payload:"second-data" () in
182180 let signed1 = sign_statement issuer_key stmt1 in
183181 let signed2 = sign_statement issuer_key stmt2 in
184182 let _ = register ts signed1 in
···205203 let issuer_key, issuer_pub = gen_key () in
206204 let ts_key, _ = gen_key () in
207205 let _, wrong_ts_pub = gen_key () in
208208- let ts = make_ts_mst ts_key in
209209- let stmt = make_statement () in
206206+ let ts = ts_mst ts_key in
207207+ let stmt = statement () in
210208 let signed = sign_statement issuer_key stmt in
211209 let receipt = register ts signed in
212210 let transparent = Scitt.Transparent_statement.v signed [ receipt ] in
···221219 Crypto_rng_unix.use_default ();
222220 let issuer_key, issuer_pub = gen_key () in
223221 let ts_key, ts_pub = gen_key () in
224224- let ts = make_ts_mst ts_key in
222222+ let ts = ts_mst ts_key in
225223 let stmt =
226226- make_statement ~issuer:"did:web:encode-mst" ~payload:"encode-mst-test" ()
224224+ statement ~issuer:"did:web:encode-mst" ~payload:"encode-mst-test" ()
227225 in
228226 let signed = sign_statement issuer_key stmt in
229227 let receipt = register ts signed in
···257255 ~vds:(Scitt.Vds_rfc9162.v ()) ~key:ts_key_rfc
258256 in
259257 let ts_mst =
260260- Scitt.Transparency_service.create ~service_id:"mst-ts"
261261- ~vds:(make_vds_mst ()) ~key:ts_key_mst
258258+ Scitt.Transparency_service.create ~service_id:"mst-ts" ~vds:(vds_mst ())
259259+ ~key:ts_key_mst
262260 in
263261 let subjects = [ "sha256:aaa"; "sha256:bbb"; "sha256:ccc" ] in
264262 List.iter
265263 (fun subject ->
266266- let stmt = make_statement ~subject ~payload:("data-" ^ subject) () in
264264+ let stmt = statement ~subject ~payload:("data-" ^ subject) () in
267265 let signed = sign_statement issuer_key stmt in
268266 (* Register in both *)
269267 let receipt_rfc =
···307305(* Attacker tests *)
308306(* ================================================================ *)
309307310310-let test_attacker_receipt_for_wrong_statement () =
308308+let test_attacker_wrong_receipt () =
311309 (* Receipt for statement B must not verify against statement A *)
312310 Crypto_rng_unix.use_default ();
313311 let issuer_key, issuer_pub = gen_key () in
314312 let ts_key, ts_pub = gen_key () in
315315- let ts = make_ts_mst ts_key in
316316- let stmt_a = make_statement ~subject:"sha256:aaa" ~payload:"payload-a" () in
317317- let stmt_b = make_statement ~subject:"sha256:bbb" ~payload:"payload-b" () in
313313+ let ts = ts_mst ts_key in
314314+ let stmt_a = statement ~subject:"sha256:aaa" ~payload:"payload-a" () in
315315+ let stmt_b = statement ~subject:"sha256:bbb" ~payload:"payload-b" () in
318316 let signed_a = sign_statement issuer_key stmt_a in
319317 let signed_b = sign_statement issuer_key stmt_b in
320318 let _receipt_a = register ts signed_a in
···333331 Crypto_rng_unix.use_default ();
334332 let issuer_key, issuer_pub = gen_key () in
335333 let ts_key, ts_pub = gen_key () in
336336- let ts = make_ts_mst ts_key in
337337- let stmt = make_statement ~subject:"sha256:aaa" ~payload:"data" () in
334334+ let ts = ts_mst ts_key in
335335+ let stmt = statement ~subject:"sha256:aaa" ~payload:"data" () in
338336 let signed = sign_statement issuer_key stmt in
339337 let receipt = register ts signed in
340338 (* Tamper the proof path *)
···355353 Crypto_rng_unix.use_default ();
356354 let issuer_key, issuer_pub = gen_key () in
357355 let _, ts_pub = gen_key () in
358358- let stmt = make_statement ~subject:"sha256:aaa" ~payload:"data" () in
356356+ let stmt = statement ~subject:"sha256:aaa" ~payload:"data" () in
359357 let signed = sign_statement issuer_key stmt in
360358 let transparent = Scitt.Transparent_statement.v signed [] in
361359 match
···365363 | Ok _ -> Alcotest.fail "should reject empty receipts"
366364 | Error _ -> ()
367365368368-let test_attacker_wrong_ts_key_mst () =
366366+let test_attacker_wrong_key () =
369367 (* Verify with wrong TS key must fail *)
370368 Crypto_rng_unix.use_default ();
371369 let issuer_key, issuer_pub = gen_key () in
372370 let ts_key, _ts_pub = gen_key () in
373371 let _, wrong_pub = gen_key () in
374374- let ts = make_ts_mst ts_key in
375375- let stmt = make_statement ~subject:"sha256:aaa" ~payload:"data" () in
372372+ let ts = ts_mst ts_key in
373373+ let stmt = statement ~subject:"sha256:aaa" ~payload:"data" () in
376374 let signed = sign_statement issuer_key stmt in
377375 let receipt = register ts signed in
378376 let transparent = Scitt.Transparent_statement.v signed [ receipt ] in
···417415 ( "attacker",
418416 [
419417 Alcotest.test_case "receipt for wrong statement" `Quick
420420- test_attacker_receipt_for_wrong_statement;
418418+ test_attacker_wrong_receipt;
421419 Alcotest.test_case "tampered proof CBOR" `Quick
422420 test_attacker_tampered_proof_cbor;
423421 Alcotest.test_case "empty receipts" `Quick
424422 test_attacker_empty_receipts;
425425- Alcotest.test_case "wrong TS key" `Quick
426426- test_attacker_wrong_ts_key_mst;
423423+ Alcotest.test_case "wrong TS key" `Quick test_attacker_wrong_key;
427424 ] );
428425 ]
+6-8
ocaml-scitt/test/gen/gen_vector.ml
···2626 let signed =
2727 match Scitt.Signed_statement.sign ~key:issuer_key stmt with
2828 | Ok s -> s
2929- | Error e -> failwith (Format.asprintf "sign: %a" Scitt.pp_error e)
2929+ | Error e -> Fmt.failwith "sign: %a" Scitt.pp_error e
3030 in
3131 let receipt =
3232 match Scitt.Transparency_service.register ts signed with
3333 | Ok r -> r
3434- | Error e -> failwith (Format.asprintf "register: %a" Scitt.pp_error e)
3434+ | Error e -> Fmt.failwith "register: %a" Scitt.pp_error e
3535 in
3636 let transparent = Scitt.Transparent_statement.v signed [ receipt ] in
3737 let encoded = Scitt.Transparent_statement.encode transparent in
3838 (* Dump everything as hex *)
3939 let key_to_hex k = Ohex.encode (X509.Public_key.encode_der k) in
4040- Printf.printf "-- Transparent Statement (hex) --\n%s\n\n"
4141- (Ohex.encode encoded);
4242- Printf.printf "-- Issuer Public Key DER (hex) --\n%s\n\n"
4343- (key_to_hex issuer_pub);
4444- Printf.printf "-- TS Public Key DER (hex) --\n%s\n\n" (key_to_hex ts_pub);
4545- Printf.printf "-- Expected payload --\n{\"test\": \"interop-vector\"}\n"
4040+ Fmt.pr "-- Transparent Statement (hex) --\n%s\n\n" (Ohex.encode encoded);
4141+ Fmt.pr "-- Issuer Public Key DER (hex) --\n%s\n\n" (key_to_hex issuer_pub);
4242+ Fmt.pr "-- TS Public Key DER (hex) --\n%s\n\n" (key_to_hex ts_pub);
4343+ Fmt.pr "-- Expected payload --\n{\"test\": \"interop-vector\"}\n"
+56-70
ocaml-scitt/test/test_scitt.ml
···2424 let pub = X509.Private_key.public key in
2525 (key, pub)
26262727-let make_statement ?(issuer = "did:web:test.com") ?(subject = "sha256:abc")
2727+let statement ?(issuer = "did:web:test.com") ?(subject = "sha256:abc")
2828 ?(content_type = "application/json") ?(payload = "{}") () =
2929 Scitt.Statement.v ~issuer ~subject ~content_type ~payload
3030···3333 | Ok s -> s
3434 | Error e -> Alcotest.failf "sign failed: %a" Scitt.pp_error e
35353636-let make_ts key =
3636+let ts key =
3737 let vds = Scitt.Vds_rfc9162.v () in
3838 Scitt.Transparency_service.create ~service_id:"test-ts" ~vds ~key
3939···339339 Crypto_rng_unix.use_default ();
340340 let issuer_key, issuer_pub = gen_key () in
341341 let ts_key, ts_pub = gen_key () in
342342- let ts = make_ts ts_key in
342342+ let ts = ts ts_key in
343343 (* Register two statements so proofs have non-empty paths *)
344344- let stmt1 = make_statement ~subject:"sha256:aaa" ~payload:"one" () in
345345- let stmt2 = make_statement ~subject:"sha256:bbb" ~payload:"two" () in
344344+ let stmt1 = statement ~subject:"sha256:aaa" ~payload:"one" () in
345345+ let stmt2 = statement ~subject:"sha256:bbb" ~payload:"two" () in
346346 let signed1 = sign_statement issuer_key stmt1 in
347347 let signed2 = sign_statement issuer_key stmt2 in
348348 let receipt1 = register ts signed1 in
···371371 Crypto_rng_unix.use_default ();
372372 let issuer_key, issuer_pub = gen_key () in
373373 let ts_key, ts_pub = gen_key () in
374374- let ts = make_ts ts_key in
375375- let stmt1 = make_statement ~subject:"sha256:aaa" ~payload:"one" () in
376376- let stmt2 = make_statement ~subject:"sha256:bbb" ~payload:"two" () in
374374+ let ts = ts ts_key in
375375+ let stmt1 = statement ~subject:"sha256:aaa" ~payload:"one" () in
376376+ let stmt2 = statement ~subject:"sha256:bbb" ~payload:"two" () in
377377 let signed1 = sign_statement issuer_key stmt1 in
378378 let signed2 = sign_statement issuer_key stmt2 in
379379 let _receipt1 = register ts signed1 in
···402402 Crypto_rng_unix.use_default ();
403403 let issuer_key, issuer_pub = gen_key () in
404404 let ts_key, ts_pub = gen_key () in
405405- let ts = make_ts ts_key in
406406- let stmt1 = make_statement ~subject:"sha256:aaa" ~payload:"one" () in
407407- let stmt2 = make_statement ~subject:"sha256:bbb" ~payload:"two" () in
405405+ let ts = ts ts_key in
406406+ let stmt1 = statement ~subject:"sha256:aaa" ~payload:"one" () in
407407+ let stmt2 = statement ~subject:"sha256:bbb" ~payload:"two" () in
408408 let signed1 = sign_statement issuer_key stmt1 in
409409 let signed2 = sign_statement issuer_key stmt2 in
410410 let _receipt1 = register ts signed1 in
···445445let test_sign_verify () =
446446 Crypto_rng_unix.use_default ();
447447 let key, _pub = gen_key () in
448448- let stmt = make_statement () in
448448+ let stmt = statement () in
449449 let signed = sign_statement key stmt in
450450 Alcotest.(check string)
451451 "issuer preserved" "did:web:test.com"
···458458 Crypto_rng_unix.use_default ();
459459 let key, _pub = gen_key () in
460460 let stmt =
461461- make_statement ~issuer:"did:web:roundtrip" ~payload:"roundtrip data" ()
461461+ statement ~issuer:"did:web:roundtrip" ~payload:"roundtrip data" ()
462462 in
463463 let signed = sign_statement key stmt in
464464 let encoded = Scitt.Signed_statement.encode signed in
···482482 let issuer_key, issuer_pub = gen_key () in
483483 let ts_key, ts_pub = gen_key () in
484484 let stmt =
485485- make_statement ~issuer:"did:web:parsimoni.co" ~subject:"sha256:deadbeef"
485485+ statement ~issuer:"did:web:parsimoni.co" ~subject:"sha256:deadbeef"
486486 ~content_type:"application/spdx+json" ~payload:"{\"spdx\": \"test\"}" ()
487487 in
488488 let signed = sign_statement issuer_key stmt in
489489- let ts = make_ts ts_key in
489489+ let ts = ts ts_key in
490490 let receipt = register ts signed in
491491 let proof = Scitt.Receipt.inclusion_proof receipt in
492492 Alcotest.(check int) "proof leaf_index" 0 proof.leaf_index;
···508508 Crypto_rng_unix.use_default ();
509509 let issuer_key, issuer_pub = gen_key () in
510510 let ts_key, ts_pub = gen_key () in
511511- let ts = make_ts ts_key in
511511+ let ts = ts ts_key in
512512 let register_and_verify subject payload =
513513- let stmt = make_statement ~subject ~payload () in
513513+ let stmt = statement ~subject ~payload () in
514514 let signed = sign_statement issuer_key stmt in
515515 let receipt = register ts signed in
516516 let transparent = Scitt.Transparent_statement.v signed [ receipt ] in
···530530 Crypto_rng_unix.use_default ();
531531 let issuer_key, _ = gen_key () in
532532 let ts_key, _ = gen_key () in
533533- let ts = make_ts ts_key in
534534- let stmt1 =
535535- make_statement ~subject:"sha256:first" ~payload:"first-payload" ()
536536- in
537537- let stmt2 =
538538- make_statement ~subject:"sha256:second" ~payload:"second-payload" ()
539539- in
533533+ let ts = ts ts_key in
534534+ let stmt1 = statement ~subject:"sha256:first" ~payload:"first-payload" () in
535535+ let stmt2 = statement ~subject:"sha256:second" ~payload:"second-payload" () in
540536 let signed1 = sign_statement issuer_key stmt1 in
541537 let signed2 = sign_statement issuer_key stmt2 in
542538 let _ = register ts signed1 in
···563559 let issuer_key, issuer_pub = gen_key () in
564560 let ts_key, _ = gen_key () in
565561 let _, wrong_ts_pub = gen_key () in
566566- let ts = make_ts ts_key in
567567- let stmt = make_statement () in
562562+ let ts = ts ts_key in
563563+ let stmt = statement () in
568564 let signed = sign_statement issuer_key stmt in
569565 let receipt = register ts signed in
570566 let transparent = Scitt.Transparent_statement.v signed [ receipt ] in
···580576 let issuer_key, _ = gen_key () in
581577 let _, wrong_issuer_pub = gen_key () in
582578 let ts_key, ts_pub = gen_key () in
583583- let ts = make_ts ts_key in
584584- let stmt = make_statement () in
579579+ let ts = ts ts_key in
580580+ let stmt = statement () in
585581 let signed = sign_statement issuer_key stmt in
586582 let receipt = register ts signed in
587583 let transparent = Scitt.Transparent_statement.v signed [ receipt ] in
···598594 Crypto_rng_unix.use_default ();
599595 let issuer_key, issuer_pub = gen_key () in
600596 let ts_key, ts_pub = gen_key () in
601601- let ts = make_ts ts_key in
602602- let stmt = make_statement () in
597597+ let ts = ts ts_key in
598598+ let stmt = statement () in
603599 let signed = sign_statement issuer_key stmt in
604600 let receipt = register ts signed in
605601 (* Tamper: set algorithm_id to 999 which is not in the VDS registry *)
···625621 Crypto_rng_unix.use_default ();
626622 let issuer_key, _ = gen_key () in
627623 let ts_key, ts_pub = gen_key () in
628628- let ts = make_ts ts_key in
629629- let stmt = make_statement () in
624624+ let ts = ts ts_key in
625625+ let stmt = statement () in
630626 let signed = sign_statement issuer_key stmt in
631627 let receipt = register ts signed in
632628 let transparent = Scitt.Transparent_statement.v signed [ receipt ] in
···640636 Crypto_rng_unix.use_default ();
641637 let issuer_key, _ = gen_key () in
642638 let _, ts_pub = gen_key () in
643643- let stmt = make_statement () in
639639+ let stmt = statement () in
644640 let signed = sign_statement issuer_key stmt in
645641 let transparent = Scitt.Transparent_statement.v signed [] in
646642 match
···657653 Crypto_rng_unix.use_default ();
658654 let issuer_key, issuer_pub = gen_key () in
659655 let ts_key, ts_pub = gen_key () in
660660- let ts = make_ts ts_key in
661661- let stmt =
662662- make_statement ~issuer:"did:web:encode" ~payload:"encode-test" ()
663663- in
656656+ let ts = ts ts_key in
657657+ let stmt = statement ~issuer:"did:web:encode" ~payload:"encode-test" () in
664658 let signed = sign_statement issuer_key stmt in
665659 let receipt = register ts signed in
666660 let transparent = Scitt.Transparent_statement.v signed [ receipt ] in
···686680 Crypto_rng_unix.use_default ();
687681 let issuer_key, _ = gen_key () in
688682 let ts_key, _ = gen_key () in
689689- let ts = make_ts ts_key in
683683+ let ts = ts ts_key in
690684 let root0 = Scitt.Transparency_service.root ts in
691691- let stmt1 = make_statement ~subject:"sha256:1" () in
685685+ let stmt1 = statement ~subject:"sha256:1" () in
692686 let signed1 = sign_statement issuer_key stmt1 in
693687 let _ = register ts signed1 in
694688 let root1 = Scitt.Transparency_service.root ts in
695689 Alcotest.(check bool) "root changed" true (root0 <> root1);
696696- let stmt2 = make_statement ~subject:"sha256:2" () in
690690+ let stmt2 = statement ~subject:"sha256:2" () in
697691 let signed2 = sign_statement issuer_key stmt2 in
698692 let _ = register ts signed2 in
699693 let root2 = Scitt.Transparency_service.root ts in
···713707 Scitt.Transparency_service.create ~service_id:"ts2"
714708 ~vds:(Scitt.Vds_rfc9162.v ()) ~key:ts_key2
715709 in
716716- let stmt = make_statement ~subject:"sha256:same" ~payload:"same" () in
710710+ let stmt = statement ~subject:"sha256:same" ~payload:"same" () in
717711 let signed = sign_statement issuer_key stmt in
718712 let _ = register ts1 signed in
719713 let _ = register ts2 signed in
···731725 Crypto_rng_unix.use_default ();
732726 let issuer_key, issuer_pub = gen_key () in
733727 let ts_key, ts_pub = gen_key () in
734734- let ts = make_ts ts_key in
728728+ let ts = ts ts_key in
735729 let n = 50 in
736730 let transparents =
737731 List.init n (fun i ->
738732 let subject = Fmt.str "sha256:%064d" i in
739733 let payload = Fmt.str "{\"index\": %d}" i in
740740- let stmt = make_statement ~subject ~payload () in
734734+ let stmt = statement ~subject ~payload () in
741735 let signed = sign_statement issuer_key stmt in
742736 let receipt = register ts signed in
743737 Scitt.Transparent_statement.v signed [ receipt ])
···772766 Crypto_rng_unix.use_default ();
773767 let issuer_key, _ = gen_key () in
774768 let ts_key, _ = gen_key () in
775775- let ts = make_ts ts_key in
776776- let stmt = make_statement () in
769769+ let ts = ts ts_key in
770770+ let stmt = statement () in
777771 let signed = sign_statement issuer_key stmt in
778772 let _ = register ts signed in
779773 let exported = Scitt.Transparency_service.export ts in
···836830 register_dummy "entry-2";
837831 register_dummy "entry-3";
838832 (* Now register the real entry — its path will be non-empty *)
839839- let stmt = make_statement () in
833833+ let stmt = statement () in
840834 let signed = sign_statement issuer_key stmt in
841835 let receipt = register ts signed in
842836 Alcotest.(check bool)
···963957 "d2845840a40126044a746573742d6b65792d3119018b010fa101782868747470733a2f2f7472616e73706172656e63792d736572766963652e6578616d706c652e636f6da119018ca12081586a8305038358203d06455dd33da4e9bbd8090677a2d0955e6dffe4b92069605a468920d1198095582033a5211719e06238a191c7244a7633187da2c9aaa5bc6dec54e2cbb49825543458204d75742d9ea02f7767dcd554a7878ff22cdb208be9f3d35f7aa7700b57e741c0f6584034e81008fb0e4e521657668745450df608d0e5c015dffc5d607dd78236c2908f4e2b643817d9191d0abd7c074aff2b1bfda519ab3fab210ff2e0a1de275de6a7"
964958965959let test_rfc9942_inclusion_proof () =
966966- (* The cose-wg vector has tree_size=5, leaf_index=3, 3 path hashes.
967967- The actual leaf data and signing key are not published, so we cannot
968968- verify the ES256 signature or match our root. We verify:
969969- 1. The COSE receipt decodes correctly per RFC 9942 structure
970970- 2. The proof fields (vds, tree_size, leaf_index, path) are correct
971971- 3. The path is self-consistent: walking verify_inclusion with a dummy
972972- leaf and the implied root succeeds *)
960960+ (* RFC 9942 cose-wg official test vector: a COSE_Sign1 inclusion receipt.
961961+ The tree entries and signing key are not published — the path hashes come
962962+ from an unknown tree. We verify:
963963+ 1. COSE structure decodes per RFC 9942 (vds=395, vdp=396, labels -1/-2)
964964+ 2. Proof fields (tree_size, leaf_index, path) parse correctly
965965+ 3. The path is self-consistent under verify_inclusion *)
973966 let expected_path =
974967 List.map hex_to_raw
975968 [
···978971 "4d75742d9ea02f7767dcd554a7878ff22cdb208be9f3d35f7aa7700b57e741c0";
979972 ]
980973 in
981981- (* Compute the root implied by this path and a dummy leaf_hash *)
982982- let dummy_leaf = sha256 "\x00dummy-leaf" in
983983- let p0 = List.nth expected_path 0 in
984984- let p1 = List.nth expected_path 1 in
985985- let p2 = List.nth expected_path 2 in
986986- (* Walk RFC 9162 §2.1.3.2: fn=3, sn=4 *)
987987- let r = Scitt.node_hash p0 dummy_leaf in
988988- (* fn=3: LSB=1, left sibling *)
989989- let r = Scitt.node_hash p1 r in
990990- (* fn=1: LSB=1, left sibling *)
991991- let r = Scitt.node_hash r p2 in
992992- (* fn=0, sn=1: right sibling *)
993993- let root = r in
974974+ (* Derive the root from the path and a plausible leaf_hash, then verify.
975975+ This proves our verify_inclusion algorithm agrees with the cose-wg
976976+ test vector's proof structure. *)
977977+ let dummy_leaf = sha256 "\x00test" in
978978+ (* Walk: fn=3, sn=4 (tree_size=5) *)
979979+ let r = Scitt.node_hash (List.nth expected_path 0) dummy_leaf in
980980+ let r = Scitt.node_hash (List.nth expected_path 1) r in
981981+ let r = Scitt.node_hash r (List.nth expected_path 2) in
994982 let proof : Scitt.inclusion_proof =
995983 {
996984 leaf_index = 3;
997985 tree_size = 5;
998998- root;
986986+ root = r;
999987 path = expected_path;
1000988 leaf_hash = dummy_leaf;
1001989 }
1002990 in
10031003- Alcotest.(check bool)
10041004- "path self-consistent" true
10051005- (Scitt.verify_inclusion proof);
991991+ Alcotest.(check bool) "path verifies" true (Scitt.verify_inclusion proof);
1006992 (* Decode the actual COSE receipt CBOR and check structure *)
1007993 let receipt_bytes = hex_to_raw rfc9942_inclusion_receipt_hex in
1008994 match Cose.Sign1.decode receipt_bytes with
+764-619
ocaml-sgp4/lib/sgp4.ml
···316316317317(** {1 Deep-Space Common Items (_dscom)} *)
318318319319+(** Solar perturbation coefficients from dscom iteration results. *)
320320+let dscom_solar_coeffs ~ss1 ~ss2 ~ss3 ~ss4 ~ss6 ~ss7 ~sz1 ~sz2 ~sz3 ~sz11 ~sz12
321321+ ~sz13 ~sz21 ~sz22 ~sz23 ~sz31 ~sz32 ~sz33 ~emsq ~zes =
322322+ let se2 = 2.0 *. ss1 *. ss6 in
323323+ let se3 = 2.0 *. ss1 *. ss7 in
324324+ let si2 = 2.0 *. ss2 *. sz12 in
325325+ let si3 = 2.0 *. ss2 *. (sz13 -. sz11) in
326326+ let sl2 = -2.0 *. ss3 *. sz2 in
327327+ let sl3 = -2.0 *. ss3 *. (sz3 -. sz1) in
328328+ let sl4 = -2.0 *. ss3 *. (-21.0 -. (9.0 *. emsq)) *. zes in
329329+ let sgh2 = 2.0 *. ss4 *. sz32 in
330330+ let sgh3 = 2.0 *. ss4 *. (sz33 -. sz31) in
331331+ let sgh4 = -18.0 *. ss4 *. zes in
332332+ let sh2 = -2.0 *. ss2 *. sz22 in
333333+ let sh3 = -2.0 *. ss2 *. (sz23 -. sz21) in
334334+ (se2, se3, si2, si3, sl2, sl3, sl4, sgh2, sgh3, sgh4, sh2, sh3)
335335+336336+(** Lunar perturbation coefficients from dscom iteration results. *)
337337+let dscom_lunar_coeffs ~s1 ~s2 ~s3 ~s4 ~s6 ~s7 ~z1 ~z2 ~z3 ~z11 ~z12 ~z13 ~z21
338338+ ~z22 ~z23 ~z31 ~z32 ~z33 ~emsq ~zel =
339339+ let ee2 = 2.0 *. s1 *. s6 in
340340+ let e3 = 2.0 *. s1 *. s7 in
341341+ let xi2 = 2.0 *. s2 *. z12 in
342342+ let xi3 = 2.0 *. s2 *. (z13 -. z11) in
343343+ let xl2 = -2.0 *. s3 *. z2 in
344344+ let xl3 = -2.0 *. s3 *. (z3 -. z1) in
345345+ let xl4 = -2.0 *. s3 *. (-21.0 -. (9.0 *. emsq)) *. zel in
346346+ let xgh2 = 2.0 *. s4 *. z32 in
347347+ let xgh3 = 2.0 *. s4 *. (z33 -. z31) in
348348+ let xgh4 = -18.0 *. s4 *. zel in
349349+ let xh2 = -2.0 *. s2 *. z22 in
350350+ let xh3 = -2.0 *. s2 *. (z23 -. z21) in
351351+ (ee2, e3, xi2, xi3, xl2, xl3, xl4, xgh2, xgh3, xgh4, xh2, xh3)
352352+319353let dscom ~epoch ~ep ~argpp ~tc ~inclp ~nodep ~np =
320354 let zes = 0.01675 in
321355 let zel = 0.05490 in
···481515 let zmol = Float.rem (4.7199672 +. (0.22997150 *. day) -. gam) twopi in
482516 let zmos = Float.rem (6.2565837 +. (0.017201977 *. day)) twopi in
483517 (* Solar perturbation coefficients *)
484484- let se2 = 2.0 *. ss1 *. ss6 in
485485- let se3 = 2.0 *. ss1 *. ss7 in
486486- let si2 = 2.0 *. ss2 *. sz12 in
487487- let si3 = 2.0 *. ss2 *. (sz13 -. sz11) in
488488- let sl2 = -2.0 *. ss3 *. sz2 in
489489- let sl3 = -2.0 *. ss3 *. (sz3 -. sz1) in
490490- let sl4 = -2.0 *. ss3 *. (-21.0 -. (9.0 *. emsq)) *. zes in
491491- let sgh2 = 2.0 *. ss4 *. sz32 in
492492- let sgh3 = 2.0 *. ss4 *. (sz33 -. sz31) in
493493- let sgh4 = -18.0 *. ss4 *. zes in
494494- let sh2 = -2.0 *. ss2 *. sz22 in
495495- let sh3 = -2.0 *. ss2 *. (sz23 -. sz21) in
518518+ let se2, se3, si2, si3, sl2, sl3, sl4, sgh2, sgh3, sgh4, sh2, sh3 =
519519+ dscom_solar_coeffs ~ss1 ~ss2 ~ss3 ~ss4 ~ss6 ~ss7 ~sz1 ~sz2 ~sz3 ~sz11 ~sz12
520520+ ~sz13 ~sz21 ~sz22 ~sz23 ~sz31 ~sz32 ~sz33 ~emsq ~zes
521521+ in
496522 (* Lunar perturbation coefficients *)
497497- let ee2 = 2.0 *. s1 *. s6 in
498498- let e3 = 2.0 *. s1 *. s7 in
499499- let xi2 = 2.0 *. s2 *. z12 in
500500- let xi3 = 2.0 *. s2 *. (z13 -. z11) in
501501- let xl2 = -2.0 *. s3 *. z2 in
502502- let xl3 = -2.0 *. s3 *. (z3 -. z1) in
503503- let xl4 = -2.0 *. s3 *. (-21.0 -. (9.0 *. emsq)) *. zel in
504504- let xgh2 = 2.0 *. s4 *. z32 in
505505- let xgh3 = 2.0 *. s4 *. (z33 -. z31) in
506506- let xgh4 = -18.0 *. s4 *. zel in
507507- let xh2 = -2.0 *. s2 *. z22 in
508508- let xh3 = -2.0 *. s2 *. (z23 -. z21) in
523523+ let ee2, e3, xi2, xi3, xl2, xl3, xl4, xgh2, xgh3, xgh4, xh2, xh3 =
524524+ dscom_lunar_coeffs ~s1 ~s2 ~s3 ~s4 ~s6 ~s7 ~z1 ~z2 ~z3 ~z11 ~z12 ~z13 ~z21
525525+ ~z22 ~z23 ~z31 ~z32 ~z33 ~emsq ~zel
526526+ in
509527 ( sinim,
510528 cosim,
511529 emsq,
···602620 let ph = shs +. shll in
603621 (pe, pinc, pl, pgh, ph)
604622623623+(** Lyddane modification for small inclination (inclp < 0.2 rad). *)
624624+let dpper_lyddane ~pinc ~pl ~pgh ~ph ~sinip ~cosip ~nodep ~argpp ~mp =
625625+ let sinop = sin nodep in
626626+ let cosop = cos nodep in
627627+ let alfdp = sinip *. sinop in
628628+ let betdp = sinip *. cosop in
629629+ let dalf = (ph *. cosop) +. (pinc *. cosip *. sinop) in
630630+ let dbet = (-.ph *. sinop) +. (pinc *. cosip *. cosop) in
631631+ let alfdp = alfdp +. dalf in
632632+ let betdp = betdp +. dbet in
633633+ (* Preserve sign of nodep when normalizing (improved opsmode) *)
634634+ let nodep =
635635+ if nodep >= 0.0 then Float.rem nodep twopi
636636+ else -.(Float.rem (-.nodep) twopi)
637637+ in
638638+ let xls = mp +. argpp +. pl +. pgh +. ((cosip -. (pinc *. sinip)) *. nodep) in
639639+ let xnoh = nodep in
640640+ let nodep = atan2 alfdp betdp in
641641+ (* For improved opsmode, do NOT add twopi for negative nodep *)
642642+ let nodep =
643643+ if abs_float (xnoh -. nodep) > pi then
644644+ if nodep < xnoh then nodep +. twopi else nodep -. twopi
645645+ else nodep
646646+ in
647647+ let mp = mp +. pl in
648648+ let argpp = xls -. mp -. (cosip *. nodep) in
649649+ (nodep, argpp, mp)
650650+605651(** Apply deep-space lunar-solar periodics during propagation. *)
606652let dpper_apply ~ds ~tsince ~ep ~inclp ~nodep ~argpp ~mp =
607653 let pe, pinc, pl, pgh, ph =
···623669 let sinip = sin inclp in
624670 let cosip = cos inclp in
625671 if inclp >= 0.2 then begin
672672+ (* Large inclination: direct application *)
626673 let ph = ph /. sinip in
627674 let pgh = pgh -. (cosip *. ph) in
628675 let argpp = argpp +. pgh in
···631678 (ep, inclp, nodep, argpp, mp)
632679 end
633680 else begin
634634- (* Lyddane modification for small inclination *)
635635- let sinop = sin nodep in
636636- let cosop = cos nodep in
637637- let alfdp = sinip *. sinop in
638638- let betdp = sinip *. cosop in
639639- let dalf = (ph *. cosop) +. (pinc *. cosip *. sinop) in
640640- let dbet = (-.ph *. sinop) +. (pinc *. cosip *. cosop) in
641641- let alfdp = alfdp +. dalf in
642642- let betdp = betdp +. dbet in
643643- (* Preserve sign of nodep when normalizing (improved opsmode) *)
644644- let nodep =
645645- if nodep >= 0.0 then Float.rem nodep twopi
646646- else -.(Float.rem (-.nodep) twopi)
681681+ let nodep, argpp, mp =
682682+ dpper_lyddane ~pinc ~pl ~pgh ~ph ~sinip ~cosip ~nodep ~argpp ~mp
647683 in
648648- let xls =
649649- mp +. argpp +. pl +. pgh +. ((cosip -. (pinc *. sinip)) *. nodep)
650650- in
651651- let xnoh = nodep in
652652- let nodep = atan2 alfdp betdp in
653653- (* For improved opsmode, do NOT add twopi for negative nodep *)
654654- let nodep =
655655- if abs_float (xnoh -. nodep) > pi then
656656- if nodep < xnoh then nodep +. twopi else nodep -. twopi
657657- else nodep
658658- in
659659- let mp = mp +. pl in
660660- let argpp = xls -. mp -. (cosip *. nodep) in
661684 (ep, inclp, nodep, argpp, mp)
662685 end
663686664687(** {1 Deep-Space Initialization (_dsinit)} *)
665688666666-let dsinit ~cosim ~emsq ~argpo ~s1 ~s2 ~s3 ~s4 ~s5 ~sinim ~ss1 ~ss2 ~ss3 ~ss4
667667- ~ss5 ~sz1 ~sz3 ~sz11 ~sz13 ~sz21 ~sz23 ~sz31 ~sz33 ~tc ~gsto ~mo ~mdot
668668- ~no_unkozai ~nodeo ~nodedot ~xpidot ~z1 ~z3 ~z11 ~z13 ~z21 ~z23 ~z31 ~z33
669669- ~ecco ~eccsq ~em ~inclm ~nm =
670670- let open Wgs72 in
671671- let _q22 = 1.7891679e-6 in
672672- let q31 = 2.1460748e-6 in
673673- let q33 = 2.2123015e-7 in
674674- let root22 = 1.7891679e-6 in
675675- let root44 = 7.3636953e-9 in
676676- let root54 = 2.1765803e-9 in
677677- let root32 = 3.7393792e-7 in
678678- let root52 = 1.1428639e-7 in
679679- let rptim = 4.37526908801129966e-3 in
689689+(** Solar and lunar secular effects for deep-space initialization. Returns
690690+ (dedt, didt, dmdt, domdt, dnodt). *)
691691+let dsinit_secular_effects ~cosim ~sinim ~emsq ~s1 ~s2 ~s3 ~s4 ~s5 ~ss1 ~ss2
692692+ ~ss3 ~ss4 ~ss5 ~sz1 ~sz3 ~sz11 ~sz13 ~sz21 ~sz23 ~sz31 ~sz33 ~z1 ~z3 ~z11
693693+ ~z13 ~z21 ~z23 ~z31 ~z33 ~inclm =
680694 let znl = 1.5835218e-4 in
681695 let zns = 1.19459e-5 in
682682- (* Determine resonance type *)
683683- let irez =
684684- if nm >= 0.0034906585 && nm < 0.0052359877 then One_day
685685- else if nm >= 8.26e-3 && nm <= 9.24e-3 && em >= 0.5 then Half_day
686686- else No_resonance
687687- in
688696 (* Solar secular effects *)
689697 let ses = ss1 *. zns *. ss5 in
690698 let sis = ss2 *. zns *. (sz11 +. sz13) in
···716724 (domdt -. (cosim /. sinim *. shll), dnodt +. (shll /. sinim))
717725 else (domdt, dnodt)
718726 in
727727+ (dedt, didt, dmdt, domdt, dnodt)
728728+729729+(** 12-hour (half-day) resonance terms. Returns (d2201..d5433, xlamo, xfact). *)
730730+let dsinit_half_day_resonance ~cosim ~sinim ~ecco ~eccsq ~nm ~aonv ~mo ~nodeo
731731+ ~theta ~mdot ~nodedot ~dmdt ~dnodt ~no_unkozai =
732732+ let open Wgs72 in
733733+ let root22 = 1.7891679e-6 in
734734+ let root44 = 7.3636953e-9 in
735735+ let root54 = 2.1765803e-9 in
736736+ let root32 = 3.7393792e-7 in
737737+ let root52 = 1.1428639e-7 in
738738+ let rptim = 4.37526908801129966e-3 in
739739+ let cosisq = cosim *. cosim in
740740+ let em_r = ecco in
741741+ let emsq_r = eccsq in
742742+ let eoc = em_r *. emsq_r in
743743+ let g201 = -0.306 -. ((em_r -. 0.64) *. 0.440) in
744744+ let g211, g310, g322, g410, g422, g520 =
745745+ if em_r <= 0.65 then
746746+ ( 3.616 -. (13.2470 *. em_r) +. (16.2900 *. emsq_r),
747747+ -19.302 +. (117.3900 *. em_r) -. (228.4190 *. emsq_r)
748748+ +. (156.5910 *. eoc),
749749+ -18.9068 +. (109.7927 *. em_r) -. (214.6334 *. emsq_r)
750750+ +. (146.5816 *. eoc),
751751+ -41.122 +. (242.6940 *. em_r) -. (471.0940 *. emsq_r)
752752+ +. (313.9530 *. eoc),
753753+ -146.407 +. (841.8800 *. em_r) -. (1629.014 *. emsq_r)
754754+ +. (1083.4350 *. eoc),
755755+ -532.114 +. (3017.977 *. em_r) -. (5740.032 *. emsq_r)
756756+ +. (3708.2760 *. eoc) )
757757+ else
758758+ ( -72.099 +. (331.819 *. em_r) -. (508.738 *. emsq_r) +. (266.724 *. eoc),
759759+ -346.844 +. (1582.851 *. em_r) -. (2415.925 *. emsq_r)
760760+ +. (1246.113 *. eoc),
761761+ -342.585 +. (1554.908 *. em_r) -. (2366.899 *. emsq_r)
762762+ +. (1215.972 *. eoc),
763763+ -1052.797 +. (4758.686 *. em_r) -. (7193.992 *. emsq_r)
764764+ +. (3651.957 *. eoc),
765765+ -3581.690 +. (16178.110 *. em_r) -. (24462.770 *. emsq_r)
766766+ +. (12422.520 *. eoc),
767767+ if em_r > 0.715 then
768768+ -5149.66 +. (29936.92 *. em_r) -. (54087.36 *. emsq_r)
769769+ +. (31324.56 *. eoc)
770770+ else 1464.74 -. (4664.75 *. em_r) +. (3763.64 *. emsq_r) )
771771+ in
772772+ let g533, g521, g532 =
773773+ if em_r < 0.7 then
774774+ ( -919.22770 +. (4988.6100 *. em_r) -. (9064.7700 *. emsq_r)
775775+ +. (5542.21 *. eoc),
776776+ -822.71072 +. (4568.6173 *. em_r) -. (8491.4146 *. emsq_r)
777777+ +. (5337.524 *. eoc),
778778+ -853.66600 +. (4690.2500 *. em_r) -. (8624.7700 *. emsq_r)
779779+ +. (5341.4 *. eoc) )
780780+ else
781781+ ( -37995.780 +. (161616.52 *. em_r) -. (229838.20 *. emsq_r)
782782+ +. (109377.94 *. eoc),
783783+ -51752.104 +. (218913.95 *. em_r) -. (309468.16 *. emsq_r)
784784+ +. (146349.42 *. eoc),
785785+ -40023.880 +. (170470.89 *. em_r) -. (242699.48 *. emsq_r)
786786+ +. (115605.82 *. eoc) )
787787+ in
788788+ let sini2 = sinim *. sinim in
789789+ let f220 = 0.75 *. (1.0 +. (2.0 *. cosim) +. cosisq) in
790790+ let f221 = 1.5 *. sini2 in
791791+ let f321 = 1.875 *. sinim *. (1.0 -. (2.0 *. cosim) -. (3.0 *. cosisq)) in
792792+ let f322 = -1.875 *. sinim *. (1.0 +. (2.0 *. cosim) -. (3.0 *. cosisq)) in
793793+ let f441 = 35.0 *. sini2 *. f220 in
794794+ let f442 = 39.3750 *. sini2 *. sini2 in
795795+ let f522 =
796796+ 9.84375 *. sinim
797797+ *. ((sini2 *. (1.0 -. (2.0 *. cosim) -. (5.0 *. cosisq)))
798798+ +. (0.33333333 *. (-2.0 +. (4.0 *. cosim) +. (6.0 *. cosisq))))
799799+ in
800800+ let f523 =
801801+ sinim
802802+ *. ((4.92187512 *. sini2 *. (-2.0 -. (4.0 *. cosim) +. (10.0 *. cosisq)))
803803+ +. (6.56250012 *. (1.0 +. (2.0 *. cosim) -. (3.0 *. cosisq))))
804804+ in
805805+ let f542 =
806806+ 29.53125 *. sinim
807807+ *. (2.0 -. (8.0 *. cosim)
808808+ +. (cosisq *. (-12.0 +. (8.0 *. cosim) +. (10.0 *. cosisq))))
809809+ in
810810+ let f543 =
811811+ 29.53125 *. sinim
812812+ *. (-2.0 -. (8.0 *. cosim)
813813+ +. (cosisq *. (12.0 +. (8.0 *. cosim) -. (10.0 *. cosisq))))
814814+ in
815815+ let xno2 = nm *. nm in
816816+ let ainv2 = aonv *. aonv in
817817+ let temp1 = 3.0 *. xno2 *. ainv2 in
818818+ let temp = temp1 *. root22 in
819819+ let d2201 = temp *. f220 *. g201 in
820820+ let d2211 = temp *. f221 *. g211 in
821821+ let temp1 = temp1 *. aonv in
822822+ let temp = temp1 *. root32 in
823823+ let d3210 = temp *. f321 *. g310 in
824824+ let d3222 = temp *. f322 *. g322 in
825825+ let temp1 = temp1 *. aonv in
826826+ let temp = 2.0 *. temp1 *. root44 in
827827+ let d4410 = temp *. f441 *. g410 in
828828+ let d4422 = temp *. f442 *. g422 in
829829+ let temp1 = temp1 *. aonv in
830830+ let temp = temp1 *. root52 in
831831+ let d5220 = temp *. f522 *. g520 in
832832+ let d5232 = temp *. f523 *. g532 in
833833+ let temp = 2.0 *. temp1 *. root54 in
834834+ let d5421 = temp *. f542 *. g521 in
835835+ let d5433 = temp *. f543 *. g533 in
836836+ let xlamo = Float.rem (mo +. nodeo +. nodeo -. theta -. theta) twopi in
837837+ let xfact =
838838+ mdot +. dmdt +. (2.0 *. (nodedot +. dnodt -. rptim)) -. no_unkozai
839839+ in
840840+ ( d2201,
841841+ d2211,
842842+ d3210,
843843+ d3222,
844844+ d4410,
845845+ d4422,
846846+ d5220,
847847+ d5232,
848848+ d5421,
849849+ d5433,
850850+ 0.0,
851851+ 0.0,
852852+ 0.0,
853853+ xlamo,
854854+ xfact )
855855+856856+(** One-day (synchronous) resonance terms. Returns (del1, del2, del3, xlamo,
857857+ xfact). *)
858858+let dsinit_one_day_resonance ~cosim ~sinim ~emsq ~nm ~aonv ~mo ~nodeo ~argpo
859859+ ~theta ~mdot ~xpidot ~dmdt ~domdt ~dnodt ~no_unkozai =
860860+ let _q22 = 1.7891679e-6 in
861861+ let q31 = 2.1460748e-6 in
862862+ let q33 = 2.2123015e-7 in
863863+ let rptim = 4.37526908801129966e-3 in
864864+ let g200 = 1.0 +. (emsq *. (-2.5 +. (0.8125 *. emsq))) in
865865+ let g310 = 1.0 +. (2.0 *. emsq) in
866866+ let g300 = 1.0 +. (emsq *. (-6.0 +. (6.60937 *. emsq))) in
867867+ let f220 = 0.75 *. (1.0 +. cosim) *. (1.0 +. cosim) in
868868+ let f311 =
869869+ (0.9375 *. sinim *. sinim *. (1.0 +. (3.0 *. cosim)))
870870+ -. (0.75 *. (1.0 +. cosim))
871871+ in
872872+ let f330 = 1.0 +. cosim in
873873+ let f330 = 1.875 *. f330 *. f330 *. f330 in
874874+ let del1_v = 3.0 *. nm *. nm *. aonv *. aonv in
875875+ let del2 = 2.0 *. del1_v *. f220 *. g200 *. _q22 in
876876+ let del3 = 3.0 *. del1_v *. f330 *. g300 *. q33 *. aonv in
877877+ let del1 = del1_v *. f311 *. g310 *. q31 *. aonv in
878878+ let xlamo = Float.rem (mo +. nodeo +. argpo -. theta) twopi in
879879+ let xfact = mdot +. xpidot -. rptim +. dmdt +. domdt +. dnodt -. no_unkozai in
880880+ (del1, del2, del3, xlamo, xfact)
881881+882882+let dsinit ~cosim ~emsq ~argpo ~s1 ~s2 ~s3 ~s4 ~s5 ~sinim ~ss1 ~ss2 ~ss3 ~ss4
883883+ ~ss5 ~sz1 ~sz3 ~sz11 ~sz13 ~sz21 ~sz23 ~sz31 ~sz33 ~tc ~gsto ~mo ~mdot
884884+ ~no_unkozai ~nodeo ~nodedot ~xpidot ~z1 ~z3 ~z11 ~z13 ~z21 ~z23 ~z31 ~z33
885885+ ~ecco ~eccsq ~em ~inclm ~nm =
886886+ let open Wgs72 in
887887+ let rptim = 4.37526908801129966e-3 in
888888+ (* Determine resonance type *)
889889+ let irez =
890890+ if nm >= 0.0034906585 && nm < 0.0052359877 then One_day
891891+ else if nm >= 8.26e-3 && nm <= 9.24e-3 && em >= 0.5 then Half_day
892892+ else No_resonance
893893+ in
894894+ (* Secular effects (solar + lunar) *)
895895+ let dedt, didt, dmdt, domdt, dnodt =
896896+ dsinit_secular_effects ~cosim ~sinim ~emsq ~s1 ~s2 ~s3 ~s4 ~s5 ~ss1 ~ss2
897897+ ~ss3 ~ss4 ~ss5 ~sz1 ~sz3 ~sz11 ~sz13 ~sz21 ~sz23 ~sz31 ~sz33 ~z1 ~z3 ~z11
898898+ ~z13 ~z21 ~z23 ~z31 ~z33 ~inclm
899899+ in
719900 let theta = Float.rem (gsto +. (tc *. rptim)) twopi in
720901 (* Resonance terms *)
721721- let d2201 = ref 0.0 in
722722- let d2211 = ref 0.0 in
723723- let d3210 = ref 0.0 in
724724- let d3222 = ref 0.0 in
725725- let d4410 = ref 0.0 in
726726- let d4422 = ref 0.0 in
727727- let d5220 = ref 0.0 in
728728- let d5232 = ref 0.0 in
729729- let d5421 = ref 0.0 in
730730- let d5433 = ref 0.0 in
731731- let del1 = ref 0.0 in
732732- let del2 = ref 0.0 in
733733- let del3 = ref 0.0 in
734734- let xfact = ref 0.0 in
735735- let xlamo = ref 0.0 in
736736- if irez <> No_resonance then begin
737737- let aonv = (nm /. xke) ** x2o3 in
902902+ let ( d2201,
903903+ d2211,
904904+ d3210,
905905+ d3222,
906906+ d4410,
907907+ d4422,
908908+ d5220,
909909+ d5232,
910910+ d5421,
911911+ d5433,
912912+ del1,
913913+ del2,
914914+ del3,
915915+ xlamo,
916916+ xfact ) =
738917 if irez = Half_day then begin
739739- (* 12-hour resonant terms *)
740740- let cosisq = cosim *. cosim in
741741- let em_r = ecco in
742742- let emsq_r = eccsq in
743743- let eoc = em_r *. emsq_r in
744744- let g201 = -0.306 -. ((em_r -. 0.64) *. 0.440) in
745745- let g211, g310, g322, g410, g422, g520 =
746746- if em_r <= 0.65 then
747747- ( 3.616 -. (13.2470 *. em_r) +. (16.2900 *. emsq_r),
748748- -19.302 +. (117.3900 *. em_r) -. (228.4190 *. emsq_r)
749749- +. (156.5910 *. eoc),
750750- -18.9068 +. (109.7927 *. em_r) -. (214.6334 *. emsq_r)
751751- +. (146.5816 *. eoc),
752752- -41.122 +. (242.6940 *. em_r) -. (471.0940 *. emsq_r)
753753- +. (313.9530 *. eoc),
754754- -146.407 +. (841.8800 *. em_r) -. (1629.014 *. emsq_r)
755755- +. (1083.4350 *. eoc),
756756- -532.114 +. (3017.977 *. em_r) -. (5740.032 *. emsq_r)
757757- +. (3708.2760 *. eoc) )
758758- else
759759- ( -72.099 +. (331.819 *. em_r) -. (508.738 *. emsq_r)
760760- +. (266.724 *. eoc),
761761- -346.844 +. (1582.851 *. em_r) -. (2415.925 *. emsq_r)
762762- +. (1246.113 *. eoc),
763763- -342.585 +. (1554.908 *. em_r) -. (2366.899 *. emsq_r)
764764- +. (1215.972 *. eoc),
765765- -1052.797 +. (4758.686 *. em_r) -. (7193.992 *. emsq_r)
766766- +. (3651.957 *. eoc),
767767- -3581.690 +. (16178.110 *. em_r) -. (24462.770 *. emsq_r)
768768- +. (12422.520 *. eoc),
769769- if em_r > 0.715 then
770770- -5149.66 +. (29936.92 *. em_r) -. (54087.36 *. emsq_r)
771771- +. (31324.56 *. eoc)
772772- else 1464.74 -. (4664.75 *. em_r) +. (3763.64 *. emsq_r) )
773773- in
774774- let g533, g521, g532 =
775775- if em_r < 0.7 then
776776- ( -919.22770 +. (4988.6100 *. em_r) -. (9064.7700 *. emsq_r)
777777- +. (5542.21 *. eoc),
778778- -822.71072 +. (4568.6173 *. em_r) -. (8491.4146 *. emsq_r)
779779- +. (5337.524 *. eoc),
780780- -853.66600 +. (4690.2500 *. em_r) -. (8624.7700 *. emsq_r)
781781- +. (5341.4 *. eoc) )
782782- else
783783- ( -37995.780 +. (161616.52 *. em_r) -. (229838.20 *. emsq_r)
784784- +. (109377.94 *. eoc),
785785- -51752.104 +. (218913.95 *. em_r) -. (309468.16 *. emsq_r)
786786- +. (146349.42 *. eoc),
787787- -40023.880 +. (170470.89 *. em_r) -. (242699.48 *. emsq_r)
788788- +. (115605.82 *. eoc) )
789789- in
790790- let sini2 = sinim *. sinim in
791791- let f220 = 0.75 *. (1.0 +. (2.0 *. cosim) +. cosisq) in
792792- let f221 = 1.5 *. sini2 in
793793- let f321 = 1.875 *. sinim *. (1.0 -. (2.0 *. cosim) -. (3.0 *. cosisq)) in
794794- let f322 =
795795- -1.875 *. sinim *. (1.0 +. (2.0 *. cosim) -. (3.0 *. cosisq))
796796- in
797797- let f441 = 35.0 *. sini2 *. f220 in
798798- let f442 = 39.3750 *. sini2 *. sini2 in
799799- let f522 =
800800- 9.84375 *. sinim
801801- *. ((sini2 *. (1.0 -. (2.0 *. cosim) -. (5.0 *. cosisq)))
802802- +. (0.33333333 *. (-2.0 +. (4.0 *. cosim) +. (6.0 *. cosisq))))
803803- in
804804- let f523 =
805805- sinim
806806- *. ((4.92187512 *. sini2 *. (-2.0 -. (4.0 *. cosim) +. (10.0 *. cosisq)))
807807- +. (6.56250012 *. (1.0 +. (2.0 *. cosim) -. (3.0 *. cosisq))))
808808- in
809809- let f542 =
810810- 29.53125 *. sinim
811811- *. (2.0 -. (8.0 *. cosim)
812812- +. (cosisq *. (-12.0 +. (8.0 *. cosim) +. (10.0 *. cosisq))))
813813- in
814814- let f543 =
815815- 29.53125 *. sinim
816816- *. (-2.0 -. (8.0 *. cosim)
817817- +. (cosisq *. (12.0 +. (8.0 *. cosim) -. (10.0 *. cosisq))))
818818- in
819819- let xno2 = nm *. nm in
820820- let ainv2 = aonv *. aonv in
821821- let temp1 = 3.0 *. xno2 *. ainv2 in
822822- let temp = temp1 *. root22 in
823823- d2201 := temp *. f220 *. g201;
824824- d2211 := temp *. f221 *. g211;
825825- let temp1 = temp1 *. aonv in
826826- let temp = temp1 *. root32 in
827827- d3210 := temp *. f321 *. g310;
828828- d3222 := temp *. f322 *. g322;
829829- let temp1 = temp1 *. aonv in
830830- let temp = 2.0 *. temp1 *. root44 in
831831- d4410 := temp *. f441 *. g410;
832832- d4422 := temp *. f442 *. g422;
833833- let temp1 = temp1 *. aonv in
834834- let temp = temp1 *. root52 in
835835- d5220 := temp *. f522 *. g520;
836836- d5232 := temp *. f523 *. g532;
837837- let temp = 2.0 *. temp1 *. root54 in
838838- d5421 := temp *. f542 *. g521;
839839- d5433 := temp *. f543 *. g533;
840840- xlamo := Float.rem (mo +. nodeo +. nodeo -. theta -. theta) twopi;
841841- xfact :=
842842- mdot +. dmdt +. (2.0 *. (nodedot +. dnodt -. rptim)) -. no_unkozai
918918+ let aonv = (nm /. xke) ** x2o3 in
919919+ dsinit_half_day_resonance ~cosim ~sinim ~ecco ~eccsq ~nm ~aonv ~mo ~nodeo
920920+ ~theta ~mdot ~nodedot ~dmdt ~dnodt ~no_unkozai
843921 end
844844- else begin
845845- (* One-day (synchronous) resonance *)
846846- let g200 = 1.0 +. (emsq *. (-2.5 +. (0.8125 *. emsq))) in
847847- let g310 = 1.0 +. (2.0 *. emsq) in
848848- let g300 = 1.0 +. (emsq *. (-6.0 +. (6.60937 *. emsq))) in
849849- let f220 = 0.75 *. (1.0 +. cosim) *. (1.0 +. cosim) in
850850- let f311 =
851851- (0.9375 *. sinim *. sinim *. (1.0 +. (3.0 *. cosim)))
852852- -. (0.75 *. (1.0 +. cosim))
922922+ else if irez = One_day then begin
923923+ let aonv = (nm /. xke) ** x2o3 in
924924+ let del1, del2, del3, xlamo, xfact =
925925+ dsinit_one_day_resonance ~cosim ~sinim ~emsq ~nm ~aonv ~mo ~nodeo ~argpo
926926+ ~theta ~mdot ~xpidot ~dmdt ~domdt ~dnodt ~no_unkozai
853927 in
854854- let f330 = 1.0 +. cosim in
855855- let f330 = 1.875 *. f330 *. f330 *. f330 in
856856- let del1_v = 3.0 *. nm *. nm *. aonv *. aonv in
857857- let del2_v = 2.0 *. del1_v *. f220 *. g200 *. _q22 in
858858- let del3_v = 3.0 *. del1_v *. f330 *. g300 *. q33 *. aonv in
859859- let del1_v = del1_v *. f311 *. g310 *. q31 *. aonv in
860860- xlamo := Float.rem (mo +. nodeo +. argpo -. theta) twopi;
861861- xfact := mdot +. xpidot -. rptim +. dmdt +. domdt +. dnodt -. no_unkozai;
862862- del1 := del1_v;
863863- del2 := del2_v;
864864- del3 := del3_v
928928+ ( 0.0,
929929+ 0.0,
930930+ 0.0,
931931+ 0.0,
932932+ 0.0,
933933+ 0.0,
934934+ 0.0,
935935+ 0.0,
936936+ 0.0,
937937+ 0.0,
938938+ del1,
939939+ del2,
940940+ del3,
941941+ xlamo,
942942+ xfact )
865943 end
866866- end;
867867- let xli = !xlamo in
944944+ else
945945+ (0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
946946+ in
947947+ let xli = xlamo in
868948 let xni = no_unkozai in
869949 ( irez,
870870- !d2201,
871871- !d2211,
872872- !d3210,
873873- !d3222,
874874- !d4410,
875875- !d4422,
876876- !d5220,
877877- !d5232,
878878- !d5421,
879879- !d5433,
950950+ d2201,
951951+ d2211,
952952+ d3210,
953953+ d3222,
954954+ d4410,
955955+ d4422,
956956+ d5220,
957957+ d5232,
958958+ d5421,
959959+ d5433,
880960 dedt,
881961 didt,
882962 dmdt,
883963 dnodt,
884964 domdt,
885885- !del1,
886886- !del2,
887887- !del3,
888888- !xfact,
889889- !xlamo,
965965+ del1,
966966+ del2,
967967+ del3,
968968+ xfact,
969969+ xlamo,
890970 xli,
891971 xni )
892972893973(** {1 Deep-Space Secular Effects (_dspace)} *)
894974895895-let dspace ~irez ~d2201 ~d2211 ~d3210 ~d3222 ~d4410 ~d4422 ~d5220 ~d5232 ~d5421
896896- ~d5433 ~dedt ~del1 ~del2 ~del3 ~didt ~dmdt ~dnodt ~domdt ~argpo ~argpdot ~t
897897- ~tc ~gsto ~xfact ~xlamo ~no ~atime ~em ~argpm ~inclm ~xli ~mm ~xni ~nodem
898898- ~nm =
975975+(** Compute resonance derivatives for one-day (synchronous) resonance. *)
976976+let dspace_one_day_derivs ~del1 ~del2 ~del3 ~xli ~xni ~xfact =
899977 let fasx2 = 0.13130908 in
900978 let fasx4 = 2.8843198 in
901979 let fasx6 = 0.37448087 in
980980+ let xndt =
981981+ (del1 *. sin (xli -. fasx2))
982982+ +. (del2 *. sin (2.0 *. (xli -. fasx4)))
983983+ +. (del3 *. sin (3.0 *. (xli -. fasx6)))
984984+ in
985985+ let xldot = xni +. xfact in
986986+ let xnddt =
987987+ (del1 *. cos (xli -. fasx2))
988988+ +. (2.0 *. del2 *. cos (2.0 *. (xli -. fasx4)))
989989+ +. (3.0 *. del3 *. cos (3.0 *. (xli -. fasx6)))
990990+ in
991991+ (xndt, xnddt *. xldot)
992992+993993+(** Compute resonance derivatives for half-day (12-hour) resonance. *)
994994+let dspace_half_day_derivs ~d2201 ~d2211 ~d3210 ~d3222 ~d4410 ~d4422 ~d5220
995995+ ~d5232 ~d5421 ~d5433 ~argpo ~argpdot ~atime ~xli ~xni ~xfact =
902996 let g22 = 5.7686396 in
903997 let g32 = 0.95240898 in
904998 let g44 = 1.8014998 in
905999 let g52 = 1.0508330 in
9061000 let g54 = 4.4108898 in
10011001+ let xomi = argpo +. (argpdot *. atime) in
10021002+ let x2omi = xomi +. xomi in
10031003+ let x2li = xli +. xli in
10041004+ let xndt =
10051005+ (d2201 *. sin (x2omi +. xli -. g22))
10061006+ +. (d2211 *. sin (xli -. g22))
10071007+ +. (d3210 *. sin (xomi +. xli -. g32))
10081008+ +. (d3222 *. sin (-.xomi +. xli -. g32))
10091009+ +. (d4410 *. sin (x2omi +. x2li -. g44))
10101010+ +. (d4422 *. sin (x2li -. g44))
10111011+ +. (d5220 *. sin (xomi +. xli -. g52))
10121012+ +. (d5232 *. sin (-.xomi +. xli -. g52))
10131013+ +. (d5421 *. sin (xomi +. x2li -. g54))
10141014+ +. (d5433 *. sin (-.xomi +. x2li -. g54))
10151015+ in
10161016+ let xldot = xni +. xfact in
10171017+ let xnddt =
10181018+ (d2201 *. cos (x2omi +. xli -. g22))
10191019+ +. (d2211 *. cos (xli -. g22))
10201020+ +. (d3210 *. cos (xomi +. xli -. g32))
10211021+ +. (d3222 *. cos (-.xomi +. xli -. g32))
10221022+ +. (d5220 *. cos (xomi +. xli -. g52))
10231023+ +. (d5232 *. cos (-.xomi +. xli -. g52))
10241024+ +. 2.0
10251025+ *. ((d4410 *. cos (x2omi +. x2li -. g44))
10261026+ +. (d4422 *. cos (x2li -. g44))
10271027+ +. (d5421 *. cos (xomi +. x2li -. g54))
10281028+ +. (d5433 *. cos (-.xomi +. x2li -. g54)))
10291029+ in
10301030+ (xndt, xnddt *. xldot)
10311031+10321032+let dspace ~irez ~d2201 ~d2211 ~d3210 ~d3222 ~d4410 ~d4422 ~d5220 ~d5232 ~d5421
10331033+ ~d5433 ~dedt ~del1 ~del2 ~del3 ~didt ~dmdt ~dnodt ~domdt ~argpo ~argpdot ~t
10341034+ ~tc ~gsto ~xfact ~xlamo ~no ~atime ~em ~argpm ~inclm ~xli ~mm ~xni ~nodem
10351035+ ~nm =
9071036 let rptim = 4.37526908801129966e-3 in
9081037 let stepp = 720.0 in
9091038 let stepn = -720.0 in
···9291058 let continue_loop = ref true in
9301059 while !continue_loop do
9311060 let xndt, xnddt =
932932- if irez <> Half_day then begin
933933- let xndt =
934934- (del1 *. sin (!xli -. fasx2))
935935- +. (del2 *. sin (2.0 *. (!xli -. fasx4)))
936936- +. (del3 *. sin (3.0 *. (!xli -. fasx6)))
937937- in
938938- let xldot = !xni +. xfact in
939939- let xnddt =
940940- (del1 *. cos (!xli -. fasx2))
941941- +. (2.0 *. del2 *. cos (2.0 *. (!xli -. fasx4)))
942942- +. (3.0 *. del3 *. cos (3.0 *. (!xli -. fasx6)))
943943- in
944944- (xndt, xnddt *. xldot)
945945- end
946946- else begin
947947- let xomi = argpo +. (argpdot *. !atime) in
948948- let x2omi = xomi +. xomi in
949949- let x2li = !xli +. !xli in
950950- let xndt =
951951- (d2201 *. sin (x2omi +. !xli -. g22))
952952- +. (d2211 *. sin (!xli -. g22))
953953- +. (d3210 *. sin (xomi +. !xli -. g32))
954954- +. (d3222 *. sin (-.xomi +. !xli -. g32))
955955- +. (d4410 *. sin (x2omi +. x2li -. g44))
956956- +. (d4422 *. sin (x2li -. g44))
957957- +. (d5220 *. sin (xomi +. !xli -. g52))
958958- +. (d5232 *. sin (-.xomi +. !xli -. g52))
959959- +. (d5421 *. sin (xomi +. x2li -. g54))
960960- +. (d5433 *. sin (-.xomi +. x2li -. g54))
961961- in
962962- let xldot = !xni +. xfact in
963963- let xnddt =
964964- (d2201 *. cos (x2omi +. !xli -. g22))
965965- +. (d2211 *. cos (!xli -. g22))
966966- +. (d3210 *. cos (xomi +. !xli -. g32))
967967- +. (d3222 *. cos (-.xomi +. !xli -. g32))
968968- +. (d5220 *. cos (xomi +. !xli -. g52))
969969- +. (d5232 *. cos (-.xomi +. !xli -. g52))
970970- +. 2.0
971971- *. ((d4410 *. cos (x2omi +. x2li -. g44))
972972- +. (d4422 *. cos (x2li -. g44))
973973- +. (d5421 *. cos (xomi +. x2li -. g54))
974974- +. (d5433 *. cos (-.xomi +. x2li -. g54)))
975975- in
976976- (xndt, xnddt *. xldot)
977977- end
10611061+ if irez <> Half_day then
10621062+ dspace_one_day_derivs ~del1 ~del2 ~del3 ~xli:!xli ~xni:!xni ~xfact
10631063+ else
10641064+ dspace_half_day_derivs ~d2201 ~d2211 ~d3210 ~d3222 ~d4410 ~d4422
10651065+ ~d5220 ~d5232 ~d5421 ~d5433 ~argpo ~argpdot ~atime:!atime ~xli:!xli
10661066+ ~xni:!xni ~xfact
9781067 in
9791068 if abs_float (t -. !atime) >= stepp then begin
9801069 xli := !xli +. ((!xni +. xfact) *. delt) +. (xndt *. step2);
···99710869981087(** {1 SGP4 Initialization} *)
999108810891089+(** Mean motion derivatives: mdot, argpdot, nodedot, xpidot, xhdot1. *)
10901090+let init_mean_motion_derivs ~no_unkozai ~cosio ~cosio2 ~con41 ~con42 ~pinvsq
10911091+ ~rteosq =
10921092+ let open Wgs72 in
10931093+ let cosio4 = cosio2 *. cosio2 in
10941094+ let temp1 = 1.5 *. j2 *. pinvsq *. no_unkozai in
10951095+ let temp2 = 0.5 *. temp1 *. j2 *. pinvsq in
10961096+ let temp3 = -0.46875 *. j4 *. pinvsq *. pinvsq *. no_unkozai in
10971097+ let mdot =
10981098+ no_unkozai
10991099+ +. (0.5 *. temp1 *. rteosq *. con41)
11001100+ +. 0.0625 *. temp2 *. rteosq
11011101+ *. (13.0 -. (78.0 *. cosio2) +. (137.0 *. cosio4))
11021102+ in
11031103+ let argpdot =
11041104+ (-0.5 *. temp1 *. con42)
11051105+ +. (0.0625 *. temp2 *. (7.0 -. (114.0 *. cosio2) +. (395.0 *. cosio4)))
11061106+ +. (temp3 *. (3.0 -. (36.0 *. cosio2) +. (49.0 *. cosio4)))
11071107+ in
11081108+ let xhdot1 = -.temp1 *. cosio in
11091109+ let nodedot =
11101110+ xhdot1
11111111+ +. ((0.5 *. temp2 *. (4.0 -. (19.0 *. cosio2)))
11121112+ +. (2.0 *. temp3 *. (3.0 -. (7.0 *. cosio2))))
11131113+ *. cosio
11141114+ in
11151115+ let xpidot = argpdot +. nodedot in
11161116+ (mdot, argpdot, nodedot, xpidot, xhdot1)
11171117+11181118+(** Compute epoch as days from 1949 Dec 31 0h UT (JD 2433281.5). JD for Jan 0.0
11191119+ of year = 2415020 + 365*(year-1900) + floor((year-1901)/4) - 0.5 Then epoch
11201120+ = JD + epoch_days - 2433281.5 *)
11211121+let init_epoch tle =
11221122+ let year =
11231123+ if tle.epoch_year < 57 then tle.epoch_year + 2000 else tle.epoch_year + 1900
11241124+ in
11251125+ let jd_jan0 =
11261126+ 2415020.0
11271127+ +. (365.0 *. float_of_int (year - 1900))
11281128+ +. floor (float_of_int (year - 1901) /. 4.0)
11291129+ -. 0.5
11301130+ in
11311131+ jd_jan0 +. tle.epoch_days -. 2433281.5
11321132+11331133+(** Drag coefficients: atmosphere parameters based on perigee height. *)
11341134+let init_drag_params ~rp =
11351135+ let open Wgs72 in
11361136+ let ss = (78.0 /. radius_earth_km) +. 1.0 in
11371137+ let qzms2t =
11381138+ let q = (120.0 -. 78.0) /. radius_earth_km in
11391139+ q *. q *. q *. q
11401140+ in
11411141+ let perige = (rp -. 1.0) *. radius_earth_km in
11421142+ let sfour, qzms24 =
11431143+ if perige < 156.0 then begin
11441144+ let ss0 = if perige < 98.0 then 20.0 else perige -. 78.0 in
11451145+ let q = (120.0 -. ss0) /. radius_earth_km in
11461146+ ((ss0 /. radius_earth_km) +. 1.0, q *. q *. q *. q)
11471147+ end
11481148+ else (ss, qzms2t)
11491149+ in
11501150+ (perige, sfour, qzms24)
11511151+11521152+(** Higher-order drag terms (near-earth, non-simplified only). *)
11531153+let init_higher_order_drag ~cc1 ~ao ~tsi ~sfour =
11541154+ let cc1sq = cc1 *. cc1 in
11551155+ let d2 = 4.0 *. ao *. tsi *. cc1sq in
11561156+ let temp = d2 *. tsi *. cc1 /. 3.0 in
11571157+ let d3 = ((17.0 *. ao) +. sfour) *. temp in
11581158+ let d4 =
11591159+ 0.5 *. temp *. ao *. tsi *. (((221.0 *. ao) +. (31.0 *. sfour)) *. cc1)
11601160+ in
11611161+ let t3cof = d2 +. (2.0 *. cc1sq) in
11621162+ let t4cof =
11631163+ 0.25 *. ((3.0 *. d3) +. (cc1 *. ((12.0 *. d2) +. (10.0 *. cc1sq))))
11641164+ in
11651165+ let t5cof =
11661166+ 0.2
11671167+ *. ((3.0 *. d4)
11681168+ +. (12.0 *. cc1 *. d3)
11691169+ +. (6.0 *. d2 *. d2)
11701170+ +. (15.0 *. cc1sq *. ((2.0 *. d2) +. cc1sq)))
11711171+ in
11721172+ (d2, d3, d4, t3cof, t4cof, t5cof)
11731173+11741174+(** Deep-space initialization: compute dscom and dsinit coefficients, build
11751175+ ds_coeffs record. *)
11761176+let init_deep_space_coeffs ~tle ~epoch ~no_unkozai ~gsto ~mdot ~nodedot ~xpidot
11771177+ =
11781178+ let tc = 0.0 in
11791179+ let ( sinim,
11801180+ cosim,
11811181+ emsq,
11821182+ s1,
11831183+ s2,
11841184+ s3,
11851185+ s4,
11861186+ s5,
11871187+ ss1,
11881188+ ss2,
11891189+ ss3,
11901190+ ss4,
11911191+ ss5,
11921192+ sz1,
11931193+ sz3,
11941194+ sz11,
11951195+ sz13,
11961196+ sz21,
11971197+ sz23,
11981198+ sz31,
11991199+ sz33,
12001200+ e3,
12011201+ ee2,
12021202+ se2,
12031203+ se3,
12041204+ sgh2,
12051205+ sgh3,
12061206+ sgh4,
12071207+ sh2,
12081208+ sh3,
12091209+ si2,
12101210+ si3,
12111211+ sl2,
12121212+ sl3,
12131213+ sl4,
12141214+ xgh2,
12151215+ xgh3,
12161216+ xgh4,
12171217+ xh2,
12181218+ xh3,
12191219+ xi2,
12201220+ xi3,
12211221+ xl2,
12221222+ xl3,
12231223+ xl4,
12241224+ _nm,
12251225+ z1,
12261226+ z3,
12271227+ z11,
12281228+ z13,
12291229+ z21,
12301230+ z23,
12311231+ z31,
12321232+ z33,
12331233+ zmol,
12341234+ zmos ) =
12351235+ dscom ~epoch ~ep:tle.ecco ~argpp:tle.argpo ~tc ~inclp:tle.inclo
12361236+ ~nodep:tle.nodeo ~np:no_unkozai
12371237+ in
12381238+ let ds_ecco = tle.ecco in
12391239+ let ds_inclo = tle.inclo in
12401240+ let ds_mo = tle.mo in
12411241+ let ds_argpo = tle.argpo in
12421242+ let ds_nodeo = tle.nodeo in
12431243+ let eccsq = ds_ecco *. ds_ecco in
12441244+ let ( irez,
12451245+ d2201,
12461246+ d2211,
12471247+ d3210,
12481248+ d3222,
12491249+ d4410,
12501250+ d4422,
12511251+ d5220,
12521252+ d5232,
12531253+ d5421,
12541254+ d5433,
12551255+ dedt,
12561256+ didt,
12571257+ dmdt,
12581258+ dnodt,
12591259+ domdt,
12601260+ del1,
12611261+ del2,
12621262+ del3,
12631263+ xfact,
12641264+ xlamo,
12651265+ xli,
12661266+ xni ) =
12671267+ dsinit ~cosim ~emsq ~argpo:ds_argpo ~s1 ~s2 ~s3 ~s4 ~s5 ~sinim ~ss1 ~ss2
12681268+ ~ss3 ~ss4 ~ss5 ~sz1 ~sz3 ~sz11 ~sz13 ~sz21 ~sz23 ~sz31 ~sz33 ~tc ~gsto
12691269+ ~mo:ds_mo ~mdot ~no_unkozai ~nodeo:ds_nodeo ~nodedot ~xpidot ~z1 ~z3 ~z11
12701270+ ~z13 ~z21 ~z23 ~z31 ~z33 ~ecco:ds_ecco ~eccsq ~em:ds_ecco ~inclm:ds_inclo
12711271+ ~nm:no_unkozai
12721272+ in
12731273+ let ds =
12741274+ {
12751275+ ds_e3 = e3;
12761276+ ds_ee2 = ee2;
12771277+ ds_peo = 0.0;
12781278+ ds_pgho = 0.0;
12791279+ ds_pho = 0.0;
12801280+ ds_pinco = 0.0;
12811281+ ds_plo = 0.0;
12821282+ ds_se2 = se2;
12831283+ ds_se3 = se3;
12841284+ ds_sgh2 = sgh2;
12851285+ ds_sgh3 = sgh3;
12861286+ ds_sgh4 = sgh4;
12871287+ ds_sh2 = sh2;
12881288+ ds_sh3 = sh3;
12891289+ ds_si2 = si2;
12901290+ ds_si3 = si3;
12911291+ ds_sl2 = sl2;
12921292+ ds_sl3 = sl3;
12931293+ ds_sl4 = sl4;
12941294+ ds_xgh2 = xgh2;
12951295+ ds_xgh3 = xgh3;
12961296+ ds_xgh4 = xgh4;
12971297+ ds_xh2 = xh2;
12981298+ ds_xh3 = xh3;
12991299+ ds_xi2 = xi2;
13001300+ ds_xi3 = xi3;
13011301+ ds_xl2 = xl2;
13021302+ ds_xl3 = xl3;
13031303+ ds_xl4 = xl4;
13041304+ ds_zmol = zmol;
13051305+ ds_zmos = zmos;
13061306+ ds_irez = irez;
13071307+ ds_d2201 = d2201;
13081308+ ds_d2211 = d2211;
13091309+ ds_d3210 = d3210;
13101310+ ds_d3222 = d3222;
13111311+ ds_d4410 = d4410;
13121312+ ds_d4422 = d4422;
13131313+ ds_d5220 = d5220;
13141314+ ds_d5232 = d5232;
13151315+ ds_d5421 = d5421;
13161316+ ds_d5433 = d5433;
13171317+ ds_dedt = dedt;
13181318+ ds_didt = didt;
13191319+ ds_dmdt = dmdt;
13201320+ ds_dnodt = dnodt;
13211321+ ds_domdt = domdt;
13221322+ ds_del1 = del1;
13231323+ ds_del2 = del2;
13241324+ ds_del3 = del3;
13251325+ ds_xfact = xfact;
13261326+ ds_xlamo = xlamo;
13271327+ ds_xli = xli;
13281328+ ds_xni = xni;
13291329+ ds_atime = 0.0;
13301330+ }
13311331+ in
13321332+ (ds, ds_ecco, ds_inclo, ds_nodeo, ds_argpo, ds_mo)
13331333+10001334let init tle =
10011335 let open Wgs72 in
10021336 if tle.ecco < 0.0 || tle.ecco >= 1.0 then Error Invalid_eccentricity
10031337 else if tle.no <= 0.0 then Error Invalid_mean_motion
10041338 else begin
10051005- (* Compute epoch as days from 1949 Dec 31 0h UT (JD 2433281.5).
10061006- JD for Jan 0.0 of year = 2415020 + 365*(year-1900) + floor((year-1901)/4) - 0.5
10071007- Then epoch = JD + epoch_days - 2433281.5 *)
10081008- let epoch =
10091009- let year =
10101010- if tle.epoch_year < 57 then tle.epoch_year + 2000
10111011- else tle.epoch_year + 1900
10121012- in
10131013- let jd_jan0 =
10141014- 2415020.0
10151015- +. (365.0 *. float_of_int (year - 1900))
10161016- +. floor (float_of_int (year - 1901) /. 4.0)
10171017- -. 0.5
10181018- in
10191019- jd_jan0 +. tle.epoch_days -. 2433281.5
10201020- in
13391339+ let epoch = init_epoch tle in
10211340 let ( no_unkozai,
10221341 ao,
10231342 con41,
···10341353 initl ~no_kozai:tle.no ~ecco:tle.ecco ~epoch ~inclo:tle.inclo
10351354 in
10361355 let isimp = rp < (220.0 /. radius_earth_km) +. 1.0 in
10371037- let ss = (78.0 /. radius_earth_km) +. 1.0 in
10381038- let qzms2t =
10391039- let q = (120.0 -. 78.0) /. radius_earth_km in
10401040- q *. q *. q *. q
10411041- in
10421042- let perige = (rp -. 1.0) *. radius_earth_km in
10431043- let sfour, qzms24 =
10441044- if perige < 156.0 then begin
10451045- let ss0 = if perige < 98.0 then 20.0 else perige -. 78.0 in
10461046- let q = (120.0 -. ss0) /. radius_earth_km in
10471047- ((ss0 /. radius_earth_km) +. 1.0, q *. q *. q *. q)
10481048- end
10491049- else (ss, qzms2t)
10501050- in
13561356+ (* Drag coefficients (ss/qzms2t/perige) *)
13571357+ let _perige, sfour, qzms24 = init_drag_params ~rp in
10511358 let pinvsq = 1.0 /. posq in
10521359 let tsi = 1.0 /. (ao -. sfour) in
10531360 let eta = ao *. tle.ecco *. tsi in
···10841391 2.0 *. coef1 *. ao *. omeosq
10851392 *. (1.0 +. (2.75 *. (etasq +. eeta)) +. (eeta *. etasq))
10861393 in
10871087- let cosio4 = cosio2 *. cosio2 in
10881088- let temp1 = 1.5 *. j2 *. pinvsq *. no_unkozai in
10891089- let temp2 = 0.5 *. temp1 *. j2 *. pinvsq in
10901090- let temp3 = -0.46875 *. j4 *. pinvsq *. pinvsq *. no_unkozai in
10911091- let mdot =
10921092- no_unkozai
10931093- +. (0.5 *. temp1 *. rteosq *. con41)
10941094- +. 0.0625 *. temp2 *. rteosq
10951095- *. (13.0 -. (78.0 *. cosio2) +. (137.0 *. cosio4))
13941394+ let mdot, argpdot, nodedot, xpidot, xhdot1 =
13951395+ init_mean_motion_derivs ~no_unkozai ~cosio ~cosio2 ~con41 ~con42 ~pinvsq
13961396+ ~rteosq
10961397 in
10971097- let argpdot =
10981098- (-0.5 *. temp1 *. con42)
10991099- +. (0.0625 *. temp2 *. (7.0 -. (114.0 *. cosio2) +. (395.0 *. cosio4)))
11001100- +. (temp3 *. (3.0 -. (36.0 *. cosio2) +. (49.0 *. cosio4)))
11011101- in
11021102- let xhdot1 = -.temp1 *. cosio in
11031103- let nodedot =
11041104- xhdot1
11051105- +. ((0.5 *. temp2 *. (4.0 -. (19.0 *. cosio2)))
11061106- +. (2.0 *. temp3 *. (3.0 -. (7.0 *. cosio2))))
11071107- *. cosio
11081108- in
11091109- let xpidot = argpdot +. nodedot in
11101398 let omgcof = tle.bstar *. cc3 *. cos tle.argpo in
11111399 let xmcof =
11121400 if tle.ecco > 1.0e-4 then -.x2o3 *. coef *. tle.bstar /. eeta else 0.0
···11261414 let isimp = if is_deep_space then true else isimp in
11271415 (* Higher-order drag terms (near-earth, non-simplified only) *)
11281416 let d2, d3, d4, t3cof, t4cof, t5cof =
11291129- if (not isimp) && not is_deep_space then begin
11301130- let cc1sq = cc1 *. cc1 in
11311131- let d2 = 4.0 *. ao *. tsi *. cc1sq in
11321132- let temp = d2 *. tsi *. cc1 /. 3.0 in
11331133- let d3 = ((17.0 *. ao) +. sfour) *. temp in
11341134- let d4 =
11351135- 0.5 *. temp *. ao *. tsi *. (((221.0 *. ao) +. (31.0 *. sfour)) *. cc1)
11361136- in
11371137- let t3cof = d2 +. (2.0 *. cc1sq) in
11381138- let t4cof =
11391139- 0.25 *. ((3.0 *. d3) +. (cc1 *. ((12.0 *. d2) +. (10.0 *. cc1sq))))
11401140- in
11411141- let t5cof =
11421142- 0.2
11431143- *. ((3.0 *. d4)
11441144- +. (12.0 *. cc1 *. d3)
11451145- +. (6.0 *. d2 *. d2)
11461146- +. (15.0 *. cc1sq *. ((2.0 *. d2) +. cc1sq)))
11471147- in
11481148- (d2, d3, d4, t3cof, t4cof, t5cof)
11491149- end
14171417+ if (not isimp) && not is_deep_space then
14181418+ init_higher_order_drag ~cc1 ~ao ~tsi ~sfour
11501419 else (0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
11511420 in
11521421 let base_state =
···11901459 ds = None;
11911460 }
11921461 in
14621462+ (* Deep-space setup *)
11931463 if is_deep_space then begin
11941194- let tc = 0.0 in
11951195- let ( sinim,
11961196- cosim,
11971197- emsq,
11981198- s1,
11991199- s2,
12001200- s3,
12011201- s4,
12021202- s5,
12031203- ss1,
12041204- ss2,
12051205- ss3,
12061206- ss4,
12071207- ss5,
12081208- sz1,
12091209- sz3,
12101210- sz11,
12111211- sz13,
12121212- sz21,
12131213- sz23,
12141214- sz31,
12151215- sz33,
12161216- e3,
12171217- ee2,
12181218- se2,
12191219- se3,
12201220- sgh2,
12211221- sgh3,
12221222- sgh4,
12231223- sh2,
12241224- sh3,
12251225- si2,
12261226- si3,
12271227- sl2,
12281228- sl3,
12291229- sl4,
12301230- xgh2,
12311231- xgh3,
12321232- xgh4,
12331233- xh2,
12341234- xh3,
12351235- xi2,
12361236- xi3,
12371237- xl2,
12381238- xl3,
12391239- xl4,
12401240- _nm,
12411241- z1,
12421242- z3,
12431243- z11,
12441244- z13,
12451245- z21,
12461246- z23,
12471247- z31,
12481248- z33,
12491249- zmol,
12501250- zmos ) =
12511251- dscom ~epoch ~ep:tle.ecco ~argpp:tle.argpo ~tc ~inclp:tle.inclo
12521252- ~nodep:tle.nodeo ~np:no_unkozai
12531253- in
12541254- let ds_ecco = tle.ecco in
12551255- let ds_inclo = tle.inclo in
12561256- let ds_mo = tle.mo in
12571257- let ds_argpo = tle.argpo in
12581258- let ds_nodeo = tle.nodeo in
12591259- let eccsq = ds_ecco *. ds_ecco in
12601260- let ( irez,
12611261- d2201,
12621262- d2211,
12631263- d3210,
12641264- d3222,
12651265- d4410,
12661266- d4422,
12671267- d5220,
12681268- d5232,
12691269- d5421,
12701270- d5433,
12711271- dedt,
12721272- didt,
12731273- dmdt,
12741274- dnodt,
12751275- domdt,
12761276- del1,
12771277- del2,
12781278- del3,
12791279- xfact,
12801280- xlamo,
12811281- xli,
12821282- xni ) =
12831283- dsinit ~cosim ~emsq ~argpo:ds_argpo ~s1 ~s2 ~s3 ~s4 ~s5 ~sinim ~ss1 ~ss2
12841284- ~ss3 ~ss4 ~ss5 ~sz1 ~sz3 ~sz11 ~sz13 ~sz21 ~sz23 ~sz31 ~sz33 ~tc ~gsto
12851285- ~mo:ds_mo ~mdot ~no_unkozai ~nodeo:ds_nodeo ~nodedot ~xpidot ~z1 ~z3
12861286- ~z11 ~z13 ~z21 ~z23 ~z31 ~z33 ~ecco:ds_ecco ~eccsq ~em:ds_ecco
12871287- ~inclm:ds_inclo ~nm:no_unkozai
12881288- in
12891289- let ds =
12901290- {
12911291- ds_e3 = e3;
12921292- ds_ee2 = ee2;
12931293- ds_peo = 0.0;
12941294- ds_pgho = 0.0;
12951295- ds_pho = 0.0;
12961296- ds_pinco = 0.0;
12971297- ds_plo = 0.0;
12981298- ds_se2 = se2;
12991299- ds_se3 = se3;
13001300- ds_sgh2 = sgh2;
13011301- ds_sgh3 = sgh3;
13021302- ds_sgh4 = sgh4;
13031303- ds_sh2 = sh2;
13041304- ds_sh3 = sh3;
13051305- ds_si2 = si2;
13061306- ds_si3 = si3;
13071307- ds_sl2 = sl2;
13081308- ds_sl3 = sl3;
13091309- ds_sl4 = sl4;
13101310- ds_xgh2 = xgh2;
13111311- ds_xgh3 = xgh3;
13121312- ds_xgh4 = xgh4;
13131313- ds_xh2 = xh2;
13141314- ds_xh3 = xh3;
13151315- ds_xi2 = xi2;
13161316- ds_xi3 = xi3;
13171317- ds_xl2 = xl2;
13181318- ds_xl3 = xl3;
13191319- ds_xl4 = xl4;
13201320- ds_zmol = zmol;
13211321- ds_zmos = zmos;
13221322- ds_irez = irez;
13231323- ds_d2201 = d2201;
13241324- ds_d2211 = d2211;
13251325- ds_d3210 = d3210;
13261326- ds_d3222 = d3222;
13271327- ds_d4410 = d4410;
13281328- ds_d4422 = d4422;
13291329- ds_d5220 = d5220;
13301330- ds_d5232 = d5232;
13311331- ds_d5421 = d5421;
13321332- ds_d5433 = d5433;
13331333- ds_dedt = dedt;
13341334- ds_didt = didt;
13351335- ds_dmdt = dmdt;
13361336- ds_dnodt = dnodt;
13371337- ds_domdt = domdt;
13381338- ds_del1 = del1;
13391339- ds_del2 = del2;
13401340- ds_del3 = del3;
13411341- ds_xfact = xfact;
13421342- ds_xlamo = xlamo;
13431343- ds_xli = xli;
13441344- ds_xni = xni;
13451345- ds_atime = 0.0;
13461346- }
14641464+ let ds, ds_ecco, ds_inclo, ds_nodeo, ds_argpo, ds_mo =
14651465+ init_deep_space_coeffs ~tle ~epoch ~no_unkozai ~gsto ~mdot ~nodedot
14661466+ ~xpidot
13471467 in
13481468 Ok
13491469 {
···1361148113621482(** {1 SGP4 Propagation} *)
1363148314841484+(** Deep-space secular effects: apply dspace perturbations. *)
14851485+let propagate_deep_space_secular ~ds ~argpo ~argpdot ~tsince ~gsto ~no_unkozai
14861486+ ~argpm ~em ~inclm ~mm ~nodem ~nm =
14871487+ let tc = tsince in
14881488+ let argpm', em', inclm', mm', nodem', nm', _dndt, _atime, _xli, _xni =
14891489+ dspace ~irez:ds.ds_irez ~d2201:ds.ds_d2201 ~d2211:ds.ds_d2211
14901490+ ~d3210:ds.ds_d3210 ~d3222:ds.ds_d3222 ~d4410:ds.ds_d4410
14911491+ ~d4422:ds.ds_d4422 ~d5220:ds.ds_d5220 ~d5232:ds.ds_d5232
14921492+ ~d5421:ds.ds_d5421 ~d5433:ds.ds_d5433 ~dedt:ds.ds_dedt ~del1:ds.ds_del1
14931493+ ~del2:ds.ds_del2 ~del3:ds.ds_del3 ~didt:ds.ds_didt ~dmdt:ds.ds_dmdt
14941494+ ~dnodt:ds.ds_dnodt ~domdt:ds.ds_domdt ~argpo ~argpdot ~t:tsince ~tc ~gsto
14951495+ ~xfact:ds.ds_xfact ~xlamo:ds.ds_xlamo ~no:no_unkozai ~atime:ds.ds_atime
14961496+ ~em ~argpm ~inclm ~xli:ds.ds_xli ~mm ~xni:ds.ds_xni ~nodem ~nm
14971497+ in
14981498+ (argpm', em', inclm', mm', nodem', nm')
14991499+15001500+(** Deep-space lunar-solar periodic corrections. *)
15011501+let propagate_deep_space_periodics ~ds ~tsince ~ep ~xincp ~nodep ~argpp ~mp =
15021502+ let ep', xincp', nodep', argpp', mp' =
15031503+ dpper_apply ~ds ~tsince ~ep ~inclp:xincp ~nodep ~argpp ~mp
15041504+ in
15051505+ let xincp', nodep', argpp' =
15061506+ if xincp' < 0.0 then (-.xincp', nodep' +. pi, argpp' -. pi)
15071507+ else (xincp', nodep', argpp')
15081508+ in
15091509+ (ep', xincp', nodep', argpp', mp')
15101510+15111511+(** Compute position and velocity vectors from short-period corrected orbital
15121512+ elements. *)
15131513+let propagate_orientation ~rl ~rdotl ~rvdotl ~betal ~su ~sin2u ~cos2u ~pl ~nm
15141514+ ~nodep ~xincp ~sinip ~cosip ~method_ ~con41_st ~x1mth2_st ~x7thm1_st =
15151515+ let open Wgs72 in
15161516+ let vkmpersec = radius_earth_km *. xke /. 60.0 in
15171517+ let temp = 1.0 /. pl in
15181518+ let temp1 = 0.5 *. j2 *. temp in
15191519+ let temp2 = temp1 *. temp in
15201520+ let con41, x1mth2, x7thm1 =
15211521+ if method_ = `Deep_space then begin
15221522+ let cosisq = cosip *. cosip in
15231523+ ((3.0 *. cosisq) -. 1.0, 1.0 -. cosisq, (7.0 *. cosisq) -. 1.0)
15241524+ end
15251525+ else (con41_st, x1mth2_st, x7thm1_st)
15261526+ in
15271527+ let mrt =
15281528+ (rl *. (1.0 -. (1.5 *. temp2 *. betal *. con41)))
15291529+ +. (0.5 *. temp1 *. x1mth2 *. cos2u)
15301530+ in
15311531+ let su = su -. (0.25 *. temp2 *. x7thm1 *. sin2u) in
15321532+ let xnode = nodep +. (1.5 *. temp2 *. cosip *. sin2u) in
15331533+ let xinc = xincp +. (1.5 *. temp2 *. cosip *. sinip *. cos2u) in
15341534+ let mvt = rdotl -. (nm *. temp1 *. x1mth2 *. sin2u /. xke) in
15351535+ let rvdot =
15361536+ rvdotl +. (nm *. temp1 *. ((x1mth2 *. cos2u) +. (1.5 *. con41)) /. xke)
15371537+ in
15381538+ let sinsu = sin su in
15391539+ let cossu = cos su in
15401540+ let snod = sin xnode in
15411541+ let cnod = cos xnode in
15421542+ let sini = sin xinc in
15431543+ let cosi = cos xinc in
15441544+ let xmx = -.snod *. cosi in
15451545+ let xmy = cnod *. cosi in
15461546+ let ux = (xmx *. sinsu) +. (cnod *. cossu) in
15471547+ let uy = (xmy *. sinsu) +. (snod *. cossu) in
15481548+ let uz = sini *. sinsu in
15491549+ let vx = (xmx *. cossu) -. (cnod *. sinsu) in
15501550+ let vy = (xmy *. cossu) -. (snod *. sinsu) in
15511551+ let vz = sini *. cossu in
15521552+ let _mr = mrt *. radius_earth_km in
15531553+ let x = _mr *. ux in
15541554+ let y = _mr *. uy in
15551555+ let z = _mr *. uz in
15561556+ let vx_out = ((mvt *. ux) +. (rvdot *. vx)) *. vkmpersec in
15571557+ let vy_out = ((mvt *. uy) +. (rvdot *. vy)) *. vkmpersec in
15581558+ let vz_out = ((mvt *. uz) +. (rvdot *. vz)) *. vkmpersec in
15591559+ if mrt < 1.0 then Error Decayed
15601560+ else Ok ({ x; y; z }, { vx = vx_out; vy = vy_out; vz = vz_out })
15611561+15621562+(** Solve Kepler's equation and compute position/velocity output. *)
15631563+let propagate_kepler_and_output ~am ~ep ~mp ~argpp ~nodep ~xincp ~sinip ~cosip
15641564+ ~aycof ~xlcof ~nm ~method_ ~con41_st ~x1mth2_st ~x7thm1_st =
15651565+ let axnl = ep *. cos argpp in
15661566+ let temp = 1.0 /. (am *. (1.0 -. (ep *. ep))) in
15671567+ let aynl = (ep *. sin argpp) +. (temp *. aycof) in
15681568+ let xl = mp +. argpp +. nodep +. (temp *. xlcof *. axnl) in
15691569+ let u = ref (Float.rem (xl -. nodep) twopi) in
15701570+ let eo1 = ref !u in
15711571+ let converged = ref false in
15721572+ let ktr = ref 1 in
15731573+ while (not !converged) && !ktr <= 10 do
15741574+ let sineo1 = sin !eo1 in
15751575+ let coseo1 = cos !eo1 in
15761576+ let tem5_denom = 1.0 -. (coseo1 *. axnl) -. (sineo1 *. aynl) in
15771577+ let tem5 =
15781578+ (!u -. (aynl *. coseo1) +. (axnl *. sineo1) -. !eo1) /. tem5_denom
15791579+ in
15801580+ let tem5 =
15811581+ if abs_float tem5 >= 0.95 then if tem5 > 0.0 then 0.95 else -0.95
15821582+ else tem5
15831583+ in
15841584+ if abs_float tem5 < 1.0e-12 then converged := true else eo1 := !eo1 +. tem5;
15851585+ ktr := !ktr + 1
15861586+ done;
15871587+ (* Orientation and output *)
15881588+ let sineo1 = sin !eo1 in
15891589+ let coseo1 = cos !eo1 in
15901590+ let ecose = (axnl *. coseo1) +. (aynl *. sineo1) in
15911591+ let esine = (axnl *. sineo1) -. (aynl *. coseo1) in
15921592+ let el2 = (axnl *. axnl) +. (aynl *. aynl) in
15931593+ let pl = am *. (1.0 -. el2) in
15941594+ if pl < 0.0 then Error Decayed
15951595+ else begin
15961596+ let rl = am *. (1.0 -. ecose) in
15971597+ let rdotl = sqrt am *. esine /. rl in
15981598+ let rvdotl = sqrt pl /. rl in
15991599+ let betal = sqrt (1.0 -. el2) in
16001600+ let temp = esine /. (1.0 +. betal) in
16011601+ let sinu = am /. rl *. (sineo1 -. aynl -. (axnl *. temp)) in
16021602+ let cosu = am /. rl *. (coseo1 -. axnl +. (aynl *. temp)) in
16031603+ let su = atan2 sinu cosu in
16041604+ let sin2u = (cosu +. cosu) *. sinu in
16051605+ let cos2u = 1.0 -. (2.0 *. sinu *. sinu) in
16061606+ propagate_orientation ~rl ~rdotl ~rvdotl ~betal ~su ~sin2u ~cos2u ~pl ~nm
16071607+ ~nodep ~xincp ~sinip ~cosip ~method_ ~con41_st ~x1mth2_st ~x7thm1_st
16081608+ end
16091609+13641610let propagate state tle tsince =
13651611 let open Wgs72 in
13661366- let vkmpersec = radius_earth_km *. xke /. 60.0 in
13671612 if not state.initialized then Error Invalid_tle
13681613 else begin
13691614 let ecco = state.init_ecco in
···13731618 let mo = state.init_mo in
13741619 if ecco < 0.0 || ecco >= 1.0 then Error Invalid_eccentricity
13751620 else begin
16211621+ (* Secular effects *)
13761622 let xmdf = mo +. (state.mdot *. tsince) in
13771623 let argpdf = argpo +. (state.argpdot *. tsince) in
13781624 let nodedf = nodeo +. (state.nodedot *. tsince) in
···14071653 (* Deep-space secular effects *)
14081654 (match state.ds with
14091655 | Some ds ->
14101410- let tc = tsince in
14111411- let argpm', em', inclm', mm', nodem', nm', _dndt, _atime, _xli, _xni =
14121412- dspace ~irez:ds.ds_irez ~d2201:ds.ds_d2201 ~d2211:ds.ds_d2211
14131413- ~d3210:ds.ds_d3210 ~d3222:ds.ds_d3222 ~d4410:ds.ds_d4410
14141414- ~d4422:ds.ds_d4422 ~d5220:ds.ds_d5220 ~d5232:ds.ds_d5232
14151415- ~d5421:ds.ds_d5421 ~d5433:ds.ds_d5433 ~dedt:ds.ds_dedt
14161416- ~del1:ds.ds_del1 ~del2:ds.ds_del2 ~del3:ds.ds_del3
14171417- ~didt:ds.ds_didt ~dmdt:ds.ds_dmdt ~dnodt:ds.ds_dnodt
14181418- ~domdt:ds.ds_domdt ~argpo ~argpdot:state.argpdot ~t:tsince ~tc
14191419- ~gsto:state.gsto ~xfact:ds.ds_xfact ~xlamo:ds.ds_xlamo
14201420- ~no:state.no_unkozai ~atime:ds.ds_atime ~em:!em ~argpm:!argpm
14211421- ~inclm:!inclm ~xli:ds.ds_xli ~mm:!mm ~xni:ds.ds_xni ~nodem:!nodem
14221422- ~nm:!nm
16561656+ let argpm', em', inclm', mm', nodem', nm' =
16571657+ propagate_deep_space_secular ~ds ~argpo ~argpdot:state.argpdot
16581658+ ~tsince ~gsto:state.gsto ~no_unkozai:state.no_unkozai
16591659+ ~argpm:!argpm ~em:!em ~inclm:!inclm ~mm:!mm ~nodem:!nodem ~nm:!nm
14231660 in
14241661 argpm := argpm';
14251662 em := em';
14261663 inclm := inclm';
14271664 mm := mm';
14281665 nodem := nodem';
14291429- nm := nm';
14301430- ()
16661666+ nm := nm'
14311667 | None -> ());
14321668 if !nm <= 0.0 then Error Invalid_mean_motion
14331669 else begin
···14541690 (match state.ds with
14551691 | Some ds ->
14561692 let ep', xincp', nodep', argpp', mp' =
14571457- dpper_apply ~ds ~tsince ~ep:!ep ~inclp:!xincp ~nodep:!nodep
14581458- ~argpp:!argpp ~mp:!mp
16931693+ propagate_deep_space_periodics ~ds ~tsince ~ep:!ep ~xincp:!xincp
16941694+ ~nodep:!nodep ~argpp:!argpp ~mp:!mp
14591695 in
14601696 ep := ep';
14611697 xincp := xincp';
14621698 nodep := nodep';
14631699 argpp := argpp';
14641464- mp := mp';
14651465- if !xincp < 0.0 then begin
14661466- xincp := -. !xincp;
14671467- nodep := !nodep +. pi;
14681468- argpp := !argpp -. pi
14691469- end
17001700+ mp := mp'
14701701 | None -> ());
14711702 if !ep < 0.0 || !ep > 1.0 then Error Invalid_eccentricity
14721703 else begin
···14911722 /. 1.5e-12
14921723 else state.xlcof
14931724 in
14941494- let axnl = !ep *. cos !argpp in
14951495- let temp = 1.0 /. (am *. (1.0 -. (!ep *. !ep))) in
14961496- let aynl = (!ep *. sin !argpp) +. (temp *. aycof) in
14971497- let xl = !mp +. !argpp +. !nodep +. (temp *. xlcof *. axnl) in
14981498- let u = ref (Float.rem (xl -. !nodep) twopi) in
14991499- let eo1 = ref !u in
15001500- let converged = ref false in
15011501- let ktr = ref 1 in
15021502- while (not !converged) && !ktr <= 10 do
15031503- let sineo1 = sin !eo1 in
15041504- let coseo1 = cos !eo1 in
15051505- let tem5_denom = 1.0 -. (coseo1 *. axnl) -. (sineo1 *. aynl) in
15061506- let tem5 =
15071507- (!u -. (aynl *. coseo1) +. (axnl *. sineo1) -. !eo1)
15081508- /. tem5_denom
15091509- in
15101510- let tem5 =
15111511- if abs_float tem5 >= 0.95 then
15121512- if tem5 > 0.0 then 0.95 else -0.95
15131513- else tem5
15141514- in
15151515- if abs_float tem5 < 1.0e-12 then converged := true
15161516- else eo1 := !eo1 +. tem5;
15171517- ktr := !ktr + 1
15181518- done;
15191519- let sineo1 = sin !eo1 in
15201520- let coseo1 = cos !eo1 in
15211521- let ecose = (axnl *. coseo1) +. (aynl *. sineo1) in
15221522- let esine = (axnl *. sineo1) -. (aynl *. coseo1) in
15231523- let el2 = (axnl *. axnl) +. (aynl *. aynl) in
15241524- let pl = am *. (1.0 -. el2) in
15251525- if pl < 0.0 then Error Decayed
15261526- else begin
15271527- let rl = am *. (1.0 -. ecose) in
15281528- let rdotl = sqrt am *. esine /. rl in
15291529- let rvdotl = sqrt pl /. rl in
15301530- let betal = sqrt (1.0 -. el2) in
15311531- let temp = esine /. (1.0 +. betal) in
15321532- let sinu = am /. rl *. (sineo1 -. aynl -. (axnl *. temp)) in
15331533- let cosu = am /. rl *. (coseo1 -. axnl +. (aynl *. temp)) in
15341534- let su = atan2 sinu cosu in
15351535- let sin2u = (cosu +. cosu) *. sinu in
15361536- let cos2u = 1.0 -. (2.0 *. sinu *. sinu) in
15371537- let temp = 1.0 /. pl in
15381538- let temp1 = 0.5 *. j2 *. temp in
15391539- let temp2 = temp1 *. temp in
15401540- let con41, x1mth2, x7thm1 =
15411541- if state.method_ = `Deep_space then begin
15421542- let cosisq = !cosip *. !cosip in
15431543- ((3.0 *. cosisq) -. 1.0, 1.0 -. cosisq, (7.0 *. cosisq) -. 1.0)
15441544- end
15451545- else (state.con41, state.x1mth2, state.x7thm1)
15461546- in
15471547- let mrt =
15481548- (rl *. (1.0 -. (1.5 *. temp2 *. betal *. con41)))
15491549- +. (0.5 *. temp1 *. x1mth2 *. cos2u)
15501550- in
15511551- let su = su -. (0.25 *. temp2 *. x7thm1 *. sin2u) in
15521552- let xnode = !nodep +. (1.5 *. temp2 *. !cosip *. sin2u) in
15531553- let xinc =
15541554- !xincp +. (1.5 *. temp2 *. !cosip *. !sinip *. cos2u)
15551555- in
15561556- let mvt = rdotl -. (!nm *. temp1 *. x1mth2 *. sin2u /. xke) in
15571557- let rvdot =
15581558- rvdotl
15591559- +. (!nm *. temp1 *. ((x1mth2 *. cos2u) +. (1.5 *. con41)) /. xke)
15601560- in
15611561- let sinsu = sin su in
15621562- let cossu = cos su in
15631563- let snod = sin xnode in
15641564- let cnod = cos xnode in
15651565- let sini = sin xinc in
15661566- let cosi = cos xinc in
15671567- let xmx = -.snod *. cosi in
15681568- let xmy = cnod *. cosi in
15691569- let ux = (xmx *. sinsu) +. (cnod *. cossu) in
15701570- let uy = (xmy *. sinsu) +. (snod *. cossu) in
15711571- let uz = sini *. sinsu in
15721572- let vx = (xmx *. cossu) -. (cnod *. sinsu) in
15731573- let vy = (xmy *. cossu) -. (snod *. sinsu) in
15741574- let vz = sini *. cossu in
15751575- let _mr = mrt *. radius_earth_km in
15761576- let x = _mr *. ux in
15771577- let y = _mr *. uy in
15781578- let z = _mr *. uz in
15791579- let vx_out = ((mvt *. ux) +. (rvdot *. vx)) *. vkmpersec in
15801580- let vy_out = ((mvt *. uy) +. (rvdot *. vy)) *. vkmpersec in
15811581- let vz_out = ((mvt *. uz) +. (rvdot *. vz)) *. vkmpersec in
15821582- if mrt < 1.0 then Error Decayed
15831583- else Ok ({ x; y; z }, { vx = vx_out; vy = vy_out; vz = vz_out })
15841584- end
17251725+ (* Kepler equation solution and output *)
17261726+ propagate_kepler_and_output ~am ~ep:!ep ~mp:!mp ~argpp:!argpp
17271727+ ~nodep:!nodep ~xincp:!xincp ~sinip:!sinip ~cosip:!cosip ~aycof
17281728+ ~xlcof ~nm:!nm ~method_:state.method_ ~con41_st:state.con41
17291729+ ~x1mth2_st:state.x1mth2 ~x7thm1_st:state.x7thm1
15851730 end
15861731 end
15871732 end