<commit_before>package revocation

import (
	"bytes"
	"crypto/rand"
	"crypto/sha256"
	"fmt"
	"math"
	"sync"

	"github.com/btcsuite/btcd/wire"
	"github.com/btcsuite/fastsha256"
)

const (
	maxIndex = 1<<64 - 1
)

// chainFragment...
type chainBranch struct {
	index uint64
	hash  [32]byte
}

// HyperShaChain...
// * https://github.com/rustyrussell/ccan/blob/master/ccan/crypto/shachain/design.txt
type HyperShaChain struct {
	sync.RWMutex

	lastChainIndex uint64
	numValid       uint64

	chainBranches [64]chainBranch

	lastHash wire.ShaHash
}

// NewHyperShaChain
//  * used to track their pre-images
func NewHyperShaChain() *HyperShaChain {
	return &HyperShaChain{lastChainIndex: 0, numValid: 0}
}

// NewHyperShaChainFromSeed...
//  * used to derive your own pre-images
func NewHyperShaChainFromSeed(seed *[32]byte, deriveTo uint64) (*HyperShaChain, error) {
	var shaSeed [32]byte

	// If no seed is specified, generate a new one.
	if seed == nil {
		_, err := rand.Read(shaSeed[:])
		if err != nil {
			return nil, err
		}
	} else {
		shaSeed = *seed
	}

	// The last possible value in the chain is our starting index.
	start := uint64(maxIndex)
	stop := deriveTo

	curHash := derive(start, stop, shaSeed)

	// TODO(roasbeef): from/to or static size?
	return &HyperShaChain{lastChainIndex: deriveTo, lastHash: curHash}, nil
}

// derive...
func derive(from, to uint64, startingHash [32]byte) [32]byte {
	nextHash := startingHash

	numBranches := from ^ to
	toDerive := uint64(math.Log2(float64(numBranches))) // uh.....
	// math? floats? nahhh! :) bit-flipp-y way to do it:
	for toDerive = 0; numBranches>>toDerive > 0; toDerive++ {
	}
	// ^^^this rounds up instead of down, may be off by 1?
	toDerive-- // needed?

	for i := int(toDerive - 1); i >= 0; i-- {
		if (numBranches>>uint(i))&1 == 1 {
			// Flip the ith bit, then hash the current state to
			// advance down the tree.
			nextHash[i/8] ^= (1 << (uint(i) % 8))
			nextHash = sha256.Sum256(nextHash[:])<commit_msg>revocation: switch to tadge's bit-shifting to figure out log2 instead of using math<commit_after>package revocation

import (
	"bytes"
	"crypto/rand"
	"crypto/sha256"
	"fmt"
	"sync"

	"github.com/btcsuite/btcd/wire"
	"github.com/btcsuite/fastsha256"
)

const (
	maxIndex = 1<<64 - 1
)

// chainFragment...
type chainBranch struct {
	index uint64
	hash  [32]byte
}

// HyperShaChain...
// * https://github.com/rustyrussell/ccan/blob/master/ccan/crypto/shachain/design.txt
type HyperShaChain struct {
	sync.RWMutex

	lastChainIndex uint64
	numValid       uint64

	chainBranches [64]chainBranch

	lastHash wire.ShaHash
}

// NewHyperShaChain
//  * used to track their pre-images
func NewHyperShaChain() *HyperShaChain {
	return &HyperShaChain{lastChainIndex: 0, numValid: 0}
}

// NewHyperShaChainFromSeed...
//  * used to derive your own pre-images
func NewHyperShaChainFromSeed(seed *[32]byte, deriveTo uint64) (*HyperShaChain, error) {
	var shaSeed [32]byte

	// If no seed is specified, generate a new one.
	if seed == nil {
		_, err := rand.Read(shaSeed[:])
		if err != nil {
			return nil, err
		}
	} else {
		shaSeed = *seed
	}

	// The last possible value in the chain is our starting index.
	start := uint64(maxIndex)
	stop := deriveTo

	curHash := derive(start, stop, shaSeed)

	// TODO(roasbeef): from/to or static size?
	return &HyperShaChain{lastChainIndex: deriveTo, lastHash: curHash}, nil
}

// derive...
func derive(from, to uint64, startingHash [32]byte) [32]byte {
	nextHash := startingHash

	numBranches := from ^ to

	// The number of branches we need to derive is log2(numBranches)
	toDerive := 0
	for ; numBranches>>uint(toDerive) > 0; toDerive++ {
	}
	toDerive-- // needed?

	for i := int(toDerive - 1); i >= 0; i-- {
		if (numBranches>>uint(i))&1 == 1 {
			// Flip the ith bit, then hash the current state to
			// advance down the tree.
			nextHash[i/8] ^= (1 << (uint(i) % 8))
			nextHash = sha256.Sum256(nextHash[:])
{'fraction_non_alphanumeric': 0.13808065339458908, 'fraction_numerical': 0.02807554874936192, 'mean_word_length': 3.5201845444059976, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 15, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3705744', 'n_tokens_mistral': 1582, 'n_tokens_neox': 1447, 'n_words': 386}