From 833be7b293729b2828a159f516acaf26cbde1c81 Mon Sep 17 00:00:00 2001 From: Tony Garnock-Jones Date: Mon, 6 Feb 2023 14:48:18 +0100 Subject: [PATCH] Update attenuations --- syndicate-server/src/script/mod.rs | 184 ++++++++++++++++++----------- syndicate/src/actor.rs | 10 +- syndicate/src/relay.rs | 2 +- syndicate/src/rewrite.rs | 68 +++++++---- syndicate/src/sturdy.rs | 29 +++-- 5 files changed, 177 insertions(+), 116 deletions(-) diff --git a/syndicate-server/src/script/mod.rs b/syndicate-server/src/script/mod.rs index 5438f1c..09ebe97 100644 --- a/syndicate-server/src/script/mod.rs +++ b/syndicate-server/src/script/mod.rs @@ -101,7 +101,7 @@ pub enum Expr { #[derive(Debug, Clone)] enum RewriteTemplate { - Filter { + Accept { pattern_template: AnyValue, }, Rewrite { @@ -110,6 +110,16 @@ enum RewriteTemplate { }, } +#[derive(Debug, Clone)] +enum CaveatTemplate { + Alts { + alternatives: Vec, + }, + Reject { + pattern_template: AnyValue, + }, +} + #[derive(Debug)] enum Symbolic { Reference(String), @@ -174,55 +184,77 @@ fn tlit(value: AnyValue) -> sturdy::Template { sturdy::Template::Lit(Box::new(sturdy::Lit { value })) } -fn parse_attenuation(r: &Record) -> io::Result)>> { +fn parse_rewrite(raw_base_name: &AnyValue, e: &AnyValue) -> io::Result { + if let Some(fields) = e.value().as_simple_record("accept", Some(1)) { + return Ok(RewriteTemplate::Accept { + pattern_template: fields[0].clone(), + }); + } + + if let Some(fields) = e.value().as_simple_record("rewrite", Some(2)) { + return Ok(RewriteTemplate::Rewrite { + pattern_template: fields[0].clone(), + template_template: fields[1].clone(), + }); + } + + Err(bad_instruction(&format!("Bad rewrite in attenuation of {:?}: {:?}", raw_base_name, e))) +} + +fn parse_caveat(raw_base_name: &AnyValue, e: &AnyValue) -> io::Result { + if let Some(fields) = e.value().as_simple_record("or", Some(1)) { + let raw_rewrites = match fields[0].value().as_sequence() { + None => Err(bad_instruction(&format!( + "Alternatives in in attenuation of {:?} must have sequence of rewrites; got {:?}", + raw_base_name, + fields[0])))?, + Some(vs) => vs, + }; + let alternatives = + raw_rewrites.iter().map(|r| parse_rewrite(raw_base_name, r)).collect::, _>>()?; + return Ok(CaveatTemplate::Alts{ alternatives }); + } + + if let Some(fields) = e.value().as_simple_record("reject", Some(1)) { + return Ok(CaveatTemplate::Reject{ pattern_template: fields[0].clone() }); + } + + if let Ok(r) = parse_rewrite(raw_base_name, e) { + return Ok(CaveatTemplate::Alts { alternatives: vec![r] }); + } + + Err(bad_instruction(&format!("Bad caveat in attenuation of {:?}: {:?}", raw_base_name, e))) +} + +fn parse_attenuation(r: &Record) -> io::Result)>> { if r.label() != &AnyValue::symbol("*") { return Ok(None); } if r.fields().len() != 2 { Err(bad_instruction(&format!( - "Attenuation requires a reference and a sequence of rewrites; got {:?}", + "Attenuation requires a reference and a sequence of caveats; got {:?}", r)))?; } - let base_name = match r.fields()[0].value().as_symbol().map(|s| analyze(&s)) { + let raw_base_name = &r.fields()[0]; + let base_name = match raw_base_name.value().as_symbol().map(|s| analyze(&s)) { Some(Symbolic::Reference(s)) => s, _ => Err(bad_instruction(&format!( "Attenuation must have variable reference as first argument; got {:?}", - r.fields()[0])))?, + raw_base_name)))?, }; - let raw_alternatives = match r.fields()[1].value().as_sequence() { + let raw_caveats = match r.fields()[1].value().as_sequence() { None => Err(bad_instruction(&format!( - "Attenuation of {:?} must have sequence of rewrites; got {:?}", - r.fields()[0], + "Attenuation of {:?} must have sequence of caveats; got {:?}", + raw_base_name, r.fields()[1])))?, Some(vs) => vs, }; - let mut alternatives = Vec::new(); - - for e in raw_alternatives.iter() { - match e.value().as_simple_record("filter", Some(1)) { - Some(fields) => - alternatives.push(RewriteTemplate::Filter { - pattern_template: fields[0].clone() - }), - None => match e.value().as_simple_record("rewrite", Some(2)) { - Some(fields) => - alternatives.push(RewriteTemplate::Rewrite { - pattern_template: fields[0].clone(), - template_template: fields[1].clone(), - }), - None => Err(bad_instruction(&format!( - "Bad rewrite in attenuation of {:?}: {:?}", - r.fields()[0], - e)))?, - } - } - } - - Ok(Some((base_name, alternatives))) + let caveats = raw_caveats.iter().map(|c| parse_caveat(raw_base_name, c)).collect::, _>>()?; + Ok(Some((base_name, caveats))) } impl<'env> PatternInstantiator<'env> { @@ -250,8 +282,8 @@ impl<'env> PatternInstantiator<'env> { }, Value::Record(r) => match parse_attenuation(r)? { - Some((base_name, alternatives)) => - dlit(self.env.eval_attenuation(base_name, alternatives)?), + Some((base_name, caveats)) => + dlit(self.env.eval_attenuation(base_name, caveats)?), None => match self.maybe_binder_with_pattern(r)? { Some(pat) => pat, None => { @@ -359,8 +391,8 @@ impl Env { }, Value::Record(r) => match parse_attenuation(r)? { - Some((base_name, alternatives)) => - self.eval_attenuation(base_name, alternatives)?, + Some((base_name, caveats)) => + self.eval_attenuation(base_name, caveats)?, None => Value::Record(Record(r.fields_vec().iter().map(|a| self.instantiate_value(a)) .collect::, _>>()?)).wrap(), @@ -398,7 +430,7 @@ impl Env { fn eval_attenuation( &self, base_name: String, - alternatives: Vec, + caveats: Vec, ) -> io::Result { let base_value = self.lookup(&base_name, "attenuation-base variable")?; match base_value.value().as_embedded() { @@ -406,9 +438,7 @@ impl Env { "Value to be attenuated is {:?} but must be capability", base_value))), Some(base_cap) => { - match base_cap.attenuate(&sturdy::Attenuation(vec![ - self.instantiate_caveat(&alternatives)?])) - { + match base_cap.attenuate(&caveats.iter().map(|c| self.instantiate_caveat(c)).collect::, _>>()?) { Ok(derived_cap) => Ok(AnyValue::domain(derived_cap)), Err(caveat_error) => Err(bad_instruction(&format!("Attenuation of {:?} failed: {:?}", @@ -517,35 +547,50 @@ impl Env { } } - fn instantiate_caveat( + fn instantiate_rewrite( &self, - alternatives: &Vec, - ) -> io::Result { - let mut rewrites = Vec::new(); - for rw in alternatives { - match rw { - RewriteTemplate::Filter { pattern_template } => { - let (_binding_names, pattern) = self.instantiate_pattern(pattern_template)?; - rewrites.push(sturdy::Rewrite { - pattern: embed_pattern(&P::Pattern::DBind(Box::new(P::DBind { pattern }))), - template: sturdy::Template::TRef(Box::new(sturdy::TRef { binding: 0.into() })), - }) - } - RewriteTemplate::Rewrite { pattern_template, template_template } => { - let (binding_names, pattern) = self.instantiate_pattern(pattern_template)?; - rewrites.push(sturdy::Rewrite { - pattern: embed_pattern(&pattern), - template: self.instantiate_template(&binding_names, template_template)?, - }) - } + rw: &RewriteTemplate, + ) -> io::Result { + match rw { + RewriteTemplate::Accept { pattern_template } => { + let (_binding_names, pattern) = self.instantiate_pattern(pattern_template)?; + Ok(sturdy::Rewrite { + pattern: embed_pattern(&P::Pattern::DBind(Box::new(P::DBind { pattern }))), + template: sturdy::Template::TRef(Box::new(sturdy::TRef { binding: 0.into() })), + }) + } + RewriteTemplate::Rewrite { pattern_template, template_template } => { + let (binding_names, pattern) = self.instantiate_pattern(pattern_template)?; + Ok(sturdy::Rewrite { + pattern: embed_pattern(&pattern), + template: self.instantiate_template(&binding_names, template_template)?, + }) } } - if rewrites.len() == 1 { - Ok(sturdy::Caveat::Rewrite(Box::new(rewrites.pop().unwrap()))) - } else { - Ok(sturdy::Caveat::Alts(Box::new(sturdy::Alts { - alternatives: rewrites, - }))) + } + + fn instantiate_caveat( + &self, + c: &CaveatTemplate, + ) -> io::Result { + match c { + CaveatTemplate::Alts { alternatives } => { + let mut rewrites = + alternatives.iter().map(|r| self.instantiate_rewrite(r)).collect::, _>>()?; + if rewrites.len() == 1 { + Ok(sturdy::Caveat::Rewrite(Box::new(rewrites.pop().unwrap()))) + } else { + Ok(sturdy::Caveat::Alts(Box::new(sturdy::Alts { + alternatives: rewrites, + }))) + } + } + CaveatTemplate::Reject { pattern_template } => { + Ok(sturdy::Caveat::Reject(Box::new( + sturdy::Reject { + pattern: embed_pattern(&self.instantiate_pattern(pattern_template)?.1), + }))) + } } } @@ -584,18 +629,19 @@ impl Env { }, Value::Record(r) => match parse_attenuation(r)? { - Some((base_name, alternatives)) => + Some((base_name, caveats)) => match find_bound(&base_name) { Some(i) => sturdy::Template::TAttenuate(Box::new(sturdy::TAttenuate { template: sturdy::Template::TRef(Box::new(sturdy::TRef { binding: i.into(), })), - attenuation: sturdy::Attenuation(vec![ - self.instantiate_caveat(&alternatives)?]), + attenuation: caveats.iter() + .map(|c| self.instantiate_caveat(c)) + .collect::, _>>()?, })), None => - tlit(self.eval_attenuation(base_name, alternatives)?), + tlit(self.eval_attenuation(base_name, caveats)?), }, None => { // TODO: properly consolidate constant templates into literals. diff --git a/syndicate/src/actor.rs b/syndicate/src/actor.rs index 6f9ae92..1b5c61f 100644 --- a/syndicate/src/actor.rs +++ b/syndicate/src/actor.rs @@ -2270,11 +2270,11 @@ impl Cap { } /// Yields a fresh `Cap` for `self`'s `underlying`, copying the - /// existing attenuation of `self` to the new `Cap` and adding - /// `attenuation` to it. - pub fn attenuate(&self, attenuation: &sturdy::Attenuation) -> Result, CaveatError> { + /// existing attenuation of `self` to the new `Cap` and adding the + /// `caveats` to it. + pub fn attenuate(&self, caveats: &[sturdy::Caveat]) -> Result, CaveatError> { let mut r = Cap { attenuation: self.attenuation.clone(), .. self.clone() }; - r.attenuation.extend(attenuation.check()?); + r.attenuation.extend(sturdy::Caveat::check_many(caveats)?); Ok(Arc::new(r)) } @@ -2282,7 +2282,7 @@ impl Cap { /// `a` is filtered out, or `Some(_)` if it is accepted (and /// possibly transformed). pub fn rewrite(&self, mut a: AnyValue) -> Option { - for c in &self.attenuation { + for c in self.attenuation.iter().rev() { match c.rewrite(&a) { Some(v) => a = v, None => return None, diff --git a/syndicate/src/relay.rs b/syndicate/src/relay.rs index 42e9ca0..5c5eb81 100644 --- a/syndicate/src/relay.rs +++ b/syndicate/src/relay.rs @@ -580,7 +580,7 @@ impl Membranes { match self.exported.oid_map.get(&oid) { None => self.exported.insert_inert_entity(t, oid), Some(ws) => { - let attenuated_obj = ws.obj.attenuate(&sturdy::Attenuation(attenuation)) + let attenuated_obj = ws.obj.attenuate(&attenuation) .map_err(|e| { io::Error::new( io::ErrorKind::InvalidInput, diff --git a/syndicate/src/rewrite.rs b/syndicate/src/rewrite.rs index f1cdc16..12ef60a 100644 --- a/syndicate/src/rewrite.rs +++ b/syndicate/src/rewrite.rs @@ -16,7 +16,10 @@ pub type CheckedRewrite = (usize, Pattern, Template); /// A safety-checked [`Caveat`]: none of the errors enumerated in /// `CaveatError` apply. #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub struct CheckedCaveat { alts: Vec } +pub enum CheckedCaveat { + Alts(Vec), + Reject(Pattern), +} /// Represents any detected error in a [`Caveat`]; that is, in a /// [`Pattern`] or a [`Template`]. @@ -28,43 +31,44 @@ pub enum CaveatError { BindingUnderNegation, } -impl Attenuation { - /// Yields `Ok(())` iff `self` has no [`CaveatError`]. - pub fn validate(&self) -> Result<(), CaveatError> { - for c in &self.0 { c.validate()? } +impl Caveat { + /// Yields `Ok(())` iff `caveats` have no [`CaveatError`]. + pub fn validate_many(caveats: &[Caveat]) -> Result<(), CaveatError> { + for c in caveats { c.validate()? } Ok(()) } - /// Yields a vector of [`CheckedCaveat`s][CheckedCaveat] iff - /// `self` has no [`CaveatError`]. - pub fn check(&self) -> Result, CaveatError> { - self.0.iter().map(Caveat::check).collect() - } -} - -impl Caveat { /// Yields `Ok(())` iff `self` has no [`CaveatError`]. pub fn validate(&self) -> Result<(), CaveatError> { match self { Caveat::Rewrite(b) => (&**b).validate(), Caveat::Alts(b) => (&**b).alternatives.iter().map(Rewrite::validate).collect::>(), + Caveat::Reject(_) => Ok(()), + Caveat::Unknown(_) => Ok(()), /* it's valid to have unknown caveats, they just won't pass anything */ } } + /// Yields a vector of [`CheckedCaveat`s][CheckedCaveat] iff + /// `caveats` have no [`CaveatError`]. + pub fn check_many(caveats: &[Caveat]) -> Result, CaveatError> { + caveats.iter().map(Caveat::check).collect() + } + /// Yields a [`CheckedCaveat`] iff `self` has no [`CaveatError`]. pub fn check(&self) -> Result { match self { Caveat::Rewrite(b) => - Ok(CheckedCaveat { - alts: vec![ (*b).check()? ] - }), + Ok(CheckedCaveat::Alts(vec![ (*b).check()? ])), Caveat::Alts(b) => { let Alts { alternatives } = &**b; - Ok(CheckedCaveat { - alts: alternatives.into_iter().map(Rewrite::check) - .collect::, CaveatError>>()? - }) + Ok(CheckedCaveat::Alts( + alternatives.into_iter().map(Rewrite::check) + .collect::, CaveatError>>()?)) } + Caveat::Reject(b) => + Ok(CheckedCaveat::Reject(b.pattern.clone())), + Caveat::Unknown(_) => + Ok(CheckedCaveat::Reject(Pattern::PDiscard(Box::new(PDiscard)))), } } } @@ -187,7 +191,7 @@ impl Template { match self { Template::TAttenuate(b) => { let TAttenuate { template, attenuation } = &**b; - attenuation.validate()?; + Caveat::validate_many(attenuation)?; Ok(template.implied_binding_count()?) } Template::TRef(b) => match usize::try_from(&(&**b).binding) { @@ -273,12 +277,24 @@ impl Rewrite { impl CheckedCaveat { /// Rewrites `a` using the patterns/templates contained in `self`. pub fn rewrite(&self, a: &_Any) -> Option<_Any> { - for (n, p, t) in &self.alts { - let mut bindings = Vec::with_capacity(*n); - if let true = p.matches(a, &mut bindings) { - return t.instantiate(&bindings); + match self { + CheckedCaveat::Alts(alts) => { + for (n, p, t) in alts { + let mut bindings = Vec::with_capacity(*n); + if p.matches(a, &mut bindings) { + return t.instantiate(&bindings); + } + } + None + }, + CheckedCaveat::Reject(pat) => { + let mut bindings = Vec::with_capacity(0); + if pat.matches(a, &mut bindings) { + None + } else { + Some(a.clone()) + } } } - None } } diff --git a/syndicate/src/sturdy.rs b/syndicate/src/sturdy.rs index 08a7cce..82aee5c 100644 --- a/syndicate/src/sturdy.rs +++ b/syndicate/src/sturdy.rs @@ -48,6 +48,14 @@ fn signature(key: &[u8], data: &[u8]) -> Vec { result } +fn chain_signature(key: &[u8], chain: &[Caveat]) -> Vec { + let mut key = key.to_vec(); + for c in chain { + key = signature(&key, &encode(&language().unparse(c))); + } + key +} + pub fn new_key() -> Vec { let mut buf = vec![0; KEY_LENGTH]; getrandom(&mut buf).expect("successful random number generation"); @@ -83,24 +91,15 @@ impl SturdyRef { unattenuated_target: &_Ptr, ) -> Result<_Ptr, ValidationError> { self.validate(key).map_err(ValidationError::SignatureError)?; - let mut attenuation = Vec::new(); - // TODO:: Make sure of the ordering here!! - for a in self.caveat_chain.iter().rev() { - attenuation.extend(a.0.iter().rev().cloned()); - } let target = unattenuated_target - .attenuate(&Attenuation(attenuation)) + .attenuate(&self.caveat_chain) .map_err(ValidationError::AttenuationError)?; Ok(target) } pub fn validate(&self, key: &[u8]) -> Result<(), MacError> { let SturdyRef { oid, caveat_chain, sig } = self; - let mut key = key.to_vec(); - key = signature(&key, &encode(oid)); - for c in caveat_chain { - key = signature(&key, &encode(&language().unparse(c))); - } + let key = chain_signature(&signature(&key, &encode(oid)), caveat_chain); if &key == sig { Ok(()) } else { @@ -108,13 +107,13 @@ impl SturdyRef { } } - pub fn attenuate(&self, attenuation: &Attenuation) -> Result { - attenuation.validate()?; + pub fn attenuate(&self, attenuation: &[Caveat]) -> Result { + Caveat::validate_many(attenuation)?; let SturdyRef { oid, caveat_chain, sig } = self; let oid = oid.clone(); let mut caveat_chain = caveat_chain.clone(); - caveat_chain.push(attenuation.clone()); - let sig = signature(&sig, &encode(&language().unparse(attenuation))); + caveat_chain.extend(attenuation.iter().cloned()); + let sig = chain_signature(&sig, attenuation); Ok(SturdyRef { oid, caveat_chain, sig }) } }