diff --git a/merkletree/pad.go b/merkletree/pad.go index 02d8d9b..bb31951 100644 --- a/merkletree/pad.go +++ b/merkletree/pad.go @@ -26,7 +26,7 @@ type PAD struct { // NewPAD creates new PAD consisting of an array of hash chain // indexed by the epoch and its maximum length is len -func NewPAD(policies Policies, signKey sign.PrivateKey, len uint64) (*PAD, error) { +func NewPAD(policies *Policies, signKey sign.PrivateKey, len uint64) (*PAD, error) { if policies == nil { panic(ErrorNilPolicies) } @@ -37,15 +37,14 @@ func NewPAD(policies Policies, signKey sign.PrivateKey, len uint64) (*PAD, error if err != nil { return nil, err } - pad.policies = policies + pad.policies = *policies pad.snapshots = make(map[uint64]*SignedTreeRoot, len) pad.loadedEpochs = make([]uint64, 0, len) pad.updateInternal(nil, 0) return pad, nil } -// if policies is nil, the previous policies will be used -func (pad *PAD) signTreeRoot(m *MerkleTree, epoch uint64) { +func (pad *PAD) signTreeRoot(epoch uint64) { var prevHash []byte if pad.latestSTR == nil { var err error @@ -57,30 +56,29 @@ func (pad *PAD) signTreeRoot(m *MerkleTree, epoch uint64) { } else { prevHash = crypto.Digest(pad.latestSTR.Signature) } + pad.tree.recomputeHash() + m := pad.tree.Clone() pad.latestSTR = NewSTR(pad.signKey, pad.policies, m, epoch, prevHash) } -func (pad *PAD) updateInternal(policies Policies, epoch uint64) { - pad.tree.recomputeHash() - m := pad.tree.Clone() +func (pad *PAD) updateInternal(policies *Policies, epoch uint64) { // create STR with the policies that were actually used in the prev. // Set() operation - pad.signTreeRoot(m, epoch) + pad.signTreeRoot(epoch) pad.snapshots[epoch] = pad.latestSTR pad.loadedEpochs = append(pad.loadedEpochs, epoch) - if policies != nil { // update the policies if necessary vrfKeyChanged := 1 != subtle.ConstantTimeCompare( - pad.policies.vrfPrivate(), - policies.vrfPrivate()) - pad.policies = policies + pad.policies.vrfPrivateKey, + policies.vrfPrivateKey) + pad.policies = *policies if vrfKeyChanged { pad.reshuffle() } } } -func (pad *PAD) Update(policies Policies) { +func (pad *PAD) Update(policies *Policies) { // delete older str(s) as needed if len(pad.loadedEpochs) == cap(pad.loadedEpochs) { n := cap(pad.loadedEpochs) / 2 @@ -89,12 +87,11 @@ func (pad *PAD) Update(policies Policies) { } pad.loadedEpochs = append(pad.loadedEpochs[:0], pad.loadedEpochs[n:]...) } - pad.updateInternal(policies, pad.latestSTR.Epoch+1) } func (pad *PAD) Set(name string, value []byte) error { - index, _ := pad.computePrivateIndex(name, pad.policies.vrfPrivate()) + index, _ := pad.computePrivateIndex(name, pad.policies.vrfPrivateKey) return pad.tree.Set(index, name, value) } @@ -107,7 +104,7 @@ func (pad *PAD) LookupInEpoch(name string, epoch uint64) (*AuthenticationPath, e if str == nil { return nil, ErrorSTRNotFound } - lookupIndex, proof := pad.computePrivateIndex(name, str.Policies.vrfPrivate()) + lookupIndex, proof := pad.computePrivateIndex(name, str.Policies.vrfPrivateKey) ap := str.tree.Get(lookupIndex) ap.VrfProof = proof return ap, nil @@ -125,7 +122,7 @@ func (pad *PAD) LatestSTR() *SignedTreeRoot { } func (pad *PAD) TB(name string, value []byte) (*TemporaryBinding, error) { - index, _ := pad.computePrivateIndex(name, pad.policies.vrfPrivate()) + index, _ := pad.computePrivateIndex(name, pad.policies.vrfPrivateKey) tb := NewTB(pad.signKey, pad.latestSTR.Signature, index, value) err := pad.tree.Set(index, name, value) return tb, err @@ -142,7 +139,7 @@ func (pad *PAD) reshuffle() { panic(err) } pad.tree.visitLeafNodes(func(n *userLeafNode) { - newIndex, _ := pad.computePrivateIndex(n.key, pad.policies.vrfPrivate()) + newIndex, _ := pad.computePrivateIndex(n.key, pad.policies.vrfPrivateKey) if err := newTree.Set(newIndex, n.key, n.value); err != nil { panic(err) } diff --git a/merkletree/policy.go b/merkletree/policy.go index 36b8713..d119a9f 100644 --- a/merkletree/policy.go +++ b/merkletree/policy.go @@ -8,55 +8,35 @@ import ( type TimeStamp uint64 -type Policies interface { - EpDeadline() TimeStamp - Serialize() []byte - vrfPrivate() vrf.PrivateKey -} - -type ConiksPolicies struct { +type Policies struct { LibVersion string HashID string vrfPrivateKey vrf.PrivateKey - VrfPubKey []byte + VrfPublicKey vrf.PublicKey EpochDeadline TimeStamp } -var _ Policies = (*ConiksPolicies)(nil) - -func NewPolicies(epDeadline TimeStamp, vrfPrivKey vrf.PrivateKey) Policies { +func NewPolicies(epDeadline TimeStamp, vrfPrivKey vrf.PrivateKey) *Policies { vrfPublicKey, ok := vrfPrivKey.Public() if !ok { panic(vrf.ErrorGetPubKey) } - return &ConiksPolicies{ + return &Policies{ LibVersion: Version, HashID: crypto.HashID, vrfPrivateKey: vrfPrivKey, - VrfPubKey: vrfPublicKey, + VrfPublicKey: vrfPublicKey, EpochDeadline: epDeadline, } } // Serialize encodes the policy to a byte array with the following format: // [lib version, cryptographic algorithm in use, epoch deadline, vrf public key] -func (p *ConiksPolicies) Serialize() []byte { - vrfPublicKey, ok := p.vrfPrivateKey.Public() - if !ok { - panic(vrf.ErrorGetPubKey) - } +func (p *Policies) Serialize() []byte { var bs []byte bs = append(bs, []byte(p.LibVersion)...) // lib Version bs = append(bs, []byte(p.HashID)...) // cryptographic algorithms in use bs = append(bs, util.ULongToBytes(uint64(p.EpochDeadline))...) // epoch deadline - bs = append(bs, vrfPublicKey...) // vrf public key + bs = append(bs, p.VrfPublicKey...) // vrf public key return bs } - -func (p *ConiksPolicies) vrfPrivate() vrf.PrivateKey { - return p.vrfPrivateKey -} - -func (p *ConiksPolicies) EpDeadline() TimeStamp { - return p.EpochDeadline -} diff --git a/protocol/directory.go b/protocol/directory.go index 3cf7684..63f13c2 100644 --- a/protocol/directory.go +++ b/protocol/directory.go @@ -12,7 +12,7 @@ type ConiksDirectory struct { pad *merkletree.PAD useTBs bool tbs map[string]*merkletree.TemporaryBinding - policies merkletree.Policies + policies *merkletree.Policies } func InitDirectory(epDeadline merkletree.TimeStamp, vrfKey vrf.PrivateKey, @@ -44,7 +44,7 @@ func (d *ConiksDirectory) SetPolicies(epDeadline merkletree.TimeStamp, vrfKey vr } func (d *ConiksDirectory) EpochDeadline() merkletree.TimeStamp { - return d.pad.LatestSTR().Policies.EpDeadline() + return d.pad.LatestSTR().Policies.EpochDeadline } func (d *ConiksDirectory) LatestSTR() *merkletree.SignedTreeRoot { diff --git a/protocol/directory_test.go b/protocol/directory_test.go index 1f37c47..07a259d 100644 --- a/protocol/directory_test.go +++ b/protocol/directory_test.go @@ -316,3 +316,34 @@ func TestHandleOps(t *testing.T) { t.Fatal("Expect error", ErrorMalformedClientMessage, "got", err) } } + +func TestPoliciesChanges(t *testing.T) { + d := newDirectory(t, false) + if p := d.LatestSTR().Policies.EpochDeadline; p != 1 { + t.Fatal("Unexpected policies", "want", 1, "got", p) + } + + // change the policies + vrfKey, err := vrf.GenerateKey(nil) + if err != nil { + t.Fatal(err) + } + d.SetPolicies(2, vrfKey) + d.Update() + // expect the policies doesn't change yet + if p := d.LatestSTR().Policies.EpochDeadline; p != 1 { + t.Fatal("Unexpected policies", "want", 1, "got", p) + } + + d.Update() + // expect the new policies + if p := d.LatestSTR().Policies.EpochDeadline; p != 2 { + t.Fatal("Unexpected policies", "want", 2, "got", p) + } + p0 := d.pad.GetSTR(0).Policies.EpochDeadline + p1 := d.pad.GetSTR(1).Policies.EpochDeadline + p2 := d.pad.GetSTR(2).Policies.EpochDeadline + if p0 != 1 || p1 != 1 || p2 != 2 { + t.Fatal("Maybe the STR's policies were malformed") + } +}