Skip to content

Commit

Permalink
move GetBlockID on Biscuit (#34)
Browse files Browse the repository at this point in the history
This aims to reduce confusion on GetBlockID usage, mostly on lack of support
for generated facts lookup.

Exposing GetBlockID on verifier is not the best approach as the verifier
is expected to run the world and work with generated facts from rules.
Instead, it makes more sense to have it on the biscuit, as a way to
lookup facts in the biscuit blocks.
  • Loading branch information
daeMOn63 committed Nov 24, 2020
1 parent ec6a56b commit 874839f
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 111 deletions.
27 changes: 27 additions & 0 deletions biscuit.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,33 @@ func (b *Biscuit) Serialize() ([]byte, error) {
return proto.Marshal(b.container)
}

var ErrFactNotFound = errors.New("biscuit: fact not found")

// GetBlockID returns the first block index containing a fact
// starting from the authority block and then each block in the order they were added.
// ErrFactNotFound is returned when no block contains the fact.
func (b *Biscuit) GetBlockID(fact Fact) (int, error) {
// don't store symbols from searched fact in the verifier table
symbols := b.symbols.Clone()
datalogFact := fact.Predicate.convert(symbols)

for _, f := range *b.authority.facts {
if f.Equal(datalogFact) {
return 0, nil
}
}

for i, b := range b.blocks {
for _, f := range *b.facts {
if f.Equal(datalogFact) {
return i + 1, nil
}
}
}

return 0, ErrFactNotFound
}

// SHA256Sum returns a hash of `count` biscuit blocks + the authority block
// along with their respective keys.
func (b *Biscuit) SHA256Sum(count int) ([]byte, error) {
Expand Down
71 changes: 71 additions & 0 deletions biscuit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -531,3 +531,74 @@ func TestBiscuitSha256Sum(t *testing.T) {
require.NoError(t, err)
require.NotEmpty(t, h22)
}

func TestGetBlockID(t *testing.T) {
rng := rand.Reader
root := sig.GenerateKeypair(rng)
builder := NewBuilder(root)

// add 3 facts authority_0_fact_{0,1,2} in authority block
for i := 0; i < 3; i++ {
require.NoError(t, builder.AddAuthorityFact(Fact{Predicate: Predicate{
Name: fmt.Sprintf("authority_0_fact_%d", i),
IDs: []Atom{Integer(i)},
}}))
}

b, err := builder.Build()
require.NoError(t, err)
// add 2 extra blocks each containing 3 facts block_{0,1}_fact_{0,1,2}
for i := 0; i < 2; i++ {
blockBuilder := b.CreateBlock()
for j := 0; j < 3; j++ {
blockBuilder.AddFact(Fact{Predicate: Predicate{
Name: fmt.Sprintf("block_%d_fact_%d", i, j),
IDs: []Atom{Symbol("block"), Integer(i), Integer(j)},
}})
}
b, err = b.Append(rng, sig.GenerateKeypair(rng), blockBuilder.Build())
require.NoError(t, err)
}

idx, err := b.GetBlockID(Fact{Predicate{
Name: "authority_0_fact_0",
IDs: []Atom{Symbol("authority"), Integer(0)},
}})
require.NoError(t, err)
require.Equal(t, 0, idx)
idx, err = b.GetBlockID(Fact{Predicate{
Name: "authority_0_fact_2",
IDs: []Atom{Symbol("authority"), Integer(2)},
}})
require.NoError(t, err)
require.Equal(t, 0, idx)

idx, err = b.GetBlockID(Fact{Predicate{
Name: "block_0_fact_2",
IDs: []Atom{Symbol("block"), Integer(0), Integer(2)},
}})
require.NoError(t, err)
require.Equal(t, 1, idx)
idx, err = b.GetBlockID(Fact{Predicate{
Name: "block_1_fact_1",
IDs: []Atom{Symbol("block"), Integer(1), Integer(1)},
}})
require.NoError(t, err)
require.Equal(t, 2, idx)

_, err = b.GetBlockID(Fact{Predicate{
Name: "block_1_fact_3",
IDs: []Atom{Symbol("block"), Integer(1), Integer(3)},
}})
require.Equal(t, ErrFactNotFound, err)
_, err = b.GetBlockID(Fact{Predicate{
Name: "block_2_fact_1",
IDs: []Atom{Symbol("block"), Integer(2), Integer(1)},
}})
require.Equal(t, ErrFactNotFound, err)
_, err = b.GetBlockID(Fact{Predicate{
Name: "block_1_fact_1",
IDs: []Atom{Integer(1), Integer(1)},
}})
require.Equal(t, ErrFactNotFound, err)
}
2 changes: 1 addition & 1 deletion experiments/pop_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ func verifySignature(t *testing.T, rootPubKey sig.PublicKey, b []byte) {
require.True(t, ok)

// retrieve the block index containing user signature
blockIdx, err := verifier.GetBlockID(biscuit.Fact{Predicate: biscuit.Predicate{
blockIdx, err := verifier.Biscuit().GetBlockID(biscuit.Fact{Predicate: biscuit.Predicate{
Name: "signature",
IDs: []biscuit.Atom{dataID, pubkey, signature, signerNonce, signerTimestamp},
}})
Expand Down
29 changes: 3 additions & 26 deletions verifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (

var (
ErrMissingSymbols = errors.New("biscuit: missing symbols")
ErrFactNotFound = errors.New("biscuit: fact not found")
)

type Verifier interface {
Expand All @@ -19,7 +18,7 @@ type Verifier interface {
AddCaveat(caveat Caveat)
Verify() error
Query(rule Rule) (FactSet, error)
GetBlockID(fact Fact) (int, error)
Biscuit() *Biscuit
Reset()
PrintWorld() string
}
Expand Down Expand Up @@ -140,30 +139,8 @@ func (v *verifier) Query(rule Rule) (FactSet, error) {
return result, nil
}

// GetBlockID returns the first block index containing a fact
// starting from the authority block and then each block in order they were added.
// Note that facts generated from rules can't be searched.
// ErrFactNotFound is returned when no matching fact is found.
func (v *verifier) GetBlockID(fact Fact) (int, error) {
// don't store symbols from searched fact in the verifier table
symbols := v.symbols.Clone()
datalogFact := fact.Predicate.convert(symbols)

for _, f := range *v.biscuit.authority.facts {
if f.Equal(datalogFact) {
return 0, nil
}
}

for i, b := range v.biscuit.blocks {
for _, f := range *b.facts {
if f.Equal(datalogFact) {
return i + 1, nil
}
}
}

return 0, ErrFactNotFound
func (v *verifier) Biscuit() *Biscuit {
return v.biscuit
}

func (v *verifier) PrintWorld() string {
Expand Down
84 changes: 0 additions & 84 deletions verifier_test.go

This file was deleted.

0 comments on commit 874839f

Please sign in to comment.