Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update #75

Merged
merged 8 commits into from
Dec 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
<maven-compiler-plugin.version>3.10.0</maven-compiler-plugin.version>

<!-- dependencies -->
<protobuf-java.version>3.16.3</protobuf-java.version>
<protobuf-java.version>3.25.0</protobuf-java.version>
<net.i2p.crypto.eddsa.version>0.3.0</net.i2p.crypto.eddsa.version>
<vavr.version>0.10.3</vavr.version>
<re2j.version>1.6</re2j.version>
Expand Down
88 changes: 88 additions & 0 deletions schema.proto
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ message SignedBlock {
required bytes block = 1;
required PublicKey nextKey = 2;
required bytes signature = 3;
optional ExternalSignature externalSignature = 4;
}

message ExternalSignature {
required bytes signature = 1;
required PublicKey publicKey = 2;
}

message PublicKey {
Expand Down Expand Up @@ -40,6 +46,20 @@ message Block {
repeated FactV2 facts_v2 = 4;
repeated RuleV2 rules_v2 = 5;
repeated CheckV2 checks_v2 = 6;
repeated Scope scope = 7;
repeated PublicKey publicKeys = 8;
}

message Scope {
enum ScopeType {
Authority = 0;
Previous = 1;
}

oneof Content {
ScopeType scopeType = 1;
int64 publicKey = 2;
}
}

message FactV2 {
Expand All @@ -50,10 +70,17 @@ message RuleV2 {
required PredicateV2 head = 1;
repeated PredicateV2 body = 2;
repeated ExpressionV2 expressions = 3;
repeated Scope scope = 4;
}

message CheckV2 {
repeated RuleV2 queries = 1;
optional Kind kind = 2;

enum Kind {
One = 0;
All = 1;
}
}

message PredicateV2 {
Expand Down Expand Up @@ -118,6 +145,10 @@ message OpBinary {
Or = 14;
Intersection = 15;
Union = 16;
BitwiseAnd = 17;
BitwiseOr = 18;
BitwiseXor = 19;
NotEqual = 20;
}

required Kind kind = 1;
Expand All @@ -141,3 +172,60 @@ message AuthorizerPolicies {
repeated CheckV2 checks = 5;
repeated Policy policies = 6;
}

message ThirdPartyBlockRequest {
required PublicKey previousKey = 1;
repeated PublicKey publicKeys = 2;
}

message ThirdPartyBlockContents {
required bytes payload = 1;
required ExternalSignature externalSignature = 2;
}

message AuthorizerSnapshot {
required RunLimits limits = 1;
required uint64 executionTime = 2;
required AuthorizerWorld world = 3;
}

message RunLimits {
required uint64 maxFacts = 1;
required uint64 maxIterations = 2;
required uint64 maxTime = 3;
}

message AuthorizerWorld {
optional uint32 version = 1;
repeated string symbols = 2;
repeated PublicKey publicKeys = 3;
repeated SnapshotBlock blocks = 4;
required SnapshotBlock authorizerBlock = 5;
repeated Policy authorizerPolicies = 6;
repeated GeneratedFacts generatedFacts = 7;
required uint64 iterations = 8;
}

message Origin {
oneof Content {
Empty authorizer = 1;
uint32 origin = 2;
}
}

message Empty {}

message GeneratedFacts {
repeated Origin origins = 1;
repeated FactV2 facts = 2;
}

message SnapshotBlock {
optional string context = 1;
optional uint32 version = 2;
repeated FactV2 facts_v2 = 3;
repeated RuleV2 rules_v2 = 4;
repeated CheckV2 checks_v2 = 5;
repeated Scope scope = 6;
optional PublicKey externalKey = 7;
}
38 changes: 36 additions & 2 deletions src/main/java/com/clevercloud/biscuit/datalog/Check.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,30 @@
import java.util.List;
import java.util.Objects;

import static biscuit.format.schema.Schema.CheckV2.Kind.All;
import static biscuit.format.schema.Schema.CheckV2.Kind.One;
import static io.vavr.API.Left;
import static io.vavr.API.Right;

public class Check {
public enum Kind {
One,
All
}

private final Kind kind;

private final List<Rule> queries;

public Check(List<Rule> queries) {
public Check(Kind kind, List<Rule> queries) {
this.kind = kind;
this.queries = queries;
}

public Kind kind() {
return kind;
}

public List<Rule> queries() {
return queries;
}
Expand All @@ -40,6 +54,13 @@ public String toString() {
public Schema.CheckV2 serialize() {
Schema.CheckV2.Builder b = Schema.CheckV2.newBuilder();

// do not set the kind to One to keep compatibility with older library versions
switch (this.kind) {
case All:
b.setKind(All);
break;
}

for(int i = 0; i < this.queries.size(); i++) {
b.addQueries(this.queries.get(i).serialize());
}
Expand All @@ -50,6 +71,19 @@ public Schema.CheckV2 serialize() {
static public Either<Error.FormatError, Check> deserializeV2(Schema.CheckV2 check) {
ArrayList<Rule> queries = new ArrayList<>();

Kind kind;
switch (check.getKind()) {
case One:
kind = Kind.One;
break;
case All:
kind = Kind.All;
break;
default:
kind = Kind.One;
break;
}

for (Schema.RuleV2 query: check.getQueriesList()) {
Either<Error.FormatError, Rule> res = Rule.deserializeV2(query);
if(res.isLeft()) {
Expand All @@ -60,6 +94,6 @@ static public Either<Error.FormatError, Check> deserializeV2(Schema.CheckV2 chec
}
}

return Right(new Check(queries));
return Right(new Check(kind, queries));
}
}
22 changes: 6 additions & 16 deletions src/main/java/com/clevercloud/biscuit/datalog/Combinator.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
public final class Combinator implements Serializable {
private final MatchedVariables variables;
private final List<Predicate> next_predicates;
private final List<Expression> expressions;
private final Set<Fact> all_facts;
private final Predicate pred;
private final Iterator<Fact> fit;
Expand All @@ -25,15 +24,7 @@ public Option<MatchedVariables> next() {
this.current_it = null;
continue;
}

MatchedVariables next_vars = next_vars_opt.get();

final Option<Map<Long, Term>> v_opt = next_vars.check_expressions(this.expressions, symbols);
if(v_opt.isEmpty()) {
continue;
} else {
return Option.some(next_vars);
}
return next_vars_opt;
}

// we iterate over the facts that match the current predicate
Expand Down Expand Up @@ -67,7 +58,7 @@ public Option<MatchedVariables> next() {

// there are no more predicates to check
if (next_predicates.isEmpty()) {
final Option<Map<Long, Term>> v_opt = vars.check_expressions(this.expressions, symbols);
final Option<Map<Long, Term>> v_opt = vars.complete();
if(v_opt.isEmpty()) {
continue;
} else {
Expand All @@ -76,7 +67,7 @@ public Option<MatchedVariables> next() {
} else {
// we found a matching fact, we create a new combinator over the rest of the predicates
// no need to copy all of the expressions at all levels
this.current_it = new Combinator(vars, next_predicates, new ArrayList<>(), this.all_facts, this.symbols);
this.current_it = new Combinator(vars, next_predicates, this.all_facts, this.symbols);
}
} else {
break;
Expand All @@ -96,17 +87,16 @@ public List<Map<Long, Term>> combine() {
return variables;
}

Optional<Map<Long, Term>> vars = res.get().complete();
if(vars.isPresent()) {
Option<Map<Long, Term>> vars = res.get().complete();
if(vars.isDefined()) {
variables.add(vars.get());
}
}
}

public Combinator(final MatchedVariables variables, final List<Predicate> predicates, final List<Expression> expressions,
public Combinator(final MatchedVariables variables, final List<Predicate> predicates,
final Set<Fact> all_facts, final SymbolTable symbols) {
this.variables = variables;
this.expressions = expressions;
this.all_facts = all_facts;
this.current_it = null;
this.pred = predicates.get(0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,16 @@ public boolean is_complete() {
return this.variables.values().stream().allMatch((v) -> v.isPresent());
}

public Optional<Map<Long, Term>> complete() {
public Option<Map<Long, Term>> complete() {
final Map<Long, Term> variables = new HashMap<>();
for (final Map.Entry<Long, Optional<Term>> entry : this.variables.entrySet()) {
if (entry.getValue().isPresent()) {
variables.put(entry.getKey(), entry.getValue().get());
} else {
return Optional.empty();
return Option.none();
}
}
return Optional.of(variables);
return Option.some(variables);
}

public MatchedVariables clone() {
Expand All @@ -57,8 +57,8 @@ public MatchedVariables(final Set<Long> ids) {
}

public Option<Map<Long, Term>> check_expressions(List<Expression> expressions, SymbolTable symbols) {
final Optional<Map<Long, Term>> vars = this.complete();
if (vars.isPresent()) {
final Option<Map<Long, Term>> vars = this.complete();
if (vars.isDefined()) {
Map<Long, Term> variables = vars.get();

for(Expression e: expressions) {
Expand Down
Loading
Loading