diff --git a/blake3.go b/blake3.go index f7ad010..d25d9d6 100644 --- a/blake3.go +++ b/blake3.go @@ -246,19 +246,6 @@ func New(size int, key []byte) *Hasher { return newHasher(keyWords, flagKeyedHash, size) } -// NewFromDerivedKey returns a Hasher whose key was derived from the supplied -// context string. -func NewFromDerivedKey(size int, ctx string) *Hasher { - const derivedKeyLen = 32 - h := newHasher(iv, flagDeriveKeyContext, derivedKeyLen) - h.Write([]byte(ctx)) - key := make([]byte, derivedKeyLen) - h.Sum(key[:0]) - var keyWords [8]uint32 - bytesToWords(key, keyWords[:]) - return newHasher(keyWords, flagDeriveKeyMaterial, size) -} - func (h *Hasher) addChunkChainingValue(cv [8]uint32, totalChunks uint64) { // This chunk might complete some subtrees. For each completed subtree, // its left child will be the current top entry in the CV stack, and @@ -356,6 +343,20 @@ func Sum512(b []byte) [64]byte { return out } +// DeriveKey derives a subkey from ctx and srcKey. +func DeriveKey(subKey []byte, ctx string, srcKey []byte) { + // construct the derivation Hasher + const derivationIVLen = 32 + h := newHasher(iv, flagDeriveKeyContext, 32) + h.Write([]byte(ctx)) + var derivationIV [8]uint32 + bytesToWords(h.Sum(make([]byte, 0, derivationIVLen)), derivationIV[:]) + h = newHasher(derivationIV, flagDeriveKeyMaterial, len(subKey)) + // derive the subKey + h.Write(srcKey) + h.Sum(subKey[:0]) +} + // ensure that Hasher implements hash.Hash var _ hash.Hash = (*Hasher)(nil) diff --git a/blake3_test.go b/blake3_test.go index a4a74cb..c727502 100644 --- a/blake3_test.go +++ b/blake3_test.go @@ -52,10 +52,10 @@ func TestVectors(t *testing.T) { } // derive key const ctx = "BLAKE3 2019-12-27 16:29:52 test vectors context" - h = blake3.NewFromDerivedKey(len(vec.DeriveKey)/2, ctx) - h.Write(in) - if out := toHex(h.Sum(nil)); out != vec.DeriveKey { - t.Errorf("output did not match test vector:\n\texpected: %v...\n\t got: %v...", vec.DeriveKey[:10], out[:10]) + subKey := make([]byte, len(vec.DeriveKey)/2) + blake3.DeriveKey(subKey, ctx, in) + if out := toHex(subKey); out != vec.DeriveKey { + t.Errorf("output did not match test vector:\n\texpected: %v...\n\t got: %v...", vec.DeriveKey[:10], subKey[:10]) } // XOF should produce identical results, even when outputting 7 bytes at a time h = blake3.New(len(vec.Hash)/2, nil)